editor: Fix `unwrap_syntax_node` panicking by not setting selections (#38329)

Lukas Wirth created

Fixes ZED-11T

Release Notes:

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

Change summary

crates/agent_ui/src/text_thread_editor.rs     |  4 
crates/editor/src/editor.rs                   | 90 ++++++++++++--------
crates/editor/src/element.rs                  | 12 +
crates/editor/src/items.rs                    |  8 
crates/editor/src/jsx_tag_auto_close.rs       |  2 
crates/editor/src/lsp_ext.rs                  |  2 
crates/editor/src/mouse_context_menu.rs       |  7 -
crates/editor/src/rust_analyzer_ext.rs        |  6 
crates/editor/src/selections_collection.rs    | 42 ++++++---
crates/editor/src/test/editor_test_context.rs |  2 
crates/git_ui/src/text_diff_view.rs           |  2 
crates/vim/src/command.rs                     |  4 
crates/vim/src/normal/mark.rs                 |  2 
crates/vim/src/surrounds.rs                   |  2 
crates/vim/src/vim.rs                         | 10 +-
crates/vim/src/visual.rs                      |  2 
16 files changed, 112 insertions(+), 85 deletions(-)

Detailed changes

crates/agent_ui/src/text_thread_editor.rs 🔗

@@ -477,7 +477,7 @@ impl TextThreadEditor {
             return;
         }
 
-        let selections = self.editor.read(cx).selections.disjoint_anchors();
+        let selections = self.editor.read(cx).selections.disjoint_anchors_arc();
         let mut commands_by_range = HashMap::default();
         let workspace = self.workspace.clone();
         self.context.update(cx, |context, cx| {
@@ -1823,7 +1823,7 @@ impl TextThreadEditor {
 
     fn split(&mut self, _: &Split, _window: &mut Window, cx: &mut Context<Self>) {
         self.context.update(cx, |context, cx| {
-            let selections = self.editor.read(cx).selections.disjoint_anchors();
+            let selections = self.editor.read(cx).selections.disjoint_anchors_arc();
             for selection in selections.as_ref() {
                 let buffer = self.editor.read(cx).buffer().read(cx).snapshot(cx);
                 let range = selection

crates/editor/src/editor.rs 🔗

@@ -2414,14 +2414,10 @@ impl Editor {
     pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
         if self
             .selections
-            .pending
-            .as_ref()
+            .pending_anchor()
             .is_some_and(|pending_selection| {
                 let snapshot = self.buffer().read(cx).snapshot(cx);
-                pending_selection
-                    .selection
-                    .range()
-                    .includes(range, &snapshot)
+                pending_selection.range().includes(range, &snapshot)
             })
         {
             return true;
@@ -3054,7 +3050,7 @@ impl Editor {
             }
         }
 
-        let selection_anchors = self.selections.disjoint_anchors();
+        let selection_anchors = self.selections.disjoint_anchors_arc();
 
         if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
             self.buffer.update(cx, |buffer, cx| {
@@ -3170,7 +3166,7 @@ impl Editor {
         self.blink_manager.update(cx, BlinkManager::pause_blinking);
         cx.emit(EditorEvent::SelectionsChanged { local });
 
-        let selections = &self.selections.disjoint;
+        let selections = &self.selections.disjoint_anchors_arc();
         if selections.len() == 1 {
             cx.emit(SearchEvent::ActiveMatchChanged)
         }
@@ -3282,14 +3278,14 @@ impl Editor {
         other: Entity<Editor>,
         cx: &mut Context<Self>,
     ) -> gpui::Subscription {
-        let other_selections = other.read(cx).selections.disjoint.to_vec();
+        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
         self.selections.change_with(cx, |selections| {
             selections.select_anchors(other_selections);
         });
 
         let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
             if let EditorEvent::SelectionsChanged { local: true } = other_evt {
-                let other_selections = other.read(cx).selections.disjoint.to_vec();
+                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
                 if other_selections.is_empty() {
                     return;
                 }
@@ -3301,7 +3297,7 @@ impl Editor {
 
         let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
             if let EditorEvent::SelectionsChanged { local: true } = this_evt {
-                let these_selections = this.selections.disjoint.to_vec();
+                let these_selections = this.selections.disjoint_anchors().to_vec();
                 if these_selections.is_empty() {
                     return;
                 }
@@ -3339,7 +3335,7 @@ impl Editor {
             effects,
             old_cursor_position: self.selections.newest_anchor().head(),
             history_entry: SelectionHistoryEntry {
-                selections: self.selections.disjoint_anchors(),
+                selections: self.selections.disjoint_anchors_arc(),
                 select_next_state: self.select_next_state.clone(),
                 select_prev_state: self.select_prev_state.clone(),
                 add_selections_state: self.add_selections_state.clone(),
@@ -3499,6 +3495,7 @@ impl Editor {
         let mut pending_selection = self
             .selections
             .pending_anchor()
+            .cloned()
             .expect("extend_selection not called with pending selection");
         if position >= tail {
             pending_selection.start = tail_anchor;
@@ -3520,7 +3517,7 @@ impl Editor {
         };
 
         self.change_selections(effects, window, cx, |s| {
-            s.set_pending(pending_selection, pending_mode)
+            s.set_pending(pending_selection.clone(), pending_mode)
         });
     }
 
@@ -3595,7 +3592,7 @@ impl Editor {
                 Some(selected_points[0].id)
             } else {
                 let clicked_point_already_selected =
-                    self.selections.disjoint.iter().find(|selection| {
+                    self.selections.disjoint_anchors().iter().find(|selection| {
                         selection.start.to_point(buffer) == start.to_point(buffer)
                             || selection.end.to_point(buffer) == end.to_point(buffer)
                     });
@@ -3700,7 +3697,7 @@ impl Editor {
 
         if self.columnar_selection_state.is_some() {
             self.select_columns(position, goal_column, &display_map, window, cx);
-        } else if let Some(mut pending) = self.selections.pending_anchor() {
+        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
             let buffer = &display_map.buffer_snapshot;
             let head;
             let tail;
@@ -3776,7 +3773,7 @@ impl Editor {
             }
 
             self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
-                s.set_pending(pending, mode);
+                s.set_pending(pending.clone(), mode);
             });
         } else {
             log::error!("update_selection dispatched with no pending selection");
@@ -3885,7 +3882,8 @@ impl Editor {
         };
 
         pending_nonempty_selection
-            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
+            || (self.columnar_selection_state.is_some()
+                && self.selections.disjoint_anchors().len() > 1)
     }
 
     pub fn has_pending_selection(&self) -> bool {
@@ -6065,7 +6063,7 @@ impl Editor {
 
             editor.refresh_edit_prediction(true, false, window, cx);
         });
-        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
+        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 
         let show_new_completions_on_confirm = completion
             .confirm
@@ -7473,7 +7471,7 @@ impl Editor {
                     s.select_anchor_ranges([last_edit_end..last_edit_end]);
                 });
 
-                let selections = self.selections.disjoint_anchors();
+                let selections = self.selections.disjoint_anchors_arc();
                 if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
                     let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
                     if has_new_transaction {
@@ -7718,7 +7716,7 @@ impl Editor {
         let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
             return;
         };
-        if self.selections.pending.is_none() {
+        if self.selections.pending_anchor().is_none() {
             return;
         }
 
@@ -10513,7 +10511,7 @@ impl Editor {
 
     fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
         let snapshot = self.buffer.read(cx).snapshot(cx);
-        for selection in self.selections.disjoint_anchors().iter() {
+        for selection in self.selections.disjoint_anchors_arc().iter() {
             if snapshot
                 .language_at(selection.start)
                 .and_then(|lang| lang.config().wrap_characters.as_ref())
@@ -10847,7 +10845,7 @@ impl Editor {
         let snapshot = self.snapshot(window, cx);
         let cursors = self
             .selections
-            .disjoint_anchors()
+            .disjoint_anchors_arc()
             .iter()
             .map(|selection| {
                 let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
@@ -14538,7 +14536,7 @@ impl Editor {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> Result<()> {
-        let selections = self.selections.disjoint_anchors();
+        let selections = self.selections.disjoint_anchors_arc();
         match selections.first() {
             Some(first) if selections.len() >= 2 => {
                 self.change_selections(Default::default(), window, cx, |s| {
@@ -14562,7 +14560,7 @@ impl Editor {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> Result<()> {
-        let selections = self.selections.disjoint_anchors();
+        let selections = self.selections.disjoint_anchors_arc();
         match selections.last() {
             Some(last) if selections.len() >= 2 => {
                 self.change_selections(Default::default(), window, cx, |s| {
@@ -15115,11 +15113,9 @@ impl Editor {
         let full_edits = selections
             .into_iter()
             .filter_map(|selection| {
-                // Only requires two branches once if-let-chains stabilize (#53667)
-                let child = if !selection.is_empty() {
-                    selection.range()
-                } else if let Some((_, ancestor_range)) =
-                    buffer.syntax_ancestor(selection.start..selection.end)
+                let child = if selection.is_empty()
+                    && let Some((_, ancestor_range)) =
+                        buffer.syntax_ancestor(selection.start..selection.end)
                 {
                     ancestor_range
                 } else {
@@ -15141,6 +15137,9 @@ impl Editor {
                 Some((selection.id, parent, text))
             })
             .collect::<Vec<_>>();
+        if full_edits.is_empty() {
+            return;
+        }
 
         self.transact(window, cx, |this, window, cx| {
             this.buffer.update(cx, |buffer, cx| {
@@ -15649,7 +15648,7 @@ impl Editor {
 
         cx: &mut Context<Self>,
     ) {
-        let selections = self.selections.disjoint_anchors();
+        let selections = self.selections.disjoint_anchors_arc();
 
         let lines = if lines == 0 {
             EditorSettings::get_global(cx).expand_excerpt_lines
@@ -17108,7 +17107,7 @@ impl Editor {
                     .transaction(transaction_id_prev)
                     .map(|t| t.0.clone())
             })
-            .unwrap_or_else(|| self.selections.disjoint_anchors());
+            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
 
         let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
         let format = project.update(cx, |project, cx| {
@@ -17648,7 +17647,7 @@ impl Editor {
             .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
         {
             self.selection_history
-                .insert_transaction(tx_id, self.selections.disjoint_anchors());
+                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
             cx.emit(EditorEvent::TransactionBegun {
                 transaction_id: tx_id,
             });
@@ -17670,7 +17669,7 @@ impl Editor {
             if let Some((_, end_selections)) =
                 self.selection_history.transaction_mut(transaction_id)
             {
-                *end_selections = Some(self.selections.disjoint_anchors());
+                *end_selections = Some(self.selections.disjoint_anchors_arc());
             } else {
                 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
             }
@@ -18340,7 +18339,12 @@ impl Editor {
         _window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
+        let ranges: Vec<_> = self
+            .selections
+            .disjoint_anchors()
+            .iter()
+            .map(|s| s.range())
+            .collect();
         self.toggle_diff_hunks_in_ranges(ranges, cx);
     }
 
@@ -18378,7 +18382,12 @@ impl Editor {
         cx: &mut Context<Self>,
     ) {
         let snapshot = self.buffer.read(cx).snapshot(cx);
-        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
+        let ranges: Vec<_> = self
+            .selections
+            .disjoint_anchors()
+            .iter()
+            .map(|s| s.range())
+            .collect();
         let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
         self.stage_or_unstage_diff_hunks(stage, ranges, cx);
     }
@@ -18542,7 +18551,12 @@ impl Editor {
     }
 
     pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
-        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
+        let ranges: Vec<_> = self
+            .selections
+            .disjoint_anchors()
+            .iter()
+            .map(|s| s.range())
+            .collect();
         self.buffer
             .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
     }
@@ -21262,7 +21276,7 @@ impl Editor {
                 buffer.finalize_last_transaction(cx);
                 if self.leader_id.is_none() {
                     buffer.set_active_selections(
-                        &self.selections.disjoint_anchors(),
+                        &self.selections.disjoint_anchors_arc(),
                         self.selections.line_mode,
                         self.cursor_shape,
                         cx,
@@ -23558,7 +23572,7 @@ impl EntityInputHandler for Editor {
             let marked_ranges = {
                 let snapshot = this.buffer.read(cx).read(cx);
                 this.selections
-                    .disjoint_anchors()
+                    .disjoint_anchors_arc()
                     .iter()
                     .map(|selection| {
                         selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)

crates/editor/src/element.rs 🔗

@@ -1060,7 +1060,7 @@ impl EditorElement {
                     );
                     if mouse_down_time.elapsed() >= drag_and_drop_delay {
                         let drop_cursor = Selection {
-                            id: post_inc(&mut editor.selections.next_selection_id),
+                            id: post_inc(&mut editor.selections.next_selection_id()),
                             start: drop_anchor,
                             end: drop_anchor,
                             reversed: false,
@@ -1547,9 +1547,13 @@ impl EditorElement {
         // Local cursors
         if !skip_local {
             let color = cx.theme().players().local().cursor;
-            editor.selections.disjoint.iter().for_each(|selection| {
-                add_cursor(selection.head(), color);
-            });
+            editor
+                .selections
+                .disjoint_anchors()
+                .iter()
+                .for_each(|selection| {
+                    add_cursor(selection.head(), color);
+                });
             if let Some(ref selection) = editor.selections.pending_anchor() {
                 add_cursor(selection.head(), color);
             }

crates/editor/src/items.rs 🔗

@@ -187,7 +187,7 @@ impl FollowableItem for Editor {
         } else if self.focus_handle.is_focused(window) {
             self.buffer.update(cx, |buffer, cx| {
                 buffer.set_active_selections(
-                    &self.selections.disjoint_anchors(),
+                    &self.selections.disjoint_anchors_arc(),
                     self.selections.line_mode,
                     self.cursor_shape,
                     cx,
@@ -231,7 +231,7 @@ impl FollowableItem for Editor {
             scroll_y: scroll_anchor.offset.y,
             selections: self
                 .selections
-                .disjoint_anchors()
+                .disjoint_anchors_arc()
                 .iter()
                 .map(|s| serialize_selection(s, &snapshot))
                 .collect(),
@@ -310,7 +310,7 @@ impl FollowableItem for Editor {
                     let snapshot = self.buffer.read(cx).snapshot(cx);
                     update.selections = self
                         .selections
-                        .disjoint_anchors()
+                        .disjoint_anchors_arc()
                         .iter()
                         .map(|s| serialize_selection(s, &snapshot))
                         .collect();
@@ -1675,7 +1675,7 @@ impl SearchableItem for Editor {
         cx: &mut Context<Self>,
     ) -> usize {
         let buffer = self.buffer().read(cx).snapshot(cx);
-        let current_index_position = if self.selections.disjoint_anchors().len() == 1 {
+        let current_index_position = if self.selections.disjoint_anchors_arc().len() == 1 {
             self.selections.newest_anchor().head()
         } else {
             matches[current_index].start

crates/editor/src/jsx_tag_auto_close.rs 🔗

@@ -507,7 +507,7 @@ pub(crate) fn handle_from(
 
             {
                 let selections = this
-                    .read_with(cx, |this, _| this.selections.disjoint_anchors())
+                    .read_with(cx, |this, _| this.selections.disjoint_anchors_arc())
                     .ok()?;
                 for selection in selections.iter() {
                     let Some(selection_buffer_offset_head) =

crates/editor/src/lsp_ext.rs 🔗

@@ -35,7 +35,7 @@ where
     let project = editor.project.clone()?;
     editor
         .selections
-        .disjoint_anchors()
+        .disjoint_anchors_arc()
         .iter()
         .filter_map(|selection| Some((selection.head(), selection.head().buffer_id?)))
         .unique_by(|(_, buffer_id)| *buffer_id)

crates/editor/src/mouse_context_menu.rs 🔗

@@ -130,12 +130,9 @@ fn display_ranges<'a>(
     display_map: &'a DisplaySnapshot,
     selections: &'a SelectionsCollection,
 ) -> impl Iterator<Item = Range<DisplayPoint>> + 'a {
-    let pending = selections
-        .pending
-        .as_ref()
-        .map(|pending| &pending.selection);
+    let pending = selections.pending_anchor();
     selections
-        .disjoint
+        .disjoint_anchors()
         .iter()
         .chain(pending)
         .map(move |s| s.start.to_display_point(display_map)..s.end.to_display_point(display_map))

crates/editor/src/rust_analyzer_ext.rs 🔗

@@ -319,7 +319,7 @@ fn cancel_flycheck_action(
     };
     let buffer_id = editor
         .selections
-        .disjoint_anchors()
+        .disjoint_anchors_arc()
         .iter()
         .find_map(|selection| {
             let buffer_id = selection.start.buffer_id.or(selection.end.buffer_id)?;
@@ -344,7 +344,7 @@ fn run_flycheck_action(
     };
     let buffer_id = editor
         .selections
-        .disjoint_anchors()
+        .disjoint_anchors_arc()
         .iter()
         .find_map(|selection| {
             let buffer_id = selection.start.buffer_id.or(selection.end.buffer_id)?;
@@ -369,7 +369,7 @@ fn clear_flycheck_action(
     };
     let buffer_id = editor
         .selections
-        .disjoint_anchors()
+        .disjoint_anchors_arc()
         .iter()
         .find_map(|selection| {
             let buffer_id = selection.start.buffer_id.or(selection.end.buffer_id)?;

crates/editor/src/selections_collection.rs 🔗

@@ -28,13 +28,13 @@ pub struct PendingSelection {
 pub struct SelectionsCollection {
     display_map: Entity<DisplayMap>,
     buffer: Entity<MultiBuffer>,
-    pub next_selection_id: usize,
+    next_selection_id: usize,
     pub line_mode: bool,
     /// The non-pending, non-overlapping selections.
     /// The [SelectionsCollection::pending] selection could possibly overlap these
-    pub disjoint: Arc<[Selection<Anchor>]>,
+    disjoint: Arc<[Selection<Anchor>]>,
     /// A pending selection, such as when the mouse is being dragged
-    pub pending: Option<PendingSelection>,
+    pending: Option<PendingSelection>,
 }
 
 impl SelectionsCollection {
@@ -84,20 +84,27 @@ impl SelectionsCollection {
     /// The non-pending, non-overlapping selections. There could be a pending selection that
     /// overlaps these if the mouse is being dragged, etc. This could also be empty if there is a
     /// pending selection. Returned as selections over Anchors.
-    pub fn disjoint_anchors(&self) -> Arc<[Selection<Anchor>]> {
+    pub fn disjoint_anchors_arc(&self) -> Arc<[Selection<Anchor>]> {
         self.disjoint.clone()
     }
 
+    /// The non-pending, non-overlapping selections. There could be a pending selection that
+    /// overlaps these if the mouse is being dragged, etc. This could also be empty if there is a
+    /// pending selection. Returned as selections over Anchors.
+    pub fn disjoint_anchors(&self) -> &[Selection<Anchor>] {
+        &self.disjoint
+    }
+
     pub fn disjoint_anchor_ranges(&self) -> impl Iterator<Item = Range<Anchor>> {
         // Mapping the Arc slice would borrow it, whereas indexing captures it.
-        let disjoint = self.disjoint_anchors();
+        let disjoint = self.disjoint_anchors_arc();
         (0..disjoint.len()).map(move |ix| disjoint[ix].range())
     }
 
     /// Non-overlapping selections using anchors, including the pending selection.
     pub fn all_anchors(&self, cx: &mut App) -> Arc<[Selection<Anchor>]> {
         if self.pending.is_none() {
-            self.disjoint_anchors()
+            self.disjoint_anchors_arc()
         } else {
             let all_offset_selections = self.all::<usize>(cx);
             let buffer = self.buffer(cx);
@@ -108,10 +115,12 @@ impl SelectionsCollection {
         }
     }
 
-    pub fn pending_anchor(&self) -> Option<Selection<Anchor>> {
-        self.pending
-            .as_ref()
-            .map(|pending| pending.selection.clone())
+    pub fn pending_anchor(&self) -> Option<&Selection<Anchor>> {
+        self.pending.as_ref().map(|pending| &pending.selection)
+    }
+
+    pub fn pending_anchor_mut(&mut self) -> Option<&mut Selection<Anchor>> {
+        self.pending.as_mut().map(|pending| &mut pending.selection)
     }
 
     pub fn pending<D: TextDimension + Ord + Sub<D, Output = D>>(
@@ -120,7 +129,7 @@ impl SelectionsCollection {
     ) -> Option<Selection<D>> {
         let map = self.display_map(cx);
 
-        resolve_selections(self.pending_anchor().as_ref(), &map).next()
+        resolve_selections(self.pending_anchor(), &map).next()
     }
 
     pub(crate) fn pending_mode(&self) -> Option<SelectMode> {
@@ -234,8 +243,7 @@ impl SelectionsCollection {
         let map = self.display_map(cx);
         let disjoint_anchors = &self.disjoint;
         let mut disjoint = resolve_selections_display(disjoint_anchors.iter(), &map).peekable();
-        let mut pending_opt =
-            resolve_selections_display(self.pending_anchor().as_ref(), &map).next();
+        let mut pending_opt = resolve_selections_display(self.pending_anchor(), &map).next();
         let selections = iter::from_fn(move || {
             if let Some(pending) = pending_opt.as_mut() {
                 while let Some(next_selection) = disjoint.peek() {
@@ -343,9 +351,9 @@ impl SelectionsCollection {
     #[cfg(any(test, feature = "test-support"))]
     pub fn display_ranges(&self, cx: &mut App) -> Vec<Range<DisplayPoint>> {
         let display_map = self.display_map(cx);
-        self.disjoint_anchors()
+        self.disjoint_anchors_arc()
             .iter()
-            .chain(self.pending_anchor().as_ref())
+            .chain(self.pending_anchor())
             .map(|s| {
                 if s.reversed {
                     s.end.to_display_point(&display_map)..s.start.to_display_point(&display_map)
@@ -412,6 +420,10 @@ impl SelectionsCollection {
         );
         (mutable_collection.selections_changed, result)
     }
+
+    pub fn next_selection_id(&self) -> usize {
+        self.next_selection_id
+    }
 }
 
 pub struct MutableSelectionsCollection<'a> {

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

@@ -396,7 +396,7 @@ impl EditorTestContext {
         let (multibuffer_snapshot, selections, excerpts) = self.update_editor(|editor, _, cx| {
             let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 
-            let selections = editor.selections.disjoint_anchors();
+            let selections = editor.selections.disjoint_anchors_arc();
             let excerpts = multibuffer_snapshot
                 .excerpts()
                 .map(|(e_id, snapshot, range)| (e_id, snapshot.clone(), range))

crates/git_ui/src/text_diff_view.rs 🔗

@@ -416,7 +416,7 @@ impl Item for TextDiffView {
 pub fn selection_location_text(editor: &Editor, cx: &App) -> Option<String> {
     let buffer = editor.buffer().read(cx);
     let buffer_snapshot = buffer.snapshot(cx);
-    let first_selection = editor.selections.disjoint.first()?;
+    let first_selection = editor.selections.disjoint_anchors().first()?;
 
     let selection_start = first_selection.start.to_point(&buffer_snapshot);
     let selection_end = first_selection.end.to_point(&buffer_snapshot);

crates/vim/src/command.rs 🔗

@@ -463,7 +463,7 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
             .collect();
         vim.switch_mode(Mode::Normal, true, window, cx);
         let initial_selections =
-            vim.update_editor(cx, |_, editor, _| editor.selections.disjoint_anchors());
+            vim.update_editor(cx, |_, editor, _| editor.selections.disjoint_anchors_arc());
         if let Some(range) = &action.range {
             let result = vim.update_editor(cx, |vim, editor, cx| {
                 let range = range.buffer_range(vim, editor, window, cx)?;
@@ -515,7 +515,7 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
                             .buffer()
                             .update(cx, |multi, cx| multi.last_transaction_id(cx))
                     {
-                        let last_sel = editor.selections.disjoint_anchors();
+                        let last_sel = editor.selections.disjoint_anchors_arc();
                         editor.modify_transaction_selection_history(tx_id, |old| {
                             old.0 = first_sel;
                             old.1 = Some(last_sel);

crates/vim/src/normal/mark.rs 🔗

@@ -22,7 +22,7 @@ impl Vim {
         self.update_editor(cx, |vim, editor, cx| {
             let anchors = editor
                 .selections
-                .disjoint_anchors()
+                .disjoint_anchors_arc()
                 .iter()
                 .map(|s| s.head())
                 .collect::<Vec<_>>();

crates/vim/src/surrounds.rs 🔗

@@ -326,7 +326,7 @@ impl Vim {
 
                     let stable_anchors = editor
                         .selections
-                        .disjoint_anchors()
+                        .disjoint_anchors_arc()
                         .iter()
                         .map(|selection| {
                             let start = selection.start.bias_left(&display_map.buffer_snapshot);

crates/vim/src/vim.rs 🔗

@@ -1075,16 +1075,16 @@ impl Vim {
                 }
 
                 let snapshot = s.display_map();
-                if let Some(pending) = s.pending.as_mut()
-                    && pending.selection.reversed
+                if let Some(pending) = s.pending_anchor_mut()
+                    && pending.reversed
                     && mode.is_visual()
                     && !last_mode.is_visual()
                 {
-                    let mut end = pending.selection.end.to_point(&snapshot.buffer_snapshot);
+                    let mut end = pending.end.to_point(&snapshot.buffer_snapshot);
                     end = snapshot
                         .buffer_snapshot
                         .clip_point(end + Point::new(0, 1), Bias::Right);
-                    pending.selection.end = snapshot.buffer_snapshot.anchor_before(end);
+                    pending.end = snapshot.buffer_snapshot.anchor_before(end);
                 }
 
                 s.move_with(|map, selection| {
@@ -1332,7 +1332,7 @@ impl Vim {
         self.update_editor(cx, |_, editor, _| {
             editor
                 .selections
-                .disjoint_anchors()
+                .disjoint_anchors_arc()
                 .iter()
                 .map(|selection| selection.tail()..selection.head())
                 .collect()

crates/vim/src/visual.rs 🔗

@@ -748,7 +748,7 @@ impl Vim {
                 // after the change
                 let stable_anchors = editor
                     .selections
-                    .disjoint_anchors()
+                    .disjoint_anchors_arc()
                     .iter()
                     .map(|selection| {
                         let start = selection.start.bias_left(&display_map.buffer_snapshot);