Don't reuse excerpt ids in MultiBuffer

Nathan Sobo and Antonio Scandurra created

This prevents anchors from swapping their ordering, which was causing issues in FoldMap.

Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

crates/editor/src/multi_buffer.rs | 12 ++++++++++--
crates/text/src/locator.rs        | 24 ++++++++++++++++++++++++
2 files changed, 34 insertions(+), 2 deletions(-)

Detailed changes

crates/editor/src/multi_buffer.rs 🔗

@@ -36,6 +36,7 @@ pub type ExcerptId = Locator;
 pub struct MultiBuffer {
     snapshot: RefCell<MultiBufferSnapshot>,
     buffers: RefCell<HashMap<usize, BufferState>>,
+    used_excerpt_ids: SumTree<Locator>,
     subscriptions: Topic,
     singleton: bool,
     replica_id: ReplicaId,
@@ -155,6 +156,7 @@ impl MultiBuffer {
         Self {
             snapshot: Default::default(),
             buffers: Default::default(),
+            used_excerpt_ids: Default::default(),
             subscriptions: Default::default(),
             singleton: false,
             replica_id,
@@ -192,6 +194,7 @@ impl MultiBuffer {
         Self {
             snapshot: RefCell::new(self.snapshot.borrow().clone()),
             buffers: RefCell::new(buffers),
+            used_excerpt_ids: Default::default(),
             subscriptions: Default::default(),
             singleton: self.singleton,
             replica_id: self.replica_id,
@@ -759,13 +762,18 @@ impl MultiBuffer {
         );
 
         let mut next_id = ExcerptId::max();
-        if let Some(next_excerpt) = cursor.item() {
-            next_id = next_excerpt.id.clone();
+        {
+            let mut used_cursor = self.used_excerpt_ids.cursor::<Locator>();
+            used_cursor.seek(&prev_id, Bias::Right, &());
+            if let Some(used_id) = used_cursor.item() {
+                next_id = used_id.clone();
+            }
         }
 
         let mut ids = Vec::new();
         while let Some(range) = ranges.next() {
             let id = ExcerptId::between(&prev_id, &next_id);
+            self.used_excerpt_ids.insert_or_replace(id.clone(), &());
             if let Err(ix) = buffer_state.excerpts.binary_search(&id) {
                 buffer_state.excerpts.insert(ix, id.clone());
             }

crates/text/src/locator.rs 🔗

@@ -49,6 +49,30 @@ impl Default for Locator {
     }
 }
 
+impl sum_tree::Item for Locator {
+    type Summary = Locator;
+
+    fn summary(&self) -> Self::Summary {
+        self.clone()
+    }
+}
+
+impl sum_tree::KeyedItem for Locator {
+    type Key = Locator;
+
+    fn key(&self) -> Self::Key {
+        self.clone()
+    }
+}
+
+impl sum_tree::Summary for Locator {
+    type Context = ();
+
+    fn add_summary(&mut self, summary: &Self, _: &()) {
+        self.assign(summary);
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;