markdown: Use parsed text (#24388)

Fixes #15463

Release Notes:

- Fixed display of symbols such as ` ` in hover popovers
This commit is contained in:
Stanislav Alekseev 2025-02-07 04:37:50 +02:00 committed by GitHub
parent 888a2df3f0
commit e689c8c01b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 40 additions and 24 deletions

View file

@ -598,7 +598,7 @@ async fn parse_blocks(
}, },
syntax: cx.theme().syntax().clone(), syntax: cx.theme().syntax().clone(),
selection_background_color: { cx.theme().players().local().selection }, selection_background_color: { cx.theme().players().local().selection },
break_style: Default::default(),
heading: StyleRefinement::default() heading: StyleRefinement::default()
.font_weight(FontWeight::BOLD) .font_weight(FontWeight::BOLD)
.text_base() .text_base()
@ -885,8 +885,10 @@ mod tests {
let slice = data; let slice = data;
for (range, event) in slice.iter() { for (range, event) in slice.iter() {
if [MarkdownEvent::Text, MarkdownEvent::Code].contains(event) { match event {
rendered_text.push_str(&text[range.clone()]) MarkdownEvent::Text(parsed) => rendered_text.push_str(parsed),
MarkdownEvent::Code => rendered_text.push_str(&text[range.clone()]),
_ => {}
} }
} }
} }

View file

@ -83,7 +83,6 @@ pub fn main() {
selection.fade_out(0.7); selection.fade_out(0.7);
selection selection
}, },
break_style: Default::default(),
heading: Default::default(), heading: Default::default(),
}; };
let markdown = cx.new(|cx| { let markdown = cx.new(|cx| {

View file

@ -28,7 +28,6 @@ pub struct MarkdownStyle {
pub block_quote_border_color: Hsla, pub block_quote_border_color: Hsla,
pub syntax: Arc<SyntaxTheme>, pub syntax: Arc<SyntaxTheme>,
pub selection_background_color: Hsla, pub selection_background_color: Hsla,
pub break_style: StyleRefinement,
pub heading: StyleRefinement, pub heading: StyleRefinement,
} }
@ -44,11 +43,11 @@ impl Default for MarkdownStyle {
block_quote_border_color: Default::default(), block_quote_border_color: Default::default(),
syntax: Arc::new(SyntaxTheme::default()), syntax: Arc::new(SyntaxTheme::default()),
selection_background_color: Default::default(), selection_background_color: Default::default(),
break_style: Default::default(),
heading: Default::default(), heading: Default::default(),
} }
} }
} }
pub struct Markdown { pub struct Markdown {
source: String, source: String,
selection: Selection, selection: Selection,
@ -751,8 +750,8 @@ impl Element for MarkdownElement {
} }
_ => log::error!("unsupported markdown tag end: {:?}", tag), _ => log::error!("unsupported markdown tag end: {:?}", tag),
}, },
MarkdownEvent::Text => { MarkdownEvent::Text(parsed) => {
builder.push_text(&parsed_markdown.source[range.clone()], range.start); builder.push_text(parsed, range.start);
} }
MarkdownEvent::Code => { MarkdownEvent::Code => {
builder.push_text_style(self.style.inline_code.clone()); builder.push_text_style(self.style.inline_code.clone());
@ -777,12 +776,7 @@ impl Element for MarkdownElement {
builder.pop_div() builder.pop_div()
} }
MarkdownEvent::SoftBreak => builder.push_text(" ", range.start), MarkdownEvent::SoftBreak => builder.push_text(" ", range.start),
MarkdownEvent::HardBreak => { MarkdownEvent::HardBreak => builder.push_text("\n", range.start),
let mut d = div().py_3();
d.style().refine(&self.style.break_style);
builder.push_div(d, range, markdown_end);
builder.pop_div()
}
_ => log::error!("unsupported markdown event {:?}", event), _ => log::error!("unsupported markdown event {:?}", event),
} }
} }

View file

@ -37,9 +37,10 @@ pub fn parse_markdown(text: &str) -> Vec<(Range<usize>, MarkdownEvent)> {
} }
events.push((range, MarkdownEvent::End(tag))); 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 // Automatically detect links in text if we're not already within a markdown
// link. // link.
let mut parsed = parsed.as_ref();
if !within_link { if !within_link {
let mut finder = LinkFinder::new(); let mut finder = LinkFinder::new();
finder.kinds(&[linkify::LinkKind::Url]); finder.kinds(&[linkify::LinkKind::Url]);
@ -49,7 +50,12 @@ pub fn parse_markdown(text: &str) -> Vec<(Range<usize>, MarkdownEvent)> {
text_range.start + link.start()..text_range.start + link.end(); text_range.start + link.start()..text_range.start + link.end();
if link_range.start > range.start { 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(( events.push((
@ -61,15 +67,20 @@ pub fn parse_markdown(text: &str) -> Vec<(Range<usize>, MarkdownEvent)> {
id: SharedString::default(), 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))); events.push((link_range.clone(), MarkdownEvent::End(MarkdownTagEnd::Link)));
range.start = link_range.end; range.start = link_range.end;
parsed = tail;
} }
} }
if range.start < range.end { if range.start < range.end {
events.push((range, MarkdownEvent::Text)); events.push((range, MarkdownEvent::Text(SharedString::new(parsed))));
} }
} }
pulldown_cmark::Event::Code(_) => { pulldown_cmark::Event::Code(_) => {
@ -94,7 +105,7 @@ pub fn parse_markdown(text: &str) -> Vec<(Range<usize>, MarkdownEvent)> {
events events
} }
pub fn parse_links_only(text: &str) -> Vec<(Range<usize>, MarkdownEvent)> { pub fn parse_links_only(mut text: &str) -> Vec<(Range<usize>, MarkdownEvent)> {
let mut events = Vec::new(); let mut events = Vec::new();
let mut finder = LinkFinder::new(); let mut finder = LinkFinder::new();
finder.kinds(&[linkify::LinkKind::Url]); finder.kinds(&[linkify::LinkKind::Url]);
@ -106,9 +117,15 @@ pub fn parse_links_only(text: &str) -> Vec<(Range<usize>, MarkdownEvent)> {
let link_range = link.start()..link.end(); let link_range = link.start()..link.end();
if link_range.start > text_range.start { 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(( events.push((
link_range.clone(), link_range.clone(),
MarkdownEvent::Start(MarkdownTag::Link { MarkdownEvent::Start(MarkdownTag::Link {
@ -118,14 +135,18 @@ pub fn parse_links_only(text: &str) -> Vec<(Range<usize>, MarkdownEvent)> {
id: SharedString::default(), 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))); events.push((link_range.clone(), MarkdownEvent::End(MarkdownTagEnd::Link)));
text_range.start = link_range.end; text_range.start = link_range.end;
text = tail;
} }
if text_range.end > text_range.start { if text_range.end > text_range.start {
events.push((text_range, MarkdownEvent::Text)); events.push((text_range, MarkdownEvent::Text(SharedString::new(text))));
} }
events events
@ -142,7 +163,7 @@ pub enum MarkdownEvent {
/// End of a tagged element. /// End of a tagged element.
End(MarkdownTagEnd), End(MarkdownTagEnd),
/// A text node. /// A text node.
Text, Text(SharedString),
/// An inline code node. /// An inline code node.
Code, Code,
/// An HTML node. /// An HTML node.