markdown: Make push_div work with Stateful<Div>s (#22622)

This PR updates the `push_div` method in the `MarkdownElementBuilder` to
support taking in a `Stateful<Div>`.

This is some groundwork for supporting horizontal scrolling in Markdown
code blocks.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-01-03 13:24:04 -05:00 committed by GitHub
parent bb24c085be
commit 7826d79a40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -6,8 +6,8 @@ use gpui::{
actions, point, quad, AnyElement, AppContext, Bounds, ClipboardItem, CursorStyle, actions, point, quad, AnyElement, AppContext, Bounds, ClipboardItem, CursorStyle,
DispatchPhase, Edges, FocusHandle, FocusableView, FontStyle, FontWeight, GlobalElementId, DispatchPhase, Edges, FocusHandle, FocusableView, FontStyle, FontWeight, GlobalElementId,
Hitbox, Hsla, KeyContext, Length, MouseDownEvent, MouseEvent, MouseMoveEvent, MouseUpEvent, Hitbox, Hsla, KeyContext, Length, MouseDownEvent, MouseEvent, MouseMoveEvent, MouseUpEvent,
Point, Render, StrikethroughStyle, StyleRefinement, StyledText, Task, TextLayout, TextRun, Point, Render, Stateful, StrikethroughStyle, StyleRefinement, StyledText, Task, TextLayout,
TextStyle, TextStyleRefinement, View, TextRun, TextStyle, TextStyleRefinement, View,
}; };
use language::{Language, LanguageRegistry, Rope}; use language::{Language, LanguageRegistry, Rope};
use parser::{parse_links_only, parse_markdown, MarkdownEvent, MarkdownTag, MarkdownTagEnd}; use parser::{parse_links_only, parse_markdown, MarkdownEvent, MarkdownTag, MarkdownTagEnd};
@ -785,8 +785,52 @@ impl IntoElement for MarkdownElement {
} }
} }
enum AnyDiv {
Div(Div),
Stateful(Stateful<Div>),
}
impl AnyDiv {
fn into_any_element(self) -> AnyElement {
match self {
Self::Div(div) => div.into_any_element(),
Self::Stateful(div) => div.into_any_element(),
}
}
}
impl From<Div> for AnyDiv {
fn from(value: Div) -> Self {
Self::Div(value)
}
}
impl From<Stateful<Div>> for AnyDiv {
fn from(value: Stateful<Div>) -> Self {
Self::Stateful(value)
}
}
impl Styled for AnyDiv {
fn style(&mut self) -> &mut StyleRefinement {
match self {
Self::Div(div) => div.style(),
Self::Stateful(div) => div.style(),
}
}
}
impl ParentElement for AnyDiv {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
match self {
Self::Div(div) => div.extend(elements),
Self::Stateful(div) => div.extend(elements),
}
}
}
struct MarkdownElementBuilder { struct MarkdownElementBuilder {
div_stack: Vec<Div>, div_stack: Vec<AnyDiv>,
rendered_lines: Vec<RenderedLine>, rendered_lines: Vec<RenderedLine>,
pending_line: PendingLine, pending_line: PendingLine,
rendered_links: Vec<RenderedLink>, rendered_links: Vec<RenderedLink>,
@ -812,7 +856,7 @@ struct ListStackEntry {
impl MarkdownElementBuilder { impl MarkdownElementBuilder {
fn new(base_text_style: TextStyle, syntax_theme: Arc<SyntaxTheme>) -> Self { fn new(base_text_style: TextStyle, syntax_theme: Arc<SyntaxTheme>) -> Self {
Self { Self {
div_stack: vec![div().debug_selector(|| "inner".into())], div_stack: vec![div().debug_selector(|| "inner".into()).into()],
rendered_lines: Vec::new(), rendered_lines: Vec::new(),
pending_line: PendingLine::default(), pending_line: PendingLine::default(),
rendered_links: Vec::new(), rendered_links: Vec::new(),
@ -841,11 +885,12 @@ impl MarkdownElementBuilder {
self.text_style_stack.pop(); self.text_style_stack.pop();
} }
fn push_div(&mut self, mut div: Div, range: &Range<usize>, markdown_end: usize) { fn push_div(&mut self, div: impl Into<AnyDiv>, range: &Range<usize>, markdown_end: usize) {
let mut div = div.into();
self.flush_text(); self.flush_text();
if range.start == 0 { if range.start == 0 {
//first element, remove top margin // Remove the top margin on the first element.
div.style().refine(&StyleRefinement { div.style().refine(&StyleRefinement {
margin: gpui::EdgesRefinement { margin: gpui::EdgesRefinement {
top: Some(Length::Definite(px(0.).into())), top: Some(Length::Definite(px(0.).into())),
@ -856,6 +901,7 @@ impl MarkdownElementBuilder {
..Default::default() ..Default::default()
}); });
} }
if range.end == markdown_end { if range.end == markdown_end {
div.style().refine(&StyleRefinement { div.style().refine(&StyleRefinement {
margin: gpui::EdgesRefinement { margin: gpui::EdgesRefinement {
@ -867,12 +913,13 @@ impl MarkdownElementBuilder {
..Default::default() ..Default::default()
}); });
} }
self.div_stack.push(div); self.div_stack.push(div);
} }
fn pop_div(&mut self) { fn pop_div(&mut self) {
self.flush_text(); self.flush_text();
let div = self.div_stack.pop().unwrap().into_any(); let div = self.div_stack.pop().unwrap().into_any_element();
self.div_stack.last_mut().unwrap().extend(iter::once(div)); self.div_stack.last_mut().unwrap().extend(iter::once(div));
} }
@ -973,7 +1020,7 @@ impl MarkdownElementBuilder {
debug_assert_eq!(self.div_stack.len(), 1); debug_assert_eq!(self.div_stack.len(), 1);
self.flush_text(); self.flush_text();
RenderedMarkdown { RenderedMarkdown {
element: self.div_stack.pop().unwrap().into_any(), element: self.div_stack.pop().unwrap().into_any_element(),
text: RenderedText { text: RenderedText {
lines: self.rendered_lines.into(), lines: self.rendered_lines.into(),
links: self.rendered_links.into(), links: self.rendered_links.into(),