Tidyup, try randomly_edit

Conrad Irwin created

Change summary

crates/multi_buffer/src/multi_buffer.rs | 229 ++++++++++----------------
crates/multi_buffer/src/path_key.rs     | 169 ++++++++----------
2 files changed, 167 insertions(+), 231 deletions(-)

Detailed changes

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -54,7 +54,6 @@ use std::{
 use sum_tree::{Bias, Cursor, Dimension, Dimensions, SumTree, TreeMap};
 use text::{
     BufferId, Edit, LineIndent, TextSummary,
-    locator::Locator,
     subscription::{Subscription, Topic},
 };
 use theme::SyntaxTheme;
@@ -95,6 +94,7 @@ pub struct MultiBuffer {
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct PathKeyIndex(u64);
 
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ExcerptInfo {
     path_key_index: PathKeyIndex,
     buffer_id: BufferId,
@@ -1710,9 +1710,8 @@ impl MultiBuffer {
     #[instrument(skip_all)]
     fn merge_excerpt_ranges<'a>(
         expanded_ranges: impl IntoIterator<Item = &'a ExcerptRange<Point>> + 'a,
-    ) -> (Vec<ExcerptRange<Point>>, Vec<usize>) {
+    ) -> Vec<ExcerptRange<Point>> {
         let mut merged_ranges: Vec<ExcerptRange<Point>> = Vec::new();
-        let mut counts: Vec<usize> = Vec::new();
         for range in expanded_ranges {
             if let Some(last_range) = merged_ranges.last_mut() {
                 assert!(
@@ -1723,14 +1722,12 @@ impl MultiBuffer {
                     || last_range.context.end.row + 1 == range.context.start.row
                 {
                     last_range.context.end = range.context.end.max(last_range.context.end);
-                    *counts.last_mut().unwrap() += 1;
                     continue;
                 }
             }
             merged_ranges.push(range.clone());
-            counts.push(1);
         }
-        (merged_ranges, counts)
+        merged_ranges
     }
 
     pub fn clear(&mut self, cx: &mut Context<Self>) {
@@ -1839,9 +1836,9 @@ impl MultiBuffer {
 
     pub fn buffer_for_anchor(&self, anchor: Anchor, cx: &App) -> Option<Entity<Buffer>> {
         match anchor {
-            Anchor::Min => Some(self.snapshot(cx).excerpts.first()?.buffer(self, cx)),
+            Anchor::Min => Some(self.snapshot(cx).excerpts.first()?.buffer(self)),
             Anchor::Excerpt(excerpt_anchor) => self.buffer(excerpt_anchor.buffer_id),
-            Anchor::Max => Some(self.snapshot(cx).excerpts.first()?.buffer(self, cx)),
+            Anchor::Max => Some(self.snapshot(cx).excerpts.first()?.buffer(self)),
         }
     }
 
@@ -2149,7 +2146,7 @@ impl MultiBuffer {
         let buffer = snapshot
             .excerpts
             .first()
-            .map(|excerpt| excerpt.buffer(self, cx));
+            .map(|excerpt| excerpt.buffer(self));
         buffer
             .map(|buffer| {
                 let buffer = buffer.read(cx);
@@ -3255,38 +3252,14 @@ impl MultiBuffer {
         use std::env;
         use util::RandomCharIter;
 
-        let max_excerpts = env::var("MAX_EXCERPTS")
+        let max_buffers = env::var("MAX_BUFFERS")
             .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
             .unwrap_or(5);
 
         let mut buffers = Vec::new();
         for _ in 0..mutation_count {
-            if rng.random_bool(0.05) {
-                log::info!("Clearing multi-buffer");
-                self.clear(cx);
-                continue;
-            } else if rng.random_bool(0.1) && !self.excerpt_ids().is_empty() {
-                let ids = self.excerpt_ids();
-                let mut excerpts = HashSet::default();
-                for _ in 0..rng.random_range(0..ids.len()) {
-                    excerpts.extend(ids.choose(rng).copied());
-                }
-
-                let line_count = rng.random_range(0..5);
-
-                log::info!("Expanding excerpts {excerpts:?} by {line_count} lines");
-
-                self.expand_excerpts(
-                    excerpts.iter().cloned(),
-                    line_count,
-                    ExpandExcerptDirection::UpAndDown,
-                    cx,
-                );
-                continue;
-            }
-
-            let excerpt_ids = self.excerpt_ids();
-            if excerpt_ids.is_empty() || (rng.random() && excerpt_ids.len() < max_excerpts) {
+            let buffer_ids = self.all_buffer_ids();
+            if buffer_ids.is_empty() || (rng.random() && buffer_ids.len() < max_buffers) {
                 let buffer_handle = if rng.random() || self.buffers.is_empty() {
                     let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
                     buffers.push(cx.new(|cx| Buffer::local(text, cx)));
@@ -3303,12 +3276,21 @@ impl MultiBuffer {
 
                 let buffer = buffer_handle.read(cx);
                 let buffer_text = buffer.text();
+                let buffer_snapshot = buffer.snapshot();
+                let mut next_min_start_ix = 0;
                 let ranges = (0..rng.random_range(0..5))
-                    .map(|_| {
-                        let end_ix =
-                            buffer.clip_offset(rng.random_range(0..=buffer.len()), Bias::Right);
-                        let start_ix = buffer.clip_offset(rng.random_range(0..=end_ix), Bias::Left);
-                        ExcerptRange::new(start_ix..end_ix)
+                    .filter_map(|_| {
+                        if next_min_start_ix == buffer.len() {
+                            return None;
+                        }
+                        let end_ix = buffer.clip_offset(
+                            rng.random_range(next_min_start_ix..=buffer.len()),
+                            Bias::Right,
+                        );
+                        let start_ix = buffer
+                            .clip_offset(rng.random_range(next_min_start_ix..=end_ix), Bias::Left);
+                        next_min_start_ix = end_ix;
+                        Some(ExcerptRange::new(start_ix..end_ix))
                     })
                     .collect::<Vec<_>>();
                 log::info!(
@@ -3321,20 +3303,25 @@ impl MultiBuffer {
                         .collect::<Vec<_>>()
                 );
 
-                let excerpt_id =
-                    self.insert_excerpts_after(ExcerptId::max(), buffer_handle, ranges, cx);
-                log::info!("Inserted with ids: {:?}", excerpt_id);
+                let path_key = PathKey::sorted(rng.random_range(0..max_buffers * 3) as u64);
+                self.set_merged_excerpt_ranges_for_path(
+                    path_key.clone(),
+                    buffer_handle,
+                    &buffer_snapshot,
+                    ranges,
+                    cx,
+                );
+                log::info!("Inserted with path_key: {:?}", path_key);
             } else {
-                let remove_count = rng.random_range(1..=excerpt_ids.len());
-                let mut excerpts_to_remove = excerpt_ids
-                    .choose_multiple(rng, remove_count)
+                let path_key = self
+                    .snapshot
+                    .borrow()
+                    .path_keys_by_buffer
+                    .get(&buffer_ids.choose(rng).unwrap())
                     .cloned()
-                    .collect::<Vec<_>>();
-                let snapshot = self.snapshot.borrow();
-                excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
-                drop(snapshot);
-                log::info!("Removing excerpts {:?}", excerpts_to_remove);
-                self.remove_excerpts(excerpts_to_remove, cx);
+                    .unwrap();
+                log::info!("Removing excerpts {:?}", path_key);
+                self.remove_excerpts_for_path(path_key, cx);
             }
         }
     }
@@ -3716,6 +3703,7 @@ impl MultiBufferSnapshot {
 
         let mut result: Vec<(&BufferSnapshot, Range<BufferOffset>, Range<text::Anchor>)> =
             Vec::new();
+        let mut last_excerpt = None;
         while let Some(region) = cursor.region() {
             let dominated_by_end_bound = match end_bound {
                 Bound::Included(end) => region.range.start > end,
@@ -3741,12 +3729,18 @@ impl MultiBufferSnapshot {
                     .end
                     .min(region.buffer_range.start + end_overshoot);
                 let context = region.excerpt.range.context.clone();
-                if let Some(prev) = result.last_mut().filter(|(_, prev_range, excerpt_id, _)| {
-                    *excerpt_id == region.excerpt.id && prev_range.end == start
-                }) {
+                if last_excerpt
+                    .as_ref()
+                    .is_some_and(|prev_excerpt| prev_excerpt == &region.excerpt.info())
+                    && let Some(prev) = result
+                        .last_mut()
+                        .filter(|(_, prev_range, _)| prev_range.end == start)
+                {
                     prev.1.end = end;
                 } else {
-                    result.push((region.buffer, start..end, region.excerpt.id, context));
+                    result.push((region.buffer, start..end, context));
+                    // todo!() is there a better way to do this?
+                    last_excerpt = Some(region.excerpt.info())
                 }
             }
             cursor.next();
@@ -3754,24 +3748,15 @@ impl MultiBufferSnapshot {
 
         if let Some(excerpt) = cursor.excerpt() {
             let dominated_by_prev_excerpt =
-                result.last().is_some_and(|(_, _, id, _)| *id == excerpt.id);
+                last_excerpt.is_some_and(|last_excerpt| last_excerpt == excerpt.info());
             if !dominated_by_prev_excerpt && excerpt.text_summary.len == 0 {
                 let excerpt_position = self.len();
+                let buffer_snapshot = excerpt.buffer_snapshot(self);
                 if bounds.contains(&excerpt_position) {
-                    let buffer_offset = BufferOffset(
-                        excerpt
-                            .range
-                            .context
-                            .start
-                            .to_offset(&excerpt.buffer_snapshot),
-                    );
+                    let buffer_offset =
+                        BufferOffset(excerpt.range.context.start.to_offset(buffer_snapshot));
                     let context = excerpt.range.context.clone();
-                    result.push((
-                        &excerpt.buffer_snapshot,
-                        buffer_offset..buffer_offset,
-                        excerpt.id,
-                        context,
-                    ));
+                    result.push((buffer_snapshot, buffer_offset..buffer_offset, context));
                 }
             }
         }
@@ -3805,18 +3790,12 @@ impl MultiBufferSnapshot {
                 .end
                 .min(region.buffer_range.start + end_overshoot);
 
-            let region_excerpt_id = region.excerpt.id;
             let deleted_hunk_anchor = if region.is_main_buffer {
                 None
             } else {
                 Some(self.anchor_before(region.range.start))
             };
-            let result = (
-                region.buffer,
-                start..end,
-                region_excerpt_id,
-                deleted_hunk_anchor,
-            );
+            let result = (region.buffer, start..end, deleted_hunk_anchor);
             cursor.next();
             Some(result)
         })
@@ -5368,32 +5347,6 @@ impl MultiBufferSnapshot {
         )
     }
 
-    fn anchor_in_excerpt_(excerpt: &Excerpt, text_anchor: text::Anchor) -> Option<Anchor> {
-        match text_anchor.buffer_id {
-            Some(buffer_id) if buffer_id == excerpt.buffer_snapshot.remote_id() => (),
-            Some(_) => return None,
-            None if text_anchor.is_max() || text_anchor.is_min() => {
-                return Some(Anchor::in_buffer(excerpt.path_key_index, text_anchor));
-            }
-            None => return None,
-        }
-
-        let context = &excerpt.range.context;
-        if context
-            .start
-            .cmp(&text_anchor, &excerpt.buffer_snapshot)
-            .is_gt()
-            || context
-                .end
-                .cmp(&text_anchor, &excerpt.buffer_snapshot)
-                .is_lt()
-        {
-            return None;
-        }
-
-        Some(Anchor::in_buffer(excerpt.path_key_index, text_anchor))
-    }
-
     pub fn can_resolve(&self, anchor: &Anchor) -> bool {
         match anchor {
             // todo(lw): should be `!self.is_empty()`
@@ -6342,38 +6295,40 @@ impl MultiBufferSnapshot {
             .expect("invalid anchor: path was never added to multibuffer")
     }
 
-    pub fn range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<Point>> {
-        let mut cursor = self
-            .excerpts
-            .cursor::<Dimensions<Option<&Locator>, ExcerptPoint>>(());
-        let locator = self.excerpt_locator_for_id(excerpt_id);
-        let mut sought_exact = cursor.seek(&Some(locator), Bias::Left);
-        if cursor.item().is_none() && excerpt_id == ExcerptId::max() {
-            sought_exact = true;
-            cursor.prev();
-        } else if excerpt_id == ExcerptId::min() {
-            sought_exact = true;
-        }
-        if sought_exact {
-            let start = cursor.start().1;
-            let end = cursor.end().1;
-            let mut diff_transforms = self
-                .diff_transforms
-                .cursor::<Dimensions<ExcerptPoint, OutputDimension<Point>>>(());
-            diff_transforms.seek(&start, Bias::Left);
-            let overshoot = start - diff_transforms.start().0;
-            let start = diff_transforms.start().1 + overshoot;
-            diff_transforms.seek(&end, Bias::Right);
-            let overshoot = end - diff_transforms.start().0;
-            let end = diff_transforms.start().1 + overshoot;
-            Some(start.0..end.0)
-        } else {
-            None
-        }
+    // todo!() this may not make sense any more
+    pub fn range_for_excerpt(&self, excerpt_id: BufferId) -> Option<Range<Point>> {
+        todo!()
+        // let mut cursor = self
+        //     .excerpts
+        //     .cursor::<Dimensions<Option<&Locator>, ExcerptPoint>>(());
+        // let locator = self.excerpt_locator_for_id(excerpt_id);
+        // let mut sought_exact = cursor.seek(&Some(locator), Bias::Left);
+        // if cursor.item().is_none() && excerpt_id == ExcerptId::max() {
+        //     sought_exact = true;
+        //     cursor.prev();
+        // } else if excerpt_id == ExcerptId::min() {
+        //     sought_exact = true;
+        // }
+        // if sought_exact {
+        //     let start = cursor.start().1;
+        //     let end = cursor.end().1;
+        //     let mut diff_transforms = self
+        //         .diff_transforms
+        //         .cursor::<Dimensions<ExcerptPoint, OutputDimension<Point>>>(());
+        //     diff_transforms.seek(&start, Bias::Left);
+        //     let overshoot = start - diff_transforms.start().0;
+        //     let start = diff_transforms.start().1 + overshoot;
+        //     diff_transforms.seek(&end, Bias::Right);
+        //     let overshoot = end - diff_transforms.start().0;
+        //     let end = diff_transforms.start().1 + overshoot;
+        //     Some(start.0..end.0)
+        // } else {
+        //     None
+        // }
     }
 
     // todo!() sort out excerpt_containing etc.
-    fn excerpt_at(&self, position: impl ToOffset) -> Option<&Excerpt> {
+    fn excerpt_at(&self, _position: impl ToOffset) -> Option<&Excerpt> {
         todo!()
     }
 
@@ -6389,7 +6344,7 @@ impl MultiBufferSnapshot {
         let start_excerpt = cursor.excerpt()?;
         if range.end != range.start {
             cursor.seek_forward(&range.end);
-            if cursor.excerpt()?.id != start_excerpt.id {
+            if cursor.excerpt()? != start_excerpt {
                 return None;
             }
         }
@@ -7011,11 +6966,9 @@ impl Excerpt {
             .buffer_snapshot
     }
 
-    fn buffer(&self, multibuffer: &MultiBuffer, cx: &App) -> Entity<Buffer> {
-        let snapshot = multibuffer.snapshot(cx);
-        let buffer_snapshot = self.buffer_snapshot(&snapshot);
+    fn buffer(&self, multibuffer: &MultiBuffer) -> Entity<Buffer> {
         multibuffer
-            .buffer(buffer_snapshot.remote_id())
+            .buffer(self.buffer_id)
             .expect("buffer entity not found for excerpt")
     }
 

crates/multi_buffer/src/path_key.rs 🔗

@@ -1,11 +1,7 @@
-use std::{
-    cell::{Cell, RefCell},
-    ops::Range,
-    rc::Rc,
-    sync::Arc,
-};
+use std::{ops::Range, rc::Rc, sync::Arc};
 
 use gpui::{App, AppContext, Context, Entity};
+use itertools::Itertools;
 use language::{Buffer, BufferSnapshot};
 use rope::Point;
 use sum_tree::{Dimensions, SumTree};
@@ -15,8 +11,8 @@ use ztracing::instrument;
 
 use crate::{
     Anchor, BufferState, BufferStateSnapshot, DiffChangeKind, Event, Excerpt, ExcerptOffset,
-    ExcerptRange, ExcerptSummary, ExpandExcerptDirection, MultiBuffer, PathKeyIndex,
-    build_excerpt_ranges,
+    ExcerptRange, ExcerptSummary, ExpandExcerptDirection, MultiBuffer, MultiBufferDimension,
+    PathKeyIndex, ToOffset, build_excerpt_ranges,
 };
 
 #[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]
@@ -103,9 +99,9 @@ impl MultiBuffer {
         let excerpt_ranges =
             build_excerpt_ranges(ranges.clone(), context_line_count, &buffer_snapshot);
 
-        let (new, _) = Self::merge_excerpt_ranges(&excerpt_ranges);
+        let merged = Self::merge_excerpt_ranges(&excerpt_ranges);
         let (inserted, path_key_index) =
-            self.set_merged_excerpt_ranges_for_path(path, buffer, &buffer_snapshot, new, cx);
+            self.set_merged_excerpt_ranges_for_path(path, buffer, &buffer_snapshot, merged, cx);
         // todo!() move this into the callers that care
         let anchors = ranges
             .into_iter()
@@ -124,9 +120,9 @@ impl MultiBuffer {
         excerpt_ranges: Vec<ExcerptRange<Point>>,
         cx: &mut Context<Self>,
     ) -> (Vec<Range<Anchor>>, bool) {
-        let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges);
+        let merged = Self::merge_excerpt_ranges(&excerpt_ranges);
         let (inserted, path_key_index) =
-            self.set_merged_excerpt_ranges_for_path(path, buffer, buffer_snapshot, new, cx);
+            self.set_merged_excerpt_ranges_for_path(path, buffer, buffer_snapshot, merged, cx);
         // todo!() move this into the callers that care
         let anchors = excerpt_ranges
             .into_iter()
@@ -158,8 +154,8 @@ impl MultiBuffer {
                     let point_ranges = ranges.iter().map(|range| range.to_point(&snapshot));
                     let excerpt_ranges =
                         build_excerpt_ranges(point_ranges, context_line_count, &snapshot);
-                    let (new, _) = Self::merge_excerpt_ranges(&excerpt_ranges);
-                    (ranges, new)
+                    let merged = Self::merge_excerpt_ranges(&excerpt_ranges);
+                    (ranges, merged)
                 })
                 .await;
 
@@ -195,99 +191,90 @@ impl MultiBuffer {
             .filter_map(|anchor| anchor.excerpt_anchor())
             .collect::<Vec<_>>();
         sorted_anchors.sort_by(|a, b| a.cmp(b, &snapshot));
+        let buffers = sorted_anchors.into_iter().chunk_by(|anchor| anchor.path);
         let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>(());
-        let mut sorted_anchors = sorted_anchors.into_iter().peekable();
-        while let Some(anchor) = sorted_anchors.next() {
-            let path = snapshot.path_for_anchor(anchor);
-            let Some(buffer) = self.buffer_for_path(&path, cx) else {
+
+        for (path_index, excerpt_anchors) in &buffers {
+            let path = snapshot
+                .path_keys_by_index
+                .get(&path_index)
+                .expect("anchor from wrong multibuffer");
+            let Some((buffer, buffer_snapshot)) = cursor
+                .item()
+                .map(|excerpt| (excerpt.buffer(&self), excerpt.buffer_snapshot(&snapshot)))
+            else {
                 continue;
             };
-            let buffer_snapshot = buffer.read(cx).snapshot();
 
-            let mut expanded_ranges = Vec::new();
-            // Move to the first excerpt for this path
-            cursor.seek_forward(&path, Bias::Left);
-            while let Some(anchor) = sorted_anchors.peek().copied()
-                && snapshot.path_for_anchor(anchor) == path
+            let mut excerpt_anchors = excerpt_anchors.peekable();
+            let mut ranges = Vec::new();
+
+            cursor.seek_forward(path, Bias::Left);
+            while let Some(excerpt) = cursor.item()
+                && &excerpt.path_key == path
             {
-                sorted_anchors.next();
-                let target = anchor.seek_target(&snapshot);
-                // Move to the next excerpt to be expanded, and push unchanged ranges for intervening excerpts
-                expanded_ranges.extend(
-                    cursor
-                        .slice(&target, Bias::Left)
-                        .iter()
-                        .map(|excerpt| excerpt.range.clone()),
-                );
-                let Some(excerpt) = cursor.item() else {
-                    continue;
+                let mut range = ExcerptRange {
+                    context: excerpt.range.context.to_point(buffer_snapshot),
+                    primary: excerpt.range.primary.to_point(buffer_snapshot),
                 };
-                if excerpt.path_key != path {
-                    continue;
+
+                let mut needs_expand = false;
+                while excerpt_anchors.peek().is_some_and(|anchor| {
+                    excerpt
+                        .range
+                        .contains(&anchor.text_anchor(), buffer_snapshot)
+                }) {
+                    needs_expand = true;
+                    excerpt_anchors.next();
                 }
-                // Expand the range for this excerpt
-                let mut context = excerpt.range.context.to_point(&buffer_snapshot);
-                match direction {
-                    ExpandExcerptDirection::Up => {
-                        context.start.row = context.start.row.saturating_sub(line_count);
-                        context.start.column = 0;
-                    }
-                    ExpandExcerptDirection::Down => {
-                        context.end.row = (context.end.row + line_count)
-                            .min(excerpt.buffer_snapshot.max_point().row);
-                        context.end.column = excerpt.buffer_snapshot.line_len(context.end.row);
-                    }
-                    ExpandExcerptDirection::UpAndDown => {
-                        context.start.row = context.start.row.saturating_sub(line_count);
-                        context.start.column = 0;
-                        context.end.row = (context.end.row + line_count)
-                            .min(excerpt.buffer_snapshot.max_point().row);
-                        context.end.column = excerpt.buffer_snapshot.line_len(context.end.row);
+
+                if needs_expand {
+                    match direction {
+                        ExpandExcerptDirection::Up => {
+                            range.context.start.row =
+                                range.context.start.row.saturating_sub(line_count);
+                            range.context.start.column = 0;
+                        }
+                        ExpandExcerptDirection::Down => {
+                            range.context.end.row = (range.context.end.row + line_count)
+                                .min(excerpt.buffer_snapshot(&snapshot).max_point().row);
+                            range.context.end.column = excerpt
+                                .buffer_snapshot(&snapshot)
+                                .line_len(range.context.end.row);
+                        }
+                        ExpandExcerptDirection::UpAndDown => {
+                            range.context.start.row =
+                                range.context.start.row.saturating_sub(line_count);
+                            range.context.start.column = 0;
+                            range.context.end.row = (range.context.end.row + line_count)
+                                .min(excerpt.buffer_snapshot(&snapshot).max_point().row);
+                            range.context.end.column = excerpt
+                                .buffer_snapshot(&snapshot)
+                                .line_len(range.context.end.row);
+                        }
                     }
                 }
-                let context = excerpt.buffer_snapshot.anchor_range_around(context);
-                expanded_ranges.push(ExcerptRange {
-                    context,
-                    primary: excerpt.range.primary.clone(),
-                });
-                cursor.next();
-            }
 
-            // Add unchanged ranges for this path after the last expanded excerpt
-            while let Some(excerpt) = cursor.item()
-                && excerpt.path_key == path
-            {
-                expanded_ranges.push(excerpt.range.clone());
+                ranges.push(range);
                 cursor.next();
             }
 
-            let mut merged_ranges: Vec<ExcerptRange<text::Anchor>> = Vec::new();
-            for range in expanded_ranges {
-                if let Some(last_range) = merged_ranges.last_mut()
-                    && last_range
-                        .context
-                        .end
-                        .cmp(&range.context.start, &buffer_snapshot)
-                        .is_ge()
-                {
-                    last_range.context.end = range.context.end;
-                    continue;
-                }
-                merged_ranges.push(range)
-            }
-            self.update_path_excerpts(path.clone(), buffer, &buffer_snapshot, &merged_ranges, cx);
+            self.set_excerpt_ranges_for_path(path.clone(), buffer, buffer_snapshot, ranges, cx);
         }
     }
 
     /// Sets excerpts, returns `true` if at least one new excerpt was added.
-    fn set_merged_excerpt_ranges_for_path(
+    pub(crate) fn set_merged_excerpt_ranges_for_path<T>(
         &mut self,
         path: PathKey,
         buffer: Entity<Buffer>,
         buffer_snapshot: &BufferSnapshot,
-        new: Vec<ExcerptRange<Point>>,
+        new: Vec<ExcerptRange<T>>,
         cx: &mut Context<Self>,
-    ) -> (bool, PathKeyIndex) {
+    ) -> (bool, PathKeyIndex)
+    where
+        T: language::ToOffset,
+    {
         let anchor_ranges = new
             .into_iter()
             .map(|r| ExcerptRange {
@@ -346,18 +333,14 @@ impl MultiBuffer {
         assert_eq!(self.history.transaction_depth(), 0);
         self.sync_mut(cx);
 
-        let buffer_snapshot = buffer.read(cx).snapshot();
         let buffer_id = buffer_snapshot.remote_id();
+
         self.buffers.entry(buffer_id).or_insert_with(|| {
             self.buffer_changed_since_sync.replace(true);
             buffer.update(cx, |buffer, _| {
                 buffer.record_changes(Rc::downgrade(&self.buffer_changed_since_sync));
             });
             BufferState {
-                last_version: RefCell::new(buffer_snapshot.version().clone()),
-                last_non_text_state_update_count: Cell::new(
-                    buffer_snapshot.non_text_state_update_count(),
-                ),
                 _subscriptions: [
                     cx.observe(&buffer, |_, _, cx| cx.notify()),
                     cx.subscribe(&buffer, Self::on_buffer_event),
@@ -431,7 +414,7 @@ impl MultiBuffer {
                     Excerpt::new(
                         path_key.clone(),
                         path_key_index,
-                        buffer_snapshot.remote_id(),
+                        &buffer_snapshot,
                         next_excerpt.clone(),
                         to_insert.peek().is_some(),
                     ),
@@ -462,8 +445,8 @@ impl MultiBuffer {
         snapshot.buffers.insert(
             buffer_id,
             BufferStateSnapshot {
-                path_key,
-                buffer_snapshot,
+                path_key: path_key.clone(),
+                buffer_snapshot: buffer_snapshot.clone(),
             },
         );
         if changed_trailing_excerpt {