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 <conrad.irwin@gmail.com>
This commit is contained in:
Cole Miller 2025-08-20 14:43:29 -04:00 committed by GitHub
parent ec8106d1db
commit b6722ca3c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 43 additions and 31 deletions

View file

@ -4876,11 +4876,7 @@ impl Editor {
cx: &mut Context<Self>,
) -> 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;
}

View file

@ -2196,6 +2196,15 @@ impl MultiBuffer {
})
}
pub fn buffer_for_anchor(&self, anchor: Anchor, cx: &App) -> Option<Entity<Buffer>> {
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<T: ToOffset>(
&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::<Dimensions<ExcerptOffset, Option<ExcerptId>>>(&());
@ -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<BufferId> {
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<Anchor>,
@ -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`]