diff --git a/Cargo.lock b/Cargo.lock index 701c2b058d..c76cf30642 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10810,6 +10810,7 @@ dependencies = [ "gpui_platform", "html5ever 0.27.0", "image", + "indoc", "language", "languages", "linkify", diff --git a/crates/markdown/Cargo.toml b/crates/markdown/Cargo.toml index 3db8d84b73..f123920536 100644 --- a/crates/markdown/Cargo.toml +++ b/crates/markdown/Cargo.toml @@ -47,6 +47,7 @@ fs = {workspace = true, features = ["test-support"]} gpui = { workspace = true, features = ["test-support"] } gpui_platform = { workspace = true, features = ["wayland", "x11"] } image.workspace = true +indoc.workspace = true language = { workspace = true, features = ["test-support"] } languages = { workspace = true, features = ["load-grammars"] } node_runtime.workspace = true diff --git a/crates/markdown/src/markdown.rs b/crates/markdown/src/markdown.rs index f9a8c0dd50..07b4d9e962 100644 --- a/crates/markdown/src/markdown.rs +++ b/crates/markdown/src/markdown.rs @@ -2816,7 +2816,14 @@ impl Element for MarkdownElement { .border(px(1.5)) .border_color(cx.theme().colors().border) .rounded_sm() - .overflow_x_scroll(), + .restrict_scroll_to_axis() + .custom_scrollbars( + Scrollbars::new(ScrollAxes::Horizontal) + .id(("markdown-table-scrollbar", range.start)) + .notify_content(), + window, + cx, + ), range, markdown_end, ); @@ -4444,7 +4451,10 @@ impl RenderedText { #[cfg(test)] mod tests { use super::*; - use gpui::{RenderImage, TestAppContext, UpdateGlobal, size}; + use gpui::{ + Modifiers, RenderImage, ScrollDelta, ScrollWheelEvent, TestAppContext, TouchPhase, + UpdateGlobal, size, + }; use language::{Language, LanguageConfig, LanguageMatcher}; use std::cell::RefCell; use std::sync::{ @@ -6184,4 +6194,80 @@ mod tests { ); }); } + + #[gpui::test] + fn test_wide_table_scrolls_horizontally(cx: &mut TestAppContext) { + ensure_theme_initialized(cx); + let source = indoc::indoc! {r#" + | left | right | + | --- | --- | + | value | far_right_cell_content_that_is_much_wider_than_the_viewport | + "#}; + let left_cell_start = source.find("left").expect("left cell should be present"); + let left_cell_range = left_cell_start..left_cell_start + "left".len(); + let right_cell = "far_right_cell_content_that_is_much_wider_than_the_viewport"; + let right_cell_start = source + .find(right_cell) + .expect("right cell should be present"); + let right_cell_range = right_cell_start..right_cell_start + right_cell.len(); + + let markdown = cx.new(|cx| Markdown::new(source.into(), None, None, cx)); + let rendered_text = Rc::new(RefCell::new(None)); + let (_, cx) = cx.add_window_view({ + let rendered_text = rendered_text.clone(); + move |_, _| MarkdownTestView { + markdown, + style: MarkdownStyle { + table_columns_min_size: true, + ..MarkdownStyle::default() + }, + code_span_link: None, + rendered_text, + } + }); + cx.simulate_resize(size(px(300.), px(200.))); + cx.run_until_parked(); + + let (event_position, right_cell_before_scroll) = { + let rendered_text = rendered_text.borrow(); + let rendered_text = rendered_text + .as_ref() + .expect("markdown should be rendered before scrolling"); + let event_position = rendered_text + .bounds_for_source_range(left_cell_range) + .into_iter() + .next() + .expect("left cell should have bounds") + .center(); + let right_cell_bounds = rendered_text + .bounds_for_source_range(right_cell_range.clone()) + .into_iter() + .next() + .expect("right cell should have bounds"); + (event_position, right_cell_bounds) + }; + + cx.simulate_event(ScrollWheelEvent { + position: event_position, + delta: ScrollDelta::Pixels(point(px(-100.), px(0.))), + modifiers: Modifiers::default(), + touch_phase: TouchPhase::Moved, + }); + cx.run_until_parked(); + + let right_cell_after_scroll = rendered_text + .borrow() + .as_ref() + .expect("markdown should be rendered after scrolling") + .bounds_for_source_range(right_cell_range) + .into_iter() + .next() + .expect("right cell should have bounds after scrolling"); + + assert!(right_cell_after_scroll.left() < right_cell_before_scroll.left()); + assert_eq!( + right_cell_after_scroll.top(), + right_cell_before_scroll.top() + ); + } }