multi_buffer: Remove redundant buffer id field (#43459)

Lukas Wirth created

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>

Change summary

crates/acp_thread/src/acp_thread.rs             |   6 
crates/acp_thread/src/diff.rs                   |  18 ++
crates/action_log/src/action_log.rs             |  30 ++-
crates/agent/src/edit_agent.rs                  |  33 +++-
crates/agent/src/tools/read_file_tool.rs        |   4 
crates/agent_ui/src/acp/thread_view.rs          |  15 +-
crates/agent_ui/src/agent_diff.rs               |   2 
crates/agent_ui/src/inline_assistant.rs         |   1 
crates/assistant_text_thread/src/text_thread.rs |  15 +-
crates/buffer_diff/src/buffer_diff.rs           |  70 ++++++++--
crates/collab/src/tests/editor_tests.rs         |  10 +
crates/diagnostics/src/diagnostic_renderer.rs   |   2 
crates/diagnostics/src/diagnostics.rs           |   2 
crates/editor/src/display_map/block_map.rs      |   2 
crates/editor/src/editor.rs                     |  35 ++---
crates/editor/src/editor_tests.rs               |   9 
crates/editor/src/element.rs                    |   2 
crates/editor/src/inlays/inlay_hints.rs         |  19 ++
crates/editor/src/items.rs                      |  49 ++-----
crates/editor/src/linked_editing_ranges.rs      |   4 
crates/editor/src/lsp_ext.rs                    |   2 
crates/editor/src/rust_analyzer_ext.rs          |  18 ++
crates/editor/src/test/editor_test_context.rs   |  12 -
crates/git_ui/src/commit_view.rs                |   6 
crates/git_ui/src/project_diff.rs               |  14 +-
crates/language/src/buffer_tests.rs             |   2 
crates/language/src/syntax_map.rs               |   6 
crates/multi_buffer/src/anchor.rs               |  56 +++-----
crates/multi_buffer/src/multi_buffer.rs         | 123 ++++++++----------
crates/multi_buffer/src/multi_buffer_tests.rs   |   7 
crates/multi_buffer/src/path_key.rs             |   7 
crates/outline_panel/src/outline_panel.rs       |   3 
crates/project/src/lsp_store.rs                 |   2 
crates/project/src/project.rs                   |   3 
crates/sum_tree/src/tree_map.rs                 |   6 
crates/text/src/anchor.rs                       |  52 +++++++
crates/text/src/text.rs                         |  25 +--
crates/vim/src/motion.rs                        |  10 -
crates/vim/src/state.rs                         |   2 
39 files changed, 378 insertions(+), 306 deletions(-)

Detailed changes

crates/acp_thread/src/acp_thread.rs 🔗

@@ -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,
                 );

crates/acp_thread/src/diff.rs 🔗

@@ -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(

crates/action_log/src/action_log.rs 🔗

@@ -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();

crates/agent/src/edit_agent.rs 🔗

@@ -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())
+                ),
             })
         );
     }

crates/agent/src/tools/read_file_tool.rs 🔗

@@ -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,
                 );

crates/agent_ui/src/acp/thread_view.rs 🔗

@@ -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]);
                         })

crates/agent_ui/src/agent_diff.rs 🔗

@@ -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,
                 )

crates/agent_ui/src/inline_assistant.rs 🔗

@@ -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),
             );
 

crates/assistant_text_thread/src/text_thread.rs 🔗

@@ -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 {

crates/buffer_diff/src/buffer_diff.rs 🔗

@@ -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());
 

crates/collab/src/tests/editor_tests.rs 🔗

@@ -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
     });

crates/diagnostics/src/diagnostic_renderer.rs 🔗

@@ -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,
                         );

crates/diagnostics/src/diagnostics.rs 🔗

@@ -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 {

crates/editor/src/display_map/block_map.rs 🔗

@@ -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);
 

crates/editor/src/editor.rs 🔗

@@ -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,

crates/editor/src/editor_tests.rs 🔗

@@ -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);

crates/editor/src/element.rs 🔗

@@ -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)| {

crates/editor/src/inlays/inlay_hints.rs 🔗

@@ -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),
             );

crates/editor/src/items.rs 🔗

@@ -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)
                                 }
                             }),
                     );

crates/editor/src/linked_editing_ranges.rs 🔗

@@ -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;

crates/editor/src/lsp_ext.rs 🔗

@@ -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)?;

crates/editor/src/rust_analyzer_ext.rs 🔗

@@ -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)?

crates/editor/src/test/editor_test_context.rs 🔗

@@ -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

crates/git_ui/src/commit_view.rs 🔗

@@ -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();

crates/git_ui/src/project_diff.rs 🔗

@@ -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())

crates/language/src/buffer_tests.rs 🔗

@@ -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

crates/language/src/syntax_map.rs 🔗

@@ -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,
                 }
             };

crates/multi_buffer/src/anchor.rs 🔗

@@ -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

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -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 {

crates/multi_buffer/src/multi_buffer_tests.rs 🔗

@@ -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));
 }

crates/multi_buffer/src/path_key.rs 🔗

@@ -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),
                 );

crates/outline_panel/src/outline_panel.rs 🔗

@@ -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

crates/project/src/lsp_store.rs 🔗

@@ -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);

crates/project/src/project.rs 🔗

@@ -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)

crates/sum_tree/src/tree_map.rs 🔗

@@ -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()

crates/text/src/anchor.rs 🔗

@@ -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 {

crates/text/src/text.rs 🔗

@@ -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))
     }
 

crates/vim/src/motion.rs 🔗

@@ -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));
         }
     }
 

crates/vim/src/state.rs 🔗

@@ -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));
             }