Implement MultiBuffer::insert_excerpt_after

Max Brunsfeld created

Change summary

crates/editor/src/multi_buffer.rs | 80 +++++++++++++++++++++++++-------
1 file changed, 63 insertions(+), 17 deletions(-)

Detailed changes

crates/editor/src/multi_buffer.rs 🔗

@@ -589,6 +589,18 @@ impl MultiBuffer {
         props: ExcerptProperties<O>,
         cx: &mut ModelContext<Self>,
     ) -> ExcerptId
+    where
+        O: text::ToOffset,
+    {
+        self.insert_excerpt_after(&ExcerptId::max(), props, cx)
+    }
+
+    pub fn insert_excerpt_after<O>(
+        &mut self,
+        prev_excerpt_id: &ExcerptId,
+        props: ExcerptProperties<O>,
+        cx: &mut ModelContext<Self>,
+    ) -> ExcerptId
     where
         O: text::ToOffset,
     {
@@ -599,19 +611,28 @@ impl MultiBuffer {
         let range = buffer_snapshot.anchor_before(&props.range.start)
             ..buffer_snapshot.anchor_after(&props.range.end);
         let mut snapshot = self.snapshot.borrow_mut();
-        let mut prev_id = None;
-        let edit_start = snapshot.excerpts.summary().text.bytes;
-        snapshot.excerpts.update_last(
+        let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
+        let mut new_excerpts = cursor.slice(&Some(prev_excerpt_id), Bias::Right, &());
+
+        let mut prev_id = ExcerptId::min();
+        let edit_start = new_excerpts.summary().text.bytes;
+        new_excerpts.update_last(
             |excerpt| {
                 excerpt.has_trailing_newline = true;
-                prev_id = Some(excerpt.id.clone());
+                prev_id = excerpt.id.clone();
             },
             &(),
         );
 
-        let id = ExcerptId::between(&prev_id.unwrap_or(ExcerptId::min()), &ExcerptId::max());
-        self.buffers
-            .borrow_mut()
+        let mut next_id = ExcerptId::max();
+        if let Some(next_excerpt) = cursor.item() {
+            next_id = next_excerpt.id.clone();
+        }
+
+        let id = ExcerptId::between(&prev_id, &next_id);
+
+        let mut buffers = self.buffers.borrow_mut();
+        let buffer_state = buffers
             .entry(props.buffer.id())
             .or_insert_with(|| BufferState {
                 last_version: buffer_snapshot.version().clone(),
@@ -623,14 +644,28 @@ impl MultiBuffer {
                     cx.subscribe(&props.buffer, Self::on_buffer_event),
                 ],
                 buffer: props.buffer.clone(),
-            })
-            .excerpts
-            .push(id.clone());
-        let excerpt = Excerpt::new(id.clone(), props.buffer.id(), buffer_snapshot, range, false);
-        snapshot.excerpts.push(excerpt, &());
+            });
+        if let Err(ix) = buffer_state.excerpts.binary_search(&id) {
+            buffer_state.excerpts.insert(ix, id.clone());
+        }
+
+        let excerpt = Excerpt::new(
+            id.clone(),
+            props.buffer.id(),
+            buffer_snapshot,
+            range,
+            cursor.item().is_some(),
+        );
+        new_excerpts.push(excerpt, &());
+        let edit_end = new_excerpts.summary().text.bytes;
+
+        new_excerpts.push_tree(cursor.suffix(&()), &());
+        drop(cursor);
+        snapshot.excerpts = new_excerpts;
+
         self.subscriptions.publish_mut([Edit {
             old: edit_start..edit_start,
-            new: edit_start..snapshot.excerpts.summary().text.bytes,
+            new: edit_start..edit_end,
         }]);
 
         cx.notify();
@@ -2302,8 +2337,17 @@ mod tests {
                     let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
                     let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
                     let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
+                    let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
+                    let prev_excerpt_id = excerpt_ids
+                        .get(prev_excerpt_ix)
+                        .cloned()
+                        .unwrap_or(ExcerptId::max());
+                    let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
+
                     log::info!(
-                        "Pushing excerpt for buffer {}: {:?}[{:?}] = {:?}",
+                        "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
+                        excerpt_ix,
+                        expected_excerpts.len(),
                         buffer_handle.id(),
                         buffer.text(),
                         start_ix..end_ix,
@@ -2311,7 +2355,8 @@ mod tests {
                     );
 
                     let excerpt_id = list.update(cx, |list, cx| {
-                        list.push_excerpt(
+                        list.insert_excerpt_after(
+                            &prev_excerpt_id,
                             ExcerptProperties {
                                 buffer: &buffer_handle,
                                 range: start_ix..end_ix,
@@ -2319,8 +2364,9 @@ mod tests {
                             cx,
                         )
                     });
-                    excerpt_ids.push(excerpt_id);
-                    expected_excerpts.push((buffer_handle.clone(), anchor_range));
+
+                    excerpt_ids.insert(excerpt_ix, excerpt_id);
+                    expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
                 }
             }