use gpui::Entity;
use markdown::{Markdown, MarkdownElement, MarkdownFont, MarkdownFontConfig, MarkdownStyle};
use crate::prelude::*;
pub fn agent_markdown_font_config(cx: &App) -> MarkdownFontConfig {
let settings = theme::theme_settings(cx);
let ui_font = settings.ui_font(cx).clone();
let buffer_font = settings.buffer_font(cx).clone();
let ui_font_size = settings.ui_font_size(cx);
let buffer_font_size = settings.buffer_font_size(cx);
MarkdownFontConfig {
ui_font_family: ui_font.family.clone(),
ui_font_fallbacks: ui_font.fallbacks.clone(),
ui_font_features: ui_font.features.clone(),
ui_font_size,
buffer_font_family: buffer_font.family.clone(),
buffer_font_fallbacks: buffer_font.fallbacks.clone(),
buffer_font_features: buffer_font.features.clone(),
buffer_font_weight: buffer_font.weight,
buffer_font_size,
agent_buffer_font_size: buffer_font_size,
agent_ui_font_size: ui_font_size,
markdown_preview_font_size: ui_font_size,
markdown_preview_font_family: ui_font.family,
markdown_preview_code_font_family: buffer_font.family,
}
}
pub fn agent_markdown_style(window: &Window, cx: &App) -> MarkdownStyle {
let fonts = agent_markdown_font_config(cx);
MarkdownStyle::themed(MarkdownFont::Agent, &fonts, window, cx)
}
pub fn agent_markdown_entity(text: impl Into<SharedString>, cx: &mut App) -> Entity<Markdown> {
cx.new(|cx| Markdown::new(text.into(), cx))
}
#[derive(IntoElement, RegisterComponent)]
pub struct AgentMarkdown {
id: ElementId,
markdown: Entity<Markdown>,
}
impl AgentMarkdown {
pub fn new(id: impl Into<ElementId>, markdown: Entity<Markdown>) -> Self {
Self {
id: id.into(),
markdown,
}
}
}
impl RenderOnce for AgentMarkdown {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let style = agent_markdown_style(window, cx);
div()
.id(self.id)
.w_full()
.child(MarkdownElement::new(self.markdown, style))
}
}
impl Component for AgentMarkdown {
fn scope() -> ComponentScope {
ComponentScope::Agent
}
fn description() -> Option<&'static str> {
Some(
"Renders a single agent chat message body as full CommonMark/GFM \
markdown (tables, footnotes, task lists, syntax-highlighted \
fenced code) via boltz-markdown, wrapping a caller-owned \
Entity<Markdown>.",
)
}
fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
let source = "# Heading One\n\n\
Some **bold** text with `inline code` and a [link](https://example.com).\n\n\
| Left | Right |\n|---|---|\n| a | b |\n\n\
- [x] Done item\n\
- [ ] Pending item\n\n\
1. Step one\n\
2. Step two\n\n\
```rust\nfn main() {\n println!(\"hi\");\n}\n```\n\n\
A footnote reference[^1].\n\n[^1]: The footnote body.";
let entity = agent_markdown_entity(source, cx);
Some(
v_flex()
.w_96()
.gap_4()
.child(single_example(
"Full document",
AgentMarkdown::new("am-preview-1", entity).into_any_element(),
))
.into_any_element(),
)
}
}