multi_buffer: Remove redundant buffer id field (#43459)

It is easy for us to get the two fields out of sync causing weird
problems, there is no reason to have both here so.

Release Notes:

- N/A *or* Added/Fixed/Improved ...

Co-authored by: Antonio Scandurra <antonio@zed.dev>
This commit is contained in:
Lukas Wirth
2025-11-25 17:13:16 +01:00
committed by GitHub
parent ab80ef1845
commit fafe1afa61
39 changed files with 378 additions and 306 deletions
+1 -1
View File
@@ -2976,7 +2976,7 @@ mod tests {
);
}
#[gpui::test(iterations = 100)]
#[gpui::test(iterations = 60)]
fn test_random_blocks(cx: &mut gpui::TestAppContext, mut rng: StdRng) {
cx.update(init_test);
+14 -21
View File
@@ -1780,7 +1780,7 @@ impl Editor {
let start_row = (multi_buffer_visible_start.row).min(max_row);
let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
let outline_items = buffer
.outline_items_containing(
Point::new(start_row, 0)..Point::new(end_row, 0),
@@ -1790,10 +1790,9 @@ impl Editor {
.into_iter()
.map(|outline_item| OutlineItem {
depth: outline_item.depth,
range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
source_range_for_text: Anchor::range_in_buffer(
*excerpt_id,
buffer_id,
outline_item.source_range_for_text,
),
text: outline_item.text,
@@ -1801,10 +1800,10 @@ impl Editor {
name_ranges: outline_item.name_ranges,
body_range: outline_item
.body_range
.map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
.map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
annotation_range: outline_item
.annotation_range
.map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
.map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
});
return Some(outline_items.collect());
}
@@ -3259,7 +3258,7 @@ impl Editor {
}
if local {
if let Some(buffer_id) = new_cursor_position.buffer_id {
if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
self.register_buffer(buffer_id, cx);
}
@@ -4198,8 +4197,8 @@ impl Editor {
continue;
}
if self.selections.disjoint_anchor_ranges().any(|s| {
if s.start.buffer_id != selection.start.buffer_id
|| s.end.buffer_id != selection.end.buffer_id
if s.start.text_anchor.buffer_id != selection.start.buffer_id
|| s.end.text_anchor.buffer_id != selection.end.buffer_id
{
return false;
}
@@ -5484,6 +5483,7 @@ impl Editor {
}
let buffer_position = multibuffer_snapshot.anchor_before(position);
let Some(buffer) = buffer_position
.text_anchor
.buffer_id
.and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
else {
@@ -6923,8 +6923,7 @@ impl Editor {
continue;
}
let range =
Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
if highlight.kind == lsp::DocumentHighlightKind::WRITE {
write_ranges.push(range);
} else {
@@ -7033,11 +7032,8 @@ impl Editor {
.anchor_after(search_range.start + match_range.start);
let match_end = buffer_snapshot
.anchor_before(search_range.start + match_range.end);
let match_anchor_range = Anchor::range_in_buffer(
excerpt_id,
buffer_snapshot.remote_id(),
match_start..match_end,
);
let match_anchor_range =
Anchor::range_in_buffer(excerpt_id, match_start..match_end);
(match_anchor_range != query_range).then_some(match_anchor_range)
}),
);
@@ -8212,8 +8208,7 @@ impl Editor {
cx,
);
for (breakpoint, state) in breakpoints {
let multi_buffer_anchor =
Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
let position = multi_buffer_anchor
.to_point(&multi_buffer_snapshot)
.to_display_point(&snapshot);
@@ -20804,8 +20799,7 @@ impl Editor {
let start = highlight.range.start.to_display_point(&snapshot);
let end = highlight.range.end.to_display_point(&snapshot);
let start_row = start.row().0;
let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
&& end.column() == 0
let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
{
end.row().0.saturating_sub(1)
} else {
@@ -21361,7 +21355,7 @@ impl Editor {
.for_each(|hint| {
let inlay = Inlay::debugger(
post_inc(&mut editor.next_inlay_id),
Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
Anchor::in_buffer(excerpt_id, hint.position),
hint.text(),
);
if !inlay.text().chars().contains(&'\n') {
@@ -24105,7 +24099,6 @@ impl EditorSnapshot {
display_row_range: hunk_display_start.row()..end_row,
multi_buffer_range: Anchor::range_in_buffer(
hunk.excerpt_id,
hunk.buffer_id,
hunk.buffer_range,
),
is_created_file,
+3 -6
View File
@@ -21550,10 +21550,9 @@ async fn test_adjacent_diff_hunks(executor: BackgroundExecutor, cx: &mut TestApp
.diff_hunks_in_ranges(&[Anchor::min()..Anchor::max()], &snapshot.buffer_snapshot())
.collect::<Vec<_>>();
let excerpt_id = editor.buffer.read(cx).excerpt_ids()[0];
let buffer_id = hunks[0].buffer_id;
hunks
.into_iter()
.map(|hunk| Anchor::range_in_buffer(excerpt_id, buffer_id, hunk.buffer_range))
.map(|hunk| Anchor::range_in_buffer(excerpt_id, hunk.buffer_range))
.collect::<Vec<_>>()
});
assert_eq!(hunk_ranges.len(), 2);
@@ -21641,10 +21640,9 @@ async fn test_adjacent_diff_hunks(executor: BackgroundExecutor, cx: &mut TestApp
.diff_hunks_in_ranges(&[Anchor::min()..Anchor::max()], &snapshot.buffer_snapshot())
.collect::<Vec<_>>();
let excerpt_id = editor.buffer.read(cx).excerpt_ids()[0];
let buffer_id = hunks[0].buffer_id;
hunks
.into_iter()
.map(|hunk| Anchor::range_in_buffer(excerpt_id, buffer_id, hunk.buffer_range))
.map(|hunk| Anchor::range_in_buffer(excerpt_id, hunk.buffer_range))
.collect::<Vec<_>>()
});
assert_eq!(hunk_ranges.len(), 2);
@@ -21707,10 +21705,9 @@ async fn test_toggle_deletion_hunk_at_start_of_file(
.diff_hunks_in_ranges(&[Anchor::min()..Anchor::max()], &snapshot.buffer_snapshot())
.collect::<Vec<_>>();
let excerpt_id = editor.buffer.read(cx).excerpt_ids()[0];
let buffer_id = hunks[0].buffer_id;
hunks
.into_iter()
.map(|hunk| Anchor::range_in_buffer(excerpt_id, buffer_id, hunk.buffer_range))
.map(|hunk| Anchor::range_in_buffer(excerpt_id, hunk.buffer_range))
.collect::<Vec<_>>()
});
assert_eq!(hunk_ranges.len(), 1);
+1 -1
View File
@@ -9283,7 +9283,7 @@ impl Element for EditorElement {
HashMap::default();
for selection in all_anchor_selections.iter() {
let head = selection.head();
if let Some(buffer_id) = head.buffer_id {
if let Some(buffer_id) = head.text_anchor.buffer_id {
anchors_by_buffer
.entry(buffer_id)
.and_modify(|(latest_id, latest_anchor)| {
+13 -6
View File
@@ -584,8 +584,11 @@ impl Editor {
})
.max_by_key(|hint| hint.id)
{
if let Some(ResolvedHint::Resolved(cached_hint)) =
hovered_hint.position.buffer_id.and_then(|buffer_id| {
if let Some(ResolvedHint::Resolved(cached_hint)) = hovered_hint
.position
.text_anchor
.buffer_id
.and_then(|buffer_id| {
lsp_store.update(cx, |lsp_store, cx| {
lsp_store.resolved_hint(buffer_id, hovered_hint.id, cx)
})
@@ -757,7 +760,7 @@ impl Editor {
let visible_inlay_hint_ids = self
.visible_inlay_hints(cx)
.iter()
.filter(|inlay| inlay.position.buffer_id == Some(buffer_id))
.filter(|inlay| inlay.position.text_anchor.buffer_id == Some(buffer_id))
.map(|inlay| inlay.id)
.collect::<Vec<_>>();
let Some(inlay_hints) = &mut self.inlay_hints else {
@@ -858,9 +861,13 @@ impl Editor {
self.visible_inlay_hints(cx)
.iter()
.filter(|inlay| {
inlay.position.buffer_id.is_none_or(|buffer_id| {
invalidate_hints_for_buffers.contains(&buffer_id)
})
inlay
.position
.text_anchor
.buffer_id
.is_none_or(|buffer_id| {
invalidate_hints_for_buffers.contains(&buffer_id)
})
})
.map(|inlay| inlay.id),
);
+15 -34
View File
@@ -455,21 +455,13 @@ async fn update_editor_from_message(
})??;
// Deserialize the editor state.
let (selections, pending_selection, scroll_top_anchor) = this.update(cx, |editor, cx| {
let buffer = editor.buffer.read(cx).read(cx);
let selections = message
.selections
.into_iter()
.filter_map(|selection| deserialize_selection(&buffer, selection))
.collect::<Vec<_>>();
let pending_selection = message
.pending_selection
.and_then(|selection| deserialize_selection(&buffer, selection));
let scroll_top_anchor = message
.scroll_top_anchor
.and_then(|anchor| deserialize_anchor(&buffer, anchor));
anyhow::Ok((selections, pending_selection, scroll_top_anchor))
})??;
let selections = message
.selections
.into_iter()
.filter_map(deserialize_selection)
.collect::<Vec<_>>();
let pending_selection = message.pending_selection.and_then(deserialize_selection);
let scroll_top_anchor = message.scroll_top_anchor.and_then(deserialize_anchor);
// Wait until the buffer has received all of the operations referenced by
// the editor's new state.
@@ -563,24 +555,20 @@ fn deserialize_excerpt_range(
))
}
fn deserialize_selection(
buffer: &MultiBufferSnapshot,
selection: proto::Selection,
) -> Option<Selection<Anchor>> {
fn deserialize_selection(selection: proto::Selection) -> Option<Selection<Anchor>> {
Some(Selection {
id: selection.id as usize,
start: deserialize_anchor(buffer, selection.start?)?,
end: deserialize_anchor(buffer, selection.end?)?,
start: deserialize_anchor(selection.start?)?,
end: deserialize_anchor(selection.end?)?,
reversed: selection.reversed,
goal: SelectionGoal::None,
})
}
fn deserialize_anchor(buffer: &MultiBufferSnapshot, anchor: proto::EditorAnchor) -> Option<Anchor> {
fn deserialize_anchor(anchor: proto::EditorAnchor) -> Option<Anchor> {
let excerpt_id = ExcerptId::from_proto(anchor.excerpt_id);
Some(Anchor::in_buffer(
excerpt_id,
buffer.buffer_id_for_excerpt(excerpt_id)?,
language::proto::deserialize_anchor(anchor.anchor?)?,
))
}
@@ -1374,7 +1362,7 @@ impl ProjectItem for Editor {
cx: &mut Context<Self>,
) -> Self {
let mut editor = Self::for_buffer(buffer.clone(), Some(project), window, cx);
if let Some((excerpt_id, buffer_id, snapshot)) =
if let Some((excerpt_id, _, snapshot)) =
editor.buffer().read(cx).snapshot(cx).as_singleton()
&& WorkspaceSettings::get(None, cx).restore_on_file_reopen
&& let Some(restoration_data) = Self::project_item_kind()
@@ -1397,11 +1385,8 @@ impl ProjectItem for Editor {
});
}
let (top_row, offset) = restoration_data.scroll_position;
let anchor = Anchor::in_buffer(
*excerpt_id,
buffer_id,
snapshot.anchor_before(Point::new(top_row, 0)),
);
let anchor =
Anchor::in_buffer(*excerpt_id, snapshot.anchor_before(Point::new(top_row, 0)));
editor.set_scroll_anchor(ScrollAnchor { anchor, offset }, window, cx);
}
@@ -1783,11 +1768,7 @@ impl SearchableItem for Editor {
.anchor_after(search_range.start + match_range.start);
let end = search_buffer
.anchor_before(search_range.start + match_range.end);
Anchor::range_in_buffer(
excerpt_id,
search_buffer.remote_id(),
start..end,
)
Anchor::range_in_buffer(excerpt_id, start..end)
}
}),
);
+2 -2
View File
@@ -70,8 +70,8 @@ pub(super) fn refresh_linked_ranges(
let cursor_position = selection.head();
let start_position = snapshot.anchor_before(cursor_position);
let end_position = snapshot.anchor_after(selection.tail());
if start_position.buffer_id != end_position.buffer_id
|| end_position.buffer_id.is_none()
if start_position.text_anchor.buffer_id != end_position.text_anchor.buffer_id
|| end_position.text_anchor.buffer_id.is_none()
{
// Throw away selections spanning multiple buffers.
continue;
+1 -1
View File
@@ -37,7 +37,7 @@ where
.selections
.disjoint_anchors_arc()
.iter()
.filter_map(|selection| Some((selection.head(), selection.head().buffer_id?)))
.filter_map(|selection| Some((selection.head(), selection.head().text_anchor.buffer_id?)))
.unique_by(|(_, buffer_id)| *buffer_id)
.find_map(|(trigger_anchor, buffer_id)| {
let buffer = editor.buffer().read(cx).buffer(buffer_id)?;
+15 -3
View File
@@ -322,7 +322,11 @@ fn cancel_flycheck_action(
.disjoint_anchors_arc()
.iter()
.find_map(|selection| {
let buffer_id = selection.start.buffer_id.or(selection.end.buffer_id)?;
let buffer_id = selection
.start
.text_anchor
.buffer_id
.or(selection.end.text_anchor.buffer_id)?;
let project = project.read(cx);
let entry_id = project
.buffer_for_id(buffer_id, cx)?
@@ -347,7 +351,11 @@ fn run_flycheck_action(
.disjoint_anchors_arc()
.iter()
.find_map(|selection| {
let buffer_id = selection.start.buffer_id.or(selection.end.buffer_id)?;
let buffer_id = selection
.start
.text_anchor
.buffer_id
.or(selection.end.text_anchor.buffer_id)?;
let project = project.read(cx);
let entry_id = project
.buffer_for_id(buffer_id, cx)?
@@ -372,7 +380,11 @@ fn clear_flycheck_action(
.disjoint_anchors_arc()
.iter()
.find_map(|selection| {
let buffer_id = selection.start.buffer_id.or(selection.end.buffer_id)?;
let buffer_id = selection
.start
.text_anchor
.buffer_id
.or(selection.end.text_anchor.buffer_id)?;
let project = project.read(cx);
let entry_id = project
.buffer_for_id(buffer_id, cx)?
+2 -10
View File
@@ -490,11 +490,7 @@ impl EditorTestContext {
);
assert_eq!(
multibuffer_snapshot
.text_for_range(Anchor::range_in_buffer(
excerpt_id,
snapshot.remote_id(),
range.context.clone()
))
.text_for_range(Anchor::range_in_buffer(excerpt_id, range.context.clone()))
.collect::<String>(),
expected_text,
"{}",
@@ -675,11 +671,7 @@ impl std::fmt::Display for FormatMultiBufferAsMarkedText {
}
let mut text = multibuffer_snapshot
.text_for_range(Anchor::range_in_buffer(
*excerpt_id,
snapshot.remote_id(),
range.context.clone(),
))
.text_for_range(Anchor::range_in_buffer(*excerpt_id, range.context.clone()))
.collect::<String>();
let selections = selections