Move inlay map to be the first one

Kirill Bulatov and Antonio Scandurra created

Co-Authored-By: Antonio Scandurra <antonio@zed.dev>

Change summary

crates/editor/src/display_map.rs                |  60 
crates/editor/src/display_map/block_map.rs      |  53 
crates/editor/src/display_map/fold_map.rs       | 545 ++++++-----
crates/editor/src/display_map/inlay_map.rs      | 540 +++++------
crates/editor/src/display_map/suggestion_map.rs | 875 -------------------
crates/editor/src/display_map/tab_map.rs        | 177 +--
crates/editor/src/display_map/wrap_map.rs       |  45 
crates/editor/src/editor.rs                     |   2 
8 files changed, 715 insertions(+), 1,582 deletions(-)

Detailed changes

crates/editor/src/display_map.rs 🔗

@@ -72,8 +72,8 @@ impl DisplayMap {
         let buffer_subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
 
         let tab_size = Self::tab_size(&buffer, cx);
-        let (fold_map, snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
-        let (inlay_map, snapshot) = InlayMap::new(snapshot);
+        let (inlay_map, snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
+        let (fold_map, snapshot) = FoldMap::new(snapshot);
         let (tab_map, snapshot) = TabMap::new(snapshot, tab_size);
         let (wrap_map, snapshot) = WrapMap::new(snapshot, font_id, font_size, wrap_width, cx);
         let block_map = BlockMap::new(snapshot, buffer_header_height, excerpt_header_height);
@@ -94,10 +94,10 @@ impl DisplayMap {
     pub fn snapshot(&mut self, cx: &mut ModelContext<Self>) -> DisplaySnapshot {
         let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
         let edits = self.buffer_subscription.consume().into_inner();
-        let (fold_snapshot, edits) = self.fold_map.read(buffer_snapshot, edits);
-        let (inlay_snapshot, edits) = self.inlay_map.sync(fold_snapshot.clone(), edits);
+        let (inlay_snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits);
+        let (fold_snapshot, edits) = self.fold_map.read(inlay_snapshot.clone(), edits);
         let tab_size = Self::tab_size(&self.buffer, cx);
-        let (tab_snapshot, edits) = self.tab_map.sync(inlay_snapshot.clone(), edits, tab_size);
+        let (tab_snapshot, edits) = self.tab_map.sync(fold_snapshot.clone(), edits, tab_size);
         let (wrap_snapshot, edits) = self
             .wrap_map
             .update(cx, |map, cx| map.sync(tab_snapshot.clone(), edits, cx));
@@ -132,15 +132,14 @@ impl DisplayMap {
         let snapshot = self.buffer.read(cx).snapshot(cx);
         let edits = self.buffer_subscription.consume().into_inner();
         let tab_size = Self::tab_size(&self.buffer, cx);
-        let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
         let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
+        let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
             .update(cx, |map, cx| map.sync(snapshot, edits, cx));
         self.block_map.read(snapshot, edits);
         let (snapshot, edits) = fold_map.fold(ranges);
-        let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
@@ -157,15 +156,14 @@ impl DisplayMap {
         let snapshot = self.buffer.read(cx).snapshot(cx);
         let edits = self.buffer_subscription.consume().into_inner();
         let tab_size = Self::tab_size(&self.buffer, cx);
-        let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
         let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
+        let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
             .update(cx, |map, cx| map.sync(snapshot, edits, cx));
         self.block_map.read(snapshot, edits);
         let (snapshot, edits) = fold_map.unfold(ranges, inclusive);
-        let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
@@ -181,8 +179,8 @@ impl DisplayMap {
         let snapshot = self.buffer.read(cx).snapshot(cx);
         let edits = self.buffer_subscription.consume().into_inner();
         let tab_size = Self::tab_size(&self.buffer, cx);
-        let (snapshot, edits) = self.fold_map.read(snapshot, edits);
         let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
+        let (snapshot, edits) = self.fold_map.read(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
@@ -199,8 +197,8 @@ impl DisplayMap {
         let snapshot = self.buffer.read(cx).snapshot(cx);
         let edits = self.buffer_subscription.consume().into_inner();
         let tab_size = Self::tab_size(&self.buffer, cx);
-        let (snapshot, edits) = self.fold_map.read(snapshot, edits);
         let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
+        let (snapshot, edits) = self.fold_map.read(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
@@ -253,9 +251,9 @@ impl DisplayMap {
     ) {
         let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
         let edits = self.buffer_subscription.consume().into_inner();
+        let (snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits);
+        let (snapshot, edits) = self.fold_map.read(snapshot, edits);
         let tab_size = Self::tab_size(&self.buffer, cx);
-        let (snapshot, edits) = self.fold_map.read(buffer_snapshot.clone(), edits);
-        let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
@@ -263,6 +261,7 @@ impl DisplayMap {
         self.block_map.read(snapshot, edits);
 
         let (snapshot, edits) = self.inlay_map.splice(to_remove, to_insert);
+        let (snapshot, edits) = self.fold_map.read(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
@@ -315,9 +314,9 @@ impl DisplaySnapshot {
 
     pub fn prev_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) {
         loop {
-            let mut fold_point = self.fold_snapshot.to_fold_point(point, Bias::Left);
-            *fold_point.column_mut() = 0;
-            point = fold_point.to_buffer_point(&self.fold_snapshot);
+            let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
+            inlay_point.0.column = 0;
+            point = self.inlay_snapshot.to_buffer_point(inlay_point);
 
             let mut display_point = self.point_to_display_point(point, Bias::Left);
             *display_point.column_mut() = 0;
@@ -331,9 +330,9 @@ impl DisplaySnapshot {
 
     pub fn next_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) {
         loop {
-            let mut fold_point = self.fold_snapshot.to_fold_point(point, Bias::Right);
-            *fold_point.column_mut() = self.fold_snapshot.line_len(fold_point.row());
-            point = fold_point.to_buffer_point(&self.fold_snapshot);
+            let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
+            inlay_point.0.column = self.inlay_snapshot.line_len(inlay_point.row());
+            point = self.inlay_snapshot.to_buffer_point(inlay_point);
 
             let mut display_point = self.point_to_display_point(point, Bias::Right);
             *display_point.column_mut() = self.line_len(display_point.row());
@@ -363,9 +362,9 @@ impl DisplaySnapshot {
     }
 
     fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint {
-        let fold_point = self.fold_snapshot.to_fold_point(point, bias);
-        let inlay_point = self.inlay_snapshot.to_inlay_point(fold_point);
-        let tab_point = self.tab_snapshot.to_tab_point(inlay_point);
+        let inlay_point = self.inlay_snapshot.to_inlay_point(point);
+        let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
+        let tab_point = self.tab_snapshot.to_tab_point(fold_point);
         let wrap_point = self.wrap_snapshot.tab_point_to_wrap_point(tab_point);
         let block_point = self.block_snapshot.to_block_point(wrap_point);
         DisplayPoint(block_point)
@@ -375,9 +374,9 @@ impl DisplaySnapshot {
         let block_point = point.0;
         let wrap_point = self.block_snapshot.to_wrap_point(block_point);
         let tab_point = self.wrap_snapshot.to_tab_point(wrap_point);
-        let inlay_point = self.tab_snapshot.to_inlay_point(tab_point, bias).0;
-        let fold_point = self.inlay_snapshot.to_fold_point(inlay_point);
-        fold_point.to_buffer_point(&self.fold_snapshot)
+        let fold_point = self.tab_snapshot.to_fold_point(tab_point, bias).0;
+        let inlay_point = fold_point.to_inlay_point(&self.fold_snapshot);
+        self.inlay_snapshot.to_buffer_point(inlay_point)
     }
 
     pub fn max_point(&self) -> DisplayPoint {
@@ -407,13 +406,13 @@ impl DisplaySnapshot {
         &self,
         display_rows: Range<u32>,
         language_aware: bool,
-        suggestion_highlight: Option<HighlightStyle>,
+        inlay_highlights: Option<HighlightStyle>,
     ) -> DisplayChunks<'_> {
         self.block_snapshot.chunks(
             display_rows,
             language_aware,
             Some(&self.text_highlights),
-            suggestion_highlight,
+            inlay_highlights,
         )
     }
 
@@ -789,9 +788,10 @@ impl DisplayPoint {
     pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> usize {
         let wrap_point = map.block_snapshot.to_wrap_point(self.0);
         let tab_point = map.wrap_snapshot.to_tab_point(wrap_point);
-        let inlay_point = map.tab_snapshot.to_inlay_point(tab_point, bias).0;
-        let fold_point = map.inlay_snapshot.to_fold_point(inlay_point);
-        fold_point.to_buffer_offset(&map.fold_snapshot)
+        let fold_point = map.tab_snapshot.to_fold_point(tab_point, bias).0;
+        let inlay_point = fold_point.to_inlay_point(&map.fold_snapshot);
+        map.inlay_snapshot
+            .to_buffer_offset(map.inlay_snapshot.to_offset(inlay_point))
     }
 }
 

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

@@ -583,7 +583,7 @@ impl BlockSnapshot {
         rows: Range<u32>,
         language_aware: bool,
         text_highlights: Option<&'a TextHighlights>,
-        suggestion_highlight: Option<HighlightStyle>,
+        inlay_highlights: Option<HighlightStyle>,
     ) -> BlockChunks<'a> {
         let max_output_row = cmp::min(rows.end, self.transforms.summary().output_rows);
         let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
@@ -616,7 +616,7 @@ impl BlockSnapshot {
                 input_start..input_end,
                 language_aware,
                 text_highlights,
-                suggestion_highlight,
+                inlay_highlights,
             ),
             input_chunk: Default::default(),
             transforms: cursor,
@@ -1030,9 +1030,9 @@ mod tests {
         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, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot);
-        let (tab_map, tab_snapshot) = TabMap::new(inlay_snapshot, 1.try_into().unwrap());
+        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        let (fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
+        let (tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 1.try_into().unwrap());
         let (wrap_map, wraps_snapshot) = WrapMap::new(tab_snapshot, font_id, 14.0, None, cx);
         let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
 
@@ -1175,11 +1175,11 @@ mod tests {
             buffer.snapshot(cx)
         });
 
-        let (fold_snapshot, fold_edits) =
-            fold_map.read(buffer_snapshot, subscription.consume().into_inner());
-        let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
+        let (inlay_snapshot, inlay_edits) =
+            inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
+        let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
         let (tab_snapshot, tab_edits) =
-            tab_map.sync(inlay_snapshot, inlay_edits, 4.try_into().unwrap());
+            tab_map.sync(fold_snapshot, fold_edits, 4.try_into().unwrap());
         let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
             wrap_map.sync(tab_snapshot, tab_edits, cx)
         });
@@ -1204,9 +1204,9 @@ mod tests {
 
         let buffer = MultiBuffer::build_simple(text, cx);
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
-        let (_, tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
+        let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
+        let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
         let (_, wraps_snapshot) = WrapMap::new(tab_snapshot, font_id, 14.0, Some(60.), cx);
         let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
 
@@ -1276,9 +1276,9 @@ mod tests {
         };
 
         let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let (fold_map, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot);
-        let (tab_map, tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
+        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        let (fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
+        let (tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
         let (wrap_map, wraps_snapshot) =
             WrapMap::new(tab_snapshot, font_id, font_size, wrap_width, cx);
         let mut block_map = BlockMap::new(
@@ -1331,11 +1331,11 @@ mod tests {
                         })
                         .collect::<Vec<_>>();
 
-                    let (fold_snapshot, fold_edits) =
-                        fold_map.read(buffer_snapshot.clone(), vec![]);
-                    let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
+                    let (inlay_snapshot, inlay_edits) =
+                        inlay_map.sync(buffer_snapshot.clone(), vec![]);
+                    let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
                     let (tab_snapshot, tab_edits) =
-                        tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
+                        tab_map.sync(fold_snapshot, fold_edits, tab_size);
                     let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
                         wrap_map.sync(tab_snapshot, tab_edits, cx)
                     });
@@ -1355,11 +1355,11 @@ mod tests {
                         })
                         .collect();
 
-                    let (fold_snapshot, fold_edits) =
-                        fold_map.read(buffer_snapshot.clone(), vec![]);
-                    let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
+                    let (inlay_snapshot, inlay_edits) =
+                        inlay_map.sync(buffer_snapshot.clone(), vec![]);
+                    let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
                     let (tab_snapshot, tab_edits) =
-                        tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
+                        tab_map.sync(fold_snapshot, fold_edits, tab_size);
                     let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
                         wrap_map.sync(tab_snapshot, tab_edits, cx)
                     });
@@ -1378,9 +1378,10 @@ mod tests {
                 }
             }
 
-            let (fold_snapshot, fold_edits) = fold_map.read(buffer_snapshot.clone(), buffer_edits);
-            let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
-            let (tab_snapshot, tab_edits) = tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
+            let (inlay_snapshot, inlay_edits) =
+                inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
+            let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
+            let (tab_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
             let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
                 wrap_map.sync(tab_snapshot, tab_edits, cx)
             });

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

@@ -1,7 +1,10 @@
-use super::TextHighlights;
+use super::{
+    inlay_map::{InlayEdit, InlayOffset, InlayPoint, InlaySnapshot},
+    TextHighlights,
+};
 use crate::{
-    multi_buffer::MultiBufferRows, Anchor, AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot,
-    ToOffset,
+    multi_buffer::{MultiBufferChunks, MultiBufferRows},
+    Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset,
 };
 use collections::BTreeMap;
 use gpui::{color::Color, fonts::HighlightStyle};
@@ -29,6 +32,10 @@ impl FoldPoint {
         self.0.row
     }
 
+    pub fn column(self) -> u32 {
+        self.0.column
+    }
+
     pub fn row_mut(&mut self) -> &mut u32 {
         &mut self.0.row
     }
@@ -37,20 +44,20 @@ impl FoldPoint {
         &mut self.0.column
     }
 
-    pub fn to_buffer_point(self, snapshot: &FoldSnapshot) -> Point {
-        let mut cursor = snapshot.transforms.cursor::<(FoldPoint, Point)>();
+    pub fn to_inlay_point(self, snapshot: &FoldSnapshot) -> InlayPoint {
+        let mut cursor = snapshot.transforms.cursor::<(FoldPoint, InlayPoint)>();
         cursor.seek(&self, Bias::Right, &());
         let overshoot = self.0 - cursor.start().0 .0;
-        cursor.start().1 + overshoot
+        InlayPoint(cursor.start().1 .0 + overshoot)
     }
 
-    pub fn to_buffer_offset(self, snapshot: &FoldSnapshot) -> usize {
-        let mut cursor = snapshot.transforms.cursor::<(FoldPoint, Point)>();
+    pub fn to_inlay_offset(self, snapshot: &FoldSnapshot) -> InlayOffset {
+        let mut cursor = snapshot.transforms.cursor::<(FoldPoint, InlayPoint)>();
         cursor.seek(&self, Bias::Right, &());
         let overshoot = self.0 - cursor.start().0 .0;
         snapshot
-            .buffer_snapshot
-            .point_to_offset(cursor.start().1 + overshoot)
+            .inlay_snapshot
+            .to_offset(InlayPoint(cursor.start().1 .0 + overshoot))
     }
 
     pub fn to_offset(self, snapshot: &FoldSnapshot) -> FoldOffset {
@@ -58,17 +65,25 @@ impl FoldPoint {
             .transforms
             .cursor::<(FoldPoint, TransformSummary)>();
         cursor.seek(&self, Bias::Right, &());
+        let inlay_snapshot = &snapshot.inlay_snapshot;
+        let to_inlay_offset = |buffer_offset: usize| {
+            let buffer_point = inlay_snapshot.buffer.offset_to_point(buffer_offset);
+            inlay_snapshot.to_offset(inlay_snapshot.to_inlay_point(buffer_point))
+        };
+        let mut inlay_offset = to_inlay_offset(cursor.start().1.output.len);
         let overshoot = self.0 - cursor.start().1.output.lines;
-        let mut offset = cursor.start().1.output.len;
         if !overshoot.is_zero() {
             let transform = cursor.item().expect("display point out of range");
             assert!(transform.output_text.is_none());
-            let end_buffer_offset = snapshot
-                .buffer_snapshot
-                .point_to_offset(cursor.start().1.input.lines + overshoot);
-            offset += end_buffer_offset - cursor.start().1.input.len;
+            let end_snapshot_offset = snapshot
+                .inlay_snapshot
+                .to_offset(InlayPoint(cursor.start().1.input.lines + overshoot));
+            inlay_offset += end_snapshot_offset - to_inlay_offset(cursor.start().1.input.len);
         }
-        FoldOffset(offset)
+
+        snapshot
+            .to_fold_point(inlay_snapshot.to_point(inlay_offset), Bias::Right)
+            .to_offset(snapshot)
     }
 }
 
@@ -87,8 +102,9 @@ impl<'a> FoldMapWriter<'a> {
     ) -> (FoldSnapshot, Vec<FoldEdit>) {
         let mut edits = Vec::new();
         let mut folds = Vec::new();
-        let buffer = self.0.buffer.lock().clone();
+        let snapshot = self.0.inlay_snapshot.lock().clone();
         for range in ranges.into_iter() {
+            let buffer = &snapshot.buffer;
             let range = range.start.to_offset(&buffer)..range.end.to_offset(&buffer);
 
             // Ignore any empty ranges.
@@ -103,31 +119,35 @@ impl<'a> FoldMapWriter<'a> {
             }
 
             folds.push(fold);
-            edits.push(text::Edit {
-                old: range.clone(),
-                new: range,
+
+            let inlay_range =
+                snapshot.to_inlay_offset(range.start)..snapshot.to_inlay_offset(range.end);
+            edits.push(InlayEdit {
+                old: inlay_range.clone(),
+                new: inlay_range,
             });
         }
 
-        folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(a, b, &buffer));
+        let buffer = &snapshot.buffer;
+        folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(a, b, buffer));
 
         self.0.folds = {
             let mut new_tree = SumTree::new();
             let mut cursor = self.0.folds.cursor::<Fold>();
             for fold in folds {
-                new_tree.append(cursor.slice(&fold, Bias::Right, &buffer), &buffer);
-                new_tree.push(fold, &buffer);
+                new_tree.append(cursor.slice(&fold, Bias::Right, buffer), buffer);
+                new_tree.push(fold, buffer);
             }
-            new_tree.append(cursor.suffix(&buffer), &buffer);
+            new_tree.append(cursor.suffix(buffer), buffer);
             new_tree
         };
 
-        consolidate_buffer_edits(&mut edits);
-        let edits = self.0.sync(buffer.clone(), edits);
+        consolidate_inlay_edits(&mut edits);
+        let edits = self.0.sync(snapshot.clone(), edits);
         let snapshot = FoldSnapshot {
             transforms: self.0.transforms.lock().clone(),
             folds: self.0.folds.clone(),
-            buffer_snapshot: buffer,
+            inlay_snapshot: snapshot,
             version: self.0.version.load(SeqCst),
             ellipses_color: self.0.ellipses_color,
         };
@@ -141,20 +161,23 @@ impl<'a> FoldMapWriter<'a> {
     ) -> (FoldSnapshot, Vec<FoldEdit>) {
         let mut edits = Vec::new();
         let mut fold_ixs_to_delete = Vec::new();
-        let buffer = self.0.buffer.lock().clone();
+        let snapshot = self.0.inlay_snapshot.lock().clone();
+        let buffer = &snapshot.buffer;
         for range in ranges.into_iter() {
             // Remove intersecting folds and add their ranges to edits that are passed to sync.
-            let mut folds_cursor = intersecting_folds(&buffer, &self.0.folds, range, inclusive);
+            let mut folds_cursor = intersecting_folds(&snapshot, &self.0.folds, range, inclusive);
             while let Some(fold) = folds_cursor.item() {
-                let offset_range = fold.0.start.to_offset(&buffer)..fold.0.end.to_offset(&buffer);
+                let offset_range = fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer);
                 if offset_range.end > offset_range.start {
-                    edits.push(text::Edit {
-                        old: offset_range.clone(),
-                        new: offset_range,
+                    let inlay_range = snapshot.to_inlay_offset(offset_range.start)
+                        ..snapshot.to_inlay_offset(offset_range.end);
+                    edits.push(InlayEdit {
+                        old: inlay_range.clone(),
+                        new: inlay_range,
                     });
                 }
                 fold_ixs_to_delete.push(*folds_cursor.start());
-                folds_cursor.next(&buffer);
+                folds_cursor.next(buffer);
             }
         }
 
@@ -165,19 +188,19 @@ impl<'a> FoldMapWriter<'a> {
             let mut cursor = self.0.folds.cursor::<usize>();
             let mut folds = SumTree::new();
             for fold_ix in fold_ixs_to_delete {
-                folds.append(cursor.slice(&fold_ix, Bias::Right, &buffer), &buffer);
-                cursor.next(&buffer);
+                folds.append(cursor.slice(&fold_ix, Bias::Right, buffer), buffer);
+                cursor.next(buffer);
             }
-            folds.append(cursor.suffix(&buffer), &buffer);
+            folds.append(cursor.suffix(buffer), buffer);
             folds
         };
 
-        consolidate_buffer_edits(&mut edits);
-        let edits = self.0.sync(buffer.clone(), edits);
+        consolidate_inlay_edits(&mut edits);
+        let edits = self.0.sync(snapshot.clone(), edits);
         let snapshot = FoldSnapshot {
             transforms: self.0.transforms.lock().clone(),
             folds: self.0.folds.clone(),
-            buffer_snapshot: buffer,
+            inlay_snapshot: snapshot,
             version: self.0.version.load(SeqCst),
             ellipses_color: self.0.ellipses_color,
         };
@@ -186,7 +209,7 @@ impl<'a> FoldMapWriter<'a> {
 }
 
 pub struct FoldMap {
-    buffer: Mutex<MultiBufferSnapshot>,
+    inlay_snapshot: Mutex<InlaySnapshot>,
     transforms: Mutex<SumTree<Transform>>,
     folds: SumTree<Fold>,
     version: AtomicUsize,
@@ -194,15 +217,15 @@ pub struct FoldMap {
 }
 
 impl FoldMap {
-    pub fn new(buffer: MultiBufferSnapshot) -> (Self, FoldSnapshot) {
+    pub fn new(inlay_snapshot: InlaySnapshot) -> (Self, FoldSnapshot) {
         let this = Self {
-            buffer: Mutex::new(buffer.clone()),
+            inlay_snapshot: Mutex::new(inlay_snapshot.clone()),
             folds: Default::default(),
             transforms: Mutex::new(SumTree::from_item(
                 Transform {
                     summary: TransformSummary {
-                        input: buffer.text_summary(),
-                        output: buffer.text_summary(),
+                        input: inlay_snapshot.text_summary(),
+                        output: inlay_snapshot.text_summary(),
                     },
                     output_text: None,
                 },
@@ -215,7 +238,7 @@ impl FoldMap {
         let snapshot = FoldSnapshot {
             transforms: this.transforms.lock().clone(),
             folds: this.folds.clone(),
-            buffer_snapshot: this.buffer.lock().clone(),
+            inlay_snapshot: inlay_snapshot.clone(),
             version: this.version.load(SeqCst),
             ellipses_color: None,
         };
@@ -224,15 +247,15 @@ impl FoldMap {
 
     pub fn read(
         &self,
-        buffer: MultiBufferSnapshot,
-        edits: Vec<Edit<usize>>,
+        inlay_snapshot: InlaySnapshot,
+        edits: Vec<InlayEdit>,
     ) -> (FoldSnapshot, Vec<FoldEdit>) {
-        let edits = self.sync(buffer, edits);
+        let edits = self.sync(inlay_snapshot, edits);
         self.check_invariants();
         let snapshot = FoldSnapshot {
             transforms: self.transforms.lock().clone(),
             folds: self.folds.clone(),
-            buffer_snapshot: self.buffer.lock().clone(),
+            inlay_snapshot: self.inlay_snapshot.lock().clone(),
             version: self.version.load(SeqCst),
             ellipses_color: self.ellipses_color,
         };
@@ -241,10 +264,10 @@ impl FoldMap {
 
     pub fn write(
         &mut self,
-        buffer: MultiBufferSnapshot,
-        edits: Vec<Edit<usize>>,
+        inlay_snapshot: InlaySnapshot,
+        edits: Vec<InlayEdit>,
     ) -> (FoldMapWriter, FoldSnapshot, Vec<FoldEdit>) {
-        let (snapshot, edits) = self.read(buffer, edits);
+        let (snapshot, edits) = self.read(inlay_snapshot, edits);
         (FoldMapWriter(self), snapshot, edits)
     }
 
@@ -259,146 +282,109 @@ impl FoldMap {
 
     fn check_invariants(&self) {
         if cfg!(test) {
+            let inlay_snapshot = self.inlay_snapshot.lock();
             assert_eq!(
                 self.transforms.lock().summary().input.len,
-                self.buffer.lock().len(),
-                "transform tree does not match buffer's length"
+                inlay_snapshot.to_buffer_offset(inlay_snapshot.len()),
+                "transform tree does not match inlay snapshot's length"
             );
 
             let mut folds = self.folds.iter().peekable();
             while let Some(fold) = folds.next() {
                 if let Some(next_fold) = folds.peek() {
-                    let comparison = fold.0.cmp(&next_fold.0, &self.buffer.lock());
+                    let comparison = fold.0.cmp(&next_fold.0, &self.inlay_snapshot.lock().buffer);
                     assert!(comparison.is_le());
                 }
             }
         }
     }
 
-    fn sync(
-        &self,
-        new_buffer: MultiBufferSnapshot,
-        buffer_edits: Vec<text::Edit<usize>>,
-    ) -> Vec<FoldEdit> {
-        if buffer_edits.is_empty() {
-            let mut buffer = self.buffer.lock();
-            if buffer.edit_count() != new_buffer.edit_count()
-                || buffer.parse_count() != new_buffer.parse_count()
-                || buffer.diagnostics_update_count() != new_buffer.diagnostics_update_count()
-                || buffer.git_diff_update_count() != new_buffer.git_diff_update_count()
-                || buffer.trailing_excerpt_update_count()
-                    != new_buffer.trailing_excerpt_update_count()
-            {
-                self.version.fetch_add(1, SeqCst);
-            }
-            *buffer = new_buffer;
-            Vec::new()
-        } else {
-            let mut buffer_edits_iter = buffer_edits.iter().cloned().peekable();
+    fn sync(&self, inlay_snapshot: InlaySnapshot, inlay_edits: Vec<InlayEdit>) -> Vec<FoldEdit> {
+        let buffer = &inlay_snapshot.buffer;
+        let mut snapshot = self.inlay_snapshot.lock();
 
-            let mut new_transforms = SumTree::new();
-            let mut transforms = self.transforms.lock();
-            let mut cursor = transforms.cursor::<usize>();
-            cursor.seek(&0, Bias::Right, &());
+        let mut new_snapshot = snapshot.clone();
+        if new_snapshot.version != inlay_snapshot.version {
+            new_snapshot.version += 1;
+        }
 
-            while let Some(mut edit) = buffer_edits_iter.next() {
-                new_transforms.append(cursor.slice(&edit.old.start, Bias::Left, &()), &());
-                edit.new.start -= edit.old.start - cursor.start();
-                edit.old.start = *cursor.start();
+        let mut inlay_edits_iter = inlay_edits.iter().cloned().peekable();
 
-                cursor.seek(&edit.old.end, Bias::Right, &());
-                cursor.next(&());
+        let mut new_transforms = SumTree::new();
+        let mut transforms = self.transforms.lock();
+        let mut cursor = transforms.cursor::<usize>();
+        cursor.seek(&0, Bias::Right, &());
 
-                let mut delta = edit.new.len() as isize - edit.old.len() as isize;
-                loop {
-                    edit.old.end = *cursor.start();
+        while let Some(mut edit) = inlay_edits_iter.next() {
+            new_transforms.append(cursor.slice(&edit.old.start, Bias::Left, &()), &());
+            edit.new.start -= edit.old.start - cursor.start();
+            edit.old.start = *cursor.start();
 
-                    if let Some(next_edit) = buffer_edits_iter.peek() {
-                        if next_edit.old.start > edit.old.end {
-                            break;
-                        }
+            cursor.seek(&edit.old.end, Bias::Right, &());
+            cursor.next(&());
 
-                        let next_edit = buffer_edits_iter.next().unwrap();
-                        delta += next_edit.new.len() as isize - next_edit.old.len() as isize;
+            let mut delta = edit.new.len() as isize - edit.old.len() as isize;
+            loop {
+                edit.old.end = *cursor.start();
 
-                        if next_edit.old.end >= edit.old.end {
-                            edit.old.end = next_edit.old.end;
-                            cursor.seek(&edit.old.end, Bias::Right, &());
-                            cursor.next(&());
-                        }
-                    } else {
+                if let Some(next_edit) = inlay_edits_iter.peek() {
+                    if next_edit.old.start > edit.old.end {
                         break;
                     }
-                }
-
-                edit.new.end = ((edit.new.start + edit.old.len()) as isize + delta) as usize;
 
-                let anchor = new_buffer.anchor_before(edit.new.start);
-                let mut folds_cursor = self.folds.cursor::<Fold>();
-                folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, &new_buffer);
+                    let next_edit = inlay_edits_iter.next().unwrap();
+                    delta += next_edit.new.len() as isize - next_edit.old.len() as isize;
 
-                let mut folds = iter::from_fn({
-                    let buffer = &new_buffer;
-                    move || {
-                        let item = folds_cursor
-                            .item()
-                            .map(|f| f.0.start.to_offset(buffer)..f.0.end.to_offset(buffer));
-                        folds_cursor.next(buffer);
-                        item
+                    if next_edit.old.end >= edit.old.end {
+                        edit.old.end = next_edit.old.end;
+                        cursor.seek(&edit.old.end, Bias::Right, &());
+                        cursor.next(&());
                     }
-                })
-                .peekable();
+                } else {
+                    break;
+                }
+            }
 
-                while folds.peek().map_or(false, |fold| fold.start < edit.new.end) {
-                    let mut fold = folds.next().unwrap();
-                    let sum = new_transforms.summary();
+            edit.new.end = ((edit.new.start + edit.old.len()) as isize + delta) as usize;
 
-                    assert!(fold.start >= sum.input.len);
+            let anchor = buffer.anchor_before(inlay_snapshot.to_buffer_offset(edit.new.start));
+            let mut folds_cursor = self.folds.cursor::<Fold>();
+            folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, &buffer);
 
-                    while folds
-                        .peek()
-                        .map_or(false, |next_fold| next_fold.start <= fold.end)
-                    {
-                        let next_fold = folds.next().unwrap();
-                        if next_fold.end > fold.end {
-                            fold.end = next_fold.end;
-                        }
-                    }
+            let mut folds = iter::from_fn({
+                move || {
+                    let item = folds_cursor.item().map(|f| {
+                        let fold_buffer_start = f.0.start.to_offset(buffer);
+                        let fold_buffer_end = f.0.end.to_offset(buffer);
 
-                    if fold.start > sum.input.len {
-                        let text_summary = new_buffer
-                            .text_summary_for_range::<TextSummary, _>(sum.input.len..fold.start);
-                        new_transforms.push(
-                            Transform {
-                                summary: TransformSummary {
-                                    output: text_summary.clone(),
-                                    input: text_summary,
-                                },
-                                output_text: None,
-                            },
-                            &(),
-                        );
-                    }
+                        inlay_snapshot.to_inlay_offset(fold_buffer_start)
+                            ..inlay_snapshot.to_inlay_offset(fold_buffer_end)
+                    });
+                    folds_cursor.next(buffer);
+                    item
+                }
+            })
+            .peekable();
 
-                    if fold.end > fold.start {
-                        let output_text = "⋯";
-                        new_transforms.push(
-                            Transform {
-                                summary: TransformSummary {
-                                    output: TextSummary::from(output_text),
-                                    input: new_buffer.text_summary_for_range(fold.start..fold.end),
-                                },
-                                output_text: Some(output_text),
-                            },
-                            &(),
-                        );
+            while folds.peek().map_or(false, |fold| fold.start < edit.new.end) {
+                let mut fold = folds.next().unwrap();
+                let sum = new_transforms.summary();
+
+                assert!(fold.start >= sum.input.len);
+
+                while folds
+                    .peek()
+                    .map_or(false, |next_fold| next_fold.start <= fold.end)
+                {
+                    let next_fold = folds.next().unwrap();
+                    if next_fold.end > fold.end {
+                        fold.end = next_fold.end;
                     }
                 }
 
-                let sum = new_transforms.summary();
-                if sum.input.len < edit.new.end {
-                    let text_summary = new_buffer
-                        .text_summary_for_range::<TextSummary, _>(sum.input.len..edit.new.end);
+                if fold.start > sum.input.len {
+                    let text_summary =
+                        buffer.text_summary_for_range::<TextSummary, _>(sum.input.len..fold.start);
                     new_transforms.push(
                         Transform {
                             summary: TransformSummary {
@@ -410,11 +396,25 @@ impl FoldMap {
                         &(),
                     );
                 }
+
+                if fold.end > fold.start {
+                    let output_text = "⋯";
+                    new_transforms.push(
+                        Transform {
+                            summary: TransformSummary {
+                                output: TextSummary::from(output_text),
+                                input: buffer.text_summary_for_range(fold.start..fold.end),
+                            },
+                            output_text: Some(output_text),
+                        },
+                        &(),
+                    );
+                }
             }
 
-            new_transforms.append(cursor.suffix(&()), &());
-            if new_transforms.is_empty() {
-                let text_summary = new_buffer.text_summary();
+            let sum = new_transforms.summary();
+            if sum.input.len < edit.new.end {
+                let text_summary = buffer.text_summary_for_range(sum.input.len..edit.new.end);
                 new_transforms.push(
                     Transform {
                         summary: TransformSummary {
@@ -426,59 +426,74 @@ impl FoldMap {
                     &(),
                 );
             }
+        }
 
-            drop(cursor);
+        new_transforms.append(cursor.suffix(&()), &());
+        if new_transforms.is_empty() {
+            let text_summary = inlay_snapshot.text_summary();
+            new_transforms.push(
+                Transform {
+                    summary: TransformSummary {
+                        output: text_summary.clone(),
+                        input: text_summary,
+                    },
+                    output_text: None,
+                },
+                &(),
+            );
+        }
 
-            let mut fold_edits = Vec::with_capacity(buffer_edits.len());
-            {
-                let mut old_transforms = transforms.cursor::<(usize, FoldOffset)>();
-                let mut new_transforms = new_transforms.cursor::<(usize, FoldOffset)>();
+        drop(cursor);
 
-                for mut edit in buffer_edits {
-                    old_transforms.seek(&edit.old.start, Bias::Left, &());
-                    if old_transforms.item().map_or(false, |t| t.is_fold()) {
-                        edit.old.start = old_transforms.start().0;
-                    }
-                    let old_start =
-                        old_transforms.start().1 .0 + (edit.old.start - old_transforms.start().0);
+        let mut fold_edits = Vec::with_capacity(inlay_edits.len());
+        {
+            let mut old_transforms = transforms.cursor::<(usize, FoldOffset)>();
+            let mut new_transforms = new_transforms.cursor::<(usize, FoldOffset)>();
 
-                    old_transforms.seek_forward(&edit.old.end, Bias::Right, &());
-                    if old_transforms.item().map_or(false, |t| t.is_fold()) {
-                        old_transforms.next(&());
-                        edit.old.end = old_transforms.start().0;
-                    }
-                    let old_end =
-                        old_transforms.start().1 .0 + (edit.old.end - old_transforms.start().0);
+            for mut edit in inlay_edits {
+                old_transforms.seek(&edit.old.start, Bias::Left, &());
+                if old_transforms.item().map_or(false, |t| t.is_fold()) {
+                    edit.old.start = old_transforms.start().0;
+                }
+                let old_start =
+                    old_transforms.start().1 .0 + (edit.old.start - old_transforms.start().0);
 
-                    new_transforms.seek(&edit.new.start, Bias::Left, &());
-                    if new_transforms.item().map_or(false, |t| t.is_fold()) {
-                        edit.new.start = new_transforms.start().0;
-                    }
-                    let new_start =
-                        new_transforms.start().1 .0 + (edit.new.start - new_transforms.start().0);
+                old_transforms.seek_forward(&edit.old.end, Bias::Right, &());
+                if old_transforms.item().map_or(false, |t| t.is_fold()) {
+                    old_transforms.next(&());
+                    edit.old.end = old_transforms.start().0;
+                }
+                let old_end =
+                    old_transforms.start().1 .0 + (edit.old.end - old_transforms.start().0);
 
-                    new_transforms.seek_forward(&edit.new.end, Bias::Right, &());
-                    if new_transforms.item().map_or(false, |t| t.is_fold()) {
-                        new_transforms.next(&());
-                        edit.new.end = new_transforms.start().0;
-                    }
-                    let new_end =
-                        new_transforms.start().1 .0 + (edit.new.end - new_transforms.start().0);
+                new_transforms.seek(&edit.new.start, Bias::Left, &());
+                if new_transforms.item().map_or(false, |t| t.is_fold()) {
+                    edit.new.start = new_transforms.start().0;
+                }
+                let new_start =
+                    new_transforms.start().1 .0 + (edit.new.start - new_transforms.start().0);
 
-                    fold_edits.push(FoldEdit {
-                        old: FoldOffset(old_start)..FoldOffset(old_end),
-                        new: FoldOffset(new_start)..FoldOffset(new_end),
-                    });
+                new_transforms.seek_forward(&edit.new.end, Bias::Right, &());
+                if new_transforms.item().map_or(false, |t| t.is_fold()) {
+                    new_transforms.next(&());
+                    edit.new.end = new_transforms.start().0;
                 }
+                let new_end =
+                    new_transforms.start().1 .0 + (edit.new.end - new_transforms.start().0);
 
-                consolidate_fold_edits(&mut fold_edits);
+                fold_edits.push(FoldEdit {
+                    old: FoldOffset(old_start)..FoldOffset(old_end),
+                    new: FoldOffset(new_start)..FoldOffset(new_end),
+                });
             }
 
-            *transforms = new_transforms;
-            *self.buffer.lock() = new_buffer;
-            self.version.fetch_add(1, SeqCst);
-            fold_edits
+            consolidate_fold_edits(&mut fold_edits);
         }
+
+        *transforms = new_transforms;
+        *self.inlay_snapshot.lock() = inlay_snapshot;
+        self.version.fetch_add(1, SeqCst);
+        fold_edits
     }
 }
 
@@ -486,26 +501,22 @@ impl FoldMap {
 pub struct FoldSnapshot {
     transforms: SumTree<Transform>,
     folds: SumTree<Fold>,
-    buffer_snapshot: MultiBufferSnapshot,
+    pub inlay_snapshot: InlaySnapshot,
     pub version: usize,
     pub ellipses_color: Option<Color>,
 }
 
 impl FoldSnapshot {
-    pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
-        &self.buffer_snapshot
-    }
-
     #[cfg(test)]
     pub fn text(&self) -> String {
-        self.chunks(FoldOffset(0)..self.len(), false, None)
+        self.chunks(FoldOffset(0)..self.len(), false, None, None)
             .map(|c| c.text)
             .collect()
     }
 
     #[cfg(test)]
     pub fn fold_count(&self) -> usize {
-        self.folds.items(&self.buffer_snapshot).len()
+        self.folds.items(&self.inlay_snapshot.buffer).len()
     }
 
     pub fn text_summary(&self) -> TextSummary {
@@ -529,7 +540,8 @@ impl FoldSnapshot {
                 let buffer_start = cursor.start().1 + start_in_transform;
                 let buffer_end = cursor.start().1 + end_in_transform;
                 summary = self
-                    .buffer_snapshot
+                    .inlay_snapshot
+                    .buffer
                     .text_summary_for_range(buffer_start..buffer_end);
             }
         }
@@ -547,7 +559,8 @@ impl FoldSnapshot {
                     let buffer_start = cursor.start().1;
                     let buffer_end = cursor.start().1 + end_in_transform;
                     summary += self
-                        .buffer_snapshot
+                        .inlay_snapshot
+                        .buffer
                         .text_summary_for_range::<TextSummary, _>(buffer_start..buffer_end);
                 }
             }
@@ -556,8 +569,8 @@ impl FoldSnapshot {
         summary
     }
 
-    pub fn to_fold_point(&self, point: Point, bias: Bias) -> FoldPoint {
-        let mut cursor = self.transforms.cursor::<(Point, FoldPoint)>();
+    pub fn to_fold_point(&self, point: InlayPoint, bias: Bias) -> FoldPoint {
+        let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
         cursor.seek(&point, Bias::Right, &());
         if cursor.item().map_or(false, |t| t.is_fold()) {
             if bias == Bias::Left || point == cursor.start().0 {
@@ -566,7 +579,7 @@ impl FoldSnapshot {
                 cursor.end(&()).1
             }
         } else {
-            let overshoot = point - cursor.start().0;
+            let overshoot = InlayPoint(point.0 - cursor.start().0 .0);
             FoldPoint(cmp::min(
                 cursor.start().1 .0 + overshoot,
                 cursor.end(&()).1 .0,
@@ -599,7 +612,7 @@ impl FoldSnapshot {
 
         let overshoot = fold_point.0 - cursor.start().0 .0;
         let buffer_point = cursor.start().1 + overshoot;
-        let input_buffer_rows = self.buffer_snapshot.buffer_rows(buffer_point.row);
+        let input_buffer_rows = self.inlay_snapshot.buffer.buffer_rows(buffer_point.row);
 
         FoldBufferRows {
             fold_point,
@@ -621,10 +634,10 @@ impl FoldSnapshot {
     where
         T: ToOffset,
     {
-        let mut folds = intersecting_folds(&self.buffer_snapshot, &self.folds, range, false);
+        let mut folds = intersecting_folds(&self.inlay_snapshot, &self.folds, range, false);
         iter::from_fn(move || {
             let item = folds.item().map(|f| &f.0);
-            folds.next(&self.buffer_snapshot);
+            folds.next(&self.inlay_snapshot.buffer);
             item
         })
     }
@@ -633,7 +646,7 @@ impl FoldSnapshot {
     where
         T: ToOffset,
     {
-        let offset = offset.to_offset(&self.buffer_snapshot);
+        let offset = offset.to_offset(&self.inlay_snapshot.buffer);
         let mut cursor = self.transforms.cursor::<usize>();
         cursor.seek(&offset, Bias::Right, &());
         cursor.item().map_or(false, |t| t.output_text.is_some())
@@ -641,6 +654,7 @@ impl FoldSnapshot {
 
     pub fn is_line_folded(&self, buffer_row: u32) -> bool {
         let mut cursor = self.transforms.cursor::<Point>();
+        // TODO kb is this right?
         cursor.seek(&Point::new(buffer_row, 0), Bias::Right, &());
         while let Some(transform) = cursor.item() {
             if transform.output_text.is_some() {
@@ -660,6 +674,7 @@ impl FoldSnapshot {
         range: Range<FoldOffset>,
         language_aware: bool,
         text_highlights: Option<&'a TextHighlights>,
+        inlay_highlights: Option<HighlightStyle>,
     ) -> FoldChunks<'a> {
         let mut highlight_endpoints = Vec::new();
         let mut transform_cursor = self.transforms.cursor::<(FoldOffset, usize)>();
@@ -681,12 +696,13 @@ impl FoldSnapshot {
                 while transform_cursor.start().0 < range.end {
                     if !transform_cursor.item().unwrap().is_fold() {
                         let transform_start = self
-                            .buffer_snapshot
+                            .inlay_snapshot
+                            .buffer
                             .anchor_after(cmp::max(buffer_start, transform_cursor.start().1));
 
                         let transform_end = {
                             let overshoot = range.end.0 - transform_cursor.start().0 .0;
-                            self.buffer_snapshot.anchor_before(cmp::min(
+                            self.inlay_snapshot.buffer.anchor_before(cmp::min(
                                 transform_cursor.end(&()).1,
                                 transform_cursor.start().1 + overshoot,
                             ))
@@ -697,7 +713,8 @@ impl FoldSnapshot {
                             let ranges = &highlights.1;
 
                             let start_ix = match ranges.binary_search_by(|probe| {
-                                let cmp = probe.end.cmp(&transform_start, self.buffer_snapshot());
+                                let cmp =
+                                    probe.end.cmp(&transform_start, &self.inlay_snapshot.buffer);
                                 if cmp.is_gt() {
                                     Ordering::Greater
                                 } else {
@@ -709,20 +726,20 @@ impl FoldSnapshot {
                             for range in &ranges[start_ix..] {
                                 if range
                                     .start
-                                    .cmp(&transform_end, &self.buffer_snapshot)
+                                    .cmp(&transform_end, &self.inlay_snapshot.buffer)
                                     .is_ge()
                                 {
                                     break;
                                 }
 
                                 highlight_endpoints.push(HighlightEndpoint {
-                                    offset: range.start.to_offset(&self.buffer_snapshot),
+                                    offset: range.start.to_offset(&self.inlay_snapshot.buffer),
                                     is_start: true,
                                     tag: *tag,
                                     style,
                                 });
                                 highlight_endpoints.push(HighlightEndpoint {
-                                    offset: range.end.to_offset(&self.buffer_snapshot),
+                                    offset: range.end.to_offset(&self.inlay_snapshot.buffer),
                                     is_start: false,
                                     tag: *tag,
                                     style,
@@ -741,9 +758,10 @@ impl FoldSnapshot {
         FoldChunks {
             transform_cursor,
             buffer_chunks: self
-                .buffer_snapshot
+                .inlay_snapshot
+                .buffer
                 .chunks(buffer_start..buffer_end, language_aware),
-            buffer_chunk: None,
+            inlay_chunk: None,
             buffer_offset: buffer_start,
             output_offset: range.start.0,
             max_output_offset: range.end.0,
@@ -753,6 +771,11 @@ impl FoldSnapshot {
         }
     }
 
+    pub fn chars_at(&self, start: FoldPoint) -> impl '_ + Iterator<Item = char> {
+        self.chunks(start.to_offset(self)..self.len(), false, None, None)
+            .flat_map(|chunk| chunk.text.chars())
+    }
+
     #[cfg(test)]
     pub fn clip_offset(&self, offset: FoldOffset, bias: Bias) -> FoldOffset {
         let mut cursor = self.transforms.cursor::<(FoldOffset, usize)>();
@@ -768,7 +791,8 @@ impl FoldSnapshot {
             } else {
                 let overshoot = offset.0 - transform_start;
                 let buffer_offset = cursor.start().1 + overshoot;
-                let clipped_buffer_offset = self.buffer_snapshot.clip_offset(buffer_offset, bias);
+                let clipped_buffer_offset =
+                    self.inlay_snapshot.buffer.clip_offset(buffer_offset, bias);
                 FoldOffset(
                     (offset.0 as isize + (clipped_buffer_offset as isize - buffer_offset as isize))
                         as usize,
@@ -794,7 +818,7 @@ impl FoldSnapshot {
                 let overshoot = point.0 - transform_start;
                 let buffer_position = cursor.start().1 + overshoot;
                 let clipped_buffer_position =
-                    self.buffer_snapshot.clip_point(buffer_position, bias);
+                    self.inlay_snapshot.buffer.clip_point(buffer_position, bias);
                 FoldPoint(cursor.start().0 .0 + (clipped_buffer_position - cursor.start().1))
             }
         } else {
@@ -804,7 +828,7 @@ impl FoldSnapshot {
 }
 
 fn intersecting_folds<'a, T>(
-    buffer: &'a MultiBufferSnapshot,
+    inlay_snapshot: &'a InlaySnapshot,
     folds: &'a SumTree<Fold>,
     range: Range<T>,
     inclusive: bool,
@@ -812,6 +836,7 @@ fn intersecting_folds<'a, T>(
 where
     T: ToOffset,
 {
+    let buffer = &inlay_snapshot.buffer;
     let start = buffer.anchor_before(range.start.to_offset(buffer));
     let end = buffer.anchor_after(range.end.to_offset(buffer));
     let mut cursor = folds.filter::<_, usize>(move |summary| {
@@ -828,7 +853,7 @@ where
     cursor
 }
 
-fn consolidate_buffer_edits(edits: &mut Vec<text::Edit<usize>>) {
+fn consolidate_inlay_edits(edits: &mut Vec<InlayEdit>) {
     edits.sort_unstable_by(|a, b| {
         a.old
             .start
@@ -956,7 +981,7 @@ impl Default for FoldSummary {
 impl sum_tree::Summary for FoldSummary {
     type Context = MultiBufferSnapshot;
 
-    fn add_summary(&mut self, other: &Self, buffer: &MultiBufferSnapshot) {
+    fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
         if other.min_start.cmp(&self.min_start, buffer) == Ordering::Less {
             self.min_start = other.min_start.clone();
         }
@@ -1034,7 +1059,7 @@ impl<'a> Iterator for FoldBufferRows<'a> {
 pub struct FoldChunks<'a> {
     transform_cursor: Cursor<'a, Transform, (FoldOffset, usize)>,
     buffer_chunks: MultiBufferChunks<'a>,
-    buffer_chunk: Option<(usize, Chunk<'a>)>,
+    inlay_chunk: Option<(usize, Chunk<'a>)>,
     buffer_offset: usize,
     output_offset: usize,
     max_output_offset: usize,
@@ -1056,7 +1081,7 @@ impl<'a> Iterator for FoldChunks<'a> {
         // If we're in a fold, then return the fold's display text and
         // advance the transform and buffer cursors to the end of the fold.
         if let Some(output_text) = transform.output_text {
-            self.buffer_chunk.take();
+            self.inlay_chunk.take();
             self.buffer_offset += transform.summary.input.len;
             self.buffer_chunks.seek(self.buffer_offset);
 
@@ -1093,13 +1118,13 @@ impl<'a> Iterator for FoldChunks<'a> {
         }
 
         // Retrieve a chunk from the current location in the buffer.
-        if self.buffer_chunk.is_none() {
+        if self.inlay_chunk.is_none() {
             let chunk_offset = self.buffer_chunks.offset();
-            self.buffer_chunk = self.buffer_chunks.next().map(|chunk| (chunk_offset, chunk));
+            self.inlay_chunk = self.buffer_chunks.next().map(|chunk| (chunk_offset, chunk));
         }
 
         // Otherwise, take a chunk from the buffer's text.
-        if let Some((buffer_chunk_start, mut chunk)) = self.buffer_chunk {
+        if let Some((buffer_chunk_start, mut chunk)) = self.inlay_chunk {
             let buffer_chunk_end = buffer_chunk_start + chunk.text.len();
             let transform_end = self.transform_cursor.end(&()).1;
             let chunk_end = buffer_chunk_end
@@ -1120,7 +1145,7 @@ impl<'a> Iterator for FoldChunks<'a> {
             if chunk_end == transform_end {
                 self.transform_cursor.next(&());
             } else if chunk_end == buffer_chunk_end {
-                self.buffer_chunk.take();
+                self.inlay_chunk.take();
             }
 
             self.buffer_offset = chunk_end;
@@ -1163,11 +1188,15 @@ impl FoldOffset {
             .transforms
             .cursor::<(FoldOffset, TransformSummary)>();
         cursor.seek(&self, Bias::Right, &());
+        // TODO kb seems wrong to use buffer points?
         let overshoot = if cursor.item().map_or(true, |t| t.is_fold()) {
             Point::new(0, (self.0 - cursor.start().0 .0) as u32)
         } else {
             let buffer_offset = cursor.start().1.input.len + self.0 - cursor.start().0 .0;
-            let buffer_point = snapshot.buffer_snapshot.offset_to_point(buffer_offset);
+            let buffer_point = snapshot
+                .inlay_snapshot
+                .buffer
+                .offset_to_point(buffer_offset);
             buffer_point - cursor.start().1.input.lines
         };
         FoldPoint(cursor.start().1.output.lines + overshoot)
@@ -1202,6 +1231,18 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldOffset {
     }
 }
 
+impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayPoint {
+    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
+        self.0 += &summary.input.lines;
+    }
+}
+
+impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {
+    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
+        self.0 += &summary.input.len;
+    }
+}
+
 impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
     fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
         *self += &summary.input.lines;
@@ -1219,7 +1260,7 @@ pub type FoldEdit = Edit<FoldOffset>;
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{MultiBuffer, ToPoint};
+    use crate::{display_map::inlay_map::InlayMap, MultiBuffer, ToPoint};
     use collections::HashSet;
     use rand::prelude::*;
     use settings::SettingsStore;
@@ -1235,9 +1276,10 @@ mod tests {
         let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx);
         let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let mut map = FoldMap::new(buffer_snapshot.clone()).0;
+        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        let mut map = FoldMap::new(inlay_snapshot.clone()).0;
 
-        let (mut writer, _, _) = map.write(buffer_snapshot, vec![]);
+        let (mut writer, _, _) = map.write(inlay_snapshot, vec![]);
         let (snapshot2, edits) = writer.fold(vec![
             Point::new(0, 2)..Point::new(2, 2),
             Point::new(2, 4)..Point::new(4, 1),
@@ -1268,7 +1310,10 @@ mod tests {
             );
             buffer.snapshot(cx)
         });
-        let (snapshot3, edits) = map.read(buffer_snapshot, subscription.consume().into_inner());
+
+        let (inlay_snapshot, inlay_edits) =
+            inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
+        let (snapshot3, edits) = map.read(inlay_snapshot, inlay_edits);
         assert_eq!(snapshot3.text(), "123a⋯c123c⋯eeeee");
         assert_eq!(
             edits,
@@ -1288,17 +1333,19 @@ mod tests {
             buffer.edit([(Point::new(2, 6)..Point::new(4, 3), "456")], None, cx);
             buffer.snapshot(cx)
         });
-        let (snapshot4, _) = map.read(buffer_snapshot.clone(), subscription.consume().into_inner());
+        let (inlay_snapshot, inlay_edits) =
+            inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
+        let (snapshot4, _) = map.read(inlay_snapshot.clone(), inlay_edits);
         assert_eq!(snapshot4.text(), "123a⋯c123456eee");
 
-        let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]);
+        let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
         writer.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), false);
-        let (snapshot5, _) = map.read(buffer_snapshot.clone(), vec![]);
+        let (snapshot5, _) = map.read(inlay_snapshot.clone(), vec![]);
         assert_eq!(snapshot5.text(), "123a⋯c123456eee");
 
-        let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]);
+        let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
         writer.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), true);
-        let (snapshot6, _) = map.read(buffer_snapshot, vec![]);
+        let (snapshot6, _) = map.read(inlay_snapshot, vec![]);
         assert_eq!(snapshot6.text(), "123aaaaa\nbbbbbb\nccc123456eee");
     }
 

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

@@ -1,9 +1,6 @@
-use super::{
-    fold_map::{FoldBufferRows, FoldChunks, FoldEdit, FoldOffset, FoldPoint, FoldSnapshot},
-    TextHighlights,
-};
 use crate::{
     inlay_cache::{Inlay, InlayId, InlayProperties},
+    multi_buffer::{MultiBufferChunks, MultiBufferRows},
     MultiBufferSnapshot, ToPoint,
 };
 use collections::{BTreeSet, HashMap};
@@ -16,17 +13,19 @@ use std::{
 };
 use sum_tree::{Bias, Cursor, SumTree};
 use text::Patch;
+use util::post_inc;
 
 pub struct InlayMap {
-    snapshot: Mutex<InlaySnapshot>,
+    buffer: Mutex<MultiBufferSnapshot>,
+    transforms: SumTree<Transform>,
     inlays_by_id: HashMap<InlayId, Inlay>,
     inlays: Vec<Inlay>,
+    version: usize,
 }
 
 #[derive(Clone)]
 pub struct InlaySnapshot {
-    // TODO kb merge these two together
-    pub fold_snapshot: FoldSnapshot,
+    pub buffer: MultiBufferSnapshot,
     transforms: SumTree<Transform>,
     pub version: usize,
 }
@@ -102,12 +101,6 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {
     }
 }
 
-impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldOffset {
-    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
-        self.0 += &summary.input.len;
-    }
-}
-
 #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
 pub struct InlayPoint(pub Point);
 
@@ -117,23 +110,29 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayPoint {
     }
 }
 
-impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldPoint {
+impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
+    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
+        *self += &summary.input.len;
+    }
+}
+
+impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
     fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
-        self.0 += &summary.input.lines;
+        *self += &summary.input.lines;
     }
 }
 
 #[derive(Clone)]
 pub struct InlayBufferRows<'a> {
-    transforms: Cursor<'a, Transform, (InlayPoint, FoldPoint)>,
-    fold_rows: FoldBufferRows<'a>,
+    transforms: Cursor<'a, Transform, (InlayPoint, Point)>,
+    buffer_rows: MultiBufferRows<'a>,
     inlay_row: u32,
 }
 
 pub struct InlayChunks<'a> {
-    transforms: Cursor<'a, Transform, (InlayOffset, FoldOffset)>,
-    fold_chunks: FoldChunks<'a>,
-    fold_chunk: Option<Chunk<'a>>,
+    transforms: Cursor<'a, Transform, (InlayOffset, usize)>,
+    buffer_chunks: MultiBufferChunks<'a>,
+    buffer_chunk: Option<Chunk<'a>>,
     inlay_chunks: Option<text::Chunks<'a>>,
     output_offset: InlayOffset,
     max_output_offset: InlayOffset,
@@ -151,10 +150,10 @@ impl<'a> Iterator for InlayChunks<'a> {
         let chunk = match self.transforms.item()? {
             Transform::Isomorphic(_) => {
                 let chunk = self
-                    .fold_chunk
-                    .get_or_insert_with(|| self.fold_chunks.next().unwrap());
+                    .buffer_chunk
+                    .get_or_insert_with(|| self.buffer_chunks.next().unwrap());
                 if chunk.text.is_empty() {
-                    *chunk = self.fold_chunks.next().unwrap();
+                    *chunk = self.buffer_chunks.next().unwrap();
                 }
 
                 let (prefix, suffix) = chunk.text.split_at(cmp::min(
@@ -201,11 +200,11 @@ impl<'a> Iterator for InlayBufferRows<'a> {
 
     fn next(&mut self) -> Option<Self::Item> {
         let buffer_row = if self.inlay_row == 0 {
-            self.fold_rows.next().unwrap()
+            self.buffer_rows.next().unwrap()
         } else {
             match self.transforms.item()? {
                 Transform::Inlay(_) => None,
-                Transform::Isomorphic(_) => self.fold_rows.next().unwrap(),
+                Transform::Isomorphic(_) => self.buffer_rows.next().unwrap(),
             }
         };
 
@@ -232,21 +231,21 @@ impl InlayPoint {
 }
 
 impl InlayMap {
-    pub fn new(fold_snapshot: FoldSnapshot) -> (Self, InlaySnapshot) {
+    pub fn new(buffer: MultiBufferSnapshot) -> (Self, InlaySnapshot) {
+        let version = 0;
         let snapshot = InlaySnapshot {
-            fold_snapshot: fold_snapshot.clone(),
-            version: 0,
-            transforms: SumTree::from_item(
-                Transform::Isomorphic(fold_snapshot.text_summary()),
-                &(),
-            ),
+            buffer: buffer.clone(),
+            transforms: SumTree::from_item(Transform::Isomorphic(buffer.text_summary()), &()),
+            version,
         };
 
         (
             Self {
-                snapshot: Mutex::new(snapshot.clone()),
+                buffer: Mutex::new(buffer),
+                transforms: snapshot.transforms.clone(),
                 inlays_by_id: Default::default(),
                 inlays: Default::default(),
+                version,
             },
             snapshot,
         )
@@ -254,144 +253,140 @@ impl InlayMap {
 
     pub fn sync(
         &mut self,
-        fold_snapshot: FoldSnapshot,
-        mut fold_edits: Vec<FoldEdit>,
+        buffer_snapshot: MultiBufferSnapshot,
+        buffer_edits: Vec<text::Edit<usize>>,
     ) -> (InlaySnapshot, Vec<InlayEdit>) {
-        let mut snapshot = self.snapshot.lock();
+        let mut buffer = self.buffer.lock();
+        if buffer_edits.is_empty() {
+            let new_version = if buffer.edit_count() != buffer_snapshot.edit_count()
+                || buffer.parse_count() != buffer_snapshot.parse_count()
+                || buffer.diagnostics_update_count() != buffer_snapshot.diagnostics_update_count()
+                || buffer.git_diff_update_count() != buffer_snapshot.git_diff_update_count()
+                || buffer.trailing_excerpt_update_count()
+                    != buffer_snapshot.trailing_excerpt_update_count()
+            {
+                post_inc(&mut self.version)
+            } else {
+                self.version
+            };
 
-        let mut new_snapshot = snapshot.clone();
-        if new_snapshot.fold_snapshot.version != fold_snapshot.version {
-            new_snapshot.version += 1;
-        }
+            *buffer = buffer_snapshot.clone();
+            (
+                InlaySnapshot {
+                    buffer: buffer_snapshot,
+                    transforms: SumTree::default(),
+                    version: new_version,
+                },
+                Vec::new(),
+            )
+        } else {
+            let mut inlay_edits = Patch::default();
+            let mut new_transforms = SumTree::new();
+            // TODO kb something is wrong with how we store it?
+            let mut transforms = self.transforms;
+            let mut cursor = transforms.cursor::<(usize, InlayOffset)>();
+            let mut buffer_edits_iter = buffer_edits.iter().peekable();
+            while let Some(buffer_edit) = buffer_edits_iter.next() {
+                new_transforms
+                    .push_tree(cursor.slice(&buffer_edit.old.start, Bias::Left, &()), &());
+                if let Some(Transform::Isomorphic(transform)) = cursor.item() {
+                    if cursor.end(&()).0 == buffer_edit.old.start {
+                        new_transforms.push(Transform::Isomorphic(transform.clone()), &());
+                        cursor.next(&());
+                    }
+                }
 
-        if fold_snapshot
-            .buffer_snapshot()
-            .trailing_excerpt_update_count()
-            != snapshot
-                .fold_snapshot
-                .buffer_snapshot()
-                .trailing_excerpt_update_count()
-        {
-            if fold_edits.is_empty() {
-                fold_edits.push(Edit {
-                    old: snapshot.fold_snapshot.len()..snapshot.fold_snapshot.len(),
-                    new: fold_snapshot.len()..fold_snapshot.len(),
-                });
-            }
-        }
+                // Remove all the inlays and transforms contained by the edit.
+                let old_start =
+                    cursor.start().1 + InlayOffset(buffer_edit.old.start - cursor.start().0);
+                cursor.seek(&buffer_edit.old.end, Bias::Right, &());
+                let old_end =
+                    cursor.start().1 + InlayOffset(buffer_edit.old.end - cursor.start().0);
 
-        let mut inlay_edits = Patch::default();
-        let mut new_transforms = SumTree::new();
-        let mut cursor = snapshot.transforms.cursor::<(FoldOffset, InlayOffset)>();
-        let mut fold_edits_iter = fold_edits.iter().peekable();
-        while let Some(fold_edit) = fold_edits_iter.next() {
-            new_transforms.push_tree(cursor.slice(&fold_edit.old.start, Bias::Left, &()), &());
-            if let Some(Transform::Isomorphic(transform)) = cursor.item() {
-                if cursor.end(&()).0 == fold_edit.old.start {
-                    new_transforms.push(Transform::Isomorphic(transform.clone()), &());
-                    cursor.next(&());
-                }
-            }
+                // Push the unchanged prefix.
+                let prefix_start = new_transforms.summary().input.len;
+                let prefix_end = buffer_edit.new.start;
+                push_isomorphic(
+                    &mut new_transforms,
+                    buffer_snapshot.text_summary_for_range(prefix_start..prefix_end),
+                );
+                let new_start = InlayOffset(new_transforms.summary().output.len);
+
+                let start_point = buffer_edit.new.start.to_point(&buffer_snapshot);
+                let start_ix = match self.inlays.binary_search_by(|probe| {
+                    probe
+                        .position
+                        .to_point(&buffer_snapshot)
+                        .cmp(&start_point)
+                        .then(std::cmp::Ordering::Greater)
+                }) {
+                    Ok(ix) | Err(ix) => ix,
+                };
+
+                for inlay in &self.inlays[start_ix..] {
+                    let buffer_point = inlay.position.to_point(&buffer_snapshot);
+                    let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
+                    if buffer_offset > buffer_edit.new.end {
+                        break;
+                    }
 
-            // Remove all the inlays and transforms contained by the edit.
-            let old_start =
-                cursor.start().1 + InlayOffset(fold_edit.old.start.0 - cursor.start().0 .0);
-            cursor.seek(&fold_edit.old.end, Bias::Right, &());
-            let old_end = cursor.start().1 + InlayOffset(fold_edit.old.end.0 - cursor.start().0 .0);
-
-            // Push the unchanged prefix.
-            let prefix_start = FoldOffset(new_transforms.summary().input.len);
-            let prefix_end = fold_edit.new.start;
-            push_isomorphic(
-                &mut new_transforms,
-                fold_snapshot.text_summary_for_range(
-                    prefix_start.to_point(&fold_snapshot)..prefix_end.to_point(&fold_snapshot),
-                ),
-            );
-            let new_start = InlayOffset(new_transforms.summary().output.len);
-
-            let start_point = fold_edit
-                .new
-                .start
-                .to_point(&fold_snapshot)
-                .to_buffer_point(&fold_snapshot);
-            let start_ix = match self.inlays.binary_search_by(|probe| {
-                probe
-                    .position
-                    .to_point(&fold_snapshot.buffer_snapshot())
-                    .cmp(&start_point)
-                    .then(std::cmp::Ordering::Greater)
-            }) {
-                Ok(ix) | Err(ix) => ix,
-            };
+                    let prefix_start = new_transforms.summary().input.len;
+                    let prefix_end = buffer_offset;
+                    push_isomorphic(
+                        &mut new_transforms,
+                        buffer_snapshot.text_summary_for_range(prefix_start..prefix_end),
+                    );
 
-            for inlay in &self.inlays[start_ix..] {
-                let buffer_point = inlay.position.to_point(fold_snapshot.buffer_snapshot());
-                let fold_point = fold_snapshot.to_fold_point(buffer_point, Bias::Left);
-                let fold_offset = fold_point.to_offset(&fold_snapshot);
-                if fold_offset > fold_edit.new.end {
-                    break;
+                    if inlay.position.is_valid(&buffer_snapshot) {
+                        new_transforms.push(Transform::Inlay(inlay.clone()), &());
+                    }
                 }
 
-                let prefix_start = FoldOffset(new_transforms.summary().input.len);
-                let prefix_end = fold_offset;
+                // Apply the rest of the edit.
+                let transform_start = new_transforms.summary().input.len;
                 push_isomorphic(
                     &mut new_transforms,
-                    fold_snapshot.text_summary_for_range(
-                        prefix_start.to_point(&fold_snapshot)..prefix_end.to_point(&fold_snapshot),
-                    ),
+                    buffer_snapshot.text_summary_for_range(transform_start..buffer_edit.new.end),
                 );
+                let new_end = InlayOffset(new_transforms.summary().output.len);
+                inlay_edits.push(Edit {
+                    old: old_start..old_end,
+                    new: new_start..new_end,
+                });
 
-                if inlay.position.is_valid(fold_snapshot.buffer_snapshot()) {
-                    new_transforms.push(Transform::Inlay(inlay.clone()), &());
+                // If the next edit doesn't intersect the current isomorphic transform, then
+                // we can push its remainder.
+                if buffer_edits_iter
+                    .peek()
+                    .map_or(true, |edit| edit.old.start >= cursor.end(&()).0)
+                {
+                    let transform_start = new_transforms.summary().input.len;
+                    let transform_end =
+                        buffer_edit.new.end + (cursor.end(&()).0 - buffer_edit.old.end);
+                    push_isomorphic(
+                        &mut new_transforms,
+                        buffer_snapshot.text_summary_for_range(transform_start..transform_end),
+                    );
+                    cursor.next(&());
                 }
             }
 
-            // Apply the rest of the edit.
-            let transform_start = FoldOffset(new_transforms.summary().input.len);
-            push_isomorphic(
-                &mut new_transforms,
-                fold_snapshot.text_summary_for_range(
-                    transform_start.to_point(&fold_snapshot)
-                        ..fold_edit.new.end.to_point(&fold_snapshot),
-                ),
-            );
-            let new_end = InlayOffset(new_transforms.summary().output.len);
-            inlay_edits.push(Edit {
-                old: old_start..old_end,
-                new: new_start..new_end,
-            });
-
-            // If the next edit doesn't intersect the current isomorphic transform, then
-            // we can push its remainder.
-            if fold_edits_iter
-                .peek()
-                .map_or(true, |edit| edit.old.start >= cursor.end(&()).0)
-            {
-                let transform_start = FoldOffset(new_transforms.summary().input.len);
-                let transform_end = fold_edit.new.end + (cursor.end(&()).0 - fold_edit.old.end);
-                push_isomorphic(
-                    &mut new_transforms,
-                    fold_snapshot.text_summary_for_range(
-                        transform_start.to_point(&fold_snapshot)
-                            ..transform_end.to_point(&fold_snapshot),
-                    ),
-                );
-                cursor.next(&());
+            new_transforms.push_tree(cursor.suffix(&()), &());
+            if new_transforms.first().is_none() {
+                new_transforms.push(Transform::Isomorphic(Default::default()), &());
             }
-        }
 
-        new_transforms.push_tree(cursor.suffix(&()), &());
-        if new_transforms.first().is_none() {
-            new_transforms.push(Transform::Isomorphic(Default::default()), &());
-        }
-        new_snapshot.transforms = new_transforms;
-        new_snapshot.fold_snapshot = fold_snapshot;
-        new_snapshot.check_invariants();
-        drop(cursor);
+            let new_snapshot = InlaySnapshot {
+                buffer: buffer_snapshot,
+                transforms: new_transforms,
+                version: post_inc(&mut self.version),
+            };
+            new_snapshot.check_invariants();
+            drop(cursor);
 
-        *snapshot = new_snapshot.clone();
-        (new_snapshot, inlay_edits.into_inner())
+            *buffer = buffer_snapshot.clone();
+            (new_snapshot, inlay_edits.into_inner())
+        }
     }
 
     pub fn splice<T: Into<Rope>>(
@@ -399,20 +394,15 @@ impl InlayMap {
         to_remove: Vec<InlayId>,
         to_insert: Vec<(InlayId, InlayProperties<T>)>,
     ) -> (InlaySnapshot, Vec<InlayEdit>) {
-        let mut snapshot = self.snapshot.lock();
-        snapshot.version += 1;
-
+        let mut buffer_snapshot = self.buffer.lock();
         let mut edits = BTreeSet::new();
 
         self.inlays.retain(|inlay| !to_remove.contains(&inlay.id));
         for inlay_id in to_remove {
             if let Some(inlay) = self.inlays_by_id.remove(&inlay_id) {
-                let buffer_point = inlay.position.to_point(snapshot.buffer_snapshot());
-                let fold_point = snapshot
-                    .fold_snapshot
-                    .to_fold_point(buffer_point, Bias::Left);
-                let fold_offset = fold_point.to_offset(&snapshot.fold_snapshot);
-                edits.insert(fold_offset);
+                let buffer_point = inlay.position.to_point(&buffer_snapshot);
+                let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
+                edits.insert(buffer_offset);
             }
         }
 
@@ -423,34 +413,28 @@ impl InlayMap {
                 text: properties.text.into(),
             };
             self.inlays_by_id.insert(inlay.id, inlay.clone());
-            match self.inlays.binary_search_by(|probe| {
-                probe
-                    .position
-                    .cmp(&inlay.position, snapshot.buffer_snapshot())
-            }) {
+            match self
+                .inlays
+                .binary_search_by(|probe| probe.position.cmp(&inlay.position, &buffer_snapshot))
+            {
                 Ok(ix) | Err(ix) => {
                     self.inlays.insert(ix, inlay.clone());
                 }
             }
 
-            let buffer_point = inlay.position.to_point(snapshot.buffer_snapshot());
-            let fold_point = snapshot
-                .fold_snapshot
-                .to_fold_point(buffer_point, Bias::Left);
-            let fold_offset = fold_point.to_offset(&snapshot.fold_snapshot);
-            edits.insert(fold_offset);
+            let buffer_point = inlay.position.to_point(&buffer_snapshot);
+            let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
+            edits.insert(buffer_offset);
         }
 
-        let fold_snapshot = snapshot.fold_snapshot.clone();
-        let fold_edits = edits
+        let buffer_edits = edits
             .into_iter()
             .map(|offset| Edit {
                 old: offset..offset,
                 new: offset..offset,
             })
             .collect();
-        drop(snapshot);
-        self.sync(fold_snapshot, fold_edits)
+        self.sync(buffer_snapshot.clone(), buffer_edits)
     }
 
     #[cfg(any(test, feature = "test-support"))]
@@ -460,14 +444,12 @@ impl InlayMap {
         rng: &mut rand::rngs::StdRng,
     ) -> (InlaySnapshot, Vec<InlayEdit>) {
         use rand::prelude::*;
-        use util::post_inc;
 
         let mut to_remove = Vec::new();
         let mut to_insert = Vec::new();
-        let snapshot = self.snapshot.lock();
+        let buffer_snapshot = self.buffer.lock();
         for _ in 0..rng.gen_range(1..=5) {
             if self.inlays.is_empty() || rng.gen() {
-                let buffer_snapshot = snapshot.buffer_snapshot();
                 let position = buffer_snapshot.random_byte_range(0, rng).start;
                 let bias = if rng.gen() { Bias::Left } else { Bias::Right };
                 let len = rng.gen_range(1..=5);
@@ -494,29 +476,25 @@ impl InlayMap {
         }
         log::info!("removing inlays: {:?}", to_remove);
 
-        drop(snapshot);
+        drop(buffer_snapshot);
         self.splice(to_remove, to_insert)
     }
 }
 
 impl InlaySnapshot {
-    pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
-        self.fold_snapshot.buffer_snapshot()
-    }
-
     pub fn to_point(&self, offset: InlayOffset) -> InlayPoint {
         let mut cursor = self
             .transforms
-            .cursor::<(InlayOffset, (InlayPoint, FoldOffset))>();
+            .cursor::<(InlayOffset, (InlayPoint, usize))>();
         cursor.seek(&offset, Bias::Right, &());
         let overshoot = offset.0 - cursor.start().0 .0;
         match cursor.item() {
             Some(Transform::Isomorphic(_)) => {
-                let fold_offset_start = cursor.start().1 .1;
-                let fold_offset_end = FoldOffset(fold_offset_start.0 + overshoot);
-                let fold_start = fold_offset_start.to_point(&self.fold_snapshot);
-                let fold_end = fold_offset_end.to_point(&self.fold_snapshot);
-                InlayPoint(cursor.start().1 .0 .0 + (fold_end.0 - fold_start.0))
+                let buffer_offset_start = cursor.start().1 .1;
+                let buffer_offset_end = buffer_offset_start + overshoot;
+                let buffer_start = self.buffer.offset_to_point(buffer_offset_start);
+                let buffer_end = self.buffer.offset_to_point(buffer_offset_end);
+                InlayPoint(cursor.start().1 .0 .0 + (buffer_end - buffer_start))
             }
             Some(Transform::Inlay(inlay)) => {
                 let overshoot = inlay.text.offset_to_point(overshoot);
@@ -537,16 +515,16 @@ impl InlaySnapshot {
     pub fn to_offset(&self, point: InlayPoint) -> InlayOffset {
         let mut cursor = self
             .transforms
-            .cursor::<(InlayPoint, (InlayOffset, FoldPoint))>();
+            .cursor::<(InlayPoint, (InlayOffset, Point))>();
         cursor.seek(&point, Bias::Right, &());
         let overshoot = point.0 - cursor.start().0 .0;
         match cursor.item() {
             Some(Transform::Isomorphic(_)) => {
-                let fold_point_start = cursor.start().1 .1;
-                let fold_point_end = FoldPoint(fold_point_start.0 + overshoot);
-                let fold_start = fold_point_start.to_offset(&self.fold_snapshot);
-                let fold_end = fold_point_end.to_offset(&self.fold_snapshot);
-                InlayOffset(cursor.start().1 .0 .0 + (fold_end.0 - fold_start.0))
+                let buffer_point_start = cursor.start().1 .1;
+                let buffer_point_end = buffer_point_start + overshoot;
+                let buffer_offset_start = self.buffer.point_to_offset(buffer_point_start);
+                let buffer_offset_end = self.buffer.point_to_offset(buffer_point_end);
+                InlayOffset(cursor.start().1 .0 .0 + (buffer_offset_end - buffer_offset_start))
             }
             Some(Transform::Inlay(inlay)) => {
                 let overshoot = inlay.text.point_to_offset(overshoot);
@@ -557,42 +535,55 @@ impl InlaySnapshot {
     }
 
     pub fn chars_at(&self, start: InlayPoint) -> impl '_ + Iterator<Item = char> {
-        self.chunks(self.to_offset(start)..self.len(), false, None, None)
+        self.chunks(self.to_offset(start)..self.len(), false, None)
             .flat_map(|chunk| chunk.text.chars())
     }
 
-    pub fn to_fold_point(&self, point: InlayPoint) -> FoldPoint {
-        let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
+    pub fn to_buffer_point(&self, point: InlayPoint) -> Point {
+        let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>();
         cursor.seek(&point, Bias::Right, &());
         match cursor.item() {
             Some(Transform::Isomorphic(_)) => {
                 let overshoot = point.0 - cursor.start().0 .0;
-                FoldPoint(cursor.start().1 .0 + overshoot)
+                cursor.start().1 + overshoot
             }
             Some(Transform::Inlay(_)) => cursor.start().1,
-            None => self.fold_snapshot.max_point(),
+            None => self.buffer.max_point(),
         }
     }
 
-    pub fn to_fold_offset(&self, offset: InlayOffset) -> FoldOffset {
-        let mut cursor = self.transforms.cursor::<(InlayOffset, FoldOffset)>();
+    pub fn to_buffer_offset(&self, offset: InlayOffset) -> usize {
+        let mut cursor = self.transforms.cursor::<(InlayOffset, usize)>();
         cursor.seek(&offset, Bias::Right, &());
         match cursor.item() {
             Some(Transform::Isomorphic(_)) => {
                 let overshoot = offset - cursor.start().0;
-                cursor.start().1 + FoldOffset(overshoot.0)
+                cursor.start().1 + overshoot.0
+            }
+            Some(Transform::Inlay(_)) => cursor.start().1,
+            None => self.buffer.len(),
+        }
+    }
+
+    pub fn to_inlay_offset(&self, offset: usize) -> InlayOffset {
+        let mut cursor = self.transforms.cursor::<(Point, InlayOffset)>();
+        cursor.seek(&offset, Bias::Left, &());
+        match cursor.item() {
+            Some(Transform::Isomorphic(_)) => {
+                let overshoot = offset - cursor.start().0;
+                InlayOffset(cursor.start().1 .0 + overshoot)
             }
             Some(Transform::Inlay(_)) => cursor.start().1,
-            None => self.fold_snapshot.len(),
+            None => self.len(),
         }
     }
 
-    pub fn to_inlay_point(&self, point: FoldPoint) -> InlayPoint {
-        let mut cursor = self.transforms.cursor::<(FoldPoint, InlayPoint)>();
+    pub fn to_inlay_point(&self, point: Point) -> InlayPoint {
+        let mut cursor = self.transforms.cursor::<(Point, InlayPoint)>();
         cursor.seek(&point, Bias::Left, &());
         match cursor.item() {
             Some(Transform::Isomorphic(_)) => {
-                let overshoot = point.0 - cursor.start().0 .0;
+                let overshoot = point - cursor.start().0;
                 InlayPoint(cursor.start().1 .0 + overshoot)
             }
             Some(Transform::Inlay(_)) => cursor.start().1,
@@ -601,7 +592,7 @@ impl InlaySnapshot {
     }
 
     pub fn clip_point(&self, point: InlayPoint, bias: Bias) -> InlayPoint {
-        let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
+        let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>();
         cursor.seek(&point, Bias::Left, &());
 
         let mut bias = bias;
@@ -623,9 +614,9 @@ impl InlaySnapshot {
                     } else {
                         point.0 - cursor.start().0 .0
                     };
-                    let fold_point = FoldPoint(cursor.start().1 .0 + overshoot);
-                    let clipped_fold_point = self.fold_snapshot.clip_point(fold_point, bias);
-                    let clipped_overshoot = clipped_fold_point.0 - cursor.start().1 .0;
+                    let buffer_point = cursor.start().1 + overshoot;
+                    let clipped_buffer_point = self.buffer.clip_point(buffer_point, bias);
+                    let clipped_overshoot = clipped_buffer_point - cursor.start().1;
                     return InlayPoint(cursor.start().0 .0 + clipped_overshoot);
                 }
                 Some(Transform::Inlay(_)) => skipped_inlay = true,
@@ -643,23 +634,24 @@ impl InlaySnapshot {
         }
     }
 
+    pub fn text_summary(&self) -> TextSummary {
+        self.transforms.summary().output
+    }
+
     pub fn text_summary_for_range(&self, range: Range<InlayPoint>) -> TextSummary {
         let mut summary = TextSummary::default();
 
-        let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
+        let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>();
         cursor.seek(&range.start, Bias::Right, &());
 
         let overshoot = range.start.0 - cursor.start().0 .0;
         match cursor.item() {
             Some(Transform::Isomorphic(_)) => {
-                let fold_start = cursor.start().1 .0;
-                let suffix_start = FoldPoint(fold_start + overshoot);
-                let suffix_end = FoldPoint(
-                    fold_start + (cmp::min(cursor.end(&()).0, range.end).0 - cursor.start().0 .0),
-                );
-                summary = self
-                    .fold_snapshot
-                    .text_summary_for_range(suffix_start..suffix_end);
+                let buffer_start = cursor.start().1;
+                let suffix_start = buffer_start + overshoot;
+                let suffix_end =
+                    buffer_start + (cmp::min(cursor.end(&()).0, range.end).0 - cursor.start().0 .0);
+                summary = self.buffer.text_summary_for_range(suffix_start..suffix_end);
                 cursor.next(&());
             }
             Some(Transform::Inlay(inlay)) => {
@@ -682,10 +674,10 @@ impl InlaySnapshot {
             match cursor.item() {
                 Some(Transform::Isomorphic(_)) => {
                     let prefix_start = cursor.start().1;
-                    let prefix_end = FoldPoint(prefix_start.0 + overshoot);
+                    let prefix_end = prefix_start + overshoot;
                     summary += self
-                        .fold_snapshot
-                        .text_summary_for_range(prefix_start..prefix_end);
+                        .buffer
+                        .text_summary_for_range::<TextSummary, Point>(prefix_start..prefix_end);
                 }
                 Some(Transform::Inlay(inlay)) => {
                     let prefix_end = inlay.text.point_to_offset(overshoot);
@@ -699,27 +691,27 @@ impl InlaySnapshot {
     }
 
     pub fn buffer_rows<'a>(&'a self, row: u32) -> InlayBufferRows<'a> {
-        let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
+        let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>();
         let inlay_point = InlayPoint::new(row, 0);
         cursor.seek(&inlay_point, Bias::Left, &());
 
-        let mut fold_point = cursor.start().1;
-        let fold_row = if row == 0 {
+        let mut buffer_point = cursor.start().1;
+        let buffer_row = if row == 0 {
             0
         } else {
             match cursor.item() {
                 Some(Transform::Isomorphic(_)) => {
-                    fold_point.0 += inlay_point.0 - cursor.start().0 .0;
-                    fold_point.row()
+                    buffer_point += inlay_point.0 - cursor.start().0 .0;
+                    buffer_point.row
                 }
-                _ => cmp::min(fold_point.row() + 1, self.fold_snapshot.max_point().row()),
+                _ => cmp::min(buffer_point.row + 1, self.buffer.max_point().row),
             }
         };
 
         InlayBufferRows {
             transforms: cursor,
             inlay_row: inlay_point.row(),
-            fold_rows: self.fold_snapshot.buffer_rows(fold_row),
+            buffer_rows: self.buffer.buffer_rows(buffer_row),
         }
     }
 
@@ -737,22 +729,19 @@ impl InlaySnapshot {
         &'a self,
         range: Range<InlayOffset>,
         language_aware: bool,
-        text_highlights: Option<&'a TextHighlights>,
         inlay_highlight_style: Option<HighlightStyle>,
     ) -> InlayChunks<'a> {
-        let mut cursor = self.transforms.cursor::<(InlayOffset, FoldOffset)>();
+        let mut cursor = self.transforms.cursor::<(InlayOffset, usize)>();
         cursor.seek(&range.start, Bias::Right, &());
 
-        let fold_range = self.to_fold_offset(range.start)..self.to_fold_offset(range.end);
-        let fold_chunks = self
-            .fold_snapshot
-            .chunks(fold_range, language_aware, text_highlights);
+        let buffer_range = self.to_buffer_offset(range.start)..self.to_buffer_offset(range.end);
+        let buffer_chunks = self.buffer.chunks(buffer_range, language_aware);
 
         InlayChunks {
             transforms: cursor,
-            fold_chunks,
+            buffer_chunks,
             inlay_chunks: None,
-            fold_chunk: None,
+            buffer_chunk: None,
             output_offset: range.start,
             max_output_offset: range.end,
             highlight_style: inlay_highlight_style,
@@ -761,7 +750,7 @@ impl InlaySnapshot {
 
     #[cfg(test)]
     pub fn text(&self) -> String {
-        self.chunks(Default::default()..self.len(), false, None, None)
+        self.chunks(Default::default()..self.len(), false, None)
             .map(|chunk| chunk.text)
             .collect()
     }
@@ -769,10 +758,7 @@ impl InlaySnapshot {
     fn check_invariants(&self) {
         #[cfg(any(debug_assertions, feature = "test-support"))]
         {
-            assert_eq!(
-                self.transforms.summary().input,
-                self.fold_snapshot.text_summary()
-            );
+            assert_eq!(self.transforms.summary().input, self.buffer.text_summary());
         }
     }
 }
@@ -800,7 +786,7 @@ fn push_isomorphic(sum_tree: &mut SumTree<Transform>, summary: TextSummary) {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{display_map::fold_map::FoldMap, MultiBuffer};
+    use crate::MultiBuffer;
     use gpui::AppContext;
     use rand::prelude::*;
     use settings::SettingsStore;
@@ -812,8 +798,7 @@ mod tests {
     fn test_basic_inlays(cx: &mut AppContext) {
         let buffer = MultiBuffer::build_simple("abcdefghi", cx);
         let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
-        let (fold_map, fold_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
-        let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot.clone());
+        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
         assert_eq!(inlay_snapshot.text(), "abcdefghi");
         let mut next_inlay_id = 0;
 
@@ -829,27 +814,27 @@ mod tests {
         );
         assert_eq!(inlay_snapshot.text(), "abc|123|defghi");
         assert_eq!(
-            inlay_snapshot.to_inlay_point(FoldPoint::new(0, 0)),
+            inlay_snapshot.to_inlay_point(Point::new(0, 0)),
             InlayPoint::new(0, 0)
         );
         assert_eq!(
-            inlay_snapshot.to_inlay_point(FoldPoint::new(0, 1)),
+            inlay_snapshot.to_inlay_point(Point::new(0, 1)),
             InlayPoint::new(0, 1)
         );
         assert_eq!(
-            inlay_snapshot.to_inlay_point(FoldPoint::new(0, 2)),
+            inlay_snapshot.to_inlay_point(Point::new(0, 2)),
             InlayPoint::new(0, 2)
         );
         assert_eq!(
-            inlay_snapshot.to_inlay_point(FoldPoint::new(0, 3)),
+            inlay_snapshot.to_inlay_point(Point::new(0, 3)),
             InlayPoint::new(0, 3)
         );
         assert_eq!(
-            inlay_snapshot.to_inlay_point(FoldPoint::new(0, 4)),
+            inlay_snapshot.to_inlay_point(Point::new(0, 4)),
             InlayPoint::new(0, 9)
         );
         assert_eq!(
-            inlay_snapshot.to_inlay_point(FoldPoint::new(0, 5)),
+            inlay_snapshot.to_inlay_point(Point::new(0, 5)),
             InlayPoint::new(0, 10)
         );
         assert_eq!(
@@ -881,20 +866,18 @@ mod tests {
         buffer.update(cx, |buffer, cx| {
             buffer.edit([(2..3, "x"), (3..3, "y"), (4..4, "z")], None, cx)
         });
-        let (fold_snapshot, fold_edits) = fold_map.read(
+        let (inlay_snapshot, _) = inlay_map.sync(
             buffer.read(cx).snapshot(cx),
             buffer_edits.consume().into_inner(),
         );
-        let (inlay_snapshot, _) = inlay_map.sync(fold_snapshot.clone(), fold_edits);
         assert_eq!(inlay_snapshot.text(), "abxy|123|dzefghi");
 
         // An edit surrounding the inlay should invalidate it.
         buffer.update(cx, |buffer, cx| buffer.edit([(4..5, "D")], None, cx));
-        let (fold_snapshot, fold_edits) = fold_map.read(
+        let (inlay_snapshot, _) = inlay_map.sync(
             buffer.read(cx).snapshot(cx),
             buffer_edits.consume().into_inner(),
         );
-        let (inlay_snapshot, _) = inlay_map.sync(fold_snapshot.clone(), fold_edits);
         assert_eq!(inlay_snapshot.text(), "abxyDzefghi");
 
         let (inlay_snapshot, _) = inlay_map.splice(
@@ -920,11 +903,10 @@ mod tests {
 
         // Edits ending where the inlay starts should not move it if it has a left bias.
         buffer.update(cx, |buffer, cx| buffer.edit([(3..3, "JKL")], None, cx));
-        let (fold_snapshot, fold_edits) = fold_map.read(
+        let (inlay_snapshot, _) = inlay_map.sync(
             buffer.read(cx).snapshot(cx),
             buffer_edits.consume().into_inner(),
         );
-        let (inlay_snapshot, _) = inlay_map.sync(fold_snapshot.clone(), fold_edits);
         assert_eq!(inlay_snapshot.text(), "abx|123|JKL|456|yDzefghi");
 
         // The inlays can be manually removed.
@@ -936,8 +918,7 @@ mod tests {
     #[gpui::test]
     fn test_buffer_rows(cx: &mut AppContext) {
         let buffer = MultiBuffer::build_simple("abc\ndef\nghi", cx);
-        let (_, fold_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
-        let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot.clone());
+        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
         assert_eq!(inlay_snapshot.text(), "abc\ndef\nghi");
 
         let (inlay_snapshot, _) = inlay_map.splice(
@@ -993,27 +974,20 @@ mod tests {
         let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
         log::info!("buffer text: {:?}", buffer_snapshot.text());
 
-        let (mut fold_map, mut fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(fold_snapshot.clone());
+        let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
         let mut next_inlay_id = 0;
 
         for _ in 0..operations {
-            let mut fold_edits = Patch::default();
             let mut inlay_edits = Patch::default();
 
             let mut prev_inlay_text = inlay_snapshot.text();
             let mut buffer_edits = Vec::new();
             match rng.gen_range(0..=100) {
-                0..=29 => {
+                0..=50 => {
                     let (snapshot, edits) = inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
                     log::info!("mutated text: {:?}", snapshot.text());
                     inlay_edits = Patch::new(edits);
                 }
-                30..=59 => {
-                    for (_, edits) in fold_map.randomly_mutate(&mut rng) {
-                        fold_edits = fold_edits.compose(edits);
-                    }
-                }
                 _ => buffer.update(cx, |buffer, cx| {
                     let subscription = buffer.subscribe();
                     let edit_count = rng.gen_range(1..=5);
@@ -1025,17 +999,12 @@ mod tests {
                 }),
             };
 
-            let (new_fold_snapshot, new_fold_edits) =
-                fold_map.read(buffer_snapshot.clone(), buffer_edits);
-            fold_snapshot = new_fold_snapshot;
-            fold_edits = fold_edits.compose(new_fold_edits);
             let (new_inlay_snapshot, new_inlay_edits) =
-                inlay_map.sync(fold_snapshot.clone(), fold_edits.into_inner());
+                inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
             inlay_snapshot = new_inlay_snapshot;
             inlay_edits = inlay_edits.compose(new_inlay_edits);
 
             log::info!("buffer text: {:?}", buffer_snapshot.text());
-            log::info!("folds text: {:?}", fold_snapshot.text());
             log::info!("inlay text: {:?}", inlay_snapshot.text());
 
             let inlays = inlay_map
@@ -1044,14 +1013,13 @@ mod tests {
                 .filter(|inlay| inlay.position.is_valid(&buffer_snapshot))
                 .map(|inlay| {
                     let buffer_point = inlay.position.to_point(&buffer_snapshot);
-                    let fold_point = fold_snapshot.to_fold_point(buffer_point, Bias::Left);
-                    let fold_offset = fold_point.to_offset(&fold_snapshot);
-                    (fold_offset, inlay.clone())
+                    let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
+                    (buffer_offset, inlay.clone())
                 })
                 .collect::<Vec<_>>();
-            let mut expected_text = Rope::from(fold_snapshot.text().as_str());
+            let mut expected_text = Rope::from(buffer_snapshot.text().as_str());
             for (offset, inlay) in inlays.into_iter().rev() {
-                expected_text.replace(offset.0..offset.0, &inlay.text.to_string());
+                expected_text.replace(offset..offset, &inlay.text.to_string());
             }
             assert_eq!(inlay_snapshot.text(), expected_text.to_string());
 
@@ -1078,7 +1046,7 @@ mod tests {
                 start = expected_text.clip_offset(start, Bias::Right);
 
                 let actual_text = inlay_snapshot
-                    .chunks(InlayOffset(start)..InlayOffset(end), false, None, None)
+                    .chunks(InlayOffset(start)..InlayOffset(end), false, None)
                     .map(|chunk| chunk.text)
                     .collect::<String>();
                 assert_eq!(
@@ -1123,11 +1091,11 @@ mod tests {
                     inlay_offset
                 );
                 assert_eq!(
-                    inlay_snapshot.to_inlay_point(inlay_snapshot.to_fold_point(inlay_point)),
+                    inlay_snapshot.to_inlay_point(inlay_snapshot.to_buffer_point(inlay_point)),
                     inlay_snapshot.clip_point(inlay_point, Bias::Left),
-                    "to_fold_point({:?}) = {:?}",
+                    "to_buffer_point({:?}) = {:?}",
                     inlay_point,
-                    inlay_snapshot.to_fold_point(inlay_point),
+                    inlay_snapshot.to_buffer_point(inlay_point),
                 );
 
                 let mut bytes = [0; 4];

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

@@ -1,875 +0,0 @@
-use super::{
-    fold_map::{FoldBufferRows, FoldChunks, FoldEdit, FoldOffset, FoldPoint, FoldSnapshot},
-    TextHighlights,
-};
-use crate::{MultiBufferSnapshot, ToPoint};
-use gpui::fonts::HighlightStyle;
-use language::{Bias, Chunk, Edit, Patch, Point, Rope, TextSummary};
-use parking_lot::Mutex;
-use std::{
-    cmp,
-    ops::{Add, AddAssign, Range, Sub},
-};
-use util::post_inc;
-
-pub type SuggestionEdit = Edit<SuggestionOffset>;
-
-#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
-pub struct SuggestionOffset(pub usize);
-
-impl Add for SuggestionOffset {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self::Output {
-        Self(self.0 + rhs.0)
-    }
-}
-
-impl Sub for SuggestionOffset {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self::Output {
-        Self(self.0 - rhs.0)
-    }
-}
-
-impl AddAssign for SuggestionOffset {
-    fn add_assign(&mut self, rhs: Self) {
-        self.0 += rhs.0;
-    }
-}
-
-#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
-pub struct SuggestionPoint(pub Point);
-
-impl SuggestionPoint {
-    pub fn new(row: u32, column: u32) -> Self {
-        Self(Point::new(row, column))
-    }
-
-    pub fn row(self) -> u32 {
-        self.0.row
-    }
-
-    pub fn column(self) -> u32 {
-        self.0.column
-    }
-}
-
-#[derive(Clone, Debug)]
-pub struct Suggestion<T> {
-    pub position: T,
-    pub text: Rope,
-}
-
-pub struct SuggestionMap(Mutex<SuggestionSnapshot>);
-
-impl SuggestionMap {
-    pub fn new(fold_snapshot: FoldSnapshot) -> (Self, SuggestionSnapshot) {
-        let snapshot = SuggestionSnapshot {
-            fold_snapshot,
-            suggestion: None,
-            version: 0,
-        };
-        (Self(Mutex::new(snapshot.clone())), snapshot)
-    }
-
-    pub fn replace<T>(
-        &self,
-        new_suggestion: Option<Suggestion<T>>,
-        fold_snapshot: FoldSnapshot,
-        fold_edits: Vec<FoldEdit>,
-    ) -> (
-        SuggestionSnapshot,
-        Vec<SuggestionEdit>,
-        Option<Suggestion<FoldOffset>>,
-    )
-    where
-        T: ToPoint,
-    {
-        let new_suggestion = new_suggestion.map(|new_suggestion| {
-            let buffer_point = new_suggestion
-                .position
-                .to_point(fold_snapshot.buffer_snapshot());
-            let fold_point = fold_snapshot.to_fold_point(buffer_point, Bias::Left);
-            let fold_offset = fold_point.to_offset(&fold_snapshot);
-            Suggestion {
-                position: fold_offset,
-                text: new_suggestion.text,
-            }
-        });
-
-        let (_, edits) = self.sync(fold_snapshot, fold_edits);
-        let mut snapshot = self.0.lock();
-
-        let mut patch = Patch::new(edits);
-        let old_suggestion = snapshot.suggestion.take();
-        if let Some(suggestion) = &old_suggestion {
-            patch = patch.compose([SuggestionEdit {
-                old: SuggestionOffset(suggestion.position.0)
-                    ..SuggestionOffset(suggestion.position.0 + suggestion.text.len()),
-                new: SuggestionOffset(suggestion.position.0)
-                    ..SuggestionOffset(suggestion.position.0),
-            }]);
-        }
-
-        if let Some(suggestion) = new_suggestion.as_ref() {
-            patch = patch.compose([SuggestionEdit {
-                old: SuggestionOffset(suggestion.position.0)
-                    ..SuggestionOffset(suggestion.position.0),
-                new: SuggestionOffset(suggestion.position.0)
-                    ..SuggestionOffset(suggestion.position.0 + suggestion.text.len()),
-            }]);
-        }
-
-        snapshot.suggestion = new_suggestion;
-        snapshot.version += 1;
-        (snapshot.clone(), patch.into_inner(), old_suggestion)
-    }
-
-    pub fn sync(
-        &self,
-        fold_snapshot: FoldSnapshot,
-        fold_edits: Vec<FoldEdit>,
-    ) -> (SuggestionSnapshot, Vec<SuggestionEdit>) {
-        let mut snapshot = self.0.lock();
-
-        if snapshot.fold_snapshot.version != fold_snapshot.version {
-            snapshot.version += 1;
-        }
-
-        let mut suggestion_edits = Vec::new();
-
-        let mut suggestion_old_len = 0;
-        let mut suggestion_new_len = 0;
-        for fold_edit in fold_edits {
-            let start = fold_edit.new.start;
-            let end = FoldOffset(start.0 + fold_edit.old_len().0);
-            if let Some(suggestion) = snapshot.suggestion.as_mut() {
-                if end <= suggestion.position {
-                    suggestion.position.0 += fold_edit.new_len().0;
-                    suggestion.position.0 -= fold_edit.old_len().0;
-                } else if start > suggestion.position {
-                    suggestion_old_len = suggestion.text.len();
-                    suggestion_new_len = suggestion_old_len;
-                } else {
-                    suggestion_old_len = suggestion.text.len();
-                    snapshot.suggestion.take();
-                    suggestion_edits.push(SuggestionEdit {
-                        old: SuggestionOffset(fold_edit.old.start.0)
-                            ..SuggestionOffset(fold_edit.old.end.0 + suggestion_old_len),
-                        new: SuggestionOffset(fold_edit.new.start.0)
-                            ..SuggestionOffset(fold_edit.new.end.0),
-                    });
-                    continue;
-                }
-            }
-
-            suggestion_edits.push(SuggestionEdit {
-                old: SuggestionOffset(fold_edit.old.start.0 + suggestion_old_len)
-                    ..SuggestionOffset(fold_edit.old.end.0 + suggestion_old_len),
-                new: SuggestionOffset(fold_edit.new.start.0 + suggestion_new_len)
-                    ..SuggestionOffset(fold_edit.new.end.0 + suggestion_new_len),
-            });
-        }
-        snapshot.fold_snapshot = fold_snapshot;
-
-        (snapshot.clone(), suggestion_edits)
-    }
-
-    pub fn has_suggestion(&self) -> bool {
-        let snapshot = self.0.lock();
-        snapshot.suggestion.is_some()
-    }
-}
-
-#[derive(Clone)]
-pub struct SuggestionSnapshot {
-    pub fold_snapshot: FoldSnapshot,
-    pub suggestion: Option<Suggestion<FoldOffset>>,
-    pub version: usize,
-}
-
-impl SuggestionSnapshot {
-    pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
-        self.fold_snapshot.buffer_snapshot()
-    }
-
-    pub fn max_point(&self) -> SuggestionPoint {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let suggestion_point = suggestion.position.to_point(&self.fold_snapshot);
-            let mut max_point = suggestion_point.0;
-            max_point += suggestion.text.max_point();
-            max_point += self.fold_snapshot.max_point().0 - suggestion_point.0;
-            SuggestionPoint(max_point)
-        } else {
-            SuggestionPoint(self.fold_snapshot.max_point().0)
-        }
-    }
-
-    pub fn len(&self) -> SuggestionOffset {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let mut len = suggestion.position.0;
-            len += suggestion.text.len();
-            len += self.fold_snapshot.len().0 - suggestion.position.0;
-            SuggestionOffset(len)
-        } else {
-            SuggestionOffset(self.fold_snapshot.len().0)
-        }
-    }
-
-    pub fn line_len(&self, row: u32) -> u32 {
-        if let Some(suggestion) = &self.suggestion {
-            let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
-            let suggestion_end = suggestion_start + suggestion.text.max_point();
-
-            if row < suggestion_start.row {
-                self.fold_snapshot.line_len(row)
-            } else if row > suggestion_end.row {
-                self.fold_snapshot
-                    .line_len(suggestion_start.row + (row - suggestion_end.row))
-            } else {
-                let mut result = suggestion.text.line_len(row - suggestion_start.row);
-                if row == suggestion_start.row {
-                    result += suggestion_start.column;
-                }
-                if row == suggestion_end.row {
-                    result +=
-                        self.fold_snapshot.line_len(suggestion_start.row) - suggestion_start.column;
-                }
-                result
-            }
-        } else {
-            self.fold_snapshot.line_len(row)
-        }
-    }
-
-    pub fn clip_point(&self, point: SuggestionPoint, bias: Bias) -> SuggestionPoint {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
-            let suggestion_end = suggestion_start + suggestion.text.max_point();
-            if point.0 <= suggestion_start {
-                SuggestionPoint(self.fold_snapshot.clip_point(FoldPoint(point.0), bias).0)
-            } else if point.0 > suggestion_end {
-                let fold_point = self.fold_snapshot.clip_point(
-                    FoldPoint(suggestion_start + (point.0 - suggestion_end)),
-                    bias,
-                );
-                let suggestion_point = suggestion_end + (fold_point.0 - suggestion_start);
-                if bias == Bias::Left && suggestion_point == suggestion_end {
-                    SuggestionPoint(suggestion_start)
-                } else {
-                    SuggestionPoint(suggestion_point)
-                }
-            } else if bias == Bias::Left || suggestion_start == self.fold_snapshot.max_point().0 {
-                SuggestionPoint(suggestion_start)
-            } else {
-                let fold_point = if self.fold_snapshot.line_len(suggestion_start.row)
-                    > suggestion_start.column
-                {
-                    FoldPoint(suggestion_start + Point::new(0, 1))
-                } else {
-                    FoldPoint(suggestion_start + Point::new(1, 0))
-                };
-                let clipped_fold_point = self.fold_snapshot.clip_point(fold_point, bias);
-                SuggestionPoint(suggestion_end + (clipped_fold_point.0 - suggestion_start))
-            }
-        } else {
-            SuggestionPoint(self.fold_snapshot.clip_point(FoldPoint(point.0), bias).0)
-        }
-    }
-
-    pub fn to_offset(&self, point: SuggestionPoint) -> SuggestionOffset {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
-            let suggestion_end = suggestion_start + suggestion.text.max_point();
-
-            if point.0 <= suggestion_start {
-                SuggestionOffset(FoldPoint(point.0).to_offset(&self.fold_snapshot).0)
-            } else if point.0 > suggestion_end {
-                let fold_offset = FoldPoint(suggestion_start + (point.0 - suggestion_end))
-                    .to_offset(&self.fold_snapshot);
-                SuggestionOffset(fold_offset.0 + suggestion.text.len())
-            } else {
-                let offset_in_suggestion =
-                    suggestion.text.point_to_offset(point.0 - suggestion_start);
-                SuggestionOffset(suggestion.position.0 + offset_in_suggestion)
-            }
-        } else {
-            SuggestionOffset(FoldPoint(point.0).to_offset(&self.fold_snapshot).0)
-        }
-    }
-
-    pub fn to_point(&self, offset: SuggestionOffset) -> SuggestionPoint {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let suggestion_point_start = suggestion.position.to_point(&self.fold_snapshot).0;
-            if offset.0 <= suggestion.position.0 {
-                SuggestionPoint(FoldOffset(offset.0).to_point(&self.fold_snapshot).0)
-            } else if offset.0 > (suggestion.position.0 + suggestion.text.len()) {
-                let fold_point = FoldOffset(offset.0 - suggestion.text.len())
-                    .to_point(&self.fold_snapshot)
-                    .0;
-
-                SuggestionPoint(
-                    suggestion_point_start
-                        + suggestion.text.max_point()
-                        + (fold_point - suggestion_point_start),
-                )
-            } else {
-                let point_in_suggestion = suggestion
-                    .text
-                    .offset_to_point(offset.0 - suggestion.position.0);
-                SuggestionPoint(suggestion_point_start + point_in_suggestion)
-            }
-        } else {
-            SuggestionPoint(FoldOffset(offset.0).to_point(&self.fold_snapshot).0)
-        }
-    }
-
-    pub fn to_fold_point(&self, point: SuggestionPoint) -> FoldPoint {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
-            let suggestion_end = suggestion_start + suggestion.text.max_point();
-
-            if point.0 <= suggestion_start {
-                FoldPoint(point.0)
-            } else if point.0 > suggestion_end {
-                FoldPoint(suggestion_start + (point.0 - suggestion_end))
-            } else {
-                FoldPoint(suggestion_start)
-            }
-        } else {
-            FoldPoint(point.0)
-        }
-    }
-
-    pub fn to_suggestion_point(&self, point: FoldPoint) -> SuggestionPoint {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
-
-            if point.0 <= suggestion_start {
-                SuggestionPoint(point.0)
-            } else {
-                let suggestion_end = suggestion_start + suggestion.text.max_point();
-                SuggestionPoint(suggestion_end + (point.0 - suggestion_start))
-            }
-        } else {
-            SuggestionPoint(point.0)
-        }
-    }
-
-    pub fn text_summary(&self) -> TextSummary {
-        self.text_summary_for_range(Default::default()..self.max_point())
-    }
-
-    pub fn text_summary_for_range(&self, range: Range<SuggestionPoint>) -> TextSummary {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
-            let suggestion_end = suggestion_start + suggestion.text.max_point();
-            let mut summary = TextSummary::default();
-
-            let prefix_range =
-                cmp::min(range.start.0, suggestion_start)..cmp::min(range.end.0, suggestion_start);
-            if prefix_range.start < prefix_range.end {
-                summary += self.fold_snapshot.text_summary_for_range(
-                    FoldPoint(prefix_range.start)..FoldPoint(prefix_range.end),
-                );
-            }
-
-            let suggestion_range =
-                cmp::max(range.start.0, suggestion_start)..cmp::min(range.end.0, suggestion_end);
-            if suggestion_range.start < suggestion_range.end {
-                let point_range = suggestion_range.start - suggestion_start
-                    ..suggestion_range.end - suggestion_start;
-                let offset_range = suggestion.text.point_to_offset(point_range.start)
-                    ..suggestion.text.point_to_offset(point_range.end);
-                summary += suggestion
-                    .text
-                    .cursor(offset_range.start)
-                    .summary::<TextSummary>(offset_range.end);
-            }
-
-            let suffix_range = cmp::max(range.start.0, suggestion_end)..range.end.0;
-            if suffix_range.start < suffix_range.end {
-                let start = suggestion_start + (suffix_range.start - suggestion_end);
-                let end = suggestion_start + (suffix_range.end - suggestion_end);
-                summary += self
-                    .fold_snapshot
-                    .text_summary_for_range(FoldPoint(start)..FoldPoint(end));
-            }
-
-            summary
-        } else {
-            self.fold_snapshot
-                .text_summary_for_range(FoldPoint(range.start.0)..FoldPoint(range.end.0))
-        }
-    }
-
-    pub fn chars_at(&self, start: SuggestionPoint) -> impl '_ + Iterator<Item = char> {
-        let start = self.to_offset(start);
-        self.chunks(start..self.len(), false, None, None)
-            .flat_map(|chunk| chunk.text.chars())
-    }
-
-    pub fn chunks<'a>(
-        &'a self,
-        range: Range<SuggestionOffset>,
-        language_aware: bool,
-        text_highlights: Option<&'a TextHighlights>,
-        suggestion_highlight: Option<HighlightStyle>,
-    ) -> SuggestionChunks<'a> {
-        if let Some(suggestion) = self.suggestion.as_ref() {
-            let suggestion_range =
-                suggestion.position.0..suggestion.position.0 + suggestion.text.len();
-
-            let prefix_chunks = if range.start.0 < suggestion_range.start {
-                Some(self.fold_snapshot.chunks(
-                    FoldOffset(range.start.0)
-                        ..cmp::min(FoldOffset(suggestion_range.start), FoldOffset(range.end.0)),
-                    language_aware,
-                    text_highlights,
-                ))
-            } else {
-                None
-            };
-
-            let clipped_suggestion_range = cmp::max(range.start.0, suggestion_range.start)
-                ..cmp::min(range.end.0, suggestion_range.end);
-            let suggestion_chunks = if clipped_suggestion_range.start < clipped_suggestion_range.end
-            {
-                let start = clipped_suggestion_range.start - suggestion_range.start;
-                let end = clipped_suggestion_range.end - suggestion_range.start;
-                Some(suggestion.text.chunks_in_range(start..end))
-            } else {
-                None
-            };
-
-            let suffix_chunks = if range.end.0 > suggestion_range.end {
-                let start = cmp::max(suggestion_range.end, range.start.0) - suggestion_range.len();
-                let end = range.end.0 - suggestion_range.len();
-                Some(self.fold_snapshot.chunks(
-                    FoldOffset(start)..FoldOffset(end),
-                    language_aware,
-                    text_highlights,
-                ))
-            } else {
-                None
-            };
-
-            SuggestionChunks {
-                prefix_chunks,
-                suggestion_chunks,
-                suffix_chunks,
-                highlight_style: suggestion_highlight,
-            }
-        } else {
-            SuggestionChunks {
-                prefix_chunks: Some(self.fold_snapshot.chunks(
-                    FoldOffset(range.start.0)..FoldOffset(range.end.0),
-                    language_aware,
-                    text_highlights,
-                )),
-                suggestion_chunks: None,
-                suffix_chunks: None,
-                highlight_style: None,
-            }
-        }
-    }
-
-    pub fn buffer_rows<'a>(&'a self, row: u32) -> SuggestionBufferRows<'a> {
-        let suggestion_range = if let Some(suggestion) = self.suggestion.as_ref() {
-            let start = suggestion.position.to_point(&self.fold_snapshot).0;
-            let end = start + suggestion.text.max_point();
-            start.row..end.row
-        } else {
-            u32::MAX..u32::MAX
-        };
-
-        let fold_buffer_rows = if row <= suggestion_range.start {
-            self.fold_snapshot.buffer_rows(row)
-        } else if row > suggestion_range.end {
-            self.fold_snapshot
-                .buffer_rows(row - (suggestion_range.end - suggestion_range.start))
-        } else {
-            let mut rows = self.fold_snapshot.buffer_rows(suggestion_range.start);
-            rows.next();
-            rows
-        };
-
-        SuggestionBufferRows {
-            current_row: row,
-            suggestion_row_start: suggestion_range.start,
-            suggestion_row_end: suggestion_range.end,
-            fold_buffer_rows,
-        }
-    }
-
-    #[cfg(test)]
-    pub fn text(&self) -> String {
-        self.chunks(Default::default()..self.len(), false, None, None)
-            .map(|chunk| chunk.text)
-            .collect()
-    }
-}
-
-pub struct SuggestionChunks<'a> {
-    prefix_chunks: Option<FoldChunks<'a>>,
-    suggestion_chunks: Option<text::Chunks<'a>>,
-    suffix_chunks: Option<FoldChunks<'a>>,
-    highlight_style: Option<HighlightStyle>,
-}
-
-impl<'a> Iterator for SuggestionChunks<'a> {
-    type Item = Chunk<'a>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if let Some(chunks) = self.prefix_chunks.as_mut() {
-            if let Some(chunk) = chunks.next() {
-                return Some(chunk);
-            } else {
-                self.prefix_chunks = None;
-            }
-        }
-
-        if let Some(chunks) = self.suggestion_chunks.as_mut() {
-            if let Some(chunk) = chunks.next() {
-                return Some(Chunk {
-                    text: chunk,
-                    highlight_style: self.highlight_style,
-                    ..Default::default()
-                });
-            } else {
-                self.suggestion_chunks = None;
-            }
-        }
-
-        if let Some(chunks) = self.suffix_chunks.as_mut() {
-            if let Some(chunk) = chunks.next() {
-                return Some(chunk);
-            } else {
-                self.suffix_chunks = None;
-            }
-        }
-
-        None
-    }
-}
-
-#[derive(Clone)]
-pub struct SuggestionBufferRows<'a> {
-    current_row: u32,
-    suggestion_row_start: u32,
-    suggestion_row_end: u32,
-    fold_buffer_rows: FoldBufferRows<'a>,
-}
-
-impl<'a> Iterator for SuggestionBufferRows<'a> {
-    type Item = Option<u32>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let row = post_inc(&mut self.current_row);
-        if row <= self.suggestion_row_start || row > self.suggestion_row_end {
-            self.fold_buffer_rows.next()
-        } else {
-            Some(None)
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::{display_map::fold_map::FoldMap, MultiBuffer};
-    use gpui::AppContext;
-    use rand::{prelude::StdRng, Rng};
-    use settings::SettingsStore;
-    use std::{
-        env,
-        ops::{Bound, RangeBounds},
-    };
-
-    #[gpui::test]
-    fn test_basic(cx: &mut AppContext) {
-        let buffer = MultiBuffer::build_simple("abcdefghi", cx);
-        let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
-        let (mut fold_map, fold_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
-        let (suggestion_map, suggestion_snapshot) = SuggestionMap::new(fold_snapshot.clone());
-        assert_eq!(suggestion_snapshot.text(), "abcdefghi");
-
-        let (suggestion_snapshot, _, _) = suggestion_map.replace(
-            Some(Suggestion {
-                position: 3,
-                text: "123\n456".into(),
-            }),
-            fold_snapshot,
-            Default::default(),
-        );
-        assert_eq!(suggestion_snapshot.text(), "abc123\n456defghi");
-
-        buffer.update(cx, |buffer, cx| {
-            buffer.edit(
-                [(0..0, "ABC"), (3..3, "DEF"), (4..4, "GHI"), (9..9, "JKL")],
-                None,
-                cx,
-            )
-        });
-        let (fold_snapshot, fold_edits) = fold_map.read(
-            buffer.read(cx).snapshot(cx),
-            buffer_edits.consume().into_inner(),
-        );
-        let (suggestion_snapshot, _) = suggestion_map.sync(fold_snapshot.clone(), fold_edits);
-        assert_eq!(suggestion_snapshot.text(), "ABCabcDEF123\n456dGHIefghiJKL");
-
-        let (mut fold_map_writer, _, _) =
-            fold_map.write(buffer.read(cx).snapshot(cx), Default::default());
-        let (fold_snapshot, fold_edits) = fold_map_writer.fold([0..3]);
-        let (suggestion_snapshot, _) = suggestion_map.sync(fold_snapshot, fold_edits);
-        assert_eq!(suggestion_snapshot.text(), "⋯abcDEF123\n456dGHIefghiJKL");
-
-        let (mut fold_map_writer, _, _) =
-            fold_map.write(buffer.read(cx).snapshot(cx), Default::default());
-        let (fold_snapshot, fold_edits) = fold_map_writer.fold([6..10]);
-        let (suggestion_snapshot, _) = suggestion_map.sync(fold_snapshot, fold_edits);
-        assert_eq!(suggestion_snapshot.text(), "⋯abc⋯GHIefghiJKL");
-    }
-
-    #[gpui::test(iterations = 100)]
-    fn test_random_suggestions(cx: &mut AppContext, mut rng: StdRng) {
-        init_test(cx);
-
-        let operations = env::var("OPERATIONS")
-            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
-            .unwrap_or(10);
-
-        let len = rng.gen_range(0..30);
-        let buffer = if rng.gen() {
-            let text = util::RandomCharIter::new(&mut rng)
-                .take(len)
-                .collect::<String>();
-            MultiBuffer::build_simple(&text, cx)
-        } else {
-            MultiBuffer::build_random(&mut rng, cx)
-        };
-        let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
-        log::info!("buffer text: {:?}", buffer_snapshot.text());
-
-        let (mut fold_map, mut fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (suggestion_map, mut suggestion_snapshot) = SuggestionMap::new(fold_snapshot.clone());
-
-        for _ in 0..operations {
-            let mut suggestion_edits = Patch::default();
-
-            let mut prev_suggestion_text = suggestion_snapshot.text();
-            let mut buffer_edits = Vec::new();
-            match rng.gen_range(0..=100) {
-                0..=29 => {
-                    let (_, edits) = suggestion_map.randomly_mutate(&mut rng);
-                    suggestion_edits = suggestion_edits.compose(edits);
-                }
-                30..=59 => {
-                    for (new_fold_snapshot, fold_edits) in fold_map.randomly_mutate(&mut rng) {
-                        fold_snapshot = new_fold_snapshot;
-                        let (_, edits) = suggestion_map.sync(fold_snapshot.clone(), fold_edits);
-                        suggestion_edits = suggestion_edits.compose(edits);
-                    }
-                }
-                _ => buffer.update(cx, |buffer, cx| {
-                    let subscription = buffer.subscribe();
-                    let edit_count = rng.gen_range(1..=5);
-                    buffer.randomly_mutate(&mut rng, edit_count, cx);
-                    buffer_snapshot = buffer.snapshot(cx);
-                    let edits = subscription.consume().into_inner();
-                    log::info!("editing {:?}", edits);
-                    buffer_edits.extend(edits);
-                }),
-            };
-
-            let (new_fold_snapshot, fold_edits) =
-                fold_map.read(buffer_snapshot.clone(), buffer_edits);
-            fold_snapshot = new_fold_snapshot;
-            let (new_suggestion_snapshot, edits) =
-                suggestion_map.sync(fold_snapshot.clone(), fold_edits);
-            suggestion_snapshot = new_suggestion_snapshot;
-            suggestion_edits = suggestion_edits.compose(edits);
-
-            log::info!("buffer text: {:?}", buffer_snapshot.text());
-            log::info!("folds text: {:?}", fold_snapshot.text());
-            log::info!("suggestions text: {:?}", suggestion_snapshot.text());
-
-            let mut expected_text = Rope::from(fold_snapshot.text().as_str());
-            let mut expected_buffer_rows = fold_snapshot.buffer_rows(0).collect::<Vec<_>>();
-            if let Some(suggestion) = suggestion_snapshot.suggestion.as_ref() {
-                expected_text.replace(
-                    suggestion.position.0..suggestion.position.0,
-                    &suggestion.text.to_string(),
-                );
-                let suggestion_start = suggestion.position.to_point(&fold_snapshot).0;
-                let suggestion_end = suggestion_start + suggestion.text.max_point();
-                expected_buffer_rows.splice(
-                    (suggestion_start.row + 1) as usize..(suggestion_start.row + 1) as usize,
-                    (0..suggestion_end.row - suggestion_start.row).map(|_| None),
-                );
-            }
-            assert_eq!(suggestion_snapshot.text(), expected_text.to_string());
-            for row_start in 0..expected_buffer_rows.len() {
-                assert_eq!(
-                    suggestion_snapshot
-                        .buffer_rows(row_start as u32)
-                        .collect::<Vec<_>>(),
-                    &expected_buffer_rows[row_start..],
-                    "incorrect buffer rows starting at {}",
-                    row_start
-                );
-            }
-
-            for _ in 0..5 {
-                let mut end = rng.gen_range(0..=suggestion_snapshot.len().0);
-                end = expected_text.clip_offset(end, Bias::Right);
-                let mut start = rng.gen_range(0..=end);
-                start = expected_text.clip_offset(start, Bias::Right);
-
-                let actual_text = suggestion_snapshot
-                    .chunks(
-                        SuggestionOffset(start)..SuggestionOffset(end),
-                        false,
-                        None,
-                        None,
-                    )
-                    .map(|chunk| chunk.text)
-                    .collect::<String>();
-                assert_eq!(
-                    actual_text,
-                    expected_text.slice(start..end).to_string(),
-                    "incorrect text in range {:?}",
-                    start..end
-                );
-
-                let start_point = SuggestionPoint(expected_text.offset_to_point(start));
-                let end_point = SuggestionPoint(expected_text.offset_to_point(end));
-                assert_eq!(
-                    suggestion_snapshot.text_summary_for_range(start_point..end_point),
-                    expected_text.slice(start..end).summary()
-                );
-            }
-
-            for edit in suggestion_edits.into_inner() {
-                prev_suggestion_text.replace_range(
-                    edit.new.start.0..edit.new.start.0 + edit.old_len().0,
-                    &suggestion_snapshot.text()[edit.new.start.0..edit.new.end.0],
-                );
-            }
-            assert_eq!(prev_suggestion_text, suggestion_snapshot.text());
-
-            assert_eq!(expected_text.max_point(), suggestion_snapshot.max_point().0);
-            assert_eq!(expected_text.len(), suggestion_snapshot.len().0);
-
-            let mut suggestion_point = SuggestionPoint::default();
-            let mut suggestion_offset = SuggestionOffset::default();
-            for ch in expected_text.chars() {
-                assert_eq!(
-                    suggestion_snapshot.to_offset(suggestion_point),
-                    suggestion_offset,
-                    "invalid to_offset({:?})",
-                    suggestion_point
-                );
-                assert_eq!(
-                    suggestion_snapshot.to_point(suggestion_offset),
-                    suggestion_point,
-                    "invalid to_point({:?})",
-                    suggestion_offset
-                );
-                assert_eq!(
-                    suggestion_snapshot
-                        .to_suggestion_point(suggestion_snapshot.to_fold_point(suggestion_point)),
-                    suggestion_snapshot.clip_point(suggestion_point, Bias::Left),
-                );
-
-                let mut bytes = [0; 4];
-                for byte in ch.encode_utf8(&mut bytes).as_bytes() {
-                    suggestion_offset.0 += 1;
-                    if *byte == b'\n' {
-                        suggestion_point.0 += Point::new(1, 0);
-                    } else {
-                        suggestion_point.0 += Point::new(0, 1);
-                    }
-
-                    let clipped_left_point =
-                        suggestion_snapshot.clip_point(suggestion_point, Bias::Left);
-                    let clipped_right_point =
-                        suggestion_snapshot.clip_point(suggestion_point, Bias::Right);
-                    assert!(
-                        clipped_left_point <= clipped_right_point,
-                        "clipped left point {:?} is greater than clipped right point {:?}",
-                        clipped_left_point,
-                        clipped_right_point
-                    );
-                    assert_eq!(
-                        clipped_left_point.0,
-                        expected_text.clip_point(clipped_left_point.0, Bias::Left)
-                    );
-                    assert_eq!(
-                        clipped_right_point.0,
-                        expected_text.clip_point(clipped_right_point.0, Bias::Right)
-                    );
-                    assert!(clipped_left_point <= suggestion_snapshot.max_point());
-                    assert!(clipped_right_point <= suggestion_snapshot.max_point());
-
-                    if let Some(suggestion) = suggestion_snapshot.suggestion.as_ref() {
-                        let suggestion_start = suggestion.position.to_point(&fold_snapshot).0;
-                        let suggestion_end = suggestion_start + suggestion.text.max_point();
-                        let invalid_range = (
-                            Bound::Excluded(suggestion_start),
-                            Bound::Included(suggestion_end),
-                        );
-                        assert!(
-                            !invalid_range.contains(&clipped_left_point.0),
-                            "clipped left point {:?} is inside invalid suggestion range {:?}",
-                            clipped_left_point,
-                            invalid_range
-                        );
-                        assert!(
-                            !invalid_range.contains(&clipped_right_point.0),
-                            "clipped right point {:?} is inside invalid suggestion range {:?}",
-                            clipped_right_point,
-                            invalid_range
-                        );
-                    }
-                }
-            }
-        }
-    }
-
-    fn init_test(cx: &mut AppContext) {
-        cx.set_global(SettingsStore::test(cx));
-        theme::init((), cx);
-    }
-
-    impl SuggestionMap {
-        pub fn randomly_mutate(
-            &self,
-            rng: &mut impl Rng,
-        ) -> (SuggestionSnapshot, Vec<SuggestionEdit>) {
-            let fold_snapshot = self.0.lock().fold_snapshot.clone();
-            let new_suggestion = if rng.gen_bool(0.3) {
-                None
-            } else {
-                let index = rng.gen_range(0..=fold_snapshot.buffer_snapshot().len());
-                let len = rng.gen_range(0..30);
-                Some(Suggestion {
-                    position: index,
-                    text: util::RandomCharIter::new(rng)
-                        .take(len)
-                        .filter(|ch| *ch != '\r')
-                        .collect::<String>()
-                        .as_str()
-                        .into(),
-                })
-            };
-
-            log::info!("replacing suggestion with {:?}", new_suggestion);
-            let (snapshot, edits, _) =
-                self.replace(new_suggestion, fold_snapshot, Default::default());
-            (snapshot, edits)
-        }
-    }
-}

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

@@ -1,5 +1,5 @@
 use super::{
-    inlay_map::{self, InlayChunks, InlayEdit, InlayPoint, InlaySnapshot},
+    fold_map::{self, FoldChunks, FoldEdit, FoldPoint, FoldSnapshot},
     TextHighlights,
 };
 use crate::MultiBufferSnapshot;
@@ -14,9 +14,9 @@ const MAX_EXPANSION_COLUMN: u32 = 256;
 pub struct TabMap(Mutex<TabSnapshot>);
 
 impl TabMap {
-    pub fn new(input: InlaySnapshot, tab_size: NonZeroU32) -> (Self, TabSnapshot) {
+    pub fn new(fold_snapshot: FoldSnapshot, tab_size: NonZeroU32) -> (Self, TabSnapshot) {
         let snapshot = TabSnapshot {
-            inlay_snapshot: input,
+            fold_snapshot,
             tab_size,
             max_expansion_column: MAX_EXPANSION_COLUMN,
             version: 0,
@@ -32,45 +32,42 @@ impl TabMap {
 
     pub fn sync(
         &self,
-        inlay_snapshot: InlaySnapshot,
-        mut suggestion_edits: Vec<InlayEdit>,
+        fold_snapshot: FoldSnapshot,
+        mut fold_edits: Vec<FoldEdit>,
         tab_size: NonZeroU32,
     ) -> (TabSnapshot, Vec<TabEdit>) {
         let mut old_snapshot = self.0.lock();
         let mut new_snapshot = TabSnapshot {
-            inlay_snapshot,
+            fold_snapshot,
             tab_size,
             max_expansion_column: old_snapshot.max_expansion_column,
             version: old_snapshot.version,
         };
 
-        if old_snapshot.inlay_snapshot.version != new_snapshot.inlay_snapshot.version {
+        if old_snapshot.fold_snapshot.version != new_snapshot.fold_snapshot.version {
             new_snapshot.version += 1;
         }
 
-        let mut tab_edits = Vec::with_capacity(suggestion_edits.len());
+        let mut tab_edits = Vec::with_capacity(fold_edits.len());
 
         if old_snapshot.tab_size == new_snapshot.tab_size {
             // Expand each edit to include the next tab on the same line as the edit,
             // and any subsequent tabs on that line that moved across the tab expansion
             // boundary.
-            for suggestion_edit in &mut suggestion_edits {
-                let old_end = old_snapshot
-                    .inlay_snapshot
-                    .to_point(suggestion_edit.old.end);
-                let old_end_row_successor_offset = old_snapshot.inlay_snapshot.to_offset(cmp::min(
-                    InlayPoint::new(old_end.row() + 1, 0),
-                    old_snapshot.inlay_snapshot.max_point(),
-                ));
-                let new_end = new_snapshot
-                    .inlay_snapshot
-                    .to_point(suggestion_edit.new.end);
+            for fold_edit in &mut fold_edits {
+                let old_end = fold_edit.old.end.to_point(&old_snapshot.fold_snapshot);
+                let old_end_row_successor_offset = cmp::min(
+                    FoldPoint::new(old_end.row() + 1, 0),
+                    old_snapshot.fold_snapshot.max_point(),
+                )
+                .to_offset(&old_snapshot.fold_snapshot);
+                let new_end = fold_edit.new.end.to_point(&new_snapshot.fold_snapshot);
 
                 let mut offset_from_edit = 0;
                 let mut first_tab_offset = None;
                 let mut last_tab_with_changed_expansion_offset = None;
-                'outer: for chunk in old_snapshot.inlay_snapshot.chunks(
-                    suggestion_edit.old.end..old_end_row_successor_offset,
+                'outer: for chunk in old_snapshot.fold_snapshot.chunks(
+                    fold_edit.old.end..old_end_row_successor_offset,
                     false,
                     None,
                     None,
@@ -101,39 +98,31 @@ impl TabMap {
                 }
 
                 if let Some(offset) = last_tab_with_changed_expansion_offset.or(first_tab_offset) {
-                    suggestion_edit.old.end.0 += offset as usize + 1;
-                    suggestion_edit.new.end.0 += offset as usize + 1;
+                    fold_edit.old.end.0 += offset as usize + 1;
+                    fold_edit.new.end.0 += offset as usize + 1;
                 }
             }
 
             // Combine any edits that overlap due to the expansion.
             let mut ix = 1;
-            while ix < suggestion_edits.len() {
-                let (prev_edits, next_edits) = suggestion_edits.split_at_mut(ix);
+            while ix < fold_edits.len() {
+                let (prev_edits, next_edits) = fold_edits.split_at_mut(ix);
                 let prev_edit = prev_edits.last_mut().unwrap();
                 let edit = &next_edits[0];
                 if prev_edit.old.end >= edit.old.start {
                     prev_edit.old.end = edit.old.end;
                     prev_edit.new.end = edit.new.end;
-                    suggestion_edits.remove(ix);
+                    fold_edits.remove(ix);
                 } else {
                     ix += 1;
                 }
             }
 
-            for suggestion_edit in suggestion_edits {
-                let old_start = old_snapshot
-                    .inlay_snapshot
-                    .to_point(suggestion_edit.old.start);
-                let old_end = old_snapshot
-                    .inlay_snapshot
-                    .to_point(suggestion_edit.old.end);
-                let new_start = new_snapshot
-                    .inlay_snapshot
-                    .to_point(suggestion_edit.new.start);
-                let new_end = new_snapshot
-                    .inlay_snapshot
-                    .to_point(suggestion_edit.new.end);
+            for fold_edit in fold_edits {
+                let old_start = fold_edit.old.start.to_point(&old_snapshot.fold_snapshot);
+                let old_end = fold_edit.old.end.to_point(&old_snapshot.fold_snapshot);
+                let new_start = fold_edit.new.start.to_point(&new_snapshot.fold_snapshot);
+                let new_end = fold_edit.new.end.to_point(&new_snapshot.fold_snapshot);
                 tab_edits.push(TabEdit {
                     old: old_snapshot.to_tab_point(old_start)..old_snapshot.to_tab_point(old_end),
                     new: new_snapshot.to_tab_point(new_start)..new_snapshot.to_tab_point(new_end),
@@ -154,7 +143,7 @@ impl TabMap {
 
 #[derive(Clone)]
 pub struct TabSnapshot {
-    pub inlay_snapshot: InlaySnapshot,
+    pub fold_snapshot: FoldSnapshot,
     pub tab_size: NonZeroU32,
     pub max_expansion_column: u32,
     pub version: usize,
@@ -162,13 +151,13 @@ pub struct TabSnapshot {
 
 impl TabSnapshot {
     pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
-        self.inlay_snapshot.buffer_snapshot()
+        &self.fold_snapshot.inlay_snapshot.buffer
     }
 
     pub fn line_len(&self, row: u32) -> u32 {
         let max_point = self.max_point();
         if row < max_point.row() {
-            self.to_tab_point(InlayPoint::new(row, self.inlay_snapshot.line_len(row)))
+            self.to_tab_point(FoldPoint::new(row, self.fold_snapshot.line_len(row)))
                 .0
                 .column
         } else {
@@ -181,10 +170,10 @@ impl TabSnapshot {
     }
 
     pub fn text_summary_for_range(&self, range: Range<TabPoint>) -> TextSummary {
-        let input_start = self.to_inlay_point(range.start, Bias::Left).0;
-        let input_end = self.to_inlay_point(range.end, Bias::Right).0;
+        let input_start = self.to_fold_point(range.start, Bias::Left).0;
+        let input_end = self.to_fold_point(range.end, Bias::Right).0;
         let input_summary = self
-            .inlay_snapshot
+            .fold_snapshot
             .text_summary_for_range(input_start..input_end);
 
         let mut first_line_chars = 0;
@@ -234,15 +223,16 @@ impl TabSnapshot {
         range: Range<TabPoint>,
         language_aware: bool,
         text_highlights: Option<&'a TextHighlights>,
-        suggestion_highlight: Option<HighlightStyle>,
+        inlay_highlights: Option<HighlightStyle>,
     ) -> TabChunks<'a> {
         let (input_start, expanded_char_column, to_next_stop) =
-            self.to_inlay_point(range.start, Bias::Left);
+            self.to_fold_point(range.start, Bias::Left);
         let input_column = input_start.column();
-        let input_start = self.inlay_snapshot.to_offset(input_start);
+        let input_start = input_start.to_offset(&self.fold_snapshot);
         let input_end = self
-            .inlay_snapshot
-            .to_offset(self.to_inlay_point(range.end, Bias::Right).0);
+            .to_fold_point(range.end, Bias::Right)
+            .0
+            .to_offset(&self.fold_snapshot);
         let to_next_stop = if range.start.0 + Point::new(0, to_next_stop) > range.end.0 {
             range.end.column() - range.start.column()
         } else {
@@ -250,11 +240,11 @@ impl TabSnapshot {
         };
 
         TabChunks {
-            inlay_chunks: self.inlay_snapshot.chunks(
+            fold_chunks: self.fold_snapshot.chunks(
                 input_start..input_end,
                 language_aware,
                 text_highlights,
-                suggestion_highlight,
+                inlay_highlights,
             ),
             input_column,
             column: expanded_char_column,
@@ -271,8 +261,8 @@ impl TabSnapshot {
         }
     }
 
-    pub fn buffer_rows(&self, row: u32) -> inlay_map::InlayBufferRows<'_> {
-        self.inlay_snapshot.buffer_rows(row)
+    pub fn buffer_rows(&self, row: u32) -> fold_map::FoldBufferRows<'_> {
+        self.fold_snapshot.buffer_rows(row)
     }
 
     #[cfg(test)]
@@ -283,48 +273,46 @@ impl TabSnapshot {
     }
 
     pub fn max_point(&self) -> TabPoint {
-        self.to_tab_point(self.inlay_snapshot.max_point())
+        self.to_tab_point(self.fold_snapshot.max_point())
     }
 
     pub fn clip_point(&self, point: TabPoint, bias: Bias) -> TabPoint {
         self.to_tab_point(
-            self.inlay_snapshot
-                .clip_point(self.to_inlay_point(point, bias).0, bias),
+            self.fold_snapshot
+                .clip_point(self.to_fold_point(point, bias).0, bias),
         )
     }
 
-    pub fn to_tab_point(&self, input: InlayPoint) -> TabPoint {
-        let chars = self
-            .inlay_snapshot
-            .chars_at(InlayPoint::new(input.row(), 0));
+    pub fn to_tab_point(&self, input: FoldPoint) -> TabPoint {
+        let chars = self.fold_snapshot.chars_at(FoldPoint::new(input.row(), 0));
         let expanded = self.expand_tabs(chars, input.column());
         TabPoint::new(input.row(), expanded)
     }
 
-    pub fn to_inlay_point(&self, output: TabPoint, bias: Bias) -> (InlayPoint, u32, u32) {
-        let chars = self
-            .inlay_snapshot
-            .chars_at(InlayPoint::new(output.row(), 0));
+    pub fn to_fold_point(&self, output: TabPoint, bias: Bias) -> (FoldPoint, u32, u32) {
+        let chars = self.fold_snapshot.chars_at(FoldPoint::new(output.row(), 0));
         let expanded = output.column();
         let (collapsed, expanded_char_column, to_next_stop) =
             self.collapse_tabs(chars, expanded, bias);
         (
-            InlayPoint::new(output.row(), collapsed as u32),
+            FoldPoint::new(output.row(), collapsed as u32),
             expanded_char_column,
             to_next_stop,
         )
     }
 
     pub fn make_tab_point(&self, point: Point, bias: Bias) -> TabPoint {
-        let fold_point = self.inlay_snapshot.fold_snapshot.to_fold_point(point, bias);
-        let inlay_point = self.inlay_snapshot.to_inlay_point(fold_point);
-        self.to_tab_point(inlay_point)
+        let inlay_point = self.fold_snapshot.inlay_snapshot.to_inlay_point(point);
+        let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
+        self.to_tab_point(fold_point)
     }
 
     pub fn to_point(&self, point: TabPoint, bias: Bias) -> Point {
-        let inlay_point = self.to_inlay_point(point, bias).0;
-        let fold_point = self.inlay_snapshot.to_fold_point(inlay_point);
-        fold_point.to_buffer_point(&self.inlay_snapshot.fold_snapshot)
+        let fold_point = self.to_fold_point(point, bias).0;
+        let inlay_point = fold_point.to_inlay_point(&self.fold_snapshot);
+        self.fold_snapshot
+            .inlay_snapshot
+            .to_buffer_point(inlay_point)
     }
 
     fn expand_tabs(&self, chars: impl Iterator<Item = char>, column: u32) -> u32 {
@@ -483,7 +471,7 @@ impl<'a> std::ops::AddAssign<&'a Self> for TextSummary {
 const SPACES: &str = "                ";
 
 pub struct TabChunks<'a> {
-    inlay_chunks: InlayChunks<'a>,
+    fold_chunks: FoldChunks<'a>,
     chunk: Chunk<'a>,
     column: u32,
     max_expansion_column: u32,
@@ -499,7 +487,7 @@ impl<'a> Iterator for TabChunks<'a> {
 
     fn next(&mut self) -> Option<Self::Item> {
         if self.chunk.text.is_empty() {
-            if let Some(chunk) = self.inlay_chunks.next() {
+            if let Some(chunk) = self.fold_chunks.next() {
                 self.chunk = chunk;
                 if self.inside_leading_tab {
                     self.chunk.text = &self.chunk.text[1..];
@@ -576,9 +564,9 @@ mod tests {
     fn test_expand_tabs(cx: &mut gpui::AppContext) {
         let buffer = MultiBuffer::build_simple("", cx);
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
-        let (_, tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
+        let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
+        let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
 
         assert_eq!(tab_snapshot.expand_tabs("\t".chars(), 0), 0);
         assert_eq!(tab_snapshot.expand_tabs("\t".chars(), 1), 4);
@@ -593,9 +581,9 @@ mod tests {
 
         let buffer = MultiBuffer::build_simple(input, cx);
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
-        let (_, mut tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
+        let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
+        let (_, mut tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
 
         tab_snapshot.max_expansion_column = max_expansion_column;
         assert_eq!(tab_snapshot.text(), output);
@@ -619,16 +607,16 @@ mod tests {
                 let input_point = Point::new(0, ix as u32);
                 let output_point = Point::new(0, output.find(c).unwrap() as u32);
                 assert_eq!(
-                    tab_snapshot.to_tab_point(InlayPoint(input_point)),
+                    tab_snapshot.to_tab_point(FoldPoint(input_point)),
                     TabPoint(output_point),
                     "to_tab_point({input_point:?})"
                 );
                 assert_eq!(
                     tab_snapshot
-                        .to_inlay_point(TabPoint(output_point), Bias::Left)
+                        .to_fold_point(TabPoint(output_point), Bias::Left)
                         .0,
-                    InlayPoint(input_point),
-                    "to_suggestion_point({output_point:?})"
+                    FoldPoint(input_point),
+                    "to_fold_point({output_point:?})"
                 );
             }
         }
@@ -641,9 +629,9 @@ mod tests {
 
         let buffer = MultiBuffer::build_simple(input, cx);
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
-        let (_, mut tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
+        let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
+        let (_, mut tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
 
         tab_snapshot.max_expansion_column = max_expansion_column;
         assert_eq!(tab_snapshot.text(), input);
@@ -655,9 +643,9 @@ mod tests {
 
         let buffer = MultiBuffer::build_simple(&input, cx);
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
-        let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
-        let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
-        let (_, tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
+        let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
+        let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
 
         assert_eq!(
             chunks(&tab_snapshot, TabPoint::zero()),
@@ -714,15 +702,16 @@ mod tests {
         let buffer_snapshot = buffer.read(cx).snapshot(cx);
         log::info!("Buffer text: {:?}", buffer_snapshot.text());
 
-        let (mut fold_map, _) = FoldMap::new(buffer_snapshot.clone());
+        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        log::info!("InlayMap text: {:?}", inlay_snapshot.text());
+        let (mut fold_map, _) = FoldMap::new(inlay_snapshot.clone());
         fold_map.randomly_mutate(&mut rng);
-        let (fold_snapshot, _) = fold_map.read(buffer_snapshot, vec![]);
+        let (fold_snapshot, _) = fold_map.read(inlay_snapshot, vec![]);
         log::info!("FoldMap text: {:?}", fold_snapshot.text());
-        let (mut inlay_map, _) = InlayMap::new(fold_snapshot.clone());
         let (inlay_snapshot, _) = inlay_map.randomly_mutate(&mut 0, &mut rng);
         log::info!("InlayMap text: {:?}", inlay_snapshot.text());
 
-        let (tab_map, _) = TabMap::new(inlay_snapshot.clone(), tab_size);
+        let (tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);
         let tabs_snapshot = tab_map.set_max_expansion_column(32);
 
         let text = text::Rope::from(tabs_snapshot.text().as_str());

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

@@ -1,5 +1,5 @@
 use super::{
-    inlay_map::InlayBufferRows,
+    fold_map::FoldBufferRows,
     tab_map::{self, TabEdit, TabPoint, TabSnapshot},
     TextHighlights,
 };
@@ -65,7 +65,7 @@ pub struct WrapChunks<'a> {
 
 #[derive(Clone)]
 pub struct WrapBufferRows<'a> {
-    input_buffer_rows: InlayBufferRows<'a>,
+    input_buffer_rows: FoldBufferRows<'a>,
     input_buffer_row: Option<u32>,
     output_row: u32,
     soft_wrapped: bool,
@@ -575,7 +575,7 @@ impl WrapSnapshot {
         rows: Range<u32>,
         language_aware: bool,
         text_highlights: Option<&'a TextHighlights>,
-        suggestion_highlight: Option<HighlightStyle>,
+        inlay_highlights: Option<HighlightStyle>,
     ) -> WrapChunks<'a> {
         let output_start = WrapPoint::new(rows.start, 0);
         let output_end = WrapPoint::new(rows.end, 0);
@@ -593,7 +593,7 @@ impl WrapSnapshot {
                 input_start..input_end,
                 language_aware,
                 text_highlights,
-                suggestion_highlight,
+                inlay_highlights,
             ),
             input_chunk: Default::default(),
             output_position: output_start,
@@ -762,13 +762,16 @@ impl WrapSnapshot {
             let mut prev_fold_row = 0;
             for display_row in 0..=self.max_point().row() {
                 let tab_point = self.to_tab_point(WrapPoint::new(display_row, 0));
-                let inlay_point = self.tab_snapshot.to_inlay_point(tab_point, Bias::Left).0;
-                let fold_point = self.tab_snapshot.inlay_snapshot.to_fold_point(inlay_point);
+                let fold_point = self.tab_snapshot.to_fold_point(tab_point, Bias::Left).0;
                 if fold_point.row() == prev_fold_row && display_row != 0 {
                     expected_buffer_rows.push(None);
                 } else {
-                    let buffer_point =
-                        fold_point.to_buffer_point(&self.tab_snapshot.inlay_snapshot.fold_snapshot);
+                    let inlay_point = fold_point.to_inlay_point(&self.tab_snapshot.fold_snapshot);
+                    let buffer_point = self
+                        .tab_snapshot
+                        .fold_snapshot
+                        .inlay_snapshot
+                        .to_buffer_point(inlay_point);
                     expected_buffer_rows.push(input_buffer_rows[buffer_point.row as usize]);
                     prev_fold_row = fold_point.row();
                 }
@@ -1083,11 +1086,11 @@ mod tests {
         });
         let mut buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
         log::info!("Buffer text: {:?}", buffer_snapshot.text());
-        let (mut fold_map, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
+        let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
+        log::info!("InlayMap text: {:?}", inlay_snapshot.text());
+        let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot.clone());
         log::info!("FoldMap text: {:?}", fold_snapshot.text());
-        let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot.clone());
-        log::info!("InlaysMap text: {:?}", inlay_snapshot.text());
-        let (tab_map, _) = TabMap::new(inlay_snapshot.clone(), tab_size);
+        let (tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);
         let tabs_snapshot = tab_map.set_max_expansion_column(32);
         log::info!("TabMap text: {:?}", tabs_snapshot.text());
 
@@ -1134,10 +1137,8 @@ mod tests {
                 }
                 20..=39 => {
                     for (fold_snapshot, fold_edits) in fold_map.randomly_mutate(&mut rng) {
-                        let (inlay_snapshot, inlay_edits) =
-                            inlay_map.sync(fold_snapshot, fold_edits);
                         let (tabs_snapshot, tab_edits) =
-                            tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
+                            tab_map.sync(fold_snapshot, fold_edits, tab_size);
                         let (mut snapshot, wrap_edits) =
                             wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx));
                         snapshot.check_invariants();
@@ -1148,8 +1149,9 @@ mod tests {
                 40..=59 => {
                     let (inlay_snapshot, inlay_edits) =
                         inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
+                    let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
                     let (tabs_snapshot, tab_edits) =
-                        tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
+                        tab_map.sync(fold_snapshot, fold_edits, tab_size);
                     let (mut snapshot, wrap_edits) =
                         wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx));
                     snapshot.check_invariants();
@@ -1168,11 +1170,12 @@ mod tests {
             }
 
             log::info!("Buffer text: {:?}", buffer_snapshot.text());
-            let (fold_snapshot, fold_edits) = fold_map.read(buffer_snapshot.clone(), buffer_edits);
-            log::info!("FoldMap text: {:?}", fold_snapshot.text());
-            let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
+            let (inlay_snapshot, inlay_edits) =
+                inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
             log::info!("InlayMap text: {:?}", inlay_snapshot.text());
-            let (tabs_snapshot, tab_edits) = tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
+            let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
+            log::info!("FoldMap text: {:?}", fold_snapshot.text());
+            let (tabs_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
             log::info!("TabMap text: {:?}", tabs_snapshot.text());
 
             let unwrapped_text = tabs_snapshot.text();
@@ -1220,7 +1223,7 @@ mod tests {
                 if tab_size.get() == 1
                     || !wrapped_snapshot
                         .tab_snapshot
-                        .inlay_snapshot
+                        .fold_snapshot
                         .text()
                         .contains('\t')
                 {

crates/editor/src/editor.rs 🔗

@@ -70,11 +70,11 @@ use link_go_to_definition::{
     hide_link_definition, show_link_definition, LinkDefinitionKind, LinkGoToDefinitionState,
 };
 use log::error;
+use multi_buffer::ToOffsetUtf16;
 pub use multi_buffer::{
     Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
     ToPoint,
 };
-use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
 use ordered_float::OrderedFloat;
 use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
 use scroll::{