Fix mouse multi cursor placement for wrapped lines (#61590)

Closes https://github.com/zed-industries/zed/issues/25237


https://github.com/user-attachments/assets/0f1d54a0-c8f1-4b49-8327-73375a2e1f4e


Release Notes:

- Fixed mouse multi cursor placement for wrapped lines

---------

Co-authored-by: Finn Evers <finn@zed.dev>
This commit is contained in:
Kirill BulatovandFinn Evers authored and GitHub committed 2026-07-28 12:49:43 +00:00
1 parent 1efdc3e63e
commit fa1d0362b4
2 files changed
+88

No files matched your search

+81
View File
@@ -42108,6 +42108,87 @@ async fn test_columnar_selection_past_end_of_line(cx: &mut TestAppContext) {
"});
}
#[gpui::test]
async fn test_columnar_selection_with_soft_wrap(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
cx.set_state(indoc! {"
ˇ1. Very long line to show how a wrapped line would look
2. Very long line to show how a wrapped line would look
"});
let soft_wrap_second_line_row = |editor: &mut Editor, cx: &mut Context<Editor>| {
editor.set_wrap_width(Some(100.0.into()), cx);
let snapshot = editor.display_snapshot(cx);
let second_line_row = Point::new(1, 0).to_display_point(&snapshot).row();
assert!(
second_line_row.0 > 1,
"expected the first line to be soft wrapped"
);
second_line_row
};
// Dragging a columnar selection across the soft-wrapped rows of the first
// line must produce one selection per buffer line, not one per display row.
cx.update_editor(|editor, window, cx| {
let second_line_row = soft_wrap_second_line_row(editor, cx);
editor.select(
SelectPhase::BeginColumnar {
position: DisplayPoint::new(DisplayRow(0), 0),
goal_column: 0,
reset: true,
mode: ColumnarMode::FromMouse,
},
window,
cx,
);
editor.select(
SelectPhase::Update {
position: DisplayPoint::new(second_line_row, 1),
goal_column: 1,
scroll_delta: gpui::Point::default(),
},
window,
cx,
);
});
cx.assert_editor_state(indoc! {"
«1ˇ». Very long line to show how a wrapped line would look
«2ˇ». Very long line to show how a wrapped line would look
"});
cx.update_editor(|editor, window, cx| {
let second_line_row = soft_wrap_second_line_row(editor, cx);
editor.select(
SelectPhase::BeginColumnar {
position: DisplayPoint::new(DisplayRow(0), 0),
goal_column: 0,
reset: true,
mode: ColumnarMode::FromMouse,
},
window,
cx,
);
editor.select(
SelectPhase::Update {
position: DisplayPoint::new(second_line_row, 0),
goal_column: 0,
scroll_delta: gpui::Point::default(),
},
window,
cx,
);
});
cx.assert_editor_state(indoc! {"
ˇ1. Very long line to show how a wrapped line would look
ˇ2. Very long line to show how a wrapped line would look
"});
}
#[gpui::test]
async fn test_toggle_markdown_block_quote(cx: &mut TestAppContext) {
init_test(cx, |_| {});
+7
View File
@@ -1809,6 +1809,7 @@ impl Editor {
let end_x = tail_x.max(head_x);
let reversed = head_x < tail_x;
let mut last_buffer_row = None;
let selection_ranges = (start_row.0..=end_row.0)
.map(DisplayRow)
.filter_map(|row| {
@@ -1816,6 +1817,12 @@ impl Editor {
return None;
}
let buffer_row = row.as_display_point().to_point(display_map).row;
if last_buffer_row == Some(buffer_row) {
return None;
}
last_buffer_row = Some(buffer_row);
let layout = display_map.layout_row(row, &text_layout_details);
if matches!(columnar_state, ColumnarSelectionState::FromSelection { .. })
&& start_x > layout.width