markdown: Allow code blocks and tables to be horizontally scrollable (#25956)

Marshall Bowers created

This PR adds the ability for Markdown code blocks and tables to be made
horizontally scrollable.

This is a feature that the caller can opt in to.

Right now we're using it for the rendered Markdown in the Assistant 2
panel.

Release Notes:

- N/A

Change summary

crates/assistant2/src/active_thread.rs        |  2 +
crates/editor/src/hover_popover.rs            |  2 
crates/markdown/examples/markdown_as_child.rs |  1 
crates/markdown/src/markdown.rs               | 22 +++++++++++++++++---
4 files changed, 22 insertions(+), 5 deletions(-)

Detailed changes

crates/assistant2/src/active_thread.rs 🔗

@@ -134,6 +134,8 @@ impl ActiveThread {
             base_text_style: text_style,
             syntax: cx.theme().syntax().clone(),
             selection_background_color: cx.theme().players().local().selection,
+            code_block_overflow_x_scroll: true,
+            table_overflow_x_scroll: true,
             code_block: StyleRefinement {
                 margin: EdgesRefinement {
                     top: Some(Length::Definite(rems(0.).into())),

crates/editor/src/hover_popover.rs 🔗

@@ -618,12 +618,12 @@ pub fn hover_markdown_style(window: &Window, cx: &App) -> MarkdownStyle {
         },
         syntax: cx.theme().syntax().clone(),
         selection_background_color: { cx.theme().players().local().selection },
-
         heading: StyleRefinement::default()
             .font_weight(FontWeight::BOLD)
             .text_base()
             .mt(rems(1.))
             .mb_0(),
+        ..Default::default()
     }
 }
 

crates/markdown/examples/markdown_as_child.rs 🔗

@@ -84,6 +84,7 @@ pub fn main() {
                         selection
                     },
                     heading: Default::default(),
+                    ..Default::default()
                 };
                 let markdown = cx.new(|cx| {
                     Markdown::new(MARKDOWN_EXAMPLE.into(), markdown_style, None, None, cx)

crates/markdown/src/markdown.rs 🔗

@@ -27,6 +27,7 @@ use crate::parser::CodeBlockKind;
 pub struct MarkdownStyle {
     pub base_text_style: TextStyle,
     pub code_block: StyleRefinement,
+    pub code_block_overflow_x_scroll: bool,
     pub inline_code: TextStyleRefinement,
     pub block_quote: TextStyleRefinement,
     pub link: TextStyleRefinement,
@@ -35,6 +36,7 @@ pub struct MarkdownStyle {
     pub syntax: Arc<SyntaxTheme>,
     pub selection_background_color: Hsla,
     pub heading: StyleRefinement,
+    pub table_overflow_x_scroll: bool,
 }
 
 impl Default for MarkdownStyle {
@@ -42,6 +44,7 @@ impl Default for MarkdownStyle {
         Self {
             base_text_style: Default::default(),
             code_block: Default::default(),
+            code_block_overflow_x_scroll: false,
             inline_code: Default::default(),
             block_quote: Default::default(),
             link: Default::default(),
@@ -50,6 +53,7 @@ impl Default for MarkdownStyle {
             syntax: Arc::new(SyntaxTheme::default()),
             selection_background_color: Default::default(),
             heading: Default::default(),
+            table_overflow_x_scroll: false,
         }
     }
 }
@@ -604,13 +608,20 @@ impl Element for MarkdownElement {
                                 None
                             };
 
-                            let mut d = div().w_full().rounded_lg();
-                            d.style().refine(&self.style.code_block);
+                            let mut code_block = div()
+                                .id(("code-block", range.start))
+                                .flex()
+                                .rounded_lg()
+                                .when(self.style.code_block_overflow_x_scroll, |mut code_block| {
+                                    code_block.style().restrict_scroll_to_axis = Some(true);
+                                    code_block.overflow_x_scroll()
+                                });
+                            code_block.style().refine(&self.style.code_block);
                             if let Some(code_block_text_style) = &self.style.code_block.text {
                                 builder.push_text_style(code_block_text_style.to_owned());
                             }
                             builder.push_code_block(language);
-                            builder.push_div(d, range, markdown_end);
+                            builder.push_div(code_block, range, markdown_end);
                         }
                         MarkdownTag::HtmlBlock => builder.push_div(div(), range, markdown_end),
                         MarkdownTag::List(bullet_index) => {
@@ -670,7 +681,10 @@ impl Element for MarkdownElement {
                                     .border_1()
                                     .border_color(cx.theme().colors().border)
                                     .rounded_md()
-                                    .overflow_x_scroll(),
+                                    .when(self.style.table_overflow_x_scroll, |mut table| {
+                                        table.style().restrict_scroll_to_axis = Some(true);
+                                        table.overflow_x_scroll()
+                                    }),
                                 range,
                                 markdown_end,
                             );