Generate edits for inlay hints

Kirill Bulatov and Antonio Scandurra created

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

Change summary

crates/editor/src/display_map.rs           | 30 +++++++++++++++++------
crates/editor/src/display_map/inlay_map.rs | 28 +++++++++++++++++----
crates/editor/src/editor.rs                |  2 
3 files changed, 45 insertions(+), 15 deletions(-)

Detailed changes

crates/editor/src/display_map.rs 🔗

@@ -285,20 +285,29 @@ impl DisplayMap {
             .update(cx, |map, cx| map.set_wrap_width(width, cx))
     }
 
-    pub fn splice_inlay_hints(
+    pub fn splice_inlays(
         &mut self,
         new_hints: &HashMap<InlayHintLocation, Vec<project::InlayHint>>,
         cx: &mut ModelContext<Self>,
     ) {
-        let multi_buffer = self.buffer.read(cx);
-        let multi_snapshot = multi_buffer.snapshot(cx);
+        let buffer_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(buffer_snapshot.clone(), edits);
+        let (snapshot, edits) = self.suggestion_map.sync(snapshot, 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
+            .update(cx, |map, cx| map.sync(snapshot, edits, cx));
+        self.block_map.read(snapshot, edits);
 
-        let mut hints_to_add = Vec::new();
+        let mut new_inlays = Vec::new();
         for (&location, hints) in new_hints {
             for hint in hints {
                 let hint_anchor =
-                    multi_snapshot.anchor_in_excerpt(location.excerpt_id, hint.position);
-                hints_to_add.push((
+                    buffer_snapshot.anchor_in_excerpt(location.excerpt_id, hint.position);
+                new_inlays.push((
                     location,
                     InlayProperties {
                         position: hint_anchor,
@@ -308,11 +317,16 @@ impl DisplayMap {
             }
         }
 
-        self.inlay_map.splice(
+        let (snapshot, edits, _) = self.inlay_map.splice(
             // TODO kb this is wrong, calc diffs in the editor instead.
             self.inlay_map.inlays.keys().copied().collect(),
-            hints_to_add,
+            new_inlays,
         );
+        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);
     }
 
     fn tab_size(buffer: &ModelHandle<MultiBuffer>, cx: &mut ModelContext<Self>) -> NonZeroU32 {

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

@@ -23,6 +23,7 @@ use parking_lot::Mutex;
 use project::InlayHint;
 use rand::Rng;
 use sum_tree::{Bias, Cursor, SumTree};
+use text::Patch;
 use util::post_inc;
 
 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -372,10 +373,11 @@ impl InlayMap {
             }
         }
 
+        let mut inlay_edits = Patch::default();
         let mut new_transforms = SumTree::new();
         let mut cursor = snapshot
             .transforms
-            .cursor::<(InlayPoint, SuggestionPoint)>();
+            .cursor::<(InlayPoint, (SuggestionPoint, InlayOffset))>();
         for ((inlay_point, inlay_id), inlay) in inlays {
             new_transforms.push_tree(cursor.slice(&inlay_point, Bias::Right, &()), &());
             while let Some(transform) = cursor.item() {
@@ -387,6 +389,11 @@ impl InlayMap {
                             cursor.next(&());
                         } else {
                             if inlay.id == inlay_id.0 {
+                                let new_start = InlayOffset(new_transforms.summary().output.len);
+                                inlay_edits.push(Edit {
+                                    old: cursor.start().1 .1..cursor.end(&()).1 .1,
+                                    new: new_start..new_start,
+                                });
                                 cursor.next(&());
                             }
                             break;
@@ -396,11 +403,14 @@ impl InlayMap {
             }
 
             if let Some(inlay) = inlay {
+                let new_start = InlayOffset(new_transforms.summary().output.len);
+                let new_end = InlayOffset(new_start.0 + inlay.properties.text.len());
                 if let Some(Transform::Isomorphic(transform)) = cursor.item() {
                     let prefix = inlay_point.0 - cursor.start().0 .0;
                     if !prefix.is_zero() {
-                        let prefix_suggestion_start = cursor.start().1;
-                        let prefix_suggestion_end = SuggestionPoint(cursor.start().1 .0 + prefix);
+                        let prefix_suggestion_start = cursor.start().1 .0;
+                        let prefix_suggestion_end =
+                            SuggestionPoint(cursor.start().1 .0 .0 + prefix);
                         new_transforms.push(
                             Transform::Isomorphic(
                                 snapshot.suggestion_snapshot.text_summary_for_range(
@@ -413,8 +423,8 @@ impl InlayMap {
 
                     new_transforms.push(Transform::Inlay(inlay), &());
 
-                    let suffix_suggestion_start = SuggestionPoint(cursor.start().1 .0 + prefix);
-                    let suffix_suggestion_end = cursor.end(&()).1;
+                    let suffix_suggestion_start = SuggestionPoint(cursor.start().1 .0 .0 + prefix);
+                    let suffix_suggestion_end = cursor.end(&()).1 .0;
                     new_transforms.push(
                         Transform::Isomorphic(snapshot.suggestion_snapshot.text_summary_for_range(
                             suffix_suggestion_start..suffix_suggestion_end,
@@ -426,6 +436,12 @@ impl InlayMap {
                 } else {
                     new_transforms.push(Transform::Inlay(inlay), &());
                 }
+
+                let old_start = snapshot.to_offset(inlay_point);
+                inlay_edits.push(Edit {
+                    old: old_start..old_start,
+                    new: new_start..new_end,
+                });
             }
         }
 
@@ -434,7 +450,7 @@ impl InlayMap {
         snapshot.transforms = new_transforms;
         snapshot.version += 1;
 
-        (snapshot.clone(), Vec::new(), new_ids)
+        (snapshot.clone(), inlay_edits.into_inner(), new_ids)
     }
 }
 

crates/editor/src/editor.rs 🔗

@@ -2702,7 +2702,7 @@ impl Editor {
                 editor
                     .update(&mut cx, |editor, cx| {
                         editor.display_map.update(cx, |display_map, cx| {
-                            display_map.splice_inlay_hints(&new_hints, cx);
+                            display_map.splice_inlays(&new_hints, cx);
                         });
                     })
                     .log_err()