Track selection changes in mutable selections collection

Keith Simmons created

Change summary

crates/editor/src/editor.rs                | 11 ++-
crates/editor/src/element.rs               | 10 --
crates/editor/src/selections_collection.rs | 75 +++++++++++------------
3 files changed, 47 insertions(+), 49 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -1401,12 +1401,14 @@ impl Editor {
         let old_cursor_position = self.selections.newest_anchor().head();
         self.push_to_selection_history();
 
-        let result = self.selections.change_with(cx, change);
+        let (changed, result) = self.selections.change_with(cx, change);
 
-        if let Some(autoscroll) = autoscroll {
-            self.request_autoscroll(autoscroll, cx);
+        if changed {
+            if let Some(autoscroll) = autoscroll {
+                self.request_autoscroll(autoscroll, cx);
+            }
+            self.selections_did_change(true, &old_cursor_position, cx);
         }
-        self.selections_did_change(true, &old_cursor_position, cx);
 
         result
     }
@@ -4691,6 +4693,7 @@ impl Editor {
                     // Position the selection in the rename editor so that it matches the current selection.
                     this.show_local_selections = false;
                     let rename_editor = cx.add_view(|cx| {
+                        println!("Rename editor created.");
                         let mut editor = Editor::single_line(None, cx);
                         if let Some(old_highlight_id) = old_highlight_id {
                             editor.override_text_style =

crates/editor/src/element.rs 🔗

@@ -41,7 +41,7 @@ struct SelectionLayout {
 }
 
 impl SelectionLayout {
-    fn from<T: ToPoint + ToDisplayPoint + Clone>(
+    fn new<T: ToPoint + ToDisplayPoint + Clone>(
         selection: Selection<T>,
         line_mode: bool,
         map: &DisplaySnapshot,
@@ -977,7 +977,7 @@ impl Element for EditorElement {
                 remote_selections
                     .entry(replica_id)
                     .or_insert(Vec::new())
-                    .push(SelectionLayout::from(selection, line_mode, &display_map));
+                    .push(SelectionLayout::new(selection, line_mode, &display_map));
             }
             selections.extend(remote_selections);
 
@@ -1007,11 +1007,7 @@ impl Element for EditorElement {
                     local_selections
                         .into_iter()
                         .map(|selection| {
-                            SelectionLayout::from(
-                                selection,
-                                view.selections.line_mode,
-                                &display_map,
-                            )
+                            SelectionLayout::new(selection, view.selections.line_mode, &display_map)
                         })
                         .collect(),
                 ));

crates/editor/src/selections_collection.rs 🔗

@@ -289,9 +289,10 @@ impl SelectionsCollection {
         &mut self,
         cx: &mut MutableAppContext,
         change: impl FnOnce(&mut MutableSelectionsCollection) -> R,
-    ) -> R {
+    ) -> (bool, R) {
         let mut mutable_collection = MutableSelectionsCollection {
             collection: self,
+            selections_changed: false,
             cx,
         };
 
@@ -300,12 +301,13 @@ impl SelectionsCollection {
             !mutable_collection.disjoint.is_empty() || mutable_collection.pending.is_some(),
             "There must be at least one selection"
         );
-        result
+        (mutable_collection.selections_changed, result)
     }
 }
 
 pub struct MutableSelectionsCollection<'a> {
     collection: &'a mut SelectionsCollection,
+    selections_changed: bool,
     cx: &'a mut MutableAppContext,
 }
 
@@ -323,16 +325,26 @@ impl<'a> MutableSelectionsCollection<'a> {
     }
 
     pub fn delete(&mut self, selection_id: usize) {
+        let mut changed = false;
         self.collection.disjoint = self
             .disjoint
             .into_iter()
-            .filter(|selection| selection.id != selection_id)
+            .filter(|selection| {
+                let found = selection.id == selection_id;
+                changed |= found;
+                !found
+            })
             .cloned()
             .collect();
+
+        self.selections_changed |= changed;
     }
 
     pub fn clear_pending(&mut self) {
-        self.collection.pending = None;
+        if self.collection.pending.is_some() {
+            self.collection.pending = None;
+            self.selections_changed = true;
+        }
     }
 
     pub fn set_pending_range(&mut self, range: Range<Anchor>, mode: SelectMode) {
@@ -345,11 +357,13 @@ impl<'a> MutableSelectionsCollection<'a> {
                 goal: SelectionGoal::None,
             },
             mode,
-        })
+        });
+        self.selections_changed = true;
     }
 
     pub fn set_pending(&mut self, selection: Selection<Anchor>, mode: SelectMode) {
         self.collection.pending = Some(PendingSelection { selection, mode });
+        self.selections_changed = true;
     }
 
     pub fn try_cancel(&mut self) -> bool {
@@ -357,12 +371,14 @@ impl<'a> MutableSelectionsCollection<'a> {
             if self.disjoint.is_empty() {
                 self.collection.disjoint = Arc::from([pending.selection]);
             }
+            self.selections_changed = true;
             return true;
         }
 
         let mut oldest = self.oldest_anchor().clone();
         if self.count() > 1 {
             self.collection.disjoint = Arc::from([oldest]);
+            self.selections_changed = true;
             return true;
         }
 
@@ -371,27 +387,13 @@ impl<'a> MutableSelectionsCollection<'a> {
             oldest.start = head.clone();
             oldest.end = head;
             self.collection.disjoint = Arc::from([oldest]);
+            self.selections_changed = true;
             return true;
         }
 
         return false;
     }
 
-    pub fn reset_biases(&mut self) {
-        let buffer = self.buffer.read(self.cx).snapshot(self.cx);
-        self.collection.disjoint = self
-            .collection
-            .disjoint
-            .into_iter()
-            .cloned()
-            .map(|selection| reset_biases(selection, &buffer))
-            .collect();
-
-        if let Some(pending) = self.collection.pending.as_mut() {
-            pending.selection = reset_biases(pending.selection.clone(), &buffer);
-        }
-    }
-
     pub fn insert_range<T>(&mut self, range: Range<T>)
     where
         T: 'a + ToOffset + ToPoint + TextDimension + Ord + Sub<T, Output = T> + std::marker::Copy,
@@ -453,6 +455,7 @@ impl<'a> MutableSelectionsCollection<'a> {
         }));
 
         self.collection.pending = None;
+        self.selections_changed = true;
     }
 
     pub fn select_anchors(&mut self, selections: Vec<Selection<Anchor>>) {
@@ -551,18 +554,27 @@ impl<'a> MutableSelectionsCollection<'a> {
         &mut self,
         mut move_selection: impl FnMut(&DisplaySnapshot, &mut Selection<DisplayPoint>),
     ) {
+        let mut changed = false;
         let display_map = self.display_map();
         let selections = self
             .all::<Point>(self.cx)
             .into_iter()
             .map(|selection| {
-                let mut selection = selection.map(|point| point.to_display_point(&display_map));
-                move_selection(&display_map, &mut selection);
-                selection.map(|display_point| display_point.to_point(&display_map))
+                let mut moved_selection =
+                    selection.map(|point| point.to_display_point(&display_map));
+                move_selection(&display_map, &mut moved_selection);
+                let moved_selection =
+                    moved_selection.map(|display_point| display_point.to_point(&display_map));
+                if selection != moved_selection {
+                    changed = true;
+                }
+                moved_selection
             })
             .collect();
 
-        self.select(selections)
+        if changed {
+            self.select(selections)
+        }
     }
 
     pub fn move_heads_with(
@@ -686,6 +698,7 @@ impl<'a> MutableSelectionsCollection<'a> {
             pending.selection.end = end;
         }
         self.collection.pending = pending;
+        self.selections_changed = true;
 
         selections_with_lost_position
     }
@@ -730,17 +743,3 @@ fn resolve<D: TextDimension + Ord + Sub<D, Output = D>>(
 ) -> Selection<D> {
     selection.map(|p| p.summary::<D>(&buffer))
 }
-
-fn reset_biases(
-    mut selection: Selection<Anchor>,
-    buffer: &MultiBufferSnapshot,
-) -> Selection<Anchor> {
-    let end_bias = if selection.end.to_offset(buffer) > selection.start.to_offset(buffer) {
-        Bias::Left
-    } else {
-        Bias::Right
-    };
-    selection.start = buffer.anchor_after(selection.start);
-    selection.end = buffer.anchor_at(selection.end, end_bias);
-    selection
-}