From b53f9c8863609b48e16c8498c6679859a4b57820 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 5 Oct 2025 21:26:27 +0200 Subject: [PATCH] editor: Fix panic in `delete_line` with multibyte characters (#39560) Fixes ZED-1TG Release Notes: - Fixed panic in `delete line` when following line contains multibyte characters --- crates/editor/src/editor.rs | 32 +++++++++++++++---------------- crates/editor/src/editor_tests.rs | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 9ac6b5447b1f256d2bee01878a0f0c3addd2edd3..5845974ed6ac78cc6fec7f2d1667a6aef6b24562 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -10446,7 +10446,6 @@ impl Editor { let mut selections = selections.iter().peekable(); while let Some(selection) = selections.next() { let mut rows = selection.spanned_rows(false, &display_map); - let goal_display_column = selection.head().to_display_point(&display_map).column(); // Accumulate contiguous regions of rows that we want to delete. while let Some(next_selection) = selections.peek() { @@ -10461,28 +10460,29 @@ impl Editor { let buffer = &display_map.buffer_snapshot; let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer); - let edit_end; - let cursor_buffer_row; - if buffer.max_point().row >= rows.end.0 { + let edit_end = 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 - // and position the cursor on the next line. - edit_end = Point::new(rows.end.0, 0).to_offset(buffer); - cursor_buffer_row = rows.end; + Point::new(rows.end.0, 0).to_offset(buffer) } else { // If there isn't a line after the range, delete the \n from the line before the - // start of the row range and position the cursor there. + // start of the row range edit_start = edit_start.saturating_sub(1); - edit_end = buffer.len(); - cursor_buffer_row = rows.start.previous_row(); - } + buffer.len() + }; - let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map); - *cursor.column_mut() = - cmp::min(goal_display_column, display_map.line_len(cursor.row())); + let (cursor, goal) = movement::down_by_rows( + &display_map, + selection.head().to_display_point(&display_map), + rows.len() as u32, + selection.goal, + false, + &self.text_layout_details(window), + ); new_cursors.push(( selection.id, buffer.anchor_after(cursor.to_point(&display_map)), + goal, )); edit_ranges.push(edit_start..edit_end); } @@ -10501,14 +10501,14 @@ impl Editor { }); let new_selections = new_cursors .into_iter() - .map(|(id, cursor)| { + .map(|(id, cursor, goal)| { let cursor = cursor.to_point(&buffer); Selection { id, start: cursor, end: cursor, reversed: false, - goal: SelectionGoal::None, + goal, } }) .collect(); diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 4bfb2c06f4324ad7c41079fcdd2e440b9178c489..148c90ba4de6338d0470fcd49b35825651e186a3 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -4300,8 +4300,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), 1)..DisplayPoint::new(DisplayRow(0), 1), + DisplayPoint::new(DisplayRow(0), 3)..DisplayPoint::new(DisplayRow(0), 3), ] ); });