wip working on summary_for_anchor

Cole Miller created

Change summary

crates/multi_buffer/src/multi_buffer.rs | 65 +++++++++++++++++---------
crates/multi_buffer/src/path_key.rs     |  6 -
2 files changed, 45 insertions(+), 26 deletions(-)

Detailed changes

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -4957,11 +4957,10 @@ impl MultiBufferSnapshot {
             + Add<MBD::TextDimension, Output = MBD>,
         MBD::TextDimension: Sub<Output = MBD::TextDimension> + Ord,
     {
-        let excerpt_id = self.latest_excerpt_id(anchor.excerpt_id);
-        let locator = self.excerpt_locator_for_id(excerpt_id);
+        let target = self.anchor_seek_target(*anchor);
         let (start, _, mut item) = self
             .excerpts
-            .find::<ExcerptSummary, _>((), locator, Bias::Left);
+            .find::<ExcerptSummary, _>((), &target, Bias::Left);
         let mut start = MBD::from_summary(&start.text);
         if item.is_none() && excerpt_id == ExcerptId::max() {
             item = self.excerpts.last();
@@ -5068,6 +5067,19 @@ impl MultiBufferSnapshot {
     where
         MBD: MultiBufferDimension + Ord + Sub + AddAssign<<MBD as Sub>::Output>,
     {
+        let (text_anchor, diff_base_anchor) = match anchor {
+            Anchor::Min | Anchor::Max => {
+                return self.resolve_summary_for_min_or_max_anchor(
+                    anchor,
+                    excerpt_position,
+                    diff_transforms,
+                );
+            }
+            Anchor::Text {
+                diff_base_anchor, ..
+            } => (anchor.text_anchor().unwrap(), *diff_base_anchor),
+        };
+
         loop {
             let transform_end_position = diff_transforms.end().0;
             let item = diff_transforms.item();
@@ -5075,7 +5087,7 @@ impl MultiBufferSnapshot {
 
             // A right-biased anchor at a transform boundary belongs to the
             // *next* transform, so advance past the current one.
-            if anchor.text_anchor.bias == Bias::Right && at_transform_end {
+            if text_anchor.bias == Bias::Right && at_transform_end {
                 diff_transforms.next();
                 continue;
             }
@@ -5088,7 +5100,7 @@ impl MultiBufferSnapshot {
                     hunk_info,
                     ..
                 }) => {
-                    if let Some(diff_base_anchor) = &anchor.diff_base_anchor
+                    if let Some(diff_base_anchor) = &diff_base_anchor
                         && let Some(base_text) =
                             self.diffs.get(buffer_id).map(|diff| diff.base_text())
                         && diff_base_anchor.is_valid(&base_text)
@@ -5111,8 +5123,7 @@ impl MultiBufferSnapshot {
                             continue;
                         }
                     } else if at_transform_end
-                        && anchor
-                            .text_anchor
+                        && text_anchor
                             .cmp(&hunk_info.hunk_start_anchor, excerpt_buffer)
                             .is_gt()
                     {
@@ -5133,7 +5144,7 @@ impl MultiBufferSnapshot {
                     // On a BufferContent (or no transform). If the anchor
                     // carries a diff_base_anchor it needs a DeletedHunk, so
                     // advance to find one.
-                    if at_transform_end && anchor.diff_base_anchor.is_some() {
+                    if at_transform_end && diff_base_anchor.is_some() {
                         diff_transforms.next();
                         continue;
                     }
@@ -6516,22 +6527,18 @@ impl MultiBufferSnapshot {
         ))
     }
 
-    fn anchor_seek_target(&self, anchor: Anchor) -> Option<AnchorSeekTarget> {
+    fn anchor_seek_target(&self, anchor: Anchor) -> AnchorSeekTarget {
         match anchor {
             Anchor::Min => Some(AnchorSeekTarget::Min),
             Anchor::Max => Some(AnchorSeekTarget::Max),
-            Anchor::Text { buffer_id, .. } => {
-                let Some(path_key) = self.path_for_buffer(buffer_id) else {
-                    return None;
-                };
-                let Some(snapshot) = self.buffer_for_path(path_key) else {
-                    return None;
-                };
+            Anchor::Text { path, .. } => {
+                let path_key = self.path_for_anchor(anchor);
+                let snapshot = self.buffer_for_path(path_key);
 
                 Some(AnchorSeekTarget::Text {
                     path_key: path_key.clone(),
                     anchor: anchor.text_anchor().unwrap(),
-                    snapshot: snapshot.clone(),
+                    snapshot: snapshot.cloned(),
                 })
             }
         }
@@ -6613,11 +6620,15 @@ impl MultiBufferSnapshot {
         self.buffer_for_path(self.path_keys_by_buffer.get(&id)?)
     }
 
-    pub fn path_for_anchor(&self, anchor: Anchor) -> Option<PathKey> {
+    pub fn path_for_anchor(&self, anchor: Anchor) -> PathKey {
         match anchor {
             Anchor::Min => Some(self.excerpts.first()?.path_key.clone()),
             Anchor::Max => Some(self.excerpts.last()?.path_key.clone()),
-            Anchor::Text { path, .. } => self.path_keys_by_index.get(&path).cloned(),
+            Anchor::Text { path, .. } => self
+                .path_keys_by_index
+                .get(&path)
+                .cloned()
+                .expect("path was never added to multibuffer"),
         }
     }
 
@@ -7607,7 +7618,8 @@ enum AnchorSeekTarget {
     Text {
         path_key: PathKey,
         anchor: text::Anchor,
-        snapshot: BufferSnapshot,
+        // None when the buffer no longer exists in the multibuffer
+        snapshot: Option<BufferSnapshot>,
     },
 }
 
@@ -7624,8 +7636,17 @@ impl sum_tree::SeekTarget<'_, ExcerptSummary, ExcerptSummary> for AnchorSeekTarg
                 path_key,
                 anchor,
                 snapshot,
-            } => Ord::cmp(path_key, &cursor_location.path_key)
-                .then_with(|| anchor.cmp(&cursor_location.max_anchor, snapshot)),
+            } => {
+                let path_comparison = Ord::cmp(path_key, &cursor_location.path_key);
+                if path_comparison.is_ne() {
+                    path_comparison
+                } else if let Some(snapshot) = snapshot {
+                    anchor.cmp(&cursor_location.max_anchor, snapshot)
+                } else {
+                    // shouldn't happen because we expect this buffer not to have any excerpts
+                    Ordering::Equal
+                }
+            }
         }
     }
 }

crates/multi_buffer/src/path_key.rs 🔗

@@ -211,9 +211,7 @@ impl MultiBuffer {
         let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>(());
         let mut sorted_anchors = sorted_anchors.into_iter().peekable();
         while let Some(anchor) = sorted_anchors.next() {
-            let Some(path) = snapshot.path_for_anchor(anchor) else {
-                continue;
-            };
+            let path = snapshot.path_for_anchor(anchor);
             let Some(buffer) = self.buffer_for_path(&path, cx) else {
                 continue;
             };
@@ -223,7 +221,7 @@ impl MultiBuffer {
             // 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).as_ref() == Some(&path)
+                && snapshot.path_for_anchor(anchor) == path
             {
                 sorted_anchors.next();
                 let Some(target) = snapshot.anchor_seek_target(anchor) else {