Extract a `Selection::buffer_row_range` method

Antonio Scandurra created

Change summary

zed/src/editor/buffer/selection.rs | 25 +++++++++++++++
zed/src/editor/buffer_view.rs      | 50 +++++++++++++++----------------
2 files changed, 48 insertions(+), 27 deletions(-)

Detailed changes

zed/src/editor/buffer/selection.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{
     editor::{
         buffer::{Anchor, Buffer, Point, ToPoint},
-        display_map::DisplayMap,
+        display_map::{Bias, DisplayMap},
         DisplayPoint,
     },
     time,
@@ -72,4 +72,27 @@ impl Selection {
             start..end
         }
     }
+
+    pub fn buffer_row_range(&self, map: &DisplayMap, ctx: &AppContext) -> Range<u32> {
+        let display_start = self.start.to_display_point(map, ctx).unwrap();
+        let buffer_start = DisplayPoint::new(display_start.row(), 0)
+            .to_buffer_point(map, Bias::Left, ctx)
+            .unwrap();
+
+        let mut display_end = self.end.to_display_point(map, ctx).unwrap();
+        if display_end != map.max_point(ctx)
+            && display_start.row() != display_end.row()
+            && display_end.column() == 0
+        {
+            *display_end.row_mut() -= 1;
+        }
+        let buffer_end = DisplayPoint::new(
+            display_end.row(),
+            map.line_len(display_end.row(), ctx).unwrap(),
+        )
+        .to_buffer_point(map, Bias::Left, ctx)
+        .unwrap();
+
+        buffer_start.row..buffer_end.row + 1
+    }
 }

zed/src/editor/buffer_view.rs 🔗

@@ -554,6 +554,7 @@ impl BufferView {
         self.start_transaction(ctx);
 
         let app = ctx.as_ref();
+        let map = self.display_map.read(app);
         let buffer = self.buffer.read(app);
 
         let mut new_cursors = Vec::new();
@@ -561,52 +562,49 @@ impl BufferView {
 
         let mut selections = self.selections(app).iter().peekable();
         while let Some(selection) = selections.next() {
-            let start = selection.start.to_point(buffer).unwrap();
-            let mut end = selection.end.to_point(buffer).unwrap();
-            let goal_column = if selection.reversed {
-                start.column
-            } else {
-                end.column
-            };
+            let mut range = selection.buffer_row_range(map, app);
+            let goal_display_column = selection
+                .head()
+                .to_display_point(map, app)
+                .unwrap()
+                .column();
 
             // Accumulate contiguous regions of rows that we want to delete.
             while let Some(next_selection) = selections.peek() {
-                let next_start = next_selection.start.to_point(buffer).unwrap();
-                if next_start.row <= end.row + 1 {
-                    end = next_selection.end.to_point(buffer).unwrap();
+                let next_range = next_selection.buffer_row_range(map, app);
+                if next_range.start <= range.end {
+                    range.end = next_range.end;
                     selections.next().unwrap();
                 } else {
                     break;
                 }
             }
 
-            // When the deletion straddles multiple rows but ends at the beginning of a line, avoid
-            // deleting that final line.
-            if start.row != end.row && end.column == 0 {
-                end.row -= 1;
-            }
-
-            let mut edit_start = Point::new(start.row, 0).to_offset(buffer).unwrap();
+            let mut edit_start = Point::new(range.start, 0).to_offset(buffer).unwrap();
             let edit_end;
-            let mut cursor;
-
-            if let Ok(end_offset) = Point::new(end.row + 1, 0).to_offset(buffer) {
+            let cursor_buffer_row;
+            if let Ok(end_offset) = Point::new(range.end, 0).to_offset(buffer) {
                 // 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 = end_offset;
-                cursor = Point::new(end.row + 1, goal_column);
+                cursor_buffer_row = range.end;
             } 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.
                 edit_start = edit_start.saturating_sub(1);
                 edit_end = buffer.len();
-                cursor = Point::new(start.row.saturating_sub(1), goal_column);
+                cursor_buffer_row = range.start.saturating_sub(1);
             }
-            // We tried to maintain the column of the original cursor but the new line may be
-            // shorter, so clip the new cursor's column.
-            cursor.column = cmp::min(cursor.column, buffer.line_len(cursor.row).unwrap());
 
-            new_cursors.push(cursor);
+            let mut cursor = Point::new(cursor_buffer_row, 0)
+                .to_display_point(map, app)
+                .unwrap();
+            *cursor.column_mut() = cmp::min(
+                goal_display_column,
+                map.line_len(cursor.row(), app).unwrap(),
+            );
+
+            new_cursors.push(cursor.to_buffer_point(map, Bias::Left, app).unwrap());
             edit_ranges.push(edit_start..edit_end);
         }