wip

Nathan Sobo created

Change summary

crates/editor/src/display_map.rs |  13 +++
crates/editor/src/editor.rs      | 121 ++++++++++++++++-----------------
2 files changed, 70 insertions(+), 64 deletions(-)

Detailed changes

crates/editor/src/display_map.rs 🔗

@@ -226,6 +226,19 @@ impl DisplaySnapshot {
         }
     }
 
+    pub fn next_line_boundary(&self, mut point: Point) -> Point {
+        loop {
+            point.column = self.buffer_snapshot.line_len(point.row);
+            let mut display_point = self.point_to_display_point(point, Bias::Right);
+            *display_point.column_mut() = self.line_len(display_point.row());
+            let next_point = self.display_point_to_point(display_point, Bias::Right);
+            if next_point == point {
+                return point;
+            }
+            point = next_point;
+        }
+    }
+
     fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint {
         let fold_point = point.to_fold_point(&self.folds_snapshot, bias);
         let tab_point = self.tabs_snapshot.to_tab_point(fold_point);

crates/editor/src/editor.rs 🔗

@@ -1783,95 +1783,88 @@ impl Editor {
     }
 
     pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
-        let selections = self.local_selections::<Point>(cx);
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let buffer = self.buffer.read(cx).snapshot(cx);
 
         let mut edits = Vec::new();
-        let mut new_selection_ranges = Vec::new();
-        let mut old_folds = Vec::new();
-        let mut new_folds = Vec::new();
+        let mut unfold_ranges = Vec::new();
+        let mut refold_ranges = Vec::new();
 
+        let selections = self.local_selections::<Point>(cx);
         let mut selections = selections.iter().peekable();
-        let mut contiguous_selections = Vec::new();
-        while let Some(selection) = selections.next() {
-            // Accumulate contiguous regions of rows that we want to move.
-            contiguous_selections.push(selection.point_range(&buffer));
+        let mut contiguous_row_selections = Vec::new();
+        let mut new_selections = Vec::new();
 
-            let SpannedRows {
-                mut buffer_rows,
-                mut display_rows,
-            } = selection.spanned_rows(false, &display_map);
+        while let Some(selection) = selections.next() {
+            // Find all the selections that span a contiguous row range
+            contiguous_row_selections.push(selection.clone());
+            let start_row = selection.start.row;
+            let mut end_row = if selection.end.column > 0 || selection.is_empty() {
+                display_map.next_line_boundary(selection.end).row + 1
+            } else {
+                selection.end.row
+            };
 
             while let Some(next_selection) = selections.peek() {
-                let SpannedRows {
-                    buffer_rows: next_buffer_rows,
-                    display_rows: next_display_rows,
-                } = next_selection.spanned_rows(false, &display_map);
-                if next_buffer_rows.start <= buffer_rows.end {
-                    buffer_rows.end = next_buffer_rows.end;
-                    display_rows.end = next_display_rows.end;
-                    contiguous_selections.push(next_selection.point_range(&buffer));
-                    selections.next().unwrap();
+                if next_selection.start.row <= end_row {
+                    end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
+                        display_map.next_line_boundary(next_selection.end).row + 1
+                    } else {
+                        next_selection.end.row
+                    };
+                    contiguous_row_selections.push(selections.next().unwrap().clone());
                 } else {
                     break;
                 }
             }
 
-            // Cut the text from the selected rows and paste it at the end of the next line.
-            if display_rows.end <= display_map.max_point().row() {
-                let start = Point::new(buffer_rows.start, 0).to_offset(&buffer);
-                let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1))
-                    .to_offset(&buffer);
-
-                let next_row_display_end =
-                    DisplayPoint::new(display_rows.end, display_map.line_len(display_rows.end));
-
-                let next_row_buffer_end = display_map.next_row_boundary(next_row_display_end).1;
-                let next_row_buffer_end_offset = next_row_buffer_end.to_offset(&buffer);
-
-                if buffer.range_contains_excerpt_boundary(start..next_row_buffer_end_offset) {
-                    new_selection_ranges.extend(contiguous_selections.drain(..));
-                    continue;
-                }
-
-                let mut text = String::new();
-                text.push('\n');
-                text.extend(buffer.text_for_range(start..end));
-                edits.push((start..end + 1, String::new()));
-                edits.push((next_row_buffer_end_offset..next_row_buffer_end_offset, text));
-
-                // Move selections down.
-                let display_row_delta = next_row_display_end.row() - display_rows.end + 1;
-                for range in &mut contiguous_selections {
-                    range.start.row += display_row_delta;
-                    range.end.row += display_row_delta;
-                }
-
-                // Move folds down.
-                old_folds.push(start..end);
-                let buffer_row_delta = next_row_buffer_end.row - buffer_rows.end + 1;
-                for fold in display_map.folds_in_range(start..end) {
+            // Move the text spanned by the row range to be after the last line of the row range
+            if end_row <= buffer.max_point().row {
+                let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
+                let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0));
+                let mut text = String::from("\n");
+                text.extend(buffer.text_for_range(range_to_move.clone()));
+                text.pop(); // Drop trailing newline
+                edits.push((range_to_move.clone(), String::new()));
+                edits.push((insertion_point..insertion_point, text));
+
+                let row_delta = insertion_point.row - range_to_move.end.row + 1;
+
+                // Make the selections relative to the insertion row
+                new_selections.extend(contiguous_row_selections.drain(..).map(|mut selection| {
+                    selection.start.row += row_delta;
+                    selection.end.row += row_delta;
+                    selection
+                }));
+
+                // Unfold all the folds spanned by these rows
+                unfold_ranges.push(range_to_move.clone());
+
+                // Refold ranges relative to the insertion row
+                for fold in display_map.folds_in_range(
+                    buffer.anchor_before(range_to_move.start)
+                        ..buffer.anchor_after(range_to_move.end),
+                ) {
                     let mut start = fold.start.to_point(&buffer);
                     let mut end = fold.end.to_point(&buffer);
-                    start.row += buffer_row_delta;
-                    end.row += buffer_row_delta;
-                    new_folds.push(start..end);
+                    start.row += row_delta;
+                    end.row += row_delta;
+                    refold_ranges.push(start..end);
                 }
+            } else {
+                new_selections.extend(contiguous_row_selections.drain(..));
             }
-
-            new_selection_ranges.extend(contiguous_selections.drain(..));
         }
 
         self.start_transaction(cx);
-        self.unfold_ranges(old_folds, cx);
+        self.unfold_ranges(unfold_ranges, cx);
         self.buffer.update(cx, |buffer, cx| {
             for (range, text) in edits.into_iter().rev() {
-                buffer.edit(Some(range), text, cx);
+                buffer.edit([range], text, cx);
             }
         });
-        self.fold_ranges(new_folds, cx);
-        self.select_ranges(new_selection_ranges, Some(Autoscroll::Fit), cx);
+        self.fold_ranges(refold_ranges, cx);
+        self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
         self.end_transaction(cx);
     }