Implement more InlaySnapshot methods

Kirill Bulatov and Antonio Scandurra created

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

Change summary

crates/editor/src/display_map.rs                |   4 
crates/editor/src/display_map/inlay_map.rs      | 114 ++++++++++++++----
crates/editor/src/display_map/suggestion_map.rs |   1 
crates/editor/src/display_map/tab_map.rs        |   2 
crates/editor/src/display_map/wrap_map.rs       |   2 
5 files changed, 94 insertions(+), 29 deletions(-)

Detailed changes

crates/editor/src/display_map.rs 🔗

@@ -423,7 +423,7 @@ impl DisplaySnapshot {
         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 suggestion_point = self.inlay_snapshot.to_suggestion_point(inlay_point, bias);
+        let suggestion_point = self.inlay_snapshot.to_suggestion_point(inlay_point);
         let fold_point = self.suggestion_snapshot.to_fold_point(suggestion_point);
         fold_point.to_buffer_point(&self.fold_snapshot)
     }
@@ -838,7 +838,7 @@ impl DisplayPoint {
         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 suggestion_point = map.inlay_snapshot.to_suggestion_point(inlay_point, bias);
+        let suggestion_point = map.inlay_snapshot.to_suggestion_point(inlay_point);
         let fold_point = map.suggestion_snapshot.to_fold_point(suggestion_point);
         fold_point.to_buffer_offset(&map.fold_snapshot)
     }

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

@@ -48,6 +48,12 @@ enum Transform {
     Inlay(Inlay),
 }
 
+impl Transform {
+    fn is_inlay(&self) -> bool {
+        matches!(self, Self::Inlay(_))
+    }
+}
+
 impl sum_tree::Item for Transform {
     type Summary = TransformSummary;
 
@@ -425,16 +431,29 @@ impl InlayMap {
 
 impl InlaySnapshot {
     pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
-        // TODO kb copied from suggestion_map
         self.suggestion_snapshot.buffer_snapshot()
     }
 
     pub fn to_point(&self, offset: InlayOffset) -> InlayPoint {
-        // TODO kb copied from suggestion_map
-        self.to_inlay_point(
-            self.suggestion_snapshot
-                .to_point(super::suggestion_map::SuggestionOffset(offset.0)),
-        )
+        let mut cursor = self
+            .transforms
+            .cursor::<(InlayOffset, (InlayPoint, SuggestionOffset))>();
+        cursor.seek(&offset, Bias::Right, &());
+        let overshoot = offset.0 - cursor.start().0 .0;
+        match cursor.item() {
+            Some(Transform::Isomorphic(transform)) => {
+                let suggestion_offset_start = cursor.start().1 .1;
+                let suggestion_offset_end = SuggestionOffset(suggestion_offset_start.0 + overshoot);
+                let suggestion_start = self.suggestion_snapshot.to_point(suggestion_offset_start);
+                let suggestion_end = self.suggestion_snapshot.to_point(suggestion_offset_end);
+                InlayPoint(cursor.start().1 .0 .0 + (suggestion_end.0 - suggestion_start.0))
+            }
+            Some(Transform::Inlay(inlay)) => {
+                let overshoot = inlay.properties.text.offset_to_point(overshoot);
+                InlayPoint(cursor.start().1 .0 .0 + overshoot)
+            }
+            None => self.max_point(),
+        }
     }
 
     pub fn len(&self) -> InlayOffset {
@@ -446,22 +465,43 @@ impl InlaySnapshot {
     }
 
     pub fn to_offset(&self, point: InlayPoint) -> InlayOffset {
-        // TODO kb copied from suggestion_map
-        InlayOffset(
-            self.suggestion_snapshot
-                .to_offset(self.to_suggestion_point(point, Bias::Left))
-                .0,
-        )
+        let mut cursor = self
+            .transforms
+            .cursor::<(InlayPoint, (InlayOffset, SuggestionPoint))>();
+        cursor.seek(&point, Bias::Right, &());
+        let overshoot = point.0 - cursor.start().0 .0;
+        match cursor.item() {
+            Some(Transform::Isomorphic(transform)) => {
+                let suggestion_point_start = cursor.start().1 .1;
+                let suggestion_point_end = SuggestionPoint(suggestion_point_start.0 + overshoot);
+                let suggestion_start = self.suggestion_snapshot.to_offset(suggestion_point_start);
+                let suggestion_end = self.suggestion_snapshot.to_offset(suggestion_point_end);
+                InlayOffset(cursor.start().1 .0 .0 + (suggestion_end.0 - suggestion_start.0))
+            }
+            Some(Transform::Inlay(inlay)) => {
+                let overshoot = inlay.properties.text.point_to_offset(overshoot);
+                InlayOffset(cursor.start().1 .0 .0 + overshoot)
+            }
+            None => self.len(),
+        }
     }
 
     pub fn chars_at(&self, start: InlayPoint) -> impl '_ + Iterator<Item = char> {
-        self.suggestion_snapshot
-            .chars_at(self.to_suggestion_point(start, Bias::Left))
+        self.chunks(self.to_offset(start)..self.len(), false, None, None)
+            .flat_map(|chunk| chunk.text.chars())
     }
 
-    // TODO kb what to do with bias?
-    pub fn to_suggestion_point(&self, point: InlayPoint, _: Bias) -> SuggestionPoint {
-        SuggestionPoint(point.0)
+    pub fn to_suggestion_point(&self, point: InlayPoint) -> SuggestionPoint {
+        let mut cursor = self.transforms.cursor::<(InlayPoint, SuggestionPoint)>();
+        cursor.seek(&point, Bias::Right, &());
+        let overshoot = point.0 - cursor.start().0 .0;
+        match cursor.item() {
+            Some(Transform::Isomorphic(transform)) => {
+                SuggestionPoint(cursor.start().1 .0 + overshoot)
+            }
+            Some(Transform::Inlay(inlay)) => cursor.start().1,
+            None => self.suggestion_snapshot.max_point(),
+        }
     }
 
     pub fn to_suggestion_offset(&self, offset: InlayOffset) -> SuggestionOffset {
@@ -478,22 +518,46 @@ impl InlaySnapshot {
     }
 
     pub fn to_inlay_point(&self, point: SuggestionPoint) -> InlayPoint {
-        InlayPoint(point.0)
+        let mut cursor = self.transforms.cursor::<(SuggestionPoint, InlayPoint)>();
+        // TODO kb is the bias right? should we have an external one instead?
+        cursor.seek(&point, Bias::Right, &());
+        let overshoot = point.0 - cursor.start().0 .0;
+        match cursor.item() {
+            Some(Transform::Isomorphic(transform)) => InlayPoint(cursor.start().1 .0 + overshoot),
+            Some(Transform::Inlay(inlay)) => cursor.start().1,
+            None => self.max_point(),
+        }
     }
 
     pub fn clip_point(&self, point: InlayPoint, bias: Bias) -> InlayPoint {
-        // TODO kb copied from suggestion_map
-        self.to_inlay_point(
-            self.suggestion_snapshot
-                .clip_point(self.to_suggestion_point(point, bias), bias),
-        )
+        let mut cursor = self.transforms.cursor::<InlayPoint>();
+        cursor.seek(&point, bias, &());
+        match cursor.item() {
+            Some(Transform::Isomorphic(_)) => return point,
+            Some(Transform::Inlay(_)) => {}
+            None => cursor.prev(&()),
+        }
+
+        while cursor
+            .item()
+            .map_or(false, |transform| transform.is_inlay())
+        {
+            match bias {
+                Bias::Left => cursor.prev(&()),
+                Bias::Right => cursor.next(&()),
+            }
+        }
+
+        match bias {
+            Bias::Left => cursor.end(&()),
+            Bias::Right => *cursor.start(),
+        }
     }
 
     pub fn text_summary_for_range(&self, range: Range<InlayPoint>) -> TextSummary {
         // TODO kb copied from suggestion_map
         self.suggestion_snapshot.text_summary_for_range(
-            self.to_suggestion_point(range.start, Bias::Left)
-                ..self.to_suggestion_point(range.end, Bias::Left),
+            self.to_suggestion_point(range.start)..self.to_suggestion_point(range.end),
         )
     }
 

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

@@ -331,7 +331,7 @@ impl TabSnapshot {
 
     pub fn to_point(&self, point: TabPoint, bias: Bias) -> Point {
         let inlay_point = self.to_inlay_point(point, bias).0;
-        let suggestion_point = self.inlay_snapshot.to_suggestion_point(inlay_point, bias);
+        let suggestion_point = self.inlay_snapshot.to_suggestion_point(inlay_point);
         let fold_point = self
             .inlay_snapshot
             .suggestion_snapshot

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

@@ -766,7 +766,7 @@ impl WrapSnapshot {
                 let suggestion_point = self
                     .tab_snapshot
                     .inlay_snapshot
-                    .to_suggestion_point(inlay_point, Bias::Left);
+                    .to_suggestion_point(inlay_point);
                 let fold_point = self
                     .tab_snapshot
                     .inlay_snapshot