markdown: Fix markdown table selection hit testing (#47720)

Release Notes:

- Fixed markdown table selection hit testing

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
This commit is contained in:
Xiaobo Liu 2026-02-03 00:37:58 +08:00 committed by GitHub
parent a1558bc5cf
commit 70c47e96bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -2044,19 +2044,33 @@ struct RenderedLink {
impl RenderedText {
fn source_index_for_position(&self, position: Point<Pixels>) -> Result<usize, usize> {
let mut lines = self.lines.iter().peekable();
let mut fallback_line: Option<&RenderedLine> = None;
while let Some(line) = lines.next() {
let line_bounds = line.layout.bounds();
// Exact match: position is within bounds (handles overlapping bounds like table columns)
if line_bounds.contains(&position) {
return line.source_index_for_position(position);
}
// Track fallback for Y-coordinate based matching
if position.y <= line_bounds.bottom() && fallback_line.is_none() {
fallback_line = Some(line);
}
// Handle gap between lines
if position.y > line_bounds.bottom() {
if let Some(next_line) = lines.peek()
&& position.y < next_line.layout.bounds().top()
{
return Err(line.source_end);
}
continue;
}
}
// Fall back to Y-coordinate matched line
if let Some(line) = fallback_line {
return line.source_index_for_position(position);
}
@ -2188,6 +2202,17 @@ mod tests {
use language::{Language, LanguageConfig, LanguageMatcher};
use std::sync::Arc;
fn ensure_theme_initialized(cx: &mut TestAppContext) {
cx.update(|cx| {
if !cx.has_global::<settings::SettingsStore>() {
settings::init(cx);
}
if !cx.has_global::<theme::GlobalTheme>() {
theme::init(theme::LoadThemes::JustBase, cx);
}
});
}
#[gpui::test]
fn test_mappings(cx: &mut TestAppContext) {
// Formatting.
@ -2256,6 +2281,8 @@ mod tests {
}
}
ensure_theme_initialized(cx);
let (_, cx) = cx.add_window_view(|_, _| TestWindow);
let markdown =
cx.new(|cx| Markdown::new(markdown.to_string().into(), language_registry, None, cx));
@ -2413,6 +2440,28 @@ mod tests {
assert_eq!(selected_text, "code");
}
#[gpui::test]
fn test_table_column_selection(cx: &mut TestAppContext) {
let rendered = render_markdown("| a | b |\n|---|---|\n| c | d |", cx);
assert!(rendered.lines.len() >= 2);
let first_bounds = rendered.lines[0].layout.bounds();
let second_bounds = rendered.lines[1].layout.bounds();
let first_index = match rendered.source_index_for_position(first_bounds.center()) {
Ok(index) | Err(index) => index,
};
let second_index = match rendered.source_index_for_position(second_bounds.center()) {
Ok(index) | Err(index) => index,
};
let first_word = rendered.text_for_range(rendered.surrounding_word_range(first_index));
let second_word = rendered.text_for_range(rendered.surrounding_word_range(second_index));
assert_eq!(first_word, "a");
assert_eq!(second_word, "b");
}
#[gpui::test]
fn test_inline_code_word_selection_excludes_backticks(cx: &mut TestAppContext) {
// Test that double-clicking on inline code selects just the code content,