Detailed changes
@@ -347,13 +347,13 @@ impl ToolCall {
let buffer = buffer.await.log_err()?;
let position = buffer
.update(cx, |buffer, _| {
+ let snapshot = buffer.snapshot();
if let Some(row) = location.line {
- let snapshot = buffer.snapshot();
let column = snapshot.indent_size_for_line(row).len;
let point = snapshot.clip_point(Point::new(row, column), Bias::Left);
snapshot.anchor_before(point)
} else {
- Anchor::MIN
+ Anchor::min_for_buffer(snapshot.remote_id())
}
})
.ok()?;
@@ -2120,7 +2120,7 @@ impl AcpThread {
position: edits
.last()
.map(|(range, _)| range.end)
- .unwrap_or(Anchor::MIN),
+ .unwrap_or(Anchor::min_for_buffer(buffer.read(cx).remote_id())),
}),
cx,
);
@@ -50,9 +50,14 @@ impl Diff {
let hunk_ranges = {
let buffer = buffer.read(cx);
let diff = diff.read(cx);
- diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, buffer, cx)
- .map(|diff_hunk| diff_hunk.buffer_range.to_point(buffer))
- .collect::<Vec<_>>()
+ diff.hunks_intersecting_range(
+ Anchor::min_for_buffer(buffer.remote_id())
+ ..Anchor::max_for_buffer(buffer.remote_id()),
+ buffer,
+ cx,
+ )
+ .map(|diff_hunk| diff_hunk.buffer_range.to_point(buffer))
+ .collect::<Vec<_>>()
};
multibuffer.set_excerpts_for_path(
@@ -316,7 +321,12 @@ impl PendingDiff {
let buffer = self.new_buffer.read(cx);
let diff = self.diff.read(cx);
let mut ranges = diff
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, buffer, cx)
+ .hunks_intersecting_range(
+ Anchor::min_for_buffer(buffer.remote_id())
+ ..Anchor::max_for_buffer(buffer.remote_id()),
+ buffer,
+ cx,
+ )
.map(|diff_hunk| diff_hunk.buffer_range.to_point(buffer))
.collect::<Vec<_>>();
ranges.extend(
@@ -409,9 +409,11 @@ impl ActionLog {
let new_diff_base = new_diff_base.clone();
async move {
let mut unreviewed_edits = Patch::default();
- for hunk in diff_snapshot
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer_snapshot)
- {
+ for hunk in diff_snapshot.hunks_intersecting_range(
+ Anchor::min_for_buffer(buffer_snapshot.remote_id())
+ ..Anchor::max_for_buffer(buffer_snapshot.remote_id()),
+ &buffer_snapshot,
+ ) {
let old_range = new_diff_base
.offset_to_point(hunk.diff_base_byte_range.start)
..new_diff_base.offset_to_point(hunk.diff_base_byte_range.end);
@@ -732,12 +734,10 @@ impl ActionLog {
cx: &mut Context<Self>,
) -> Task<()> {
let futures = self.changed_buffers(cx).into_keys().map(|buffer| {
- let reject = self.reject_edits_in_ranges(
- buffer,
- vec![Anchor::MIN..Anchor::MAX],
- telemetry.clone(),
- cx,
- );
+ let buffer_ranges = vec![Anchor::min_max_range_for_buffer(
+ buffer.read(cx).remote_id(),
+ )];
+ let reject = self.reject_edits_in_ranges(buffer, buffer_ranges, telemetry.clone(), cx);
async move {
reject.await.log_err();
@@ -2010,7 +2010,8 @@ mod tests {
// User accepts the single hunk
action_log.update(cx, |log, cx| {
- log.keep_edits_in_range(buffer.clone(), Anchor::MIN..Anchor::MAX, None, cx)
+ let buffer_range = Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id());
+ log.keep_edits_in_range(buffer.clone(), buffer_range, None, cx)
});
cx.run_until_parked();
assert_eq!(unreviewed_hunks(&action_log, cx), vec![]);
@@ -2031,7 +2032,14 @@ mod tests {
// User rejects the hunk
action_log
.update(cx, |log, cx| {
- log.reject_edits_in_ranges(buffer.clone(), vec![Anchor::MIN..Anchor::MAX], None, cx)
+ log.reject_edits_in_ranges(
+ buffer.clone(),
+ vec![Anchor::min_max_range_for_buffer(
+ buffer.read(cx).remote_id(),
+ )],
+ None,
+ cx,
+ )
})
.await
.unwrap();
@@ -172,14 +172,14 @@ impl EditAgent {
project.set_agent_location(
Some(AgentLocation {
buffer: buffer.downgrade(),
- position: language::Anchor::MAX,
+ position: language::Anchor::max_for_buffer(buffer.read(cx).remote_id()),
}),
cx,
)
});
output_events_tx
.unbounded_send(EditAgentOutputEvent::Edited(
- language::Anchor::MIN..language::Anchor::MAX,
+ Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
))
.ok();
})?;
@@ -187,7 +187,7 @@ impl EditAgent {
while let Some(event) = parse_rx.next().await {
match event? {
CreateFileParserEvent::NewTextChunk { chunk } => {
- cx.update(|cx| {
+ let buffer_id = cx.update(|cx| {
buffer.update(cx, |buffer, cx| buffer.append(chunk, cx));
self.action_log
.update(cx, |log, cx| log.buffer_edited(buffer.clone(), cx));
@@ -195,15 +195,18 @@ impl EditAgent {
project.set_agent_location(
Some(AgentLocation {
buffer: buffer.downgrade(),
- position: language::Anchor::MAX,
+ position: language::Anchor::max_for_buffer(
+ buffer.read(cx).remote_id(),
+ ),
}),
cx,
)
});
+ buffer.read(cx).remote_id()
})?;
output_events_tx
.unbounded_send(EditAgentOutputEvent::Edited(
- language::Anchor::MIN..language::Anchor::MAX,
+ Anchor::min_max_range_for_buffer(buffer_id),
))
.ok();
}
@@ -1200,7 +1203,9 @@ mod tests {
project.read_with(cx, |project, _| project.agent_location()),
Some(AgentLocation {
buffer: buffer.downgrade(),
- position: language::Anchor::MAX
+ position: language::Anchor::max_for_buffer(
+ cx.update(|cx| buffer.read(cx).remote_id())
+ ),
})
);
@@ -1218,7 +1223,9 @@ mod tests {
project.read_with(cx, |project, _| project.agent_location()),
Some(AgentLocation {
buffer: buffer.downgrade(),
- position: language::Anchor::MAX
+ position: language::Anchor::max_for_buffer(
+ cx.update(|cx| buffer.read(cx).remote_id())
+ ),
})
);
@@ -1236,7 +1243,9 @@ mod tests {
project.read_with(cx, |project, _| project.agent_location()),
Some(AgentLocation {
buffer: buffer.downgrade(),
- position: language::Anchor::MAX
+ position: language::Anchor::max_for_buffer(
+ cx.update(|cx| buffer.read(cx).remote_id())
+ ),
})
);
@@ -1254,7 +1263,9 @@ mod tests {
project.read_with(cx, |project, _| project.agent_location()),
Some(AgentLocation {
buffer: buffer.downgrade(),
- position: language::Anchor::MAX
+ position: language::Anchor::max_for_buffer(
+ cx.update(|cx| buffer.read(cx).remote_id())
+ ),
})
);
@@ -1269,7 +1280,9 @@ mod tests {
project.read_with(cx, |project, _| project.agent_location()),
Some(AgentLocation {
buffer: buffer.downgrade(),
- position: language::Anchor::MAX
+ position: language::Anchor::max_for_buffer(
+ cx.update(|cx| buffer.read(cx).remote_id())
+ ),
})
);
}
@@ -275,7 +275,9 @@ impl AgentTool for ReadFileTool {
project.set_agent_location(
Some(AgentLocation {
buffer: buffer.downgrade(),
- position: anchor.unwrap_or(text::Anchor::MIN),
+ position: anchor.unwrap_or_else(|| {
+ text::Anchor::min_for_buffer(buffer.read(cx).remote_id())
+ }),
}),
cx,
);
@@ -4103,7 +4103,9 @@ impl AcpThreadView {
action_log
.reject_edits_in_ranges(
buffer.clone(),
- vec![Anchor::MIN..Anchor::MAX],
+ vec![Anchor::min_max_range_for_buffer(
+ buffer.read(cx).remote_id(),
+ )],
Some(telemetry.clone()),
cx,
)
@@ -4124,7 +4126,9 @@ impl AcpThreadView {
action_log.update(cx, |action_log, cx| {
action_log.keep_edits_in_range(
buffer.clone(),
- Anchor::MIN..Anchor::MAX,
+ Anchor::min_max_range_for_buffer(
+ buffer.read(cx).remote_id(),
+ ),
Some(telemetry.clone()),
cx,
);
@@ -4743,11 +4747,8 @@ impl AcpThreadView {
let buffer = multibuffer.as_singleton();
if agent_location.buffer.upgrade() == buffer {
let excerpt_id = multibuffer.excerpt_ids().first().cloned();
- let anchor = editor::Anchor::in_buffer(
- excerpt_id.unwrap(),
- buffer.unwrap().read(cx).remote_id(),
- agent_location.position,
- );
+ let anchor =
+ editor::Anchor::in_buffer(excerpt_id.unwrap(), agent_location.position);
editor.change_selections(Default::default(), window, cx, |selections| {
selections.select_anchor_ranges([anchor..anchor]);
})
@@ -145,7 +145,7 @@ impl AgentDiffPane {
let diff_hunk_ranges = diff
.hunks_intersecting_range(
- language::Anchor::MIN..language::Anchor::MAX,
+ language::Anchor::min_max_range_for_buffer(snapshot.remote_id()),
&snapshot,
cx,
)
@@ -440,7 +440,6 @@ impl InlineAssistant {
{
let anchor_range = Anchor::range_in_buffer(
excerpt_id,
- buffer.remote_id(),
buffer.anchor_before(buffer_range.start)..buffer.anchor_after(buffer_range.end),
);
@@ -797,7 +797,7 @@ impl TextThread {
});
let message = MessageAnchor {
id: first_message_id,
- start: language::Anchor::MIN,
+ start: language::Anchor::min_for_buffer(this.buffer.read(cx).remote_id()),
};
this.messages_metadata.insert(
first_message_id,
@@ -1147,12 +1147,10 @@ impl TextThread {
cx: &App,
) -> bool {
let version = &self.buffer.read(cx).version;
- let observed_start = range.start == language::Anchor::MIN
- || range.start == language::Anchor::MAX
- || version.observed(range.start.timestamp);
- let observed_end = range.end == language::Anchor::MIN
- || range.end == language::Anchor::MAX
- || version.observed(range.end.timestamp);
+ let observed_start =
+ range.start.is_min() || range.start.is_max() || version.observed(range.start.timestamp);
+ let observed_end =
+ range.end.is_min() || range.end.is_max() || version.observed(range.end.timestamp);
observed_start && observed_end
}
@@ -2858,7 +2856,8 @@ impl TextThread {
messages.next();
}
}
- let message_end_anchor = message_end.unwrap_or(language::Anchor::MAX);
+ let message_end_anchor =
+ message_end.unwrap_or(language::Anchor::max_for_buffer(buffer.remote_id()));
let message_end = message_end_anchor.to_offset(buffer);
return Some(Message {
@@ -153,6 +153,10 @@ impl std::fmt::Debug for BufferDiffInner {
}
impl BufferDiffSnapshot {
+ pub fn buffer_diff_id(&self) -> BufferId {
+ self.inner.base_text.remote_id()
+ }
+
fn empty(buffer: &text::BufferSnapshot, cx: &mut App) -> BufferDiffSnapshot {
BufferDiffSnapshot {
inner: BufferDiffInner {
@@ -340,7 +344,7 @@ impl BufferDiffInner {
};
let hunk = PendingHunk {
- buffer_range: Anchor::MIN..Anchor::MAX,
+ buffer_range: Anchor::min_max_range_for_buffer(buffer.remote_id()),
diff_base_byte_range: 0..index_text.map_or(0, |rope| rope.len()),
buffer_version: buffer.version().clone(),
new_status,
@@ -780,7 +784,7 @@ fn compute_hunks(
} else {
tree.push(
InternalDiffHunk {
- buffer_range: Anchor::MIN..Anchor::MAX,
+ buffer_range: Anchor::min_max_range_for_buffer(buffer.remote_id()),
diff_base_byte_range: 0..0,
},
&buffer,
@@ -941,10 +945,10 @@ impl BufferDiff {
pub fn clear_pending_hunks(&mut self, cx: &mut Context<Self>) {
if self.secondary_diff.is_some() {
self.inner.pending_hunks = SumTree::from_summary(DiffHunkSummary {
- buffer_range: Anchor::MIN..Anchor::MIN,
+ buffer_range: Anchor::min_min_range_for_buffer(self.buffer_id),
});
cx.emit(BufferDiffEvent::DiffChanged {
- changed_range: Some(Anchor::MIN..Anchor::MAX),
+ changed_range: Some(Anchor::min_max_range_for_buffer(self.buffer_id)),
});
}
}
@@ -1065,7 +1069,10 @@ impl BufferDiff {
{
(false, new_state.compare(state, buffer))
}
- _ => (true, Some(text::Anchor::MIN..text::Anchor::MAX)),
+ _ => (
+ true,
+ Some(text::Anchor::min_max_range_for_buffer(self.buffer_id)),
+ ),
};
if let Some(secondary_changed_range) = secondary_diff_change
@@ -1126,7 +1133,11 @@ impl BufferDiff {
buffer_snapshot: &'a text::BufferSnapshot,
cx: &'a App,
) -> impl 'a + Iterator<Item = DiffHunk> {
- self.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, buffer_snapshot, cx)
+ self.hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(buffer_snapshot.remote_id()),
+ buffer_snapshot,
+ cx,
+ )
}
pub fn hunks_intersecting_range<'a>(
@@ -1222,7 +1233,9 @@ impl BufferDiff {
impl DiffHunk {
pub fn is_created_file(&self) -> bool {
- self.diff_base_byte_range == (0..0) && self.buffer_range == (Anchor::MIN..Anchor::MAX)
+ self.diff_base_byte_range == (0..0)
+ && self.buffer_range.start.is_min()
+ && self.buffer_range.end.is_min()
}
pub fn status(&self) -> DiffHunkStatus {
@@ -1389,7 +1402,10 @@ mod tests {
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text);
let mut diff = BufferDiffSnapshot::new_sync(buffer.clone(), diff_base.clone(), cx);
assert_hunks(
- diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer),
+ diff.hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(buffer.remote_id()),
+ &buffer,
+ ),
&buffer,
&diff_base,
&[(1..2, "two\n", "HELLO\n", DiffHunkStatus::modified_none())],
@@ -1398,7 +1414,10 @@ mod tests {
buffer.edit([(0..0, "point five\n")]);
diff = BufferDiffSnapshot::new_sync(buffer.clone(), diff_base.clone(), cx);
assert_hunks(
- diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer),
+ diff.hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(buffer.remote_id()),
+ &buffer,
+ ),
&buffer,
&diff_base,
&[
@@ -1409,7 +1428,10 @@ mod tests {
diff = cx.update(|cx| BufferDiffSnapshot::empty(&buffer, cx));
assert_hunks::<&str, _>(
- diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer),
+ diff.hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(buffer.remote_id()),
+ &buffer,
+ ),
&buffer,
&diff_base,
&[],
@@ -1483,7 +1505,10 @@ mod tests {
];
assert_hunks(
- uncommitted_diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer),
+ uncommitted_diff.hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(buffer.remote_id()),
+ &buffer,
+ ),
&buffer,
&head_text,
&expected_hunks,
@@ -1542,8 +1567,11 @@ mod tests {
})
.await;
assert_eq!(
- diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer)
- .count(),
+ diff.hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(buffer.remote_id()),
+ &buffer
+ )
+ .count(),
8
);
@@ -2155,8 +2183,12 @@ mod tests {
let mut diff = uncommitted_diff(&working_copy, &index_text, head_text.clone(), cx);
let mut hunks = diff.update(cx, |diff, cx| {
- diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &working_copy, cx)
- .collect::<Vec<_>>()
+ diff.hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(diff.buffer_id),
+ &working_copy,
+ cx,
+ )
+ .collect::<Vec<_>>()
});
if hunks.is_empty() {
return;
@@ -2185,8 +2217,12 @@ mod tests {
diff = uncommitted_diff(&working_copy, &index_text, head_text.clone(), cx);
let found_hunks = diff.update(cx, |diff, cx| {
- diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &working_copy, cx)
- .collect::<Vec<_>>()
+ diff.hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(diff.buffer_id),
+ &working_copy,
+ cx,
+ )
+ .collect::<Vec<_>>()
});
assert_eq!(hunks.len(), found_hunks.len());
@@ -1581,7 +1581,10 @@ async fn test_share_project(
buffer_a.read_with(cx_a, |buffer, _| {
buffer
.snapshot()
- .selections_in_range(text::Anchor::MIN..text::Anchor::MAX, false)
+ .selections_in_range(
+ text::Anchor::min_max_range_for_buffer(buffer.remote_id()),
+ false,
+ )
.count()
== 1
});
@@ -1622,7 +1625,10 @@ async fn test_share_project(
buffer_a.read_with(cx_a, |buffer, _| {
buffer
.snapshot()
- .selections_in_range(text::Anchor::MIN..text::Anchor::MAX, false)
+ .selections_in_range(
+ text::Anchor::min_max_range_for_buffer(buffer.remote_id()),
+ false,
+ )
.count()
== 0
});
@@ -284,7 +284,7 @@ impl DiagnosticBlock {
if range.context.overlaps(&diagnostic.range, &snapshot) {
Self::jump_to(
editor,
- Anchor::range_in_buffer(excerpt_id, buffer_id, diagnostic.range),
+ Anchor::range_in_buffer(excerpt_id, diagnostic.range),
window,
cx,
);
@@ -308,7 +308,7 @@ impl ProjectDiagnosticsEditor {
.selections
.all_anchors(&snapshot)
.iter()
- .filter_map(|anchor| anchor.start.buffer_id)
+ .filter_map(|anchor| anchor.start.text_anchor.buffer_id)
.collect::<HashSet<_>>()
});
for buffer_id in buffer_ids {
@@ -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);
@@ -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,
@@ -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);
@@ -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)| {
@@ -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),
);
@@ -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)
}
}),
);
@@ -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;
@@ -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)?;
@@ -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)?
@@ -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
@@ -223,7 +223,11 @@ impl CommitView {
let snapshot = buffer.read(cx).snapshot();
let diff = buffer_diff.read(cx);
let diff_hunk_ranges = diff
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot, cx)
+ .hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(diff.buffer_id),
+ &snapshot,
+ cx,
+ )
.map(|diff_hunk| diff_hunk.buffer_range.to_point(&snapshot))
.collect::<Vec<_>>();
let path = snapshot.file().unwrap().path().clone();
@@ -383,12 +383,8 @@ impl ProjectDiff {
.collect::<Vec<_>>();
if !ranges.iter().any(|range| range.start != range.end) {
selection = false;
- if let Some((excerpt_id, buffer, range)) = self.editor.read(cx).active_excerpt(cx) {
- ranges = vec![multi_buffer::Anchor::range_in_buffer(
- excerpt_id,
- buffer.read(cx).remote_id(),
- range,
- )];
+ if let Some((excerpt_id, _, range)) = self.editor.read(cx).active_excerpt(cx) {
+ ranges = vec![multi_buffer::Anchor::range_in_buffer(excerpt_id, range)];
} else {
ranges = Vec::default();
}
@@ -488,7 +484,11 @@ impl ProjectDiff {
let snapshot = buffer.read(cx).snapshot();
let diff_read = diff.read(cx);
let diff_hunk_ranges = diff_read
- .hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot, cx)
+ .hunks_intersecting_range(
+ Anchor::min_max_range_for_buffer(diff_read.buffer_id),
+ &snapshot,
+ cx,
+ )
.map(|diff_hunk| diff_hunk.buffer_range);
let conflicts = conflict_addon
.conflict_set(snapshot.remote_id())
@@ -3427,7 +3427,7 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
for buffer in &buffers {
let buffer = buffer.read(cx).snapshot();
let actual_remote_selections = buffer
- .selections_in_range(Anchor::MIN..Anchor::MAX, false)
+ .selections_in_range(Anchor::min_max_range_for_buffer(buffer.remote_id()), false)
.map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
.collect::<Vec<_>>();
let expected_remote_selections = active_selections
@@ -330,7 +330,7 @@ impl SyntaxSnapshot {
let slice = cursor.slice(
&SyntaxLayerPosition {
depth: depth + 1,
- range: Anchor::MIN..Anchor::MAX,
+ range: Anchor::min_max_range_for_buffer(text.remote_id()),
language: None,
},
Bias::Left,
@@ -493,7 +493,7 @@ impl SyntaxSnapshot {
start_point: Point::zero().to_ts_point(),
end_point: text.max_point().to_ts_point(),
}],
- range: Anchor::MIN..Anchor::MAX,
+ range: Anchor::min_max_range_for_buffer(text.remote_id()),
mode: ParseMode::Single,
});
@@ -515,7 +515,7 @@ impl SyntaxSnapshot {
} else {
SyntaxLayerPosition {
depth: max_depth + 1,
- range: Anchor::MAX..Anchor::MAX,
+ range: Anchor::min_max_range_for_buffer(text.remote_id()),
language: None,
}
};
@@ -7,12 +7,9 @@ use std::{
ops::{AddAssign, Range, Sub},
};
use sum_tree::Bias;
-use text::BufferId;
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct Anchor {
- /// Invariant: If buffer id is `None`, excerpt id must be `ExcerptId::min()` or `ExcerptId::max()`.
- pub buffer_id: Option<BufferId>,
pub excerpt_id: ExcerptId,
pub text_anchor: text::Anchor,
pub diff_base_anchor: Option<text::Anchor>,
@@ -20,15 +17,14 @@ pub struct Anchor {
impl std::fmt::Debug for Anchor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- if *self == Self::min() {
- return f.write_str("Anchor::MIN");
+ if self.is_min() {
+ return write!(f, "Anchor::min({:?})", self.text_anchor.buffer_id);
}
- if *self == Self::max() {
- return f.write_str("Anchor::MAX");
+ if self.is_max() {
+ return write!(f, "Anchor::max({:?})", self.text_anchor.buffer_id);
}
f.debug_struct("Anchor")
- .field("buffer_id", &self.buffer_id)
.field("excerpt_id", &self.excerpt_id)
.field("text_anchor", &self.text_anchor)
.field("diff_base_anchor", &self.diff_base_anchor)
@@ -44,35 +40,20 @@ impl Anchor {
}
}
- pub fn in_buffer(
- excerpt_id: ExcerptId,
- buffer_id: BufferId,
- text_anchor: text::Anchor,
- ) -> Self {
- debug_assert!(
- text_anchor.buffer_id.is_none_or(|id| id == buffer_id),
- "buffer id does not match the one in the text anchor: {buffer_id:?} {text_anchor:?}",
- );
+ pub fn in_buffer(excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Self {
Self {
- buffer_id: Some(buffer_id),
excerpt_id,
text_anchor,
diff_base_anchor: None,
}
}
- pub fn range_in_buffer(
- excerpt_id: ExcerptId,
- buffer_id: BufferId,
- range: Range<text::Anchor>,
- ) -> Range<Self> {
- Self::in_buffer(excerpt_id, buffer_id, range.start)
- ..Self::in_buffer(excerpt_id, buffer_id, range.end)
+ pub fn range_in_buffer(excerpt_id: ExcerptId, range: Range<text::Anchor>) -> Range<Self> {
+ Self::in_buffer(excerpt_id, range.start)..Self::in_buffer(excerpt_id, range.end)
}
pub fn min() -> Self {
Self {
- buffer_id: None,
excerpt_id: ExcerptId::min(),
text_anchor: text::Anchor::MIN,
diff_base_anchor: None,
@@ -81,13 +62,24 @@ impl Anchor {
pub fn max() -> Self {
Self {
- buffer_id: None,
excerpt_id: ExcerptId::max(),
text_anchor: text::Anchor::MAX,
diff_base_anchor: None,
}
}
+ pub fn is_min(&self) -> bool {
+ self.excerpt_id == ExcerptId::min()
+ && self.text_anchor.is_min()
+ && self.diff_base_anchor.is_none()
+ }
+
+ pub fn is_max(&self) -> bool {
+ self.excerpt_id == ExcerptId::max()
+ && self.text_anchor.is_max()
+ && self.diff_base_anchor.is_none()
+ }
+
pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
if self == other {
return Ordering::Equal;
@@ -101,8 +93,8 @@ impl Anchor {
return excerpt_id_cmp;
}
if self_excerpt_id == ExcerptId::max()
- && self.text_anchor == text::Anchor::MAX
- && self.text_anchor == text::Anchor::MAX
+ && self.text_anchor.is_max()
+ && self.text_anchor.is_max()
&& self.diff_base_anchor.is_none()
&& other.diff_base_anchor.is_none()
{
@@ -147,7 +139,6 @@ impl Anchor {
&& let Some(excerpt) = snapshot.excerpt(self.excerpt_id)
{
return Self {
- buffer_id: Some(excerpt.buffer_id),
excerpt_id: excerpt.id,
text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
diff_base_anchor: self.diff_base_anchor.map(|a| {
@@ -171,7 +162,6 @@ impl Anchor {
&& let Some(excerpt) = snapshot.excerpt(self.excerpt_id)
{
return Self {
- buffer_id: Some(excerpt.buffer_id),
excerpt_id: excerpt.id,
text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
diff_base_anchor: self.diff_base_anchor.map(|a| {
@@ -202,8 +192,8 @@ impl Anchor {
}
pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool {
- if *self == Anchor::min() || self.excerpt_id == ExcerptId::max() {
- !snapshot.is_empty()
+ if self.is_min() || self.is_max() {
+ true
} else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
(self.text_anchor == excerpt.range.context.start
|| self.text_anchor == excerpt.range.context.end
@@ -158,12 +158,13 @@ impl MultiBufferDiffHunk {
pub fn is_created_file(&self) -> bool {
self.diff_base_byte_range == (BufferOffset(0)..BufferOffset(0))
- && self.buffer_range == (text::Anchor::MIN..text::Anchor::MAX)
+ && self.buffer_range.start.is_min()
+ && self.buffer_range.end.is_max()
}
pub fn multi_buffer_range(&self) -> Range<Anchor> {
- let start = Anchor::in_buffer(self.excerpt_id, self.buffer_id, self.buffer_range.start);
- let end = Anchor::in_buffer(self.excerpt_id, self.buffer_id, self.buffer_range.end);
+ let start = Anchor::in_buffer(self.excerpt_id, self.buffer_range.start);
+ let end = Anchor::in_buffer(self.excerpt_id, self.buffer_range.end);
start..end
}
}
@@ -1028,9 +1029,12 @@ impl MultiBuffer {
},
);
this.singleton = true;
+ let buffer_id = buffer.read(cx).remote_id();
this.push_excerpts(
buffer,
- [ExcerptRange::new(text::Anchor::MIN..text::Anchor::MAX)],
+ [ExcerptRange::new(text::Anchor::min_max_range_for_buffer(
+ buffer_id,
+ ))],
cx,
);
this
@@ -1912,7 +1916,7 @@ impl MultiBuffer {
}
pub fn buffer_for_anchor(&self, anchor: Anchor, cx: &App) -> Option<Entity<Buffer>> {
- if let Some(buffer_id) = anchor.buffer_id {
+ if let Some(buffer_id) = anchor.text_anchor.buffer_id {
self.buffer(buffer_id)
} else {
let (_, buffer, _) = self.excerpt_containing(anchor, cx)?;
@@ -1975,7 +1979,7 @@ impl MultiBuffer {
found.map(|(point, excerpt_id)| {
let text_anchor = snapshot.anchor_after(point);
- Anchor::in_buffer(excerpt_id, snapshot.remote_id(), text_anchor)
+ Anchor::in_buffer(excerpt_id, text_anchor)
})
}
@@ -1990,7 +1994,7 @@ impl MultiBuffer {
if range.context.start.cmp(&anchor, &snapshot).is_le()
&& range.context.end.cmp(&anchor, &snapshot).is_ge()
{
- return Some(Anchor::in_buffer(excerpt_id, snapshot.remote_id(), anchor));
+ return Some(Anchor::in_buffer(excerpt_id, anchor));
}
}
@@ -2112,7 +2116,7 @@ impl MultiBuffer {
let mut error = None;
let mut futures = Vec::new();
for anchor in anchors {
- if let Some(buffer_id) = anchor.buffer_id {
+ if let Some(buffer_id) = anchor.text_anchor.buffer_id {
if let Some(buffer) = self.buffers.get(&buffer_id) {
buffer.buffer.update(cx, |buffer, _| {
futures.push(buffer.wait_for_anchors([anchor.text_anchor]))
@@ -2143,7 +2147,11 @@ impl MultiBuffer {
) -> Option<(Entity<Buffer>, language::Anchor)> {
let snapshot = self.read(cx);
let anchor = snapshot.anchor_before(position);
- let buffer = self.buffers.get(&anchor.buffer_id?)?.buffer.clone();
+ let buffer = self
+ .buffers
+ .get(&anchor.text_anchor.buffer_id?)?
+ .buffer
+ .clone();
Some((buffer, anchor.text_anchor))
}
@@ -2205,7 +2213,7 @@ impl MultiBuffer {
.get(&buffer_id)
.is_none_or(|old_diff| !new_diff.base_texts_eq(old_diff));
- snapshot.diffs.insert(buffer_id, new_diff);
+ snapshot.diffs.insert_or_replace(buffer_id, new_diff);
let mut excerpt_edits = Vec::new();
for locator in &buffer_state.excerpts {
@@ -2402,7 +2410,11 @@ impl MultiBuffer {
pub fn add_diff(&mut self, diff: Entity<BufferDiff>, cx: &mut Context<Self>) {
let buffer_id = diff.read(cx).buffer_id;
- self.buffer_diff_changed(diff.clone(), text::Anchor::MIN..text::Anchor::MAX, cx);
+ self.buffer_diff_changed(
+ diff.clone(),
+ text::Anchor::min_max_range_for_buffer(buffer_id),
+ cx,
+ );
self.diffs.insert(buffer_id, DiffState::new(diff, cx));
}
@@ -2500,16 +2512,8 @@ impl MultiBuffer {
if last_hunk_row.is_some_and(|row| row >= diff_hunk.row_range.start) {
continue;
}
- let start = Anchor::in_buffer(
- diff_hunk.excerpt_id,
- diff_hunk.buffer_id,
- diff_hunk.buffer_range.start,
- );
- let end = Anchor::in_buffer(
- diff_hunk.excerpt_id,
- diff_hunk.buffer_id,
- diff_hunk.buffer_range.end,
- );
+ let start = Anchor::in_buffer(diff_hunk.excerpt_id, diff_hunk.buffer_range.start);
+ let end = Anchor::in_buffer(diff_hunk.excerpt_id, diff_hunk.buffer_range.end);
let start = snapshot.excerpt_offset_for_anchor(&start);
let end = snapshot.excerpt_offset_for_anchor(&end);
last_hunk_row = Some(diff_hunk.row_range.start);
@@ -3945,9 +3949,7 @@ impl MultiBufferSnapshot {
if hunk_end >= current_position {
continue;
}
- let start =
- Anchor::in_buffer(excerpt.id, excerpt.buffer_id, hunk.buffer_range.start)
- .to_point(self);
+ let start = Anchor::in_buffer(excerpt.id, hunk.buffer_range.start).to_point(self);
return Some(MultiBufferRow(start.row));
}
}
@@ -3964,8 +3966,7 @@ impl MultiBufferSnapshot {
let Some(hunk) = hunks.next() else {
continue;
};
- let start = Anchor::in_buffer(excerpt.id, excerpt.buffer_id, hunk.buffer_range.start)
- .to_point(self);
+ let start = Anchor::in_buffer(excerpt.id, hunk.buffer_range.start).to_point(self);
return Some(MultiBufferRow(start.row));
}
}
@@ -4955,7 +4956,7 @@ impl MultiBufferSnapshot {
{
text_anchor = excerpt.range.context.end;
}
- Anchor::in_buffer(excerpt.id, excerpt.buffer_id, text_anchor)
+ Anchor::in_buffer(excerpt.id, text_anchor)
} else if let Some(excerpt) = prev_excerpt {
let mut text_anchor = excerpt
.range
@@ -4968,7 +4969,7 @@ impl MultiBufferSnapshot {
{
text_anchor = excerpt.range.context.start;
}
- Anchor::in_buffer(excerpt.id, excerpt.buffer_id, text_anchor)
+ Anchor::in_buffer(excerpt.id, text_anchor)
} else if anchor.text_anchor.bias == Bias::Left {
Anchor::min()
} else {
@@ -5050,7 +5051,7 @@ impl MultiBufferSnapshot {
let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
let text_anchor =
excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
- let anchor = Anchor::in_buffer(excerpt.id, excerpt.buffer_id, text_anchor);
+ let anchor = Anchor::in_buffer(excerpt.id, text_anchor);
match diff_base_anchor {
Some(diff_base_anchor) => anchor.with_diff_base_anchor(diff_base_anchor),
None => anchor,
@@ -5066,7 +5067,11 @@ impl MultiBufferSnapshot {
/// Wraps the [`text::Anchor`] in a [`multi_buffer::Anchor`] if this multi-buffer is a singleton.
pub fn as_singleton_anchor(&self, text_anchor: text::Anchor) -> Option<Anchor> {
let (excerpt, buffer, _) = self.as_singleton()?;
- Some(Anchor::in_buffer(*excerpt, buffer, text_anchor))
+ if text_anchor.buffer_id.is_none_or(|id| id == buffer) {
+ Some(Anchor::in_buffer(*excerpt, text_anchor))
+ } else {
+ None
+ }
}
/// Returns an anchor for the given excerpt and text anchor,
@@ -5099,12 +5104,8 @@ impl MultiBufferSnapshot {
match text_anchor.buffer_id {
Some(buffer_id) if buffer_id == excerpt.buffer_id => (),
Some(_) => return None,
- None if text_anchor == text::Anchor::MAX || text_anchor == text::Anchor::MIN => {
- return Some(Anchor::in_buffer(
- excerpt.id,
- excerpt.buffer_id,
- text_anchor,
- ));
+ None if text_anchor.is_max() || text_anchor.is_min() => {
+ return Some(Anchor::in_buffer(excerpt.id, text_anchor));
}
None => return None,
}
@@ -5116,11 +5117,7 @@ impl MultiBufferSnapshot {
return None;
}
- Some(Anchor::in_buffer(
- excerpt.id,
- excerpt.buffer_id,
- text_anchor,
- ))
+ Some(Anchor::in_buffer(excerpt.id, text_anchor))
}
pub fn context_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
@@ -5128,7 +5125,7 @@ impl MultiBufferSnapshot {
}
pub fn can_resolve(&self, anchor: &Anchor) -> bool {
- if *anchor == Anchor::min() || anchor.excerpt_id == ExcerptId::max() {
+ if anchor.is_min() || anchor.is_max() {
// todo(lw): should be `!self.is_empty()`
true
} else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) {
@@ -5998,7 +5995,7 @@ impl MultiBufferSnapshot {
..
} = self.excerpt(anchor.excerpt_id)?;
if cfg!(debug_assertions) {
- match anchor.buffer_id {
+ match anchor.text_anchor.buffer_id {
// we clearly are hitting this according to sentry, but in what situations can this occur?
Some(anchor_buffer_id) => {
assert_eq!(
@@ -6006,7 +6003,7 @@ impl MultiBufferSnapshot {
"anchor {anchor:?} does not match with resolved excerpt {excerpt:?}"
)
}
- None => assert_eq!(anchor, Anchor::max()),
+ None => assert!(anchor.is_max()),
}
};
Some((
@@ -6019,19 +6016,18 @@ impl MultiBufferSnapshot {
depth: item.depth,
source_range_for_text: Anchor::range_in_buffer(
excerpt_id,
- buffer_id,
item.source_range_for_text,
),
- range: Anchor::range_in_buffer(excerpt_id, buffer_id, item.range),
+ range: Anchor::range_in_buffer(excerpt_id, item.range),
text: item.text,
highlight_ranges: item.highlight_ranges,
name_ranges: item.name_ranges,
- body_range: item.body_range.map(|body_range| {
- Anchor::range_in_buffer(excerpt_id, buffer_id, body_range)
- }),
- annotation_range: item.annotation_range.map(|body_range| {
- Anchor::range_in_buffer(excerpt_id, buffer_id, body_range)
- }),
+ body_range: item
+ .body_range
+ .map(|body_range| Anchor::range_in_buffer(excerpt_id, body_range)),
+ annotation_range: item
+ .annotation_range
+ .map(|body_range| Anchor::range_in_buffer(excerpt_id, body_range)),
})
})
.collect(),
@@ -6180,7 +6176,7 @@ impl MultiBufferSnapshot {
}
pub fn buffer_id_for_anchor(&self, anchor: Anchor) -> Option<BufferId> {
- if let Some(id) = anchor.buffer_id {
+ if let Some(id) = anchor.text_anchor.buffer_id {
return Some(id);
}
let excerpt = self.excerpt_containing(anchor..anchor)?;
@@ -6212,10 +6208,8 @@ impl MultiBufferSnapshot {
.selections_in_range(query_range, include_local)
.flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
selections.map(move |selection| {
- let mut start =
- Anchor::in_buffer(excerpt.id, excerpt.buffer_id, selection.start);
- let mut end =
- Anchor::in_buffer(excerpt.id, excerpt.buffer_id, selection.end);
+ let mut start = Anchor::in_buffer(excerpt.id, selection.start);
+ let mut end = Anchor::in_buffer(excerpt.id, selection.end);
if range.start.cmp(&start, self).is_gt() {
start = range.start;
}
@@ -6687,7 +6681,8 @@ impl Excerpt {
}
fn contains(&self, anchor: &Anchor) -> bool {
- (anchor.buffer_id == None || anchor.buffer_id == Some(self.buffer_id))
+ (anchor.text_anchor.buffer_id == None
+ || anchor.text_anchor.buffer_id == Some(self.buffer_id))
&& self
.range
.context
@@ -6723,19 +6718,11 @@ impl<'a> MultiBufferExcerpt<'a> {
}
pub fn start_anchor(&self) -> Anchor {
- Anchor::in_buffer(
- self.excerpt.id,
- self.excerpt.buffer_id,
- self.excerpt.range.context.start,
- )
+ Anchor::in_buffer(self.excerpt.id, self.excerpt.range.context.start)
}
pub fn end_anchor(&self) -> Anchor {
- Anchor::in_buffer(
- self.excerpt.id,
- self.excerpt.buffer_id,
- self.excerpt.range.context.end,
- )
+ Anchor::in_buffer(self.excerpt.id, self.excerpt.range.context.end)
}
pub fn buffer(&self) -> &'a BufferSnapshot {
@@ -3401,14 +3401,11 @@ fn test_summaries_for_anchors(cx: &mut TestAppContext) {
),
);
- let id_1 = buffer_1.read_with(cx, |buffer, _| buffer.remote_id());
- let id_2 = buffer_2.read_with(cx, |buffer, _| buffer.remote_id());
-
- let anchor_1 = Anchor::in_buffer(ids[0], id_1, text::Anchor::MIN);
+ let anchor_1 = Anchor::in_buffer(ids[0], text::Anchor::MIN);
let point_1 = snapshot.summaries_for_anchors::<Point, _>([&anchor_1])[0];
assert_eq!(point_1, Point::new(0, 0));
- let anchor_2 = Anchor::in_buffer(ids[1], id_2, text::Anchor::MIN);
+ let anchor_2 = Anchor::in_buffer(ids[1], text::Anchor::MIN);
let point_2 = snapshot.summaries_for_anchors::<Point, _>([&anchor_2])[0];
assert_eq!(point_2, Point::new(3, 0));
}
@@ -56,11 +56,7 @@ impl MultiBuffer {
let excerpt_id = self.excerpts_by_path.get(path)?.first()?;
let snapshot = self.read(cx);
let excerpt = snapshot.excerpt(*excerpt_id)?;
- Some(Anchor::in_buffer(
- excerpt.id,
- excerpt.buffer_id,
- excerpt.range.context.start,
- ))
+ Some(Anchor::in_buffer(excerpt.id, excerpt.range.context.start))
}
pub fn excerpt_paths(&self) -> impl Iterator<Item = &PathKey> {
@@ -263,7 +259,6 @@ impl MultiBuffer {
for range in ranges.by_ref().take(range_count) {
let range = Anchor::range_in_buffer(
excerpt_id,
- buffer_snapshot.remote_id(),
buffer_snapshot.anchor_before(&range.primary.start)
..buffer_snapshot.anchor_after(&range.primary.end),
);
@@ -2044,8 +2044,9 @@ impl OutlinePanel {
PanelEntry::Fs(FsEntry::ExternalFile(..)) => None,
PanelEntry::Search(SearchEntry { match_range, .. }) => match_range
.start
+ .text_anchor
.buffer_id
- .or(match_range.end.buffer_id)
+ .or(match_range.end.text_anchor.buffer_id)
.map(|buffer_id| {
outline_panel.update(cx, |outline_panel, cx| {
outline_panel
@@ -2746,7 +2746,7 @@ impl LocalLspStore {
let actions = lsp_store
.update(cx, move |this, cx| {
let request = GetCodeActions {
- range: text::Anchor::MIN..text::Anchor::MAX,
+ range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
kinds: Some(code_action_kinds),
};
let server = LanguageServerToQuery::Other(language_server_id);
@@ -4002,7 +4002,8 @@ impl Project {
) -> Task<anyhow::Result<Vec<InlayHint>>> {
let snapshot = buffer_handle.read(cx).snapshot();
- let captures = snapshot.debug_variables_query(Anchor::MIN..range.end);
+ let captures =
+ snapshot.debug_variables_query(Anchor::min_for_buffer(snapshot.remote_id())..range.end);
let row = snapshot
.summary_for_anchor::<text::PointUtf16>(&range.end)
@@ -72,6 +72,12 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
self.0.insert_or_replace(MapEntry { key, value }, ());
}
+ pub fn insert_or_replace(&mut self, key: K, value: V) -> Option<V> {
+ self.0
+ .insert_or_replace(MapEntry { key, value }, ())
+ .map(|it| it.value)
+ }
+
pub fn extend(&mut self, iter: impl IntoIterator<Item = (K, V)>) {
let edits: Vec<_> = iter
.into_iter()
@@ -18,11 +18,11 @@ pub struct Anchor {
impl Debug for Anchor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- if *self == Self::MIN {
- return f.write_str("Anchor::MIN");
+ if self.is_min() {
+ return write!(f, "Anchor::min({:?})", self.buffer_id);
}
- if *self == Self::MAX {
- return f.write_str("Anchor::MAX");
+ if self.is_max() {
+ return write!(f, "Anchor::max({:?})", self.buffer_id);
}
f.debug_struct("Anchor")
@@ -49,6 +49,36 @@ impl Anchor {
buffer_id: None,
};
+ pub fn min_for_buffer(buffer_id: BufferId) -> Self {
+ Self {
+ timestamp: clock::Lamport::MIN,
+ offset: usize::MIN,
+ bias: Bias::Left,
+ buffer_id: Some(buffer_id),
+ }
+ }
+
+ pub fn max_for_buffer(buffer_id: BufferId) -> Self {
+ Self {
+ timestamp: clock::Lamport::MAX,
+ offset: usize::MAX,
+ bias: Bias::Right,
+ buffer_id: Some(buffer_id),
+ }
+ }
+
+ pub fn min_min_range_for_buffer(buffer_id: BufferId) -> std::ops::Range<Self> {
+ let min = Self::min_for_buffer(buffer_id);
+ min..min
+ }
+ pub fn max_max_range_for_buffer(buffer_id: BufferId) -> std::ops::Range<Self> {
+ let max = Self::max_for_buffer(buffer_id);
+ max..max
+ }
+ pub fn min_max_range_for_buffer(buffer_id: BufferId) -> std::ops::Range<Self> {
+ Self::min_for_buffer(buffer_id)..Self::max_for_buffer(buffer_id)
+ }
+
pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
let fragment_id_comparison = if self.timestamp == other.timestamp {
Ordering::Equal
@@ -109,7 +139,7 @@ impl Anchor {
/// Returns true when the [`Anchor`] is located inside a visible fragment.
pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool {
- if *self == Anchor::MIN || *self == Anchor::MAX {
+ if self.is_min() || self.is_max() {
true
} else if self.buffer_id.is_none_or(|id| id != buffer.remote_id) {
false
@@ -127,6 +157,18 @@ impl Anchor {
item.is_some_and(|fragment| fragment.visible)
}
}
+
+ pub fn is_min(&self) -> bool {
+ self.timestamp == clock::Lamport::MIN
+ && self.offset == usize::MIN
+ && self.bias == Bias::Left
+ }
+
+ pub fn is_max(&self) -> bool {
+ self.timestamp == clock::Lamport::MAX
+ && self.offset == usize::MAX
+ && self.bias == Bias::Right
+ }
}
pub trait OffsetRangeExt {
@@ -1652,10 +1652,7 @@ impl Buffer {
) -> impl 'static + Future<Output = Result<()>> + use<It> {
let mut futures = Vec::new();
for anchor in anchors {
- if !self.version.observed(anchor.timestamp)
- && anchor != Anchor::MAX
- && anchor != Anchor::MIN
- {
+ if !self.version.observed(anchor.timestamp) && !anchor.is_max() && !anchor.is_min() {
let (tx, rx) = oneshot::channel();
self.edit_id_resolvers
.entry(anchor.timestamp)
@@ -2258,9 +2255,9 @@ impl BufferSnapshot {
let mut position = D::zero(());
anchors.map(move |(anchor, payload)| {
- if *anchor == Anchor::MIN {
+ if anchor.is_min() {
return (D::zero(()), payload);
- } else if *anchor == Anchor::MAX {
+ } else if anchor.is_max() {
return (D::from_text_summary(&self.visible_text.summary()), payload);
}
@@ -2318,9 +2315,9 @@ impl BufferSnapshot {
}
pub fn offset_for_anchor(&self, anchor: &Anchor) -> usize {
- if *anchor == Anchor::MIN {
+ if anchor.is_min() {
0
- } else if *anchor == Anchor::MAX {
+ } else if anchor.is_max() {
self.visible_text.len()
} else {
debug_assert!(anchor.buffer_id == Some(self.remote_id));
@@ -2393,9 +2390,9 @@ impl BufferSnapshot {
}
fn try_fragment_id_for_anchor(&self, anchor: &Anchor) -> Option<&Locator> {
- if *anchor == Anchor::MIN {
+ if anchor.is_min() {
Some(Locator::min_ref())
- } else if *anchor == Anchor::MAX {
+ } else if anchor.is_max() {
Some(Locator::max_ref())
} else {
let anchor_key = InsertionFragmentKey {
@@ -2440,9 +2437,9 @@ impl BufferSnapshot {
fn anchor_at_offset(&self, offset: usize, bias: Bias) -> Anchor {
if bias == Bias::Left && offset == 0 {
- Anchor::MIN
+ Anchor::min_for_buffer(self.remote_id)
} else if bias == Bias::Right && offset == self.len() {
- Anchor::MAX
+ Anchor::max_for_buffer(self.remote_id)
} else {
if cfg!(debug_assertions) {
self.visible_text.assert_char_boundary(offset);
@@ -2462,8 +2459,8 @@ impl BufferSnapshot {
}
pub fn can_resolve(&self, anchor: &Anchor) -> bool {
- *anchor == Anchor::MIN
- || *anchor == Anchor::MAX
+ anchor.is_min()
+ || anchor.is_max()
|| (Some(self.remote_id) == anchor.buffer_id && self.version.observed(anchor.timestamp))
}
@@ -2268,17 +2268,13 @@ fn go_to_line(map: &DisplaySnapshot, display_point: DisplayPoint, line: usize) -
..language::ToOffset::to_offset(&range.context.end, buffer);
if offset >= excerpt_range.start && offset <= excerpt_range.end {
let text_anchor = buffer.anchor_after(offset);
- let anchor = Anchor::in_buffer(excerpt, buffer.remote_id(), text_anchor);
+ let anchor = Anchor::in_buffer(excerpt, text_anchor);
return anchor.to_display_point(map);
} else if offset <= excerpt_range.start {
- let anchor = Anchor::in_buffer(excerpt, buffer.remote_id(), range.context.start);
+ let anchor = Anchor::in_buffer(excerpt, range.context.start);
return anchor.to_display_point(map);
} else {
- last_position = Some(Anchor::in_buffer(
- excerpt,
- buffer.remote_id(),
- range.context.end,
- ));
+ last_position = Some(Anchor::in_buffer(excerpt, range.context.end));
}
}
@@ -606,7 +606,7 @@ impl MarksState {
let text_anchors = anchors.get(name)?;
let anchors = text_anchors
.iter()
- .map(|anchor| Anchor::in_buffer(excerpt_id, buffer_id, *anchor))
+ .map(|anchor| Anchor::in_buffer(excerpt_id, *anchor))
.collect();
return Some(Mark::Local(anchors));
}