diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 2e097a56530dda803a2f7062e99f1a3a8818e1fb..fd17819d73040b55eb5816a4af36797a3dbc6d1a 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -4957,11 +4957,10 @@ impl MultiBufferSnapshot { + Add, MBD::TextDimension: Sub + 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::((), locator, Bias::Left); + .find::((), &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<::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 { + 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 { + 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, }, } @@ -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 + } + } } } } diff --git a/crates/multi_buffer/src/path_key.rs b/crates/multi_buffer/src/path_key.rs index 18e729c18de341a9789e44d572a528a1aab68c5f..62bdc9f7ff14d5101b2bcd0b5b51e0c9e2da4a15 100644 --- a/crates/multi_buffer/src/path_key.rs +++ b/crates/multi_buffer/src/path_key.rs @@ -211,9 +211,7 @@ impl MultiBuffer { let mut cursor = snapshot.excerpts.cursor::(()); 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 {