editor: Fix panic in `delete_line` with multibyte characters

Lukas Wirth created

Change summary

crates/editor/src/editor.rs       | 32 ++++++++++++++++----------------
crates/editor/src/editor_tests.rs |  4 ++--
2 files changed, 18 insertions(+), 18 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -10435,7 +10435,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() {
@@ -10450,28 +10449,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);
         }
@@ -10490,14 +10490,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();

crates/editor/src/editor_tests.rs 🔗

@@ -4243,8 +4243,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),
             ]
         );
     });