From af0cd30a9c2c824d1f45cea8e3b539e7276c423e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 13 Oct 2025 15:40:45 +0200 Subject: [PATCH] editor: Fix `delete line` moving the cursor too far (#40102) Release Notes: - N/A *or* Added/Fixed/Improved ... --- crates/editor/src/editor.rs | 26 +++++++++++++++----------- crates/editor/src/editor_tests.rs | 20 +++++++++++++++++++- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 848e9c76f6fd6e8d9ed2df60daa611799f51ff29..5b609301da326c7fe64964afb3eba29d96af8807 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -10499,29 +10499,33 @@ impl Editor { let buffer = display_map.buffer_snapshot(); let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer); - let edit_end = if buffer.max_point().row >= rows.end.0 { + let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 { // If there's a line after the range, delete the \n from the end of the row range - ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer) + ( + ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer), + rows.end, + ) } else { // If there isn't a line after the range, delete the \n from the line before the // start of the row range edit_start = edit_start.saturating_sub(1); - buffer.len() + (buffer.len(), rows.start.previous_row()) }; - let (cursor, goal) = movement::down_by_rows( - &display_map, + let text_layout_details = self.text_layout_details(window); + let x = display_map.x_for_display_point( selection.head().to_display_point(&display_map), - rows.len() as u32, - selection.goal, - false, - &self.text_layout_details(window), + &text_layout_details, ); + let row = Point::new(target_row.0, 0) + .to_display_point(&display_map) + .row(); + let column = display_map.display_column_for_x(row, x, &text_layout_details); new_cursors.push(( selection.id, - buffer.anchor_after(cursor.to_point(&display_map)), - goal, + buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)), + SelectionGoal::None, )); edit_ranges.push(edit_start..edit_end); } diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index f6a0406fecf957a836ed0cd701319f5ab7f50a23..dd8fa50c33d730859a92da3077e2316b755f3f7c 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -4387,8 +4387,8 @@ fn test_delete_line(cx: &mut TestAppContext) { assert_eq!( editor.selections.display_ranges(cx), vec![ + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1), - DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 3), ] ); }); @@ -4410,6 +4410,24 @@ fn test_delete_line(cx: &mut TestAppContext) { vec![DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1)] ); }); + + let editor = cx.add_window(|window, cx| { + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n\njkl\nmno", cx); + build_editor(buffer, window, cx) + }); + _ = editor.update(cx, |editor, window, cx| { + editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(2), 1) + ]) + }); + editor.delete_line(&DeleteLine, window, cx); + assert_eq!(editor.display_text(cx), "\njkl\nmno"); + assert_eq!( + editor.selections.display_ranges(cx), + vec![DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0)] + ); + }); } #[gpui::test]