diff --git a/Cargo.lock b/Cargo.lock index a54d895434..6fc2b73d23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9563,7 +9563,6 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" name = "markdown" version = "0.1.0" dependencies = [ - "anyhow", "assets", "base64 0.22.1", "env_logger 0.11.8", diff --git a/crates/editor/src/code_context_menus.rs b/crates/editor/src/code_context_menus.rs index c28f788ec8..6664a38271 100644 --- a/crates/editor/src/code_context_menus.rs +++ b/crates/editor/src/code_context_menus.rs @@ -646,7 +646,7 @@ impl CompletionsMenu { } => div().child(text.clone()), CompletionDocumentation::MultiLineMarkdown(parsed) if !parsed.is_empty() => { let markdown = self.markdown_element.get_or_insert_with(|| { - cx.new(|cx| { + let markdown = cx.new(|cx| { let languages = editor .workspace .as_ref() @@ -656,11 +656,19 @@ impl CompletionsMenu { .language_at(self.initial_position, cx) .map(|l| l.name().to_proto()); Markdown::new(SharedString::default(), languages, language, cx) - }) + }); + // Handles redraw when the markdown is done parsing. The current render is for a + // deferred draw and so was not getting redrawn when `markdown` notified. + cx.observe(&markdown, |_, _, cx| cx.notify()).detach(); + markdown }); - markdown.update(cx, |markdown, cx| { + let is_parsing = markdown.update(cx, |markdown, cx| { markdown.reset(parsed.clone(), cx); + markdown.is_parsing() }); + if is_parsing { + return None; + } div().child( MarkdownElement::new(markdown.clone(), hover_markdown_style(window, cx)) .code_block_renderer(markdown::CodeBlockRenderer::Default { diff --git a/crates/markdown/Cargo.toml b/crates/markdown/Cargo.toml index e925d6c4a5..b899cfe795 100644 --- a/crates/markdown/Cargo.toml +++ b/crates/markdown/Cargo.toml @@ -19,7 +19,6 @@ test-support = [ ] [dependencies] -anyhow.workspace = true base64.workspace = true gpui.workspace = true language.workspace = true diff --git a/crates/markdown/src/markdown.rs b/crates/markdown/src/markdown.rs index 72442dcc8c..455df3ef0d 100644 --- a/crates/markdown/src/markdown.rs +++ b/crates/markdown/src/markdown.rs @@ -30,7 +30,7 @@ use pulldown_cmark::Alignment; use sum_tree::TreeMap; use theme::SyntaxTheme; use ui::{Tooltip, prelude::*}; -use util::{ResultExt, TryFutureExt}; +use util::ResultExt; use crate::parser::CodeBlockKind; @@ -98,7 +98,7 @@ pub struct Markdown { parsed_markdown: ParsedMarkdown, images_by_source_offset: HashMap>, should_reparse: bool, - pending_parse: Option>>, + pending_parse: Option>, focus_handle: FocusHandle, language_registry: Option>, fallback_code_block_language: Option, @@ -192,6 +192,10 @@ impl Markdown { this } + pub fn is_parsing(&self) -> bool { + self.pending_parse.is_some() + } + pub fn source(&self) -> &str { &self.source } @@ -219,6 +223,7 @@ impl Markdown { self.parse(cx); } + #[cfg(feature = "test-support")] pub fn parsed_markdown(&self) -> &ParsedMarkdown { &self.parsed_markdown } @@ -275,14 +280,19 @@ impl Markdown { self.should_reparse = true; return; } + self.should_reparse = false; + self.pending_parse = Some(self.start_background_parse(cx)); + } + fn start_background_parse(&self, cx: &Context) -> Task<()> { let source = self.source.clone(); let should_parse_links_only = self.options.parse_links_only; let language_registry = self.language_registry.clone(); let fallback = self.fallback_code_block_language.clone(); + let parsed = cx.background_spawn(async move { if should_parse_links_only { - return anyhow::Ok(( + return ( ParsedMarkdown { events: Arc::from(parse_links_only(source.as_ref())), source, @@ -290,8 +300,9 @@ impl Markdown { languages_by_path: TreeMap::default(), }, Default::default(), - )); + ); } + let (events, language_names, paths) = parse_markdown(&source); let mut images_by_source_offset = HashMap::default(); let mut languages_by_name = TreeMap::default(); @@ -343,7 +354,7 @@ impl Markdown { } } - anyhow::Ok(( + ( ParsedMarkdown { source, events: Arc::from(events), @@ -351,29 +362,23 @@ impl Markdown { languages_by_path, }, images_by_source_offset, - )) + ) }); - self.should_reparse = false; - self.pending_parse = Some(cx.spawn(async move |this, cx| { - async move { - let (parsed, images_by_source_offset) = parsed.await?; + cx.spawn(async move |this, cx| { + let (parsed, images_by_source_offset) = parsed.await; - this.update(cx, |this, cx| { - this.parsed_markdown = parsed; - this.images_by_source_offset = images_by_source_offset; - this.pending_parse.take(); - if this.should_reparse { - this.parse(cx); - } - cx.notify(); - }) - .ok(); - anyhow::Ok(()) - } - .log_err() - .await - })); + this.update(cx, |this, cx| { + this.parsed_markdown = parsed; + this.images_by_source_offset = images_by_source_offset; + this.pending_parse.take(); + if this.should_reparse { + this.parse(cx); + } + cx.refresh_windows(); + }) + .ok(); + }) } }