Calculate an `old_lines` range in `Edits` iterator

Antonio Scandurra created

Change summary

zed/src/editor/buffer.rs               | 124 +++++++++++++++------------
zed/src/editor/display_map/fold_map.rs |  50 +++++-----
zed/src/editor/display_map/wrap_map.rs |   3 
3 files changed, 96 insertions(+), 81 deletions(-)

Detailed changes

zed/src/editor/buffer.rs 🔗

@@ -372,28 +372,39 @@ impl UndoMap {
 }
 
 struct Edits<'a, F: Fn(&FragmentSummary) -> bool> {
+    visible_text: &'a Rope,
     deleted_text: &'a Rope,
     cursor: FilterCursor<'a, F, Fragment, FragmentTextSummary>,
     undos: &'a UndoMap,
     since: time::Global,
-    delta: isize,
+    old_offset: usize,
+    new_offset: usize,
+    old_point: Point,
+    new_point: Point,
 }
 
 #[derive(Clone, Debug, Default, Eq, PartialEq)]
 pub struct Edit {
-    pub old_range: Range<usize>,
-    pub new_range: Range<usize>,
-    pub old_lines: Point,
+    pub old_bytes: Range<usize>,
+    pub new_bytes: Range<usize>,
+    pub old_lines: Range<Point>,
 }
 
 impl Edit {
     pub fn delta(&self) -> isize {
-        (self.new_range.end - self.new_range.start) as isize
-            - (self.old_range.end - self.old_range.start) as isize
+        self.inserted_bytes() as isize - self.deleted_bytes() as isize
     }
 
-    pub fn old_extent(&self) -> usize {
-        self.old_range.end - self.old_range.start
+    pub fn deleted_bytes(&self) -> usize {
+        self.old_bytes.end - self.old_bytes.start
+    }
+
+    pub fn inserted_bytes(&self) -> usize {
+        self.new_bytes.end - self.new_bytes.start
+    }
+
+    pub fn deleted_lines(&self) -> Point {
+        self.old_lines.end - self.old_lines.start
     }
 }
 
@@ -776,25 +787,21 @@ impl Buffer {
         if let Some(syntax_tree) = self.syntax_tree.lock().as_mut() {
             let mut edited = false;
             let mut delta = 0_isize;
-            for Edit {
-                old_range,
-                new_range,
-                old_lines,
-            } in self.edits_since(syntax_tree.version.clone())
-            {
-                let start_offset = (old_range.start as isize + delta) as usize;
+            for edit in self.edits_since(syntax_tree.version.clone()) {
+                let start_offset = (edit.old_bytes.start as isize + delta) as usize;
                 let start_point = self.visible_text.to_point(start_offset);
-                let old_bytes = old_range.end - old_range.start;
-                let new_bytes = new_range.end - new_range.start;
                 syntax_tree.tree.edit(&InputEdit {
                     start_byte: start_offset,
-                    old_end_byte: start_offset + old_bytes,
-                    new_end_byte: start_offset + new_bytes,
+                    old_end_byte: start_offset + edit.deleted_bytes(),
+                    new_end_byte: start_offset + edit.inserted_bytes(),
                     start_position: start_point.into(),
-                    old_end_position: (start_point + old_lines).into(),
-                    new_end_position: self.visible_text.to_point(start_offset + new_bytes).into(),
+                    old_end_position: (start_point + edit.deleted_lines()).into(),
+                    new_end_position: self
+                        .visible_text
+                        .to_point(start_offset + edit.inserted_bytes())
+                        .into(),
                 });
-                delta += new_bytes as isize - old_bytes as isize;
+                delta += edit.inserted_bytes() as isize - edit.deleted_bytes() as isize;
                 edited = true;
             }
             syntax_tree.parsed &= !edited;
@@ -1051,11 +1058,15 @@ impl Buffer {
         );
 
         Edits {
+            visible_text: &self.visible_text,
             deleted_text: &self.deleted_text,
             cursor,
             undos: &self.undo_map,
             since,
-            delta: 0,
+            old_offset: 0,
+            new_offset: 0,
+            old_point: Point::zero(),
+            new_point: Point::zero(),
         }
     }
 
@@ -2089,45 +2100,53 @@ impl<'a, F: Fn(&FragmentSummary) -> bool> Iterator for Edits<'a, F> {
         let mut change: Option<Edit> = None;
 
         while let Some(fragment) = self.cursor.item() {
-            let new_offset = self.cursor.start().visible;
-            let old_offset = (new_offset as isize - self.delta) as usize;
+            let bytes = self.cursor.start().visible - self.new_offset;
+            let lines = self.visible_text.to_point(self.cursor.start().visible) - self.new_point;
+            self.old_offset += bytes;
+            self.old_point += &lines;
+            self.new_offset += bytes;
+            self.new_point += &lines;
 
             if !fragment.was_visible(&self.since, &self.undos) && fragment.visible {
+                let fragment_lines =
+                    self.visible_text.to_point(self.new_offset + fragment.len) - self.new_point;
                 if let Some(ref mut change) = change {
-                    if change.new_range.end == new_offset {
-                        change.new_range.end += fragment.len;
-                        self.delta += fragment.len as isize;
+                    if change.new_bytes.end == self.new_offset {
+                        change.new_bytes.end += fragment.len;
                     } else {
                         break;
                     }
                 } else {
                     change = Some(Edit {
-                        old_range: old_offset..old_offset,
-                        new_range: new_offset..new_offset + fragment.len,
-                        old_lines: Point::zero(),
+                        old_bytes: self.old_offset..self.old_offset,
+                        new_bytes: self.new_offset..self.new_offset + fragment.len,
+                        old_lines: self.old_point..self.old_point,
                     });
-                    self.delta += fragment.len as isize;
                 }
+
+                self.new_offset += fragment.len;
+                self.new_point += &fragment_lines;
             } else if fragment.was_visible(&self.since, &self.undos) && !fragment.visible {
                 let deleted_start = self.cursor.start().deleted;
-                let old_lines = self.deleted_text.to_point(deleted_start + fragment.len)
+                let fragment_lines = self.deleted_text.to_point(deleted_start + fragment.len)
                     - self.deleted_text.to_point(deleted_start);
                 if let Some(ref mut change) = change {
-                    if change.new_range.end == new_offset {
-                        change.old_range.end += fragment.len;
-                        change.old_lines += &old_lines;
-                        self.delta -= fragment.len as isize;
+                    if change.new_bytes.end == self.new_offset {
+                        change.old_bytes.end += fragment.len;
+                        change.old_lines.end += &fragment_lines;
                     } else {
                         break;
                     }
                 } else {
                     change = Some(Edit {
-                        old_range: old_offset..old_offset + fragment.len,
-                        new_range: new_offset..new_offset,
-                        old_lines,
+                        old_bytes: self.old_offset..self.old_offset + fragment.len,
+                        new_bytes: self.new_offset..self.new_offset,
+                        old_lines: self.old_point..self.old_point + &fragment_lines,
                     });
-                    self.delta -= fragment.len as isize;
                 }
+
+                self.old_offset += fragment.len;
+                self.old_point += &fragment_lines;
             }
 
             self.cursor.next(&None);
@@ -2898,19 +2917,16 @@ mod tests {
                     );
 
                     let mut delta = 0_isize;
-                    for Edit {
-                        old_range,
-                        new_range,
-                        ..
-                    } in edits
-                    {
-                        let old_len = old_range.end - old_range.start;
-                        let new_len = new_range.end - new_range.start;
-                        let old_start = (old_range.start as isize + delta) as usize;
-                        let new_text: String = buffer.text_for_range(new_range).collect();
-                        old_buffer.edit(Some(old_start..old_start + old_len), new_text, cx);
-
-                        delta += new_len as isize - old_len as isize;
+                    for edit in edits {
+                        let old_start = (edit.old_bytes.start as isize + delta) as usize;
+                        let new_text: String =
+                            buffer.text_for_range(edit.new_bytes.clone()).collect();
+                        old_buffer.edit(
+                            Some(old_start..old_start + edit.deleted_bytes()),
+                            new_text,
+                            cx,
+                        );
+                        delta += edit.delta();
                     }
                     assert_eq!(old_buffer.text(), buffer.text());
                 }

zed/src/editor/display_map/fold_map.rs 🔗

@@ -106,8 +106,8 @@ impl FoldMap {
                 let fold = Fold(buffer.anchor_after(range.start)..buffer.anchor_before(range.end));
                 folds.push(fold);
                 edits.push(Edit {
-                    old_range: range.clone(),
-                    new_range: range.clone(),
+                    old_bytes: range.clone(),
+                    new_bytes: range.clone(),
                     ..Default::default()
                 });
             }
@@ -115,10 +115,10 @@ impl FoldMap {
 
         folds.sort_unstable_by(|a, b| sum_tree::SeekDimension::cmp(a, b, buffer));
         edits.sort_unstable_by(|a, b| {
-            a.old_range
+            a.old_bytes
                 .start
-                .cmp(&b.old_range.start)
-                .then_with(|| b.old_range.end.cmp(&a.old_range.end))
+                .cmp(&b.old_bytes.start)
+                .then_with(|| b.old_bytes.end.cmp(&a.old_bytes.end))
         });
 
         self.folds = {
@@ -151,8 +151,8 @@ impl FoldMap {
             while let Some(fold) = folds_cursor.item() {
                 let offset_range = fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer);
                 edits.push(Edit {
-                    old_range: offset_range.clone(),
-                    new_range: offset_range,
+                    old_bytes: offset_range.clone(),
+                    new_bytes: offset_range,
                     ..Default::default()
                 });
                 fold_ixs_to_delete.push(*folds_cursor.start());
@@ -163,10 +163,10 @@ impl FoldMap {
         fold_ixs_to_delete.sort_unstable();
         fold_ixs_to_delete.dedup();
         edits.sort_unstable_by(|a, b| {
-            a.old_range
+            a.old_bytes
                 .start
-                .cmp(&b.old_range.start)
-                .then_with(|| b.old_range.end.cmp(&a.old_range.end))
+                .cmp(&b.old_bytes.start)
+                .then_with(|| b.old_bytes.end.cmp(&a.old_bytes.end))
         });
 
         self.folds = {
@@ -278,28 +278,28 @@ impl FoldMap {
         cursor.seek(&0, Bias::Right, &());
 
         while let Some(mut edit) = edits.next() {
-            new_transforms.push_tree(cursor.slice(&edit.old_range.start, Bias::Left, &()), &());
-            edit.new_range.start -= edit.old_range.start - cursor.seek_start();
-            edit.old_range.start = *cursor.seek_start();
+            new_transforms.push_tree(cursor.slice(&edit.old_bytes.start, Bias::Left, &()), &());
+            edit.new_bytes.start -= edit.old_bytes.start - cursor.seek_start();
+            edit.old_bytes.start = *cursor.seek_start();
 
-            cursor.seek(&edit.old_range.end, Bias::Right, &());
+            cursor.seek(&edit.old_bytes.end, Bias::Right, &());
             cursor.next(&());
 
             let mut delta = edit.delta();
             loop {
-                edit.old_range.end = *cursor.seek_start();
+                edit.old_bytes.end = *cursor.seek_start();
 
                 if let Some(next_edit) = edits.peek() {
-                    if next_edit.old_range.start > edit.old_range.end {
+                    if next_edit.old_bytes.start > edit.old_bytes.end {
                         break;
                     }
 
                     let next_edit = edits.next().unwrap();
                     delta += next_edit.delta();
 
-                    if next_edit.old_range.end >= edit.old_range.end {
-                        edit.old_range.end = next_edit.old_range.end;
-                        cursor.seek(&edit.old_range.end, Bias::Right, &());
+                    if next_edit.old_bytes.end >= edit.old_bytes.end {
+                        edit.old_bytes.end = next_edit.old_bytes.end;
+                        cursor.seek(&edit.old_bytes.end, Bias::Right, &());
                         cursor.next(&());
                     }
                 } else {
@@ -307,10 +307,10 @@ impl FoldMap {
                 }
             }
 
-            edit.new_range.end =
-                ((edit.new_range.start + edit.old_extent()) as isize + delta) as usize;
+            edit.new_bytes.end =
+                ((edit.new_bytes.start + edit.deleted_bytes()) as isize + delta) as usize;
 
-            let anchor = buffer.anchor_before(edit.new_range.start);
+            let anchor = buffer.anchor_before(edit.new_bytes.start);
             let mut folds_cursor = self.folds.cursor::<_, ()>();
             folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, buffer);
             let mut folds = iter::from_fn(move || {
@@ -324,7 +324,7 @@ impl FoldMap {
 
             while folds
                 .peek()
-                .map_or(false, |fold| fold.start < edit.new_range.end)
+                .map_or(false, |fold| fold.start < edit.new_bytes.end)
             {
                 let mut fold = folds.next().unwrap();
                 let sum = new_transforms.summary();
@@ -380,9 +380,9 @@ impl FoldMap {
             }
 
             let sum = new_transforms.summary();
-            if sum.buffer.bytes < edit.new_range.end {
+            if sum.buffer.bytes < edit.new_bytes.end {
                 let text_summary =
-                    buffer.text_summary_for_range(sum.buffer.bytes..edit.new_range.end);
+                    buffer.text_summary_for_range(sum.buffer.bytes..edit.new_bytes.end);
                 new_transforms.push(
                     Transform {
                         summary: TransformSummary {

zed/src/editor/display_map/wrap_map.rs 🔗

@@ -117,9 +117,8 @@ impl BackgroundWrapper {
         {
             let mut old_cursor = self.snapshot.transforms.cursor::<Point, ()>();
             for edit in buffer.edits_since(self.snapshot.version.clone()) {
-                // TODO: old lines gives us an extent but we really want to park ourselves at the start of the line.
                 new_transforms.push_tree(
-                    old_cursor.slice(&Point::new(edit.old_lines.row, 0), Bias::Left, &()),
+                    old_cursor.slice(&Point::new(edit.old_lines.start.row, 0), Bias::Left, &()),
                     &(),
                 );
             }