Merge pull request #88 from zed-industries/seek-start

Antonio Scandurra created

Introduce `Cursor::seek_start` and `Cursor::seek_end`

Change summary

zed/src/editor/buffer.rs               | 38 +++++-----
zed/src/editor/buffer/rope.rs          | 52 +++++++-------
zed/src/editor/display_map/fold_map.rs | 95 +++++++++++++--------------
zed/src/sum_tree.rs                    | 56 ++++++----------
zed/src/sum_tree/cursor.rs             | 22 +++++-
zed/src/worktree.rs                    |  8 +-
6 files changed, 135 insertions(+), 136 deletions(-)

Detailed changes

zed/src/editor/buffer.rs 🔗

@@ -1210,7 +1210,7 @@ impl Buffer {
             old_fragments.slice(&VersionedOffset::Offset(ranges[0].start), Bias::Left, &cx);
         new_ropes.push_tree(new_fragments.summary().text);
 
-        let mut fragment_start = old_fragments.start().offset();
+        let mut fragment_start = old_fragments.sum_start().offset();
         for range in ranges {
             let fragment_end = old_fragments.end(&cx).offset();
 
@@ -1219,7 +1219,7 @@ impl Buffer {
             if fragment_end < range.start {
                 // If the current fragment has been partially consumed, then consume the rest of it
                 // and advance to the next fragment before slicing.
-                if fragment_start > old_fragments.start().offset() {
+                if fragment_start > old_fragments.sum_start().offset() {
                     if fragment_end > fragment_start {
                         let mut suffix = old_fragments.item().unwrap().clone();
                         suffix.len = fragment_end - fragment_start;
@@ -1233,7 +1233,7 @@ impl Buffer {
                     old_fragments.slice(&VersionedOffset::Offset(range.start), Bias::Left, &cx);
                 new_ropes.push_tree(slice.summary().text);
                 new_fragments.push_tree(slice, &None);
-                fragment_start = old_fragments.start().offset();
+                fragment_start = old_fragments.sum_start().offset();
             }
 
             // If we are at the end of a non-concurrent fragment, advance to the next one.
@@ -1244,7 +1244,7 @@ impl Buffer {
                 new_ropes.push_fragment(&fragment, fragment.visible);
                 new_fragments.push(fragment, &None);
                 old_fragments.next(&cx);
-                fragment_start = old_fragments.start().offset();
+                fragment_start = old_fragments.sum_start().offset();
             }
 
             // Skip over insertions that are concurrent to this edit, but have a lower lamport
@@ -1312,7 +1312,7 @@ impl Buffer {
 
         // If the current fragment has been partially consumed, then consume the rest of it
         // and advance to the next fragment before slicing.
-        if fragment_start > old_fragments.start().offset() {
+        if fragment_start > old_fragments.sum_start().offset() {
             let fragment_end = old_fragments.end(&cx).offset();
             if fragment_end > fragment_start {
                 let mut suffix = old_fragments.item().unwrap().clone();
@@ -1539,7 +1539,7 @@ impl Buffer {
         let mut new_fragments = old_fragments.slice(&ranges[0].start, Bias::Right, &None);
         new_ropes.push_tree(new_fragments.summary().text);
 
-        let mut fragment_start = old_fragments.start().visible;
+        let mut fragment_start = old_fragments.sum_start().visible;
         for range in ranges {
             let fragment_end = old_fragments.end(&None).visible;
 
@@ -1548,7 +1548,7 @@ impl Buffer {
             if fragment_end < range.start {
                 // If the current fragment has been partially consumed, then consume the rest of it
                 // and advance to the next fragment before slicing.
-                if fragment_start > old_fragments.start().visible {
+                if fragment_start > old_fragments.sum_start().visible {
                     if fragment_end > fragment_start {
                         let mut suffix = old_fragments.item().unwrap().clone();
                         suffix.len = fragment_end - fragment_start;
@@ -1561,10 +1561,10 @@ impl Buffer {
                 let slice = old_fragments.slice(&range.start, Bias::Right, &None);
                 new_ropes.push_tree(slice.summary().text);
                 new_fragments.push_tree(slice, &None);
-                fragment_start = old_fragments.start().visible;
+                fragment_start = old_fragments.sum_start().visible;
             }
 
-            let full_range_start = range.start + old_fragments.start().deleted;
+            let full_range_start = range.start + old_fragments.sum_start().deleted;
 
             // Preserve any portion of the current fragment that precedes this range.
             if fragment_start < range.start {
@@ -1612,13 +1612,13 @@ impl Buffer {
                 }
             }
 
-            let full_range_end = range.end + old_fragments.start().deleted;
+            let full_range_end = range.end + old_fragments.sum_start().deleted;
             edit.ranges.push(full_range_start..full_range_end);
         }
 
         // If the current fragment has been partially consumed, then consume the rest of it
         // and advance to the next fragment before slicing.
-        if fragment_start > old_fragments.start().visible {
+        if fragment_start > old_fragments.sum_start().visible {
             let fragment_end = old_fragments.end(&None).visible;
             if fragment_end > fragment_start {
                 let mut suffix = old_fragments.item().unwrap().clone();
@@ -1663,7 +1663,7 @@ impl Buffer {
             let mut cursor = self.fragments.cursor::<usize, FragmentTextSummary>();
             cursor.seek(&offset, bias, &None);
             Anchor::Middle {
-                offset: offset + cursor.start().deleted,
+                offset: offset + cursor.sum_start().deleted,
                 bias,
                 version: self.version(),
             }
@@ -1679,9 +1679,7 @@ impl Buffer {
                 bias,
                 version,
             } => {
-                let mut cursor = self
-                    .fragments
-                    .cursor::<VersionedOffset, (VersionedOffset, usize)>();
+                let mut cursor = self.fragments.cursor::<VersionedOffset, usize>();
                 cursor.seek(
                     &VersionedOffset::Offset(*offset),
                     *bias,
@@ -1689,12 +1687,12 @@ impl Buffer {
                 );
                 let fragment = cursor.item().unwrap();
                 let overshoot = if fragment.visible {
-                    offset - cursor.start().0.offset()
+                    offset - cursor.seek_start().offset()
                 } else {
                     0
                 };
 
-                self.text_summary_for_range(0..cursor.start().1 + overshoot)
+                self.text_summary_for_range(0..cursor.sum_start() + overshoot)
             }
         }
     }
@@ -1713,14 +1711,14 @@ impl Buffer {
             } => {
                 let mut cursor = self
                     .fragments
-                    .cursor::<VersionedOffset, (VersionedOffset, FragmentTextSummary)>();
+                    .cursor::<VersionedOffset, FragmentTextSummary>();
                 cursor.seek(
                     &VersionedOffset::Offset(*offset),
                     *bias,
                     &Some(version.clone()),
                 );
-                let overshoot = offset - cursor.start().0.offset();
-                let summary = cursor.start().1;
+                let overshoot = offset - cursor.seek_start().offset();
+                let summary = cursor.sum_start();
                 summary.visible + summary.deleted + overshoot
             }
         }

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

@@ -128,10 +128,10 @@ impl Rope {
 
     pub fn to_point(&self, offset: usize) -> Point {
         assert!(offset <= self.summary().bytes);
-        let mut cursor = self.chunks.cursor::<usize, TextSummary>();
+        let mut cursor = self.chunks.cursor::<usize, Point>();
         cursor.seek(&offset, Bias::Left, &());
-        let overshoot = offset - cursor.start().bytes;
-        cursor.start().lines
+        let overshoot = offset - cursor.seek_start();
+        *cursor.sum_start()
             + cursor
                 .item()
                 .map_or(Point::zero(), |chunk| chunk.to_point(overshoot))
@@ -139,17 +139,17 @@ impl Rope {
 
     pub fn to_offset(&self, point: Point) -> usize {
         assert!(point <= self.summary().lines);
-        let mut cursor = self.chunks.cursor::<Point, TextSummary>();
+        let mut cursor = self.chunks.cursor::<Point, usize>();
         cursor.seek(&point, Bias::Left, &());
-        let overshoot = point - cursor.start().lines;
-        cursor.start().bytes + cursor.item().map_or(0, |chunk| chunk.to_offset(overshoot))
+        let overshoot = point - cursor.seek_start();
+        cursor.sum_start() + cursor.item().map_or(0, |chunk| chunk.to_offset(overshoot))
     }
 
     pub fn clip_offset(&self, mut offset: usize, bias: Bias) -> usize {
-        let mut cursor = self.chunks.cursor::<usize, usize>();
+        let mut cursor = self.chunks.cursor::<usize, ()>();
         cursor.seek(&offset, Bias::Left, &());
         if let Some(chunk) = cursor.item() {
-            let mut ix = offset - cursor.start();
+            let mut ix = offset - cursor.seek_start();
             while !chunk.0.is_char_boundary(ix) {
                 match bias {
                     Bias::Left => {
@@ -169,11 +169,11 @@ impl Rope {
     }
 
     pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
-        let mut cursor = self.chunks.cursor::<Point, Point>();
+        let mut cursor = self.chunks.cursor::<Point, ()>();
         cursor.seek(&point, Bias::Right, &());
         if let Some(chunk) = cursor.item() {
-            let overshoot = point - cursor.start();
-            *cursor.start() + chunk.clip_point(overshoot, bias)
+            let overshoot = point - cursor.seek_start();
+            *cursor.seek_start() + chunk.clip_point(overshoot, bias)
         } else {
             self.summary().lines
         }
@@ -190,7 +190,7 @@ impl<'a> From<&'a str> for Rope {
 
 pub struct Cursor<'a> {
     rope: &'a Rope,
-    chunks: sum_tree::Cursor<'a, Chunk, usize, usize>,
+    chunks: sum_tree::Cursor<'a, Chunk, usize, ()>,
     offset: usize,
 }
 
@@ -222,18 +222,18 @@ impl<'a> Cursor<'a> {
 
         let mut slice = Rope::new();
         if let Some(start_chunk) = self.chunks.item() {
-            let start_ix = self.offset - self.chunks.start();
-            let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start();
+            let start_ix = self.offset - self.chunks.seek_start();
+            let end_ix = cmp::min(end_offset, self.chunks.seek_end(&())) - self.chunks.seek_start();
             slice.push(&start_chunk.0[start_ix..end_ix]);
         }
 
-        if end_offset > self.chunks.end(&()) {
+        if end_offset > self.chunks.seek_end(&()) {
             self.chunks.next(&());
             slice.append(Rope {
                 chunks: self.chunks.slice(&end_offset, Bias::Right, &()),
             });
             if let Some(end_chunk) = self.chunks.item() {
-                let end_ix = end_offset - self.chunks.start();
+                let end_ix = end_offset - self.chunks.seek_start();
                 slice.push(&end_chunk.0[..end_ix]);
             }
         }
@@ -247,16 +247,16 @@ impl<'a> Cursor<'a> {
 
         let mut summary = TextSummary::default();
         if let Some(start_chunk) = self.chunks.item() {
-            let start_ix = self.offset - self.chunks.start();
-            let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start();
+            let start_ix = self.offset - self.chunks.seek_start();
+            let end_ix = cmp::min(end_offset, self.chunks.seek_end(&())) - self.chunks.seek_start();
             summary = TextSummary::from(&start_chunk.0[start_ix..end_ix]);
         }
 
-        if end_offset > self.chunks.end(&()) {
+        if end_offset > self.chunks.seek_end(&()) {
             self.chunks.next(&());
             summary += &self.chunks.summary(&end_offset, Bias::Right, &());
             if let Some(end_chunk) = self.chunks.item() {
-                let end_ix = end_offset - self.chunks.start();
+                let end_ix = end_offset - self.chunks.seek_start();
                 summary += TextSummary::from(&end_chunk.0[..end_ix]);
             }
         }
@@ -274,7 +274,7 @@ impl<'a> Cursor<'a> {
 }
 
 pub struct Chunks<'a> {
-    chunks: sum_tree::Cursor<'a, Chunk, usize, usize>,
+    chunks: sum_tree::Cursor<'a, Chunk, usize, ()>,
     range: Range<usize>,
 }
 
@@ -286,11 +286,11 @@ impl<'a> Chunks<'a> {
     }
 
     pub fn offset(&self) -> usize {
-        self.range.start.max(*self.chunks.start())
+        self.range.start.max(*self.chunks.seek_start())
     }
 
     pub fn seek(&mut self, offset: usize) {
-        if offset >= self.chunks.end(&()) {
+        if offset >= self.chunks.seek_end(&()) {
             self.chunks.seek_forward(&offset, Bias::Right, &());
         } else {
             self.chunks.seek(&offset, Bias::Right, &());
@@ -300,10 +300,10 @@ impl<'a> Chunks<'a> {
 
     pub fn peek(&self) -> Option<&'a str> {
         if let Some(chunk) = self.chunks.item() {
-            let offset = *self.chunks.start();
+            let offset = *self.chunks.seek_start();
             if self.range.end > offset {
-                let start = self.range.start.saturating_sub(*self.chunks.start());
-                let end = self.range.end - self.chunks.start();
+                let start = self.range.start.saturating_sub(*self.chunks.seek_start());
+                let end = self.range.end - self.chunks.seek_start();
                 return Some(&chunk.0[start..chunk.0.len().min(end)]);
             }
         }

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

@@ -210,20 +210,20 @@ impl FoldMap {
         let buffer = self.buffer.read(cx);
         let offset = offset.to_offset(buffer);
         let transforms = self.sync(cx);
-        let mut cursor = transforms.cursor::<usize, usize>();
+        let mut cursor = transforms.cursor::<usize, ()>();
         cursor.seek(&offset, Bias::Right, &());
         cursor.item().map_or(false, |t| t.display_text.is_some())
     }
 
     pub fn is_line_folded(&self, display_row: u32, cx: &AppContext) -> bool {
         let transforms = self.sync(cx);
-        let mut cursor = transforms.cursor::<DisplayPoint, DisplayPoint>();
+        let mut cursor = transforms.cursor::<DisplayPoint, ()>();
         cursor.seek(&DisplayPoint::new(display_row, 0), Bias::Right, &());
         while let Some(transform) = cursor.item() {
             if transform.display_text.is_some() {
                 return true;
             }
-            if cursor.end(&()).row() == display_row {
+            if cursor.seek_end(&()).row() == display_row {
                 cursor.next(&())
             } else {
                 break;
@@ -242,20 +242,20 @@ impl FoldMap {
 
     pub fn to_buffer_point(&self, display_point: DisplayPoint, cx: &AppContext) -> Point {
         let transforms = self.sync(cx);
-        let mut cursor = transforms.cursor::<DisplayPoint, TransformSummary>();
+        let mut cursor = transforms.cursor::<DisplayPoint, Point>();
         cursor.seek(&display_point, Bias::Right, &());
-        let overshoot = display_point.0 - cursor.start().display.lines;
-        cursor.start().buffer.lines + overshoot
+        let overshoot = display_point.0 - cursor.seek_start().0;
+        *cursor.sum_start() + overshoot
     }
 
     pub fn to_display_point(&self, point: Point, cx: &AppContext) -> DisplayPoint {
         let transforms = self.sync(cx);
-        let mut cursor = transforms.cursor::<Point, TransformSummary>();
+        let mut cursor = transforms.cursor::<Point, DisplayPoint>();
         cursor.seek(&point, Bias::Right, &());
-        let overshoot = point - cursor.start().buffer.lines;
+        let overshoot = point - cursor.seek_start();
         DisplayPoint(cmp::min(
-            cursor.start().display.lines + overshoot,
-            cursor.end(&()).display.lines,
+            cursor.sum_start().0 + overshoot,
+            cursor.end(&()).0,
         ))
     }
 
@@ -275,20 +275,20 @@ impl FoldMap {
 
         let mut new_transforms = SumTree::new();
         let mut transforms = self.transforms.lock();
-        let mut cursor = transforms.cursor::<usize, usize>();
+        let mut cursor = transforms.cursor::<usize, ()>();
         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.start();
-            edit.old_range.start = *cursor.start();
+            edit.new_range.start -= edit.old_range.start - cursor.seek_start();
+            edit.old_range.start = *cursor.seek_start();
 
             cursor.seek(&edit.old_range.end, Bias::Right, &());
             cursor.next(&());
 
             let mut delta = edit.delta();
             loop {
-                edit.old_range.end = *cursor.start();
+                edit.old_range.end = *cursor.seek_start();
 
                 if let Some(next_edit) = edits.peek() {
                     if next_edit.old_range.start > edit.old_range.end {
@@ -443,10 +443,10 @@ impl FoldMapSnapshot {
     }
 
     pub fn chunks_at(&self, offset: DisplayOffset) -> Chunks {
-        let mut transform_cursor = self.transforms.cursor::<DisplayOffset, TransformSummary>();
+        let mut transform_cursor = self.transforms.cursor::<DisplayOffset, usize>();
         transform_cursor.seek(&offset, Bias::Right, &());
-        let overshoot = offset.0 - transform_cursor.start().display.bytes;
-        let buffer_offset = transform_cursor.start().buffer.bytes + overshoot;
+        let overshoot = offset.0 - transform_cursor.seek_start().0;
+        let buffer_offset = transform_cursor.sum_start() + overshoot;
         Chunks {
             transform_cursor,
             buffer_offset,
@@ -455,15 +455,15 @@ impl FoldMapSnapshot {
     }
 
     pub fn highlighted_chunks(&mut self, range: Range<DisplayOffset>) -> HighlightedChunks {
-        let mut transform_cursor = self.transforms.cursor::<DisplayOffset, TransformSummary>();
+        let mut transform_cursor = self.transforms.cursor::<DisplayOffset, usize>();
 
         transform_cursor.seek(&range.end, Bias::Right, &());
-        let overshoot = range.end.0 - transform_cursor.start().display.bytes;
-        let buffer_end = transform_cursor.start().buffer.bytes + overshoot;
+        let overshoot = range.end.0 - transform_cursor.seek_start().0;
+        let buffer_end = transform_cursor.sum_start() + overshoot;
 
         transform_cursor.seek(&range.start, Bias::Right, &());
-        let overshoot = range.start.0 - transform_cursor.start().display.bytes;
-        let buffer_start = transform_cursor.start().buffer.bytes + overshoot;
+        let overshoot = range.start.0 - transform_cursor.seek_start().0;
+        let buffer_start = transform_cursor.sum_start() + overshoot;
 
         HighlightedChunks {
             transform_cursor,
@@ -483,42 +483,41 @@ impl FoldMapSnapshot {
     pub fn to_display_offset(&self, point: DisplayPoint) -> DisplayOffset {
         let mut cursor = self.transforms.cursor::<DisplayPoint, TransformSummary>();
         cursor.seek(&point, Bias::Right, &());
-        let overshoot = point.0 - cursor.start().display.lines;
-        let mut offset = cursor.start().display.bytes;
+        let overshoot = point.0 - cursor.sum_start().display.lines;
+        let mut offset = cursor.sum_start().display.bytes;
         if !overshoot.is_zero() {
             let transform = cursor.item().expect("display point out of range");
             assert!(transform.display_text.is_none());
             let end_buffer_offset = self
                 .buffer
-                .to_offset(cursor.start().buffer.lines + overshoot);
-            offset += end_buffer_offset - cursor.start().buffer.bytes;
+                .to_offset(cursor.sum_start().buffer.lines + overshoot);
+            offset += end_buffer_offset - cursor.sum_start().buffer.bytes;
         }
         DisplayOffset(offset)
     }
 
     pub fn to_buffer_offset(&self, point: DisplayPoint) -> usize {
-        let mut cursor = self.transforms.cursor::<DisplayPoint, TransformSummary>();
+        let mut cursor = self.transforms.cursor::<DisplayPoint, Point>();
         cursor.seek(&point, Bias::Right, &());
-        let overshoot = point.0 - cursor.start().display.lines;
-        self.buffer
-            .to_offset(cursor.start().buffer.lines + overshoot)
+        let overshoot = point.0 - cursor.seek_start().0;
+        self.buffer.to_offset(*cursor.sum_start() + overshoot)
     }
 
     #[cfg(test)]
     pub fn clip_offset(&self, offset: DisplayOffset, bias: Bias) -> DisplayOffset {
-        let mut cursor = self.transforms.cursor::<DisplayOffset, TransformSummary>();
+        let mut cursor = self.transforms.cursor::<DisplayOffset, usize>();
         cursor.seek(&offset, Bias::Right, &());
         if let Some(transform) = cursor.item() {
-            let transform_start = cursor.start().display.bytes;
+            let transform_start = cursor.seek_start().0;
             if transform.display_text.is_some() {
                 if offset.0 == transform_start || matches!(bias, Bias::Left) {
                     DisplayOffset(transform_start)
                 } else {
-                    DisplayOffset(cursor.end(&()).display.bytes)
+                    DisplayOffset(cursor.seek_end(&()).0)
                 }
             } else {
                 let overshoot = offset.0 - transform_start;
-                let buffer_offset = cursor.start().buffer.bytes + overshoot;
+                let buffer_offset = cursor.sum_start() + overshoot;
                 let clipped_buffer_offset = self.buffer.clip_offset(buffer_offset, bias);
                 DisplayOffset(
                     (offset.0 as isize + (clipped_buffer_offset as isize - buffer_offset as isize))
@@ -531,19 +530,19 @@ impl FoldMapSnapshot {
     }
 
     pub fn clip_point(&self, point: DisplayPoint, bias: Bias) -> DisplayPoint {
-        let mut cursor = self.transforms.cursor::<DisplayPoint, TransformSummary>();
+        let mut cursor = self.transforms.cursor::<DisplayPoint, Point>();
         cursor.seek(&point, Bias::Right, &());
         if let Some(transform) = cursor.item() {
-            let transform_start = cursor.start().display.lines;
+            let transform_start = cursor.seek_start().0;
             if transform.display_text.is_some() {
                 if point.0 == transform_start || matches!(bias, Bias::Left) {
                     DisplayPoint(transform_start)
                 } else {
-                    DisplayPoint(cursor.end(&()).display.lines)
+                    DisplayPoint(cursor.seek_end(&()).0)
                 }
             } else {
                 let overshoot = point.0 - transform_start;
-                let buffer_position = cursor.start().buffer.lines + overshoot;
+                let buffer_position = *cursor.sum_start() + overshoot;
                 let clipped_buffer_position = self.buffer.clip_point(buffer_position, bias);
                 DisplayPoint::new(
                     point.row(),
@@ -681,7 +680,7 @@ impl<'a> sum_tree::Dimension<'a, FoldSummary> for usize {
 }
 
 pub struct BufferRows<'a> {
-    cursor: Cursor<'a, Transform, DisplayPoint, TransformSummary>,
+    cursor: Cursor<'a, Transform, DisplayPoint, Point>,
     display_point: Point,
 }
 
@@ -689,7 +688,7 @@ impl<'a> Iterator for BufferRows<'a> {
     type Item = u32;
 
     fn next(&mut self) -> Option<Self::Item> {
-        while self.display_point > self.cursor.end(&()).display.lines {
+        while self.display_point > self.cursor.seek_end(&()).0 {
             self.cursor.next(&());
             if self.cursor.item().is_none() {
                 // TODO: Return a bool from next?
@@ -698,8 +697,8 @@ impl<'a> Iterator for BufferRows<'a> {
         }
 
         if self.cursor.item().is_some() {
-            let overshoot = self.display_point - self.cursor.start().display.lines;
-            let buffer_point = self.cursor.start().buffer.lines + overshoot;
+            let overshoot = self.display_point - self.cursor.seek_start().0;
+            let buffer_point = *self.cursor.sum_start() + overshoot;
             self.display_point.row += 1;
             Some(buffer_point.row)
         } else {
@@ -709,7 +708,7 @@ impl<'a> Iterator for BufferRows<'a> {
 }
 
 pub struct Chunks<'a> {
-    transform_cursor: Cursor<'a, Transform, DisplayOffset, TransformSummary>,
+    transform_cursor: Cursor<'a, Transform, DisplayOffset, usize>,
     buffer_chunks: buffer::Chunks<'a>,
     buffer_offset: usize,
 }
@@ -730,7 +729,7 @@ impl<'a> Iterator for Chunks<'a> {
             self.buffer_offset += transform.summary.buffer.bytes;
             self.buffer_chunks.seek(self.buffer_offset);
 
-            while self.buffer_offset >= self.transform_cursor.end(&()).buffer.bytes
+            while self.buffer_offset >= self.transform_cursor.end(&())
                 && self.transform_cursor.item().is_some()
             {
                 self.transform_cursor.next(&());
@@ -745,7 +744,7 @@ impl<'a> Iterator for Chunks<'a> {
             chunk = &chunk[offset_in_chunk..];
 
             // Truncate the chunk so that it ends at the next fold.
-            let region_end = self.transform_cursor.end(&()).buffer.bytes - self.buffer_offset;
+            let region_end = self.transform_cursor.end(&()) - self.buffer_offset;
             if chunk.len() >= region_end {
                 chunk = &chunk[0..region_end];
                 self.transform_cursor.next(&());
@@ -762,7 +761,7 @@ impl<'a> Iterator for Chunks<'a> {
 }
 
 pub struct HighlightedChunks<'a> {
-    transform_cursor: Cursor<'a, Transform, DisplayOffset, TransformSummary>,
+    transform_cursor: Cursor<'a, Transform, DisplayOffset, usize>,
     buffer_chunks: buffer::HighlightedChunks<'a>,
     buffer_chunk: Option<(usize, &'a str, StyleId)>,
     buffer_offset: usize,
@@ -785,7 +784,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
             self.buffer_offset += transform.summary.buffer.bytes;
             self.buffer_chunks.seek(self.buffer_offset);
 
-            while self.buffer_offset >= self.transform_cursor.end(&()).buffer.bytes
+            while self.buffer_offset >= self.transform_cursor.end(&())
                 && self.transform_cursor.item().is_some()
             {
                 self.transform_cursor.next(&());
@@ -809,7 +808,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
             chunk = &chunk[offset_in_chunk..];
 
             // Truncate the chunk so that it ends at the next fold.
-            let region_end = self.transform_cursor.end(&()).buffer.bytes - self.buffer_offset;
+            let region_end = self.transform_cursor.end(&()) - self.buffer_offset;
             if chunk.len() >= region_end {
                 chunk = &chunk[0..region_end];
                 self.transform_cursor.next(&());

zed/src/sum_tree.rs 🔗

@@ -37,18 +37,6 @@ impl<'a, T: Summary> Dimension<'a, T> for () {
     fn add_summary(&mut self, _: &'a T, _: &T::Context) {}
 }
 
-impl<'a, S, D1, D2> Dimension<'a, S> for (D1, D2)
-where
-    S: Summary,
-    D1: Dimension<'a, S>,
-    D2: Dimension<'a, S>,
-{
-    fn add_summary(&mut self, summary: &'a S, cx: &S::Context) {
-        self.0.add_summary(summary, cx);
-        self.1.add_summary(summary, cx);
-    }
-}
-
 pub trait SeekDimension<'a, T: Summary>: Dimension<'a, T> {
     fn cmp(&self, other: &Self, cx: &T::Context) -> Ordering;
 }
@@ -663,7 +651,7 @@ mod tests {
                 cursor.seek(&Count(pos), Bias::Right, &());
 
                 for i in 0..10 {
-                    assert_eq!(cursor.start().0, pos);
+                    assert_eq!(cursor.sum_start().0, pos);
 
                     if pos > 0 {
                         assert_eq!(cursor.prev_item().unwrap(), &reference_items[pos - 1]);
@@ -722,7 +710,7 @@ mod tests {
         );
         assert_eq!(cursor.item(), None);
         assert_eq!(cursor.prev_item(), None);
-        assert_eq!(cursor.start(), &Sum(0));
+        assert_eq!(cursor.sum_start(), &Sum(0));
 
         // Single-element tree
         let mut tree = SumTree::<u8>::new();
@@ -734,23 +722,23 @@ mod tests {
         );
         assert_eq!(cursor.item(), Some(&1));
         assert_eq!(cursor.prev_item(), None);
-        assert_eq!(cursor.start(), &Sum(0));
+        assert_eq!(cursor.sum_start(), &Sum(0));
 
         cursor.next(&());
         assert_eq!(cursor.item(), None);
         assert_eq!(cursor.prev_item(), Some(&1));
-        assert_eq!(cursor.start(), &Sum(1));
+        assert_eq!(cursor.sum_start(), &Sum(1));
 
         cursor.prev(&());
         assert_eq!(cursor.item(), Some(&1));
         assert_eq!(cursor.prev_item(), None);
-        assert_eq!(cursor.start(), &Sum(0));
+        assert_eq!(cursor.sum_start(), &Sum(0));
 
         let mut cursor = tree.cursor::<Count, Sum>();
         assert_eq!(cursor.slice(&Count(1), Bias::Right, &()).items(&()), [1]);
         assert_eq!(cursor.item(), None);
         assert_eq!(cursor.prev_item(), Some(&1));
-        assert_eq!(cursor.start(), &Sum(1));
+        assert_eq!(cursor.sum_start(), &Sum(1));
 
         cursor.seek(&Count(0), Bias::Right, &());
         assert_eq!(
@@ -761,7 +749,7 @@ mod tests {
         );
         assert_eq!(cursor.item(), None);
         assert_eq!(cursor.prev_item(), Some(&1));
-        assert_eq!(cursor.start(), &Sum(1));
+        assert_eq!(cursor.sum_start(), &Sum(1));
 
         // Multiple-element tree
         let mut tree = SumTree::new();
@@ -771,68 +759,68 @@ mod tests {
         assert_eq!(cursor.slice(&Count(2), Bias::Right, &()).items(&()), [1, 2]);
         assert_eq!(cursor.item(), Some(&3));
         assert_eq!(cursor.prev_item(), Some(&2));
-        assert_eq!(cursor.start(), &Sum(3));
+        assert_eq!(cursor.sum_start(), &Sum(3));
 
         cursor.next(&());
         assert_eq!(cursor.item(), Some(&4));
         assert_eq!(cursor.prev_item(), Some(&3));
-        assert_eq!(cursor.start(), &Sum(6));
+        assert_eq!(cursor.sum_start(), &Sum(6));
 
         cursor.next(&());
         assert_eq!(cursor.item(), Some(&5));
         assert_eq!(cursor.prev_item(), Some(&4));
-        assert_eq!(cursor.start(), &Sum(10));
+        assert_eq!(cursor.sum_start(), &Sum(10));
 
         cursor.next(&());
         assert_eq!(cursor.item(), Some(&6));
         assert_eq!(cursor.prev_item(), Some(&5));
-        assert_eq!(cursor.start(), &Sum(15));
+        assert_eq!(cursor.sum_start(), &Sum(15));
 
         cursor.next(&());
         cursor.next(&());
         assert_eq!(cursor.item(), None);
         assert_eq!(cursor.prev_item(), Some(&6));
-        assert_eq!(cursor.start(), &Sum(21));
+        assert_eq!(cursor.sum_start(), &Sum(21));
 
         cursor.prev(&());
         assert_eq!(cursor.item(), Some(&6));
         assert_eq!(cursor.prev_item(), Some(&5));
-        assert_eq!(cursor.start(), &Sum(15));
+        assert_eq!(cursor.sum_start(), &Sum(15));
 
         cursor.prev(&());
         assert_eq!(cursor.item(), Some(&5));
         assert_eq!(cursor.prev_item(), Some(&4));
-        assert_eq!(cursor.start(), &Sum(10));
+        assert_eq!(cursor.sum_start(), &Sum(10));
 
         cursor.prev(&());
         assert_eq!(cursor.item(), Some(&4));
         assert_eq!(cursor.prev_item(), Some(&3));
-        assert_eq!(cursor.start(), &Sum(6));
+        assert_eq!(cursor.sum_start(), &Sum(6));
 
         cursor.prev(&());
         assert_eq!(cursor.item(), Some(&3));
         assert_eq!(cursor.prev_item(), Some(&2));
-        assert_eq!(cursor.start(), &Sum(3));
+        assert_eq!(cursor.sum_start(), &Sum(3));
 
         cursor.prev(&());
         assert_eq!(cursor.item(), Some(&2));
         assert_eq!(cursor.prev_item(), Some(&1));
-        assert_eq!(cursor.start(), &Sum(1));
+        assert_eq!(cursor.sum_start(), &Sum(1));
 
         cursor.prev(&());
         assert_eq!(cursor.item(), Some(&1));
         assert_eq!(cursor.prev_item(), None);
-        assert_eq!(cursor.start(), &Sum(0));
+        assert_eq!(cursor.sum_start(), &Sum(0));
 
         cursor.prev(&());
         assert_eq!(cursor.item(), None);
         assert_eq!(cursor.prev_item(), None);
-        assert_eq!(cursor.start(), &Sum(0));
+        assert_eq!(cursor.sum_start(), &Sum(0));
 
         cursor.next(&());
         assert_eq!(cursor.item(), Some(&1));
         assert_eq!(cursor.prev_item(), None);
-        assert_eq!(cursor.start(), &Sum(0));
+        assert_eq!(cursor.sum_start(), &Sum(0));
 
         let mut cursor = tree.cursor::<Count, Sum>();
         assert_eq!(
@@ -843,7 +831,7 @@ mod tests {
         );
         assert_eq!(cursor.item(), None);
         assert_eq!(cursor.prev_item(), Some(&6));
-        assert_eq!(cursor.start(), &Sum(21));
+        assert_eq!(cursor.sum_start(), &Sum(21));
 
         cursor.seek(&Count(3), Bias::Right, &());
         assert_eq!(
@@ -854,7 +842,7 @@ mod tests {
         );
         assert_eq!(cursor.item(), None);
         assert_eq!(cursor.prev_item(), Some(&6));
-        assert_eq!(cursor.start(), &Sum(21));
+        assert_eq!(cursor.sum_start(), &Sum(21));
 
         // Seeking can bias left or right
         cursor.seek(&Count(1), Bias::Left, &());

zed/src/sum_tree/cursor.rs 🔗

@@ -45,17 +45,31 @@ where
         self.sum_dimension = U::default();
     }
 
-    pub fn start(&self) -> &U {
+    pub fn seek_start(&self) -> &S {
+        &self.seek_dimension
+    }
+
+    pub fn seek_end(&self, cx: &<T::Summary as Summary>::Context) -> S {
+        if let Some(item_summary) = self.item_summary() {
+            let mut end = self.seek_start().clone();
+            end.add_summary(item_summary, cx);
+            end
+        } else {
+            self.seek_start().clone()
+        }
+    }
+
+    pub fn sum_start(&self) -> &U {
         &self.sum_dimension
     }
 
     pub fn end(&self, cx: &<T::Summary as Summary>::Context) -> U {
         if let Some(item_summary) = self.item_summary() {
-            let mut end = self.start().clone();
+            let mut end = self.sum_start().clone();
             end.add_summary(item_summary, cx);
             end
         } else {
-            self.start().clone()
+            self.sum_start().clone()
         }
     }
 
@@ -613,7 +627,7 @@ where
     }
 
     pub fn start(&self) -> &U {
-        self.cursor.start()
+        self.cursor.sum_start()
     }
 
     pub fn item(&self) -> Option<&'a T> {

zed/src/worktree.rs 🔗

@@ -1290,8 +1290,8 @@ impl WorktreeHandle for ModelHandle<Worktree> {
 }
 
 pub enum FileIter<'a> {
-    All(Cursor<'a, Entry, FileCount, FileCount>),
-    Visible(Cursor<'a, Entry, VisibleFileCount, VisibleFileCount>),
+    All(Cursor<'a, Entry, FileCount, ()>),
+    Visible(Cursor<'a, Entry, VisibleFileCount, ()>),
 }
 
 impl<'a> FileIter<'a> {
@@ -1310,11 +1310,11 @@ impl<'a> FileIter<'a> {
     fn next_internal(&mut self) {
         match self {
             Self::All(cursor) => {
-                let ix = *cursor.start();
+                let ix = *cursor.seek_start();
                 cursor.seek_forward(&FileCount(ix.0 + 1), Bias::Right, &());
             }
             Self::Visible(cursor) => {
-                let ix = *cursor.start();
+                let ix = *cursor.seek_start();
                 cursor.seek_forward(&VisibleFileCount(ix.0 + 1), Bias::Right, &());
             }
         }