WIP: Probably the wrong direction

Nathan Sobo created

Change summary

crates/buffer/src/rope.rs                      |  23 +
crates/editor/src/display_map/injection_map.rs | 219 ++++++++++++++-----
crates/sum_tree/src/lib.rs                     |   6 
3 files changed, 183 insertions(+), 65 deletions(-)

Detailed changes

crates/buffer/src/rope.rs 🔗

@@ -303,7 +303,7 @@ impl<'a> Cursor<'a> {
         if let Some(start_chunk) = self.chunks.item() {
             let start_ix = self.offset - self.chunks.start();
             let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start();
-            summary.add_assign(&D::from_summary(&TextSummary::from(
+            summary.add_assign(&D::from_text_summary(&TextSummary::from(
                 &start_chunk.0[start_ix..end_ix],
             )));
         }
@@ -313,7 +313,9 @@ impl<'a> Cursor<'a> {
             summary.add_assign(&self.chunks.summary(&end_offset, Bias::Right, &()));
             if let Some(end_chunk) = self.chunks.item() {
                 let end_ix = end_offset - self.chunks.start();
-                summary.add_assign(&D::from_summary(&TextSummary::from(&end_chunk.0[..end_ix])));
+                summary.add_assign(&D::from_text_summary(&TextSummary::from(
+                    &end_chunk.0[..end_ix],
+                )));
             }
         }
 
@@ -634,13 +636,16 @@ impl std::ops::AddAssign<Self> for TextSummary {
 }
 
 pub trait TextDimension<'a>: Dimension<'a, TextSummary> {
-    fn from_summary(summary: &TextSummary) -> Self;
+    fn from_text_summary(summary: &TextSummary) -> Self;
     fn add_assign(&mut self, other: &Self);
 }
 
 impl<'a, D1: TextDimension<'a>, D2: TextDimension<'a>> TextDimension<'a> for (D1, D2) {
-    fn from_summary(summary: &TextSummary) -> Self {
-        (D1::from_summary(summary), D2::from_summary(summary))
+    fn from_text_summary(summary: &TextSummary) -> Self {
+        (
+            D1::from_text_summary(summary),
+            D2::from_text_summary(summary),
+        )
     }
 
     fn add_assign(&mut self, other: &Self) {
@@ -650,7 +655,7 @@ impl<'a, D1: TextDimension<'a>, D2: TextDimension<'a>> TextDimension<'a> for (D1
 }
 
 impl<'a> TextDimension<'a> for TextSummary {
-    fn from_summary(summary: &TextSummary) -> Self {
+    fn from_text_summary(summary: &TextSummary) -> Self {
         summary.clone()
     }
 
@@ -666,7 +671,7 @@ impl<'a> sum_tree::Dimension<'a, TextSummary> for usize {
 }
 
 impl<'a> TextDimension<'a> for usize {
-    fn from_summary(summary: &TextSummary) -> Self {
+    fn from_text_summary(summary: &TextSummary) -> Self {
         summary.bytes
     }
 
@@ -682,7 +687,7 @@ impl<'a> sum_tree::Dimension<'a, TextSummary> for Point {
 }
 
 impl<'a> TextDimension<'a> for Point {
-    fn from_summary(summary: &TextSummary) -> Self {
+    fn from_text_summary(summary: &TextSummary) -> Self {
         summary.lines
     }
 
@@ -698,7 +703,7 @@ impl<'a> sum_tree::Dimension<'a, TextSummary> for PointUtf16 {
 }
 
 impl<'a> TextDimension<'a> for PointUtf16 {
-    fn from_summary(summary: &TextSummary) -> Self {
+    fn from_text_summary(summary: &TextSummary) -> Self {
         summary.lines_utf16
     }
 

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

@@ -1,13 +1,15 @@
 use std::{
-    cmp, mem,
+    cmp::Ordering,
+    mem,
     sync::atomic::{AtomicUsize, Ordering::SeqCst},
 };
 
-use buffer::{Anchor, Bias, Edit, Point, Rope, TextSummary};
+use buffer::{rope::TextDimension, Anchor, Bias, Edit, Rope, TextSummary, ToOffset};
 use gpui::{fonts::HighlightStyle, AppContext, ModelHandle};
 use language::Buffer;
 use parking_lot::Mutex;
-use sum_tree::SumTree;
+use sum_tree::{SeekTarget, SumTree};
+use util::post_inc;
 
 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
 pub struct InjectionId(usize);
@@ -16,14 +18,14 @@ pub struct InjectionMap {
     buffer: ModelHandle<Buffer>,
     transforms: Mutex<SumTree<Transform>>,
     injections: SumTree<Injection>,
-    injection_contents: SumTree<InjectionContent>,
     version: AtomicUsize,
     last_sync: Mutex<SyncState>,
+    next_injection_id: usize,
 }
 
 pub struct InjectionSnapshot {
     transforms: SumTree<Transform>,
-    injection_contents: SumTree<InjectionContent>,
+    injections: SumTree<Injection>,
     buffer_snapshot: language::Snapshot,
     pub version: usize,
 }
@@ -37,13 +39,6 @@ struct SyncState {
     diagnostics_update_count: usize,
 }
 
-#[derive(Clone, Debug)]
-struct Injection {
-    id: InjectionId,
-    position: Anchor,
-    is_block: bool,
-}
-
 #[derive(Clone, Debug)]
 struct InjectionSummary {
     min_id: InjectionId,
@@ -53,25 +48,28 @@ struct InjectionSummary {
 }
 
 #[derive(Clone, Debug)]
-struct InjectionContent {
-    injection_id: InjectionId,
-    runs: Vec<(usize, HighlightStyle)>,
+struct Injection {
+    id: InjectionId,
     text: Rope,
+    runs: Vec<(usize, HighlightStyle)>,
 }
 
 #[derive(Clone, Debug, Default, PartialEq)]
 struct Transform {
-    summary: TransformSummary,
+    input: TextSummary,
+    output: TextSummary,
     injection_id: Option<InjectionId>,
 }
 
 #[derive(Clone, Debug, Default, Eq, PartialEq)]
 struct TransformSummary {
-    output: TextSummary,
     input: TextSummary,
+    output: TextSummary,
+    min_injection_id: InjectionId,
+    max_injection_id: InjectionId,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug, Default)]
 struct InjectionOffset(usize);
 
 impl sum_tree::Summary for InjectionId {
@@ -88,7 +86,7 @@ impl InjectionMap {
         // self.check_invariants(cx);
         let snapshot = InjectionSnapshot {
             transforms: self.transforms.lock().clone(),
-            injection_contents: self.injection_contents.clone(),
+            injections: self.injections.clone(),
             buffer_snapshot: self.buffer.read(cx).snapshot(),
             version: self.version.load(SeqCst),
         };
@@ -146,11 +144,11 @@ impl InjectionMap {
         let mut cursor = transforms.cursor::<usize>();
 
         while let Some(mut edit) = buffer_edits_iter.next() {
-            new_transforms.push_tree(cursor.slice(&edit.old.start, Bias::Left, &()), &());
+            new_transforms.push_tree(cursor.slice(&edit.old.start, Bias::Right, &()), &());
             edit.new.start -= edit.old.start - cursor.start();
             edit.old.start = *cursor.start();
 
-            cursor.seek(&edit.old.end, Bias::Right, &());
+            cursor.seek(&edit.old.end, Bias::Left, &());
             cursor.next(&());
 
             let mut delta = edit.new.len() as isize - edit.old.len() as isize;
@@ -158,7 +156,7 @@ impl InjectionMap {
                 edit.old.end = *cursor.start();
 
                 if let Some(next_edit) = buffer_edits_iter.peek() {
-                    if next_edit.old.start > edit.old.end {
+                    if next_edit.old.start >= edit.old.end {
                         break;
                     }
 
@@ -167,7 +165,7 @@ impl InjectionMap {
 
                     if next_edit.old.end >= edit.old.end {
                         edit.old.end = next_edit.old.end;
-                        cursor.seek(&edit.old.end, Bias::Right, &());
+                        cursor.seek(&edit.old.end, Bias::Left, &());
                         cursor.next(&());
                     }
                 } else {
@@ -177,62 +175,165 @@ impl InjectionMap {
 
             edit.new.end = ((edit.new.start + edit.old.len()) as isize + delta) as usize;
 
-            let anchor = buffer.anchor_before(edit.new.start);
-            let mut injections_cursor = self.injections.cursor::<Anchor>();
-            // folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, &buffer);
+            if !edit.new.is_empty() {
+                let text_summary = buffer.text_summary_for_range(edit.new.start..edit.new.end);
+                new_transforms.push(
+                    Transform {
+                        input: text_summary.clone(),
+                        output: text_summary,
+                        injection_id: None,
+                    },
+                    &(),
+                );
+            }
         }
+        new_transforms.push_tree(cursor.suffix(&()), &());
+        drop(cursor);
+
+        let injection_edits = {
+            let mut old_transforms = transforms.cursor::<(usize, InjectionOffset)>();
+            let mut new_transforms = new_transforms.cursor::<(usize, InjectionOffset)>();
+
+            buffer_edits
+                .into_iter()
+                .map(|edit| {
+                    old_transforms.seek(&edit.old.start, Bias::Right, &());
+                    let old_start =
+                        old_transforms.start().1 .0 + (edit.old.start - old_transforms.start().0);
+
+                    old_transforms.seek_forward(&edit.old.end, Bias::Left, &());
+                    let old_end =
+                        old_transforms.start().1 .0 + (edit.old.end - old_transforms.start().0);
+
+                    new_transforms.seek(&edit.new.start, Bias::Right, &());
+                    let new_start =
+                        new_transforms.start().1 .0 + (edit.new.start - new_transforms.start().0);
+
+                    new_transforms.seek_forward(&edit.new.end, Bias::Left, &());
+                    let new_end =
+                        new_transforms.start().1 .0 + (edit.new.end - new_transforms.start().0);
+
+                    Edit {
+                        old: InjectionOffset(old_start)..InjectionOffset(old_end),
+                        new: InjectionOffset(new_start)..InjectionOffset(new_end),
+                    }
+                })
+                .collect()
+        };
 
-        todo!()
+        *transforms = new_transforms;
+        injection_edits
     }
 }
 
-impl sum_tree::Item for Injection {
-    type Summary = InjectionSummary;
+impl<'a> InjectionMapWriter<'a> {
+    pub fn insert<'b, T, U>(
+        &mut self,
+        injections: T,
+        cx: &AppContext,
+    ) -> (
+        Vec<InjectionId>,
+        InjectionSnapshot,
+        Vec<Edit<InjectionOffset>>,
+    )
+    where
+        T: IntoIterator<Item = (U, &'b str, Vec<(usize, HighlightStyle)>)>,
+        U: ToOffset,
+    {
+        let buffer = self.0.buffer.read(cx);
+        let mut injections = injections
+            .into_iter()
+            .map(|(position, text, runs)| (position.to_offset(buffer), text, runs))
+            .peekable();
+        let mut edits = Vec::new();
+        let mut injection_ids = Vec::new();
+        let mut new_transforms = SumTree::new();
+        let mut transforms = self.0.transforms.lock();
+        let mut cursor = transforms.cursor::<usize>();
 
-    fn summary(&self) -> Self::Summary {
-        InjectionSummary {
-            min_id: self.id,
-            max_id: self.id,
-            min_position: self.position.clone(),
-            max_position: self.position.clone(),
+        while let Some((injection_offset, text, runs)) = injections.next() {
+            new_transforms.push_tree(cursor.slice(&injection_offset, Bias::Right, &()), &());
+            let new_transforms_end = new_transforms.summary().input.bytes;
+            if injection_offset > new_transforms_end {
+                new_transforms.push(
+                    Transform::isomorphic(
+                        buffer.text_summary_for_range(new_transforms_end..injection_offset),
+                    ),
+                    &(),
+                );
+            }
+
+            let injection = Injection {
+                id: InjectionId(post_inc(&mut self.0.next_injection_id)),
+                runs,
+                text: text.into(),
+            };
+            new_transforms.push(
+                Transform {
+                    input: Default::default(),
+                    output: injection.text.summary(),
+                    injection_id: Some(injection.id),
+                },
+                &(),
+            );
+            self.0.injections.push(injection, &());
+
+            if let Some((next_injection_offset, _, _)) = injections.peek() {
+                let old_transform_end = cursor.end(&());
+                if *next_injection_offset > old_transform_end {
+                    new_transforms.push(
+                        Transform::isomorphic(
+                            buffer.text_summary_for_range(new_transforms_end..old_transform_end),
+                        ),
+                        &(),
+                    );
+                    cursor.next(&());
+                }
+            }
         }
+
+        (injection_ids, todo!(), edits)
     }
 }
 
-impl sum_tree::Summary for InjectionSummary {
-    type Context = buffer::Snapshot;
+impl sum_tree::Item for Injection {
+    type Summary = InjectionId;
 
-    fn add_summary(&mut self, summary: &Self, _: &buffer::Snapshot) {
-        self.max_position = summary.max_position.clone();
-        self.min_id = cmp::min(self.min_id, summary.min_id);
-        self.max_id = cmp::max(self.max_id, summary.max_id);
+    fn summary(&self) -> Self::Summary {
+        self.id
     }
 }
 
-impl Default for InjectionSummary {
-    fn default() -> Self {
+impl Transform {
+    fn isomorphic(text_summary: TextSummary) -> Self {
         Self {
-            min_id: InjectionId(0),
-            max_id: InjectionId(usize::MAX),
-            min_position: Anchor::max(),
-            max_position: Anchor::min(),
+            input: text_summary.clone(),
+            output: text_summary,
+            injection_id: None,
         }
     }
 }
 
-impl sum_tree::Item for InjectionContent {
-    type Summary = InjectionId;
-
-    fn summary(&self) -> Self::Summary {
-        self.injection_id
-    }
-}
-
 impl sum_tree::Item for Transform {
     type Summary = TransformSummary;
 
     fn summary(&self) -> Self::Summary {
-        self.summary.clone()
+        let min_injection_id;
+        let max_injection_id;
+        if let Some(id) = self.injection_id {
+            min_injection_id = id;
+            max_injection_id = id;
+        } else {
+            min_injection_id = InjectionId(usize::MAX);
+            max_injection_id = InjectionId(0);
+        }
+
+        TransformSummary {
+            input: self.input.clone(),
+            output: self.output.clone(),
+            min_injection_id,
+            max_injection_id,
+        }
     }
 }
 
@@ -250,3 +351,9 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
         *self += summary.input.bytes
     }
 }
+
+impl<'a> sum_tree::Dimension<'a, TransformSummary> for InjectionOffset {
+    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
+        self.0 += summary.output.bytes
+    }
+}

crates/sum_tree/src/lib.rs 🔗

@@ -31,6 +31,12 @@ pub trait Summary: Default + Clone + fmt::Debug {
 
 pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug + Default {
     fn add_summary(&mut self, _summary: &'a S, _: &S::Context);
+
+    fn from_summary(summary: &'a S, cx: &S::Context) -> Self {
+        let mut dimension = Self::default();
+        dimension.add_summary(summary, cx);
+        dimension
+    }
 }
 
 impl<'a, T: Summary> Dimension<'a, T> for T {