Merge pull request #301 from zed-industries/move-lines-in-multibuffer

Nathan Sobo created

Support moving lines up and down in multi-buffers

Change summary

crates/editor/src/display_map.rs           |  9 ++----
crates/editor/src/display_map/block_map.rs | 29 +++++++++----------
crates/editor/src/editor.rs                | 36 ++++++++++++++---------
3 files changed, 39 insertions(+), 35 deletions(-)

Detailed changes

crates/editor/src/display_map.rs 🔗

@@ -123,14 +123,11 @@ impl DisplayMap {
         self.block_map.read(snapshot, edits);
     }
 
-    pub fn insert_blocks<P>(
+    pub fn insert_blocks(
         &mut self,
-        blocks: impl IntoIterator<Item = BlockProperties<P>>,
+        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
         cx: &mut ModelContext<Self>,
-    ) -> Vec<BlockId>
-    where
-        P: ToOffset + Clone,
-    {
+    ) -> Vec<BlockId> {
         let snapshot = self.buffer.read(cx).snapshot(cx);
         let edits = self.buffer_subscription.consume().into_inner();
         let (snapshot, edits) = self.fold_map.read(snapshot, edits);

crates/editor/src/display_map/block_map.rs 🔗

@@ -1,5 +1,5 @@
 use super::wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot};
-use crate::{Anchor, ToOffset, ToPoint as _};
+use crate::{Anchor, ToPoint as _};
 use collections::{HashMap, HashSet};
 use gpui::{AppContext, ElementBox};
 use language::Chunk;
@@ -362,13 +362,10 @@ impl std::ops::DerefMut for BlockPoint {
 }
 
 impl<'a> BlockMapWriter<'a> {
-    pub fn insert<P>(
+    pub fn insert(
         &mut self,
-        blocks: impl IntoIterator<Item = BlockProperties<P>>,
-    ) -> Vec<BlockId>
-    where
-        P: ToOffset + Clone,
-    {
+        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
+    ) -> Vec<BlockId> {
         let mut ids = Vec::new();
         let mut edits = Vec::<Edit<u32>>::new();
         let wrap_snapshot = &*self.0.wrap_snapshot.lock();
@@ -378,7 +375,7 @@ impl<'a> BlockMapWriter<'a> {
             let id = BlockId(self.0.next_block_id.fetch_add(1, SeqCst));
             ids.push(id);
 
-            let position = buffer.anchor_after(block.position);
+            let position = block.position;
             let point = position.to_point(&buffer);
             let wrap_row = wrap_snapshot
                 .from_point(Point::new(point.row, 0), Bias::Left)
@@ -903,8 +900,9 @@ mod tests {
         let text = "aaa\nbbb\nccc\nddd";
 
         let buffer = MultiBuffer::build_simple(text, cx);
+        let buffer_snapshot = buffer.read(cx).snapshot(cx);
         let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
-        let (fold_map, folds_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
+        let (fold_map, folds_snapshot) = FoldMap::new(buffer_snapshot.clone());
         let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
         let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx);
         let mut block_map = BlockMap::new(wraps_snapshot.clone());
@@ -912,19 +910,19 @@ mod tests {
         let mut writer = block_map.write(wraps_snapshot.clone(), vec![]);
         writer.insert(vec![
             BlockProperties {
-                position: Point::new(1, 0),
+                position: buffer_snapshot.anchor_after(Point::new(1, 0)),
                 height: 1,
                 disposition: BlockDisposition::Above,
                 render: Arc::new(|_| Empty::new().named("block 1")),
             },
             BlockProperties {
-                position: Point::new(1, 2),
+                position: buffer_snapshot.anchor_after(Point::new(1, 2)),
                 height: 2,
                 disposition: BlockDisposition::Above,
                 render: Arc::new(|_| Empty::new().named("block 2")),
             },
             BlockProperties {
-                position: Point::new(3, 3),
+                position: buffer_snapshot.anchor_after(Point::new(3, 3)),
                 height: 3,
                 disposition: BlockDisposition::Below,
                 render: Arc::new(|_| Empty::new().named("block 3")),
@@ -1071,7 +1069,8 @@ mod tests {
         let text = "one two three\nfour five six\nseven eight";
 
         let buffer = MultiBuffer::build_simple(text, cx);
-        let (_, folds_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
+        let buffer_snapshot = buffer.read(cx).snapshot(cx);
+        let (_, folds_snapshot) = FoldMap::new(buffer_snapshot.clone());
         let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
         let (_, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, Some(60.), cx);
         let mut block_map = BlockMap::new(wraps_snapshot.clone());
@@ -1079,13 +1078,13 @@ mod tests {
         let mut writer = block_map.write(wraps_snapshot.clone(), vec![]);
         writer.insert(vec![
             BlockProperties {
-                position: Point::new(1, 12),
+                position: buffer_snapshot.anchor_after(Point::new(1, 12)),
                 disposition: BlockDisposition::Above,
                 render: Arc::new(|_| Empty::new().named("block 1")),
                 height: 1,
             },
             BlockProperties {
-                position: Point::new(1, 1),
+                position: buffer_snapshot.anchor_after(Point::new(1, 1)),
                 disposition: BlockDisposition::Below,
                 render: Arc::new(|_| Empty::new().named("block 2")),
                 height: 1,

crates/editor/src/editor.rs 🔗

@@ -1737,8 +1737,13 @@ impl Editor {
                         .chain(['\n'])
                         .collect::<String>();
 
-                    edits.push((insertion_point..insertion_point, text));
-                    edits.push((range_to_move.clone(), String::new()));
+                    edits.push((
+                        buffer.anchor_after(range_to_move.start)
+                            ..buffer.anchor_before(range_to_move.end),
+                        String::new(),
+                    ));
+                    let insertion_anchor = buffer.anchor_after(insertion_point);
+                    edits.push((insertion_anchor.clone()..insertion_anchor, text));
 
                     let row_delta = range_to_move.start.row - insertion_point.row + 1;
 
@@ -1773,7 +1778,7 @@ impl Editor {
         self.start_transaction(cx);
         self.unfold_ranges(unfold_ranges, cx);
         self.buffer.update(cx, |buffer, cx| {
-            for (range, text) in edits.into_iter().rev() {
+            for (range, text) in edits {
                 buffer.edit([range], text, cx);
             }
         });
@@ -1828,8 +1833,13 @@ impl Editor {
                     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));
+                    edits.push((
+                        buffer.anchor_after(range_to_move.start)
+                            ..buffer.anchor_before(range_to_move.end),
+                        String::new(),
+                    ));
+                    let insertion_anchor = buffer.anchor_after(insertion_point);
+                    edits.push((insertion_anchor.clone()..insertion_anchor, text));
 
                     let row_delta = insertion_point.row - range_to_move.end.row + 1;
 
@@ -1864,7 +1874,7 @@ impl Editor {
         self.start_transaction(cx);
         self.unfold_ranges(unfold_ranges, cx);
         self.buffer.update(cx, |buffer, cx| {
-            for (range, text) in edits.into_iter().rev() {
+            for (range, text) in edits {
                 buffer.edit([range], text, cx);
             }
         });
@@ -2962,7 +2972,7 @@ impl Editor {
                         let message_height = diagnostic.message.lines().count() as u8;
 
                         BlockProperties {
-                            position: entry.range.start,
+                            position: buffer.anchor_after(entry.range.start),
                             height: message_height,
                             render: diagnostic_block_renderer(diagnostic, true, build_settings),
                             disposition: BlockDisposition::Below,
@@ -3421,14 +3431,11 @@ impl Editor {
         }
     }
 
-    pub fn insert_blocks<P>(
+    pub fn insert_blocks(
         &mut self,
-        blocks: impl IntoIterator<Item = BlockProperties<P>>,
+        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
         cx: &mut ViewContext<Self>,
-    ) -> Vec<BlockId>
-    where
-        P: ToOffset + Clone,
-    {
+    ) -> Vec<BlockId> {
         let blocks = self
             .display_map
             .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
@@ -5130,12 +5137,13 @@ mod tests {
     fn test_move_line_up_down_with_blocks(cx: &mut gpui::MutableAppContext) {
         let settings = EditorSettings::test(&cx);
         let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
+        let snapshot = buffer.read(cx).snapshot(cx);
         let (_, editor) =
             cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
         editor.update(cx, |editor, cx| {
             editor.insert_blocks(
                 [BlockProperties {
-                    position: Point::new(2, 0),
+                    position: snapshot.anchor_after(Point::new(2, 0)),
                     disposition: BlockDisposition::Below,
                     height: 1,
                     render: Arc::new(|_| Empty::new().boxed()),