Add `SuggestionMap::replace`

Antonio Scandurra created

Change summary

crates/editor/src/display_map/suggestion_map.rs | 73 +++++++++++++++++-
1 file changed, 66 insertions(+), 7 deletions(-)

Detailed changes

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

@@ -1,6 +1,10 @@
+use std::ops::{Add, AddAssign, Sub};
+
+use crate::{ToOffset, ToPoint};
+
 use super::fold_map::{FoldEdit, FoldOffset, FoldSnapshot};
 use gpui::fonts::HighlightStyle;
-use language::{Edit, Rope};
+use language::{Bias, Edit, Patch, Rope};
 use parking_lot::Mutex;
 
 pub type SuggestionEdit = Edit<SuggestionOffset>;
@@ -8,16 +12,71 @@ 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(Clone)]
 pub struct Suggestion {
-    position: FoldOffset,
+    offset: FoldOffset,
     text: Rope,
-    highlight_style: HighlightStyle,
 }
 
 pub struct SuggestionMap(Mutex<SuggestionSnapshot>);
 
 impl SuggestionMap {
+    pub fn replace<P, T>(
+        &mut self,
+        position: P,
+        text: T,
+        fold_snapshot: FoldSnapshot,
+        fold_edits: Vec<FoldEdit>,
+    ) -> (SuggestionSnapshot, Vec<SuggestionEdit>)
+    where
+        P: ToPoint,
+        T: Into<Rope>,
+    {
+        let buffer_point = 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);
+        let new_suggestion = Suggestion {
+            offset: fold_offset,
+            text: text.into(),
+        };
+
+        let (_, edits) = self.sync(fold_snapshot, fold_edits);
+        let mut snapshot = self.0.lock();
+        let old = if let Some(suggestion) = snapshot.suggestion.take() {
+            SuggestionOffset(suggestion.offset.0)
+                ..SuggestionOffset(suggestion.offset.0 + suggestion.text.len())
+        } else {
+            SuggestionOffset(new_suggestion.offset.0)..SuggestionOffset(new_suggestion.offset.0)
+        };
+        let new = SuggestionOffset(new_suggestion.offset.0)
+            ..SuggestionOffset(new_suggestion.offset.0 + new_suggestion.text.len());
+        let patch = Patch::new(edits).compose([SuggestionEdit { old, new }]);
+        snapshot.suggestion = Some(new_suggestion);
+        (snapshot.clone(), patch.into_inner())
+    }
+
     pub fn sync(
         &self,
         fold_snapshot: FoldSnapshot,
@@ -32,10 +91,10 @@ impl SuggestionMap {
             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 {
+                if end < suggestion.offset {
+                    suggestion.offset.0 += fold_edit.new_len().0;
+                    suggestion.offset.0 -= fold_edit.old_len().0;
+                } else if start > suggestion.offset {
                     suggestion_old_len = suggestion.text.len();
                     suggestion_new_len = suggestion_old_len;
                 } else {