From e689c8c01b2b04e076242e0748a4033fbe81730e Mon Sep 17 00:00:00 2001 From: Stanislav Alekseev <43210583+WeetHet@users.noreply.github.com> Date: Fri, 7 Feb 2025 04:37:50 +0200 Subject: [PATCH] markdown: Use parsed text (#24388) Fixes #15463 Release Notes: - Fixed display of symbols such as ` ` in hover popovers --- crates/editor/src/hover_popover.rs | 8 ++-- crates/markdown/examples/markdown_as_child.rs | 1 - crates/markdown/src/markdown.rs | 14 ++----- crates/markdown/src/parser.rs | 41 ++++++++++++++----- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index dd37c34afe..128ee45341 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -598,7 +598,7 @@ async fn parse_blocks( }, syntax: cx.theme().syntax().clone(), selection_background_color: { cx.theme().players().local().selection }, - break_style: Default::default(), + heading: StyleRefinement::default() .font_weight(FontWeight::BOLD) .text_base() @@ -885,8 +885,10 @@ mod tests { let slice = data; for (range, event) in slice.iter() { - if [MarkdownEvent::Text, MarkdownEvent::Code].contains(event) { - rendered_text.push_str(&text[range.clone()]) + match event { + MarkdownEvent::Text(parsed) => rendered_text.push_str(parsed), + MarkdownEvent::Code => rendered_text.push_str(&text[range.clone()]), + _ => {} } } } diff --git a/crates/markdown/examples/markdown_as_child.rs b/crates/markdown/examples/markdown_as_child.rs index e2a919ae51..5aa543a4fc 100644 --- a/crates/markdown/examples/markdown_as_child.rs +++ b/crates/markdown/examples/markdown_as_child.rs @@ -83,7 +83,6 @@ pub fn main() { selection.fade_out(0.7); selection }, - break_style: Default::default(), heading: Default::default(), }; let markdown = cx.new(|cx| { diff --git a/crates/markdown/src/markdown.rs b/crates/markdown/src/markdown.rs index cc525e4b59..d6190c43db 100644 --- a/crates/markdown/src/markdown.rs +++ b/crates/markdown/src/markdown.rs @@ -28,7 +28,6 @@ pub struct MarkdownStyle { pub block_quote_border_color: Hsla, pub syntax: Arc, pub selection_background_color: Hsla, - pub break_style: StyleRefinement, pub heading: StyleRefinement, } @@ -44,11 +43,11 @@ impl Default for MarkdownStyle { block_quote_border_color: Default::default(), syntax: Arc::new(SyntaxTheme::default()), selection_background_color: Default::default(), - break_style: Default::default(), heading: Default::default(), } } } + pub struct Markdown { source: String, selection: Selection, @@ -751,8 +750,8 @@ impl Element for MarkdownElement { } _ => log::error!("unsupported markdown tag end: {:?}", tag), }, - MarkdownEvent::Text => { - builder.push_text(&parsed_markdown.source[range.clone()], range.start); + MarkdownEvent::Text(parsed) => { + builder.push_text(parsed, range.start); } MarkdownEvent::Code => { builder.push_text_style(self.style.inline_code.clone()); @@ -777,12 +776,7 @@ impl Element for MarkdownElement { builder.pop_div() } MarkdownEvent::SoftBreak => builder.push_text(" ", range.start), - MarkdownEvent::HardBreak => { - let mut d = div().py_3(); - d.style().refine(&self.style.break_style); - builder.push_div(d, range, markdown_end); - builder.pop_div() - } + MarkdownEvent::HardBreak => builder.push_text("\n", range.start), _ => log::error!("unsupported markdown event {:?}", event), } } diff --git a/crates/markdown/src/parser.rs b/crates/markdown/src/parser.rs index b605a35af5..9e69f3192e 100644 --- a/crates/markdown/src/parser.rs +++ b/crates/markdown/src/parser.rs @@ -37,9 +37,10 @@ pub fn parse_markdown(text: &str) -> Vec<(Range, MarkdownEvent)> { } events.push((range, MarkdownEvent::End(tag))); } - pulldown_cmark::Event::Text(_) => { + pulldown_cmark::Event::Text(parsed) => { // Automatically detect links in text if we're not already within a markdown // link. + let mut parsed = parsed.as_ref(); if !within_link { let mut finder = LinkFinder::new(); finder.kinds(&[linkify::LinkKind::Url]); @@ -49,7 +50,12 @@ pub fn parse_markdown(text: &str) -> Vec<(Range, MarkdownEvent)> { text_range.start + link.start()..text_range.start + link.end(); if link_range.start > range.start { - events.push((range.start..link_range.start, MarkdownEvent::Text)); + let (text, tail) = parsed.split_at(link_range.start - range.start); + events.push(( + range.start..link_range.start, + MarkdownEvent::Text(SharedString::new(text)), + )); + parsed = tail; } events.push(( @@ -61,15 +67,20 @@ pub fn parse_markdown(text: &str) -> Vec<(Range, MarkdownEvent)> { id: SharedString::default(), }), )); - events.push((link_range.clone(), MarkdownEvent::Text)); + + let (link_text, tail) = parsed.split_at(link_range.end - link_range.start); + events.push(( + link_range.clone(), + MarkdownEvent::Text(SharedString::new(link_text)), + )); events.push((link_range.clone(), MarkdownEvent::End(MarkdownTagEnd::Link))); range.start = link_range.end; + parsed = tail; } } - if range.start < range.end { - events.push((range, MarkdownEvent::Text)); + events.push((range, MarkdownEvent::Text(SharedString::new(parsed)))); } } pulldown_cmark::Event::Code(_) => { @@ -94,7 +105,7 @@ pub fn parse_markdown(text: &str) -> Vec<(Range, MarkdownEvent)> { events } -pub fn parse_links_only(text: &str) -> Vec<(Range, MarkdownEvent)> { +pub fn parse_links_only(mut text: &str) -> Vec<(Range, MarkdownEvent)> { let mut events = Vec::new(); let mut finder = LinkFinder::new(); finder.kinds(&[linkify::LinkKind::Url]); @@ -106,9 +117,15 @@ pub fn parse_links_only(text: &str) -> Vec<(Range, MarkdownEvent)> { let link_range = link.start()..link.end(); if link_range.start > text_range.start { - events.push((text_range.start..link_range.start, MarkdownEvent::Text)); + let (head, tail) = text.split_at(link_range.start - text_range.start); + events.push(( + text_range.start..link_range.start, + MarkdownEvent::Text(SharedString::new(head)), + )); + text = tail; } + let (link_text, tail) = text.split_at(link_range.end - link_range.start); events.push(( link_range.clone(), MarkdownEvent::Start(MarkdownTag::Link { @@ -118,14 +135,18 @@ pub fn parse_links_only(text: &str) -> Vec<(Range, MarkdownEvent)> { id: SharedString::default(), }), )); - events.push((link_range.clone(), MarkdownEvent::Text)); + events.push(( + link_range.clone(), + MarkdownEvent::Text(SharedString::new(link_text)), + )); events.push((link_range.clone(), MarkdownEvent::End(MarkdownTagEnd::Link))); text_range.start = link_range.end; + text = tail; } if text_range.end > text_range.start { - events.push((text_range, MarkdownEvent::Text)); + events.push((text_range, MarkdownEvent::Text(SharedString::new(text)))); } events @@ -142,7 +163,7 @@ pub enum MarkdownEvent { /// End of a tagged element. End(MarkdownTagEnd), /// A text node. - Text, + Text(SharedString), /// An inline code node. Code, /// An HTML node.