From 819a1eb4560853ceb6a487b297c9dc53b37efdbb Mon Sep 17 00:00:00 2001 From: atharvaajmera Date: Sat, 18 Jul 2026 20:37:18 +0530 Subject: [PATCH 1/2] Fix squashed Mermaid diagrams in markdown preview Wide diagrams were forced through max_w_full, so height shrank with width and text became unreadable. When code_block_overflow_x_scroll is enabled (markdown preview), keep the raster at intrinsic size and allow horizontal scroll, matching fenced code blocks. Compact UIs still fit to pane. Fixes #61051 --- crates/markdown/src/mermaid.rs | 70 +++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/crates/markdown/src/mermaid.rs b/crates/markdown/src/mermaid.rs index d6ab952496326f..116e5a09709632 100644 --- a/crates/markdown/src/mermaid.rs +++ b/crates/markdown/src/mermaid.rs @@ -1,7 +1,7 @@ use collections::HashMap; use gpui::{ - Animation, AnimationExt, AnyElement, ClipboardItem, Context, Entity, ImageSource, RenderImage, - StyledText, Task, img, pulsating_between, + Animation, AnimationExt, AnyElement, ClipboardItem, Context, Div, Entity, ImageSource, + RenderImage, StyledText, Task, img, pulsating_between, }; use std::collections::BTreeMap; use std::ops::Range; @@ -322,6 +322,10 @@ pub(crate) fn render_mermaid_diagram( let cached = mermaid_state.cache.get(&parsed.contents); let render_result = cached.and_then(|cached| cached.render_image.get()); let show_interactive = copy_button_visibility != CopyButtonVisibility::Hidden; + // Match fenced code blocks: when horizontal overflow is enabled (markdown + // preview), keep the diagram at its natural raster size and scroll instead + // of crushing wide graphs into the pane via `max_w_full` (see #61051). + let allow_overflow_x = style.code_block_overflow_x_scroll; let code = parsed.contents.contents.clone(); @@ -333,16 +337,7 @@ pub(crate) fn render_mermaid_diagram( let body = if showing_code { render_mermaid_code_view(&parsed.contents.contents) } else { - div() - .w_full() - .child( - img(ImageSource::Render(render_image.clone())) - .max_w_full() - .with_fallback(|| { - Label::new("Failed to Load Mermaid Diagram").into_any_element() - }), - ) - .into_any_element() + render_mermaid_image(render_image.clone(), allow_overflow_x) }; container @@ -381,24 +376,13 @@ pub(crate) fn render_mermaid_diagram( if let Some(fallback) = cached.and_then(|cached| cached.fallback_image.as_ref()) { container .child( - div() - .w_full() - .child( - img(ImageSource::Render(fallback.clone())) - .max_w_full() - .with_fallback(|| { - div() - .child(Label::new("Failed to load mermaid diagram")) - .into_any_element() - }), - ) - .with_animation( - "mermaid-fallback-pulse", - Animation::new(Duration::from_secs(2)) - .repeat() - .with_easing(pulsating_between(0.6, 1.0)), - |element, delta| element.opacity(delta), - ), + render_mermaid_image(fallback.clone(), allow_overflow_x).with_animation( + "mermaid-fallback-pulse", + Animation::new(Duration::from_secs(2)) + .repeat() + .with_easing(pulsating_between(0.6, 1.0)), + |element, delta| element.opacity(delta), + ), ) .when(show_interactive, |container| { container.child(render_mermaid_copy_button( @@ -439,6 +423,32 @@ pub(crate) fn render_mermaid_diagram( } } +/// Renders a mermaid diagram image. +/// +/// When `allow_overflow_x` is true (markdown preview), the image keeps its +/// intrinsic size so large diagrams stay readable and the container scrolls +/// horizontally. When false (e.g. compact agent UI), the image is capped to the +/// parent width via `max_w_full`, matching previous fit-to-pane behavior. +fn render_mermaid_image(render_image: Arc, allow_overflow_x: bool) -> Div { + let image = img(ImageSource::Render(render_image)).with_fallback(|| { + Label::new("Failed to Load Mermaid Diagram").into_any_element() + }); + + div() + .w_full() + .map(|container| { + if allow_overflow_x { + // Intrinsic image size + horizontal pan — do not apply max_w_full. + // Match fenced code blocks: keep wheel vertical scroll on the parent. + let mut scroll = container.overflow_x_scroll(); + scroll.style().restrict_scroll_to_axis = Some(true); + scroll.child(image) + } else { + container.child(image.max_w_full()) + } + }) +} + fn render_mermaid_tab_header( source_offset: usize, showing_code: bool, From 4626a0c399fbfb78e396e561987dea7a9a91069f Mon Sep 17 00:00:00 2001 From: atharvaajmera Date: Wed, 22 Jul 2026 22:28:07 +0530 Subject: [PATCH 2/2] Thread source_offset into mermaid scroll containers for stable per-diagram scroll state Gives each mermaid diagram's horizontal-scroll container a stable id so scroll position doesn't get shared/reset across multiple diagrams in one document. Also trims comment verbosity from the prior commit. --- crates/markdown/src/mermaid.rs | 76 +++++++++++++++++----------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/crates/markdown/src/mermaid.rs b/crates/markdown/src/mermaid.rs index 116e5a09709632..ae42ad453d65d3 100644 --- a/crates/markdown/src/mermaid.rs +++ b/crates/markdown/src/mermaid.rs @@ -1,7 +1,7 @@ use collections::HashMap; use gpui::{ - Animation, AnimationExt, AnyElement, ClipboardItem, Context, Div, Entity, ImageSource, - RenderImage, StyledText, Task, img, pulsating_between, + Animation, AnimationExt, AnyElement, ClipboardItem, Context, Entity, ImageSource, RenderImage, + StyledText, Task, img, pulsating_between, }; use std::collections::BTreeMap; use std::ops::Range; @@ -322,9 +322,7 @@ pub(crate) fn render_mermaid_diagram( let cached = mermaid_state.cache.get(&parsed.contents); let render_result = cached.and_then(|cached| cached.render_image.get()); let show_interactive = copy_button_visibility != CopyButtonVisibility::Hidden; - // Match fenced code blocks: when horizontal overflow is enabled (markdown - // preview), keep the diagram at its natural raster size and scroll instead - // of crushing wide graphs into the pane via `max_w_full` (see #61051). + // Preview keeps diagrams at natural size + scroll instead of crushing them via max_w_full (#61051). let allow_overflow_x = style.code_block_overflow_x_scroll; let code = parsed.contents.contents.clone(); @@ -337,7 +335,7 @@ pub(crate) fn render_mermaid_diagram( let body = if showing_code { render_mermaid_code_view(&parsed.contents.contents) } else { - render_mermaid_image(render_image.clone(), allow_overflow_x) + render_mermaid_image(render_image.clone(), allow_overflow_x, source_offset) }; container @@ -376,13 +374,19 @@ pub(crate) fn render_mermaid_diagram( if let Some(fallback) = cached.and_then(|cached| cached.fallback_image.as_ref()) { container .child( - render_mermaid_image(fallback.clone(), allow_overflow_x).with_animation( - "mermaid-fallback-pulse", - Animation::new(Duration::from_secs(2)) - .repeat() - .with_easing(pulsating_between(0.6, 1.0)), - |element, delta| element.opacity(delta), - ), + div() + .child(render_mermaid_image( + fallback.clone(), + allow_overflow_x, + source_offset, + )) + .with_animation( + "mermaid-fallback-pulse", + Animation::new(Duration::from_secs(2)) + .repeat() + .with_easing(pulsating_between(0.6, 1.0)), + |element, delta| element.opacity(delta), + ), ) .when(show_interactive, |container| { container.child(render_mermaid_copy_button( @@ -423,30 +427,28 @@ pub(crate) fn render_mermaid_diagram( } } -/// Renders a mermaid diagram image. -/// -/// When `allow_overflow_x` is true (markdown preview), the image keeps its -/// intrinsic size so large diagrams stay readable and the container scrolls -/// horizontally. When false (e.g. compact agent UI), the image is capped to the -/// parent width via `max_w_full`, matching previous fit-to-pane behavior. -fn render_mermaid_image(render_image: Arc, allow_overflow_x: bool) -> Div { - let image = img(ImageSource::Render(render_image)).with_fallback(|| { - Label::new("Failed to Load Mermaid Diagram").into_any_element() - }); - - div() - .w_full() - .map(|container| { - if allow_overflow_x { - // Intrinsic image size + horizontal pan — do not apply max_w_full. - // Match fenced code blocks: keep wheel vertical scroll on the parent. - let mut scroll = container.overflow_x_scroll(); - scroll.style().restrict_scroll_to_axis = Some(true); - scroll.child(image) - } else { - container.child(image.max_w_full()) - } - }) +/// Renders a mermaid diagram image, scrolling at intrinsic size in preview or fit-to-pane elsewhere. +fn render_mermaid_image( + render_image: Arc, + allow_overflow_x: bool, + source_offset: usize, +) -> AnyElement { + let image = img(ImageSource::Render(render_image)) + .with_fallback(|| Label::new("Failed to Load Mermaid Diagram").into_any_element()); + + if allow_overflow_x { + div() + .id(("mermaid-scroll", source_offset)) + .w_full() + .map(|mut container| { + container.style().restrict_scroll_to_axis = Some(true); + container.overflow_x_scroll() + }) + .child(image) + .into_any_element() + } else { + div().w_full().child(image.max_w_full()).into_any_element() + } } fn render_mermaid_tab_header(