markdown.rs

 1use anyhow::Result;
 2use gpui::{div, prelude::*, ClipboardItem, Task, ViewContext, WindowContext};
 3use markdown_preview::{
 4    markdown_elements::ParsedMarkdown, markdown_parser::parse_markdown,
 5    markdown_renderer::render_markdown_block,
 6};
 7use ui::v_flex;
 8
 9use crate::outputs::SupportsClipboard;
10
11pub struct MarkdownView {
12    raw_text: String,
13    contents: Option<ParsedMarkdown>,
14    parsing_markdown_task: Option<Task<Result<()>>>,
15}
16
17impl MarkdownView {
18    pub fn from(text: String, cx: &mut ViewContext<Self>) -> Self {
19        let task = cx.spawn(|markdown_view, mut cx| {
20            let text = text.clone();
21            let parsed = cx
22                .background_executor()
23                .spawn(async move { parse_markdown(&text, None, None).await });
24
25            async move {
26                let content = parsed.await;
27
28                markdown_view.update(&mut cx, |markdown, cx| {
29                    markdown.parsing_markdown_task.take();
30                    markdown.contents = Some(content);
31                    cx.notify();
32                })
33            }
34        });
35
36        Self {
37            raw_text: text.clone(),
38            contents: None,
39            parsing_markdown_task: Some(task),
40        }
41    }
42}
43
44impl SupportsClipboard for MarkdownView {
45    fn clipboard_content(&self, _cx: &WindowContext) -> Option<ClipboardItem> {
46        Some(ClipboardItem::new_string(self.raw_text.clone()))
47    }
48
49    fn has_clipboard_content(&self, _cx: &WindowContext) -> bool {
50        true
51    }
52}
53
54impl Render for MarkdownView {
55    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
56        let Some(parsed) = self.contents.as_ref() else {
57            return div().into_any_element();
58        };
59
60        let mut markdown_render_context =
61            markdown_preview::markdown_renderer::RenderContext::new(None, cx);
62
63        v_flex()
64            .gap_3()
65            .py_4()
66            .children(parsed.children.iter().map(|child| {
67                div().relative().child(
68                    div()
69                        .relative()
70                        .child(render_markdown_block(child, &mut markdown_render_context)),
71                )
72            }))
73            .into_any_element()
74    }
75}