From b6722ca3c8de3921f150e83294e84fbc9bdb9016 Mon Sep 17 00:00:00 2001 From: Cole Miller Date: Wed, 20 Aug 2025 14:43:29 -0400 Subject: [PATCH] Remove special case for singleton buffers from `MultiBufferSnapshot::anchor_at` (#36524) This may be responsible for a panic that we've been seeing with increased frequency in agent2 threads. Release Notes: - N/A Co-authored-by: Conrad Irwin --- crates/editor/src/editor.rs | 8 +-- crates/multi_buffer/src/multi_buffer.rs | 66 +++++++++++++++---------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 45a90b843b..25fddf5cf1 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -4876,11 +4876,7 @@ impl Editor { cx: &mut Context, ) -> bool { let position = self.selections.newest_anchor().head(); - let multibuffer = self.buffer.read(cx); - let Some(buffer) = position - .buffer_id - .and_then(|buffer_id| multibuffer.buffer(buffer_id)) - else { + let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else { return false; }; @@ -5844,7 +5840,7 @@ impl Editor { multibuffer_anchor.start.to_offset(&snapshot) ..multibuffer_anchor.end.to_offset(&snapshot) }; - if newest_anchor.head().buffer_id != Some(buffer.remote_id()) { + if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) { return None; } diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 60e9c14c34..f73014a6ff 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -2196,6 +2196,15 @@ impl MultiBuffer { }) } + pub fn buffer_for_anchor(&self, anchor: Anchor, cx: &App) -> Option> { + if let Some(buffer_id) = anchor.buffer_id { + self.buffer(buffer_id) + } else { + let (_, buffer, _) = self.excerpt_containing(anchor, cx)?; + Some(buffer) + } + } + // If point is at the end of the buffer, the last excerpt is returned pub fn point_to_buffer_offset( &self, @@ -5228,15 +5237,6 @@ impl MultiBufferSnapshot { excerpt_offset += ExcerptOffset::new(offset_in_transform); }; - if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() { - return Anchor { - buffer_id: Some(buffer_id), - excerpt_id: *excerpt_id, - text_anchor: buffer.anchor_at(excerpt_offset.value, bias), - diff_base_anchor, - }; - } - let mut excerpts = self .excerpts .cursor::>>(&()); @@ -5260,10 +5260,17 @@ impl MultiBufferSnapshot { text_anchor, diff_base_anchor, } - } else if excerpt_offset.is_zero() && bias == Bias::Left { - Anchor::min() } else { - Anchor::max() + let mut anchor = if excerpt_offset.is_zero() && bias == Bias::Left { + Anchor::min() + } else { + Anchor::max() + }; + // TODO this is a hack, remove it + if let Some((excerpt_id, _, _)) = self.as_singleton() { + anchor.excerpt_id = *excerpt_id; + } + anchor } } @@ -6305,6 +6312,14 @@ impl MultiBufferSnapshot { }) } + pub fn buffer_id_for_anchor(&self, anchor: Anchor) -> Option { + if let Some(id) = anchor.buffer_id { + return Some(id); + } + let excerpt = self.excerpt_containing(anchor..anchor)?; + Some(excerpt.buffer_id()) + } + pub fn selections_in_range<'a>( &'a self, range: &'a Range, @@ -6983,19 +6998,20 @@ impl Excerpt { } fn contains(&self, anchor: &Anchor) -> bool { - Some(self.buffer_id) == anchor.buffer_id - && self - .range - .context - .start - .cmp(&anchor.text_anchor, &self.buffer) - .is_le() - && self - .range - .context - .end - .cmp(&anchor.text_anchor, &self.buffer) - .is_ge() + anchor.buffer_id == None + || anchor.buffer_id == Some(self.buffer_id) + && self + .range + .context + .start + .cmp(&anchor.text_anchor, &self.buffer) + .is_le() + && self + .range + .context + .end + .cmp(&anchor.text_anchor, &self.buffer) + .is_ge() } /// The [`Excerpt`]'s start offset in its [`Buffer`]