WIP: Start on removing selections from buffer in favor of editor

Nathan Sobo created

Change summary

crates/editor/src/editor.rs       | 317 +++++++++++++++----------------
crates/editor/src/element.rs      |  51 ++--
crates/editor/src/items.rs        |   4 
crates/editor/src/multi_buffer.rs | 187 +-----------------
crates/language/src/buffer.rs     | 169 ++---------------
crates/language/src/tests.rs      | 121 ++++++-----
crates/project/src/worktree.rs    |  59 +++--
crates/server/src/rpc.rs          |  20 +
crates/text/src/tests.rs          |  58 +----
crates/text/src/text.rs           | 327 +-------------------------------
10 files changed, 352 insertions(+), 961 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -23,11 +23,11 @@ use gpui::{
 use items::BufferItemHandle;
 use language::{
     BracketPair, Buffer, Diagnostic, DiagnosticSeverity, Language, Point, Selection, SelectionGoal,
-    SelectionSetId,
+    SelectionSetId, TransactionId,
 };
 pub use multi_buffer::MultiBuffer;
 use multi_buffer::{
-    Anchor, AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot, SelectionSet, ToOffset, ToPoint,
+    Anchor, AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot, ToOffset, ToPoint,
 };
 use serde::{Deserialize, Serialize};
 use smallvec::SmallVec;
@@ -36,7 +36,8 @@ use std::{
     cell::RefCell,
     cmp,
     collections::HashMap,
-    iter, mem,
+    iter::{self, FromIterator},
+    mem,
     ops::{Deref, Range, RangeInclusive, Sub},
     rc::Rc,
     sync::Arc,
@@ -359,12 +360,14 @@ pub struct Editor {
     handle: WeakViewHandle<Self>,
     buffer: ModelHandle<MultiBuffer>,
     display_map: ModelHandle<DisplayMap>,
-    selection_set_id: SelectionSetId,
+    next_selection_id: usize,
+    selections: Arc<[Selection<Anchor>]>,
     pending_selection: Option<PendingSelection>,
     columnar_selection_tail: Option<Anchor>,
-    next_selection_id: usize,
     add_selections_state: Option<AddSelectionsState>,
     select_next_state: Option<SelectNextState>,
+    selection_history:
+        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
     autoclose_stack: Vec<BracketPairState>,
     select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
     active_diagnostics: Option<ActiveDiagnosticGroup>,
@@ -487,28 +490,27 @@ impl Editor {
             .detach();
 
         let mut next_selection_id = 0;
-        let selection_set_id = buffer.update(cx, |buffer, cx| {
-            buffer.add_selection_set(
-                &[Selection {
-                    id: post_inc(&mut next_selection_id),
-                    start: 0,
-                    end: 0,
-                    reversed: false,
-                    goal: SelectionGoal::None,
-                }],
-                cx,
-            )
-        });
+        let selections = Arc::from(
+            &[Selection {
+                id: post_inc(&mut next_selection_id),
+                start: Anchor::min(),
+                end: Anchor::min(),
+                reversed: false,
+                goal: SelectionGoal::None,
+            }][..],
+        );
+
         Self {
             handle: cx.weak_handle(),
             buffer,
             display_map,
-            selection_set_id,
+            selections,
             pending_selection: None,
             columnar_selection_tail: None,
             next_selection_id,
             add_selections_state: None,
             select_next_state: None,
+            selection_history: Default::default(),
             autoclose_stack: Default::default(),
             select_larger_syntax_node_stack: Vec::new(),
             active_diagnostics: None,
@@ -636,7 +638,7 @@ impl Editor {
         let first_cursor_top;
         let last_cursor_bottom;
         if autoscroll == Autoscroll::Newest {
-            let newest_selection = self.newest_selection::<Point>(cx);
+            let newest_selection = self.newest_selection::<Point>(&display_map.buffer_snapshot, cx);
             first_cursor_top = newest_selection.head().to_display_point(&display_map).row() as f32;
             last_cursor_bottom = first_cursor_top + 1.;
         } else {
@@ -769,7 +771,9 @@ impl Editor {
         cx: &mut ViewContext<Self>,
     ) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let tail = self.newest_selection::<usize>(cx).tail();
+        let tail = self
+            .newest_selection::<usize>(&display_map.buffer_snapshot, cx)
+            .tail();
         self.begin_selection(position, false, click_count, cx);
 
         let position = position.to_offset(&display_map, Bias::Left);
@@ -851,7 +855,7 @@ impl Editor {
             self.update_selections::<usize>(Vec::new(), None, cx);
         } else if click_count > 1 {
             // Remove the newest selection since it was only added as part of this multi-click.
-            let newest_selection = self.newest_selection::<usize>(cx);
+            let newest_selection = self.newest_selection::<usize>(buffer, cx);
             let mut selections = self.selections(cx);
             selections.retain(|selection| selection.id != newest_selection.id);
             self.update_selections::<usize>(selections, None, cx)
@@ -874,7 +878,9 @@ impl Editor {
         }
 
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let tail = self.newest_selection::<Point>(cx).tail();
+        let tail = self
+            .newest_selection::<Point>(&display_map.buffer_snapshot, cx)
+            .tail();
         self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 
         self.select_columns(
@@ -2812,7 +2818,7 @@ impl Editor {
 
     pub fn show_next_diagnostic(&mut self, _: &ShowNextDiagnostic, cx: &mut ViewContext<Self>) {
         let buffer = self.buffer.read(cx).snapshot(cx);
-        let selection = self.newest_selection::<usize>(cx);
+        let selection = self.newest_selection::<usize>(&buffer, cx);
         let active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
             active_diagnostics
                 .primary_range
@@ -2992,120 +2998,119 @@ impl Editor {
         }
     }
 
-    pub fn active_selection_sets<'a>(
-        &'a self,
-        cx: &'a AppContext,
-    ) -> impl 'a + Iterator<Item = SelectionSetId> {
-        let buffer = self.buffer.read(cx);
-        let replica_id = buffer.replica_id();
-        buffer
-            .selection_sets(cx)
-            .filter(move |(set_id, set)| {
-                set.active && (set_id.replica_id != replica_id || **set_id == self.selection_set_id)
-            })
-            .map(|(set_id, _)| *set_id)
-    }
-
     pub fn intersecting_selections<'a>(
         &'a self,
         set_id: SelectionSetId,
         range: Range<DisplayPoint>,
         cx: &'a mut MutableAppContext,
     ) -> Vec<Selection<DisplayPoint>> {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = self.buffer.read(cx);
-
-        let pending_selection = if set_id == self.selection_set_id {
-            self.pending_selection.as_ref().and_then(|pending| {
-                let selection_start = pending.selection.start.to_display_point(&display_map);
-                let selection_end = pending.selection.end.to_display_point(&display_map);
-                if selection_start <= range.end || selection_end <= range.end {
-                    Some(Selection {
-                        id: pending.selection.id,
-                        start: selection_start,
-                        end: selection_end,
-                        reversed: pending.selection.reversed,
-                        goal: pending.selection.goal,
-                    })
-                } else {
-                    None
-                }
-            })
-        } else {
-            None
-        };
-
-        let range = (range.start.to_offset(&display_map, Bias::Left), Bias::Left)
-            ..(range.end.to_offset(&display_map, Bias::Left), Bias::Right);
-        buffer
-            .selection_set(set_id, cx)
-            .unwrap()
-            .intersecting_selections::<Point, _>(range, &buffer.read(cx))
-            .map(move |s| Selection {
-                id: s.id,
-                start: s.start.to_display_point(&display_map),
-                end: s.end.to_display_point(&display_map),
-                reversed: s.reversed,
-                goal: s.goal,
-            })
-            .chain(pending_selection)
-            .collect()
+        todo!()
+        // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+        // let buffer = self.buffer.read(cx);
+
+        // let pending_selection = if set_id == self.selection_set_id {
+        //     self.pending_selection.as_ref().and_then(|pending| {
+        //         let selection_start = pending.selection.start.to_display_point(&display_map);
+        //         let selection_end = pending.selection.end.to_display_point(&display_map);
+        //         if selection_start <= range.end || selection_end <= range.end {
+        //             Some(Selection {
+        //                 id: pending.selection.id,
+        //                 start: selection_start,
+        //                 end: selection_end,
+        //                 reversed: pending.selection.reversed,
+        //                 goal: pending.selection.goal,
+        //             })
+        //         } else {
+        //             None
+        //         }
+        //     })
+        // } else {
+        //     None
+        // };
+
+        // let range = (range.start.to_offset(&display_map, Bias::Left), Bias::Left)
+        //     ..(range.end.to_offset(&display_map, Bias::Left), Bias::Right);
+        // buffer
+        //     .selection_set(set_id, cx)
+        //     .unwrap()
+        //     .intersecting_selections::<Point, _>(range, &buffer.read(cx))
+        //     .map(move |s| Selection {
+        //         id: s.id,
+        //         start: s.start.to_display_point(&display_map),
+        //         end: s.end.to_display_point(&display_map),
+        //         reversed: s.reversed,
+        //         goal: s.goal,
+        //     })
+        //     .chain(pending_selection)
+        //     .collect()
     }
 
     pub fn selections<'a, D>(&self, cx: &'a AppContext) -> Vec<Selection<D>>
     where
         D: 'a + TextDimension + Ord + Sub<D, Output = D>,
     {
-        let buffer = self.buffer.read(cx).snapshot(cx);
-        let mut selections = self.selection_set(cx).selections::<D>(&buffer).peekable();
-        let mut pending_selection = self.pending_selection(cx);
-
-        iter::from_fn(move || {
-            if let Some(pending) = pending_selection.as_mut() {
-                while let Some(next_selection) = selections.peek() {
-                    if pending.start <= next_selection.end && pending.end >= next_selection.start {
-                        let next_selection = selections.next().unwrap();
-                        if next_selection.start < pending.start {
-                            pending.start = next_selection.start;
-                        }
-                        if next_selection.end > pending.end {
-                            pending.end = next_selection.end;
-                        }
-                    } else if next_selection.end < pending.start {
-                        return selections.next();
-                    } else {
-                        break;
-                    }
-                }
-
-                pending_selection.take()
-            } else {
-                selections.next()
-            }
-        })
-        .collect()
+        // let buffer = self.buffer.read(cx).snapshot(cx);
+        // let mut selections = self.selection_set(cx).selections::<D>(&buffer).peekable();
+        // let mut pending_selection = self.pending_selection(cx);
+
+        // iter::from_fn(move || {
+        //     if let Some(pending) = pending_selection.as_mut() {
+        //         while let Some(next_selection) = selections.peek() {
+        //             if pending.start <= next_selection.end && pending.end >= next_selection.start {
+        //                 let next_selection = selections.next().unwrap();
+        //                 if next_selection.start < pending.start {
+        //                     pending.start = next_selection.start;
+        //                 }
+        //                 if next_selection.end > pending.end {
+        //                     pending.end = next_selection.end;
+        //                 }
+        //             } else if next_selection.end < pending.start {
+        //                 return selections.next();
+        //             } else {
+        //                 break;
+        //             }
+        //         }
+
+        //         pending_selection.take()
+        //     } else {
+        //         selections.next()
+        //     }
+        // })
+        // .collect()
+        todo!()
     }
 
     fn pending_selection<D: TextDimension + Ord + Sub<D, Output = D>>(
         &self,
+        snapshot: &MultiBufferSnapshot,
         cx: &AppContext,
     ) -> Option<Selection<D>> {
-        let buffer = self.buffer.read(cx).read(cx);
-        self.pending_selection.as_ref().map(|pending| Selection {
-            id: pending.selection.id,
-            start: pending.selection.start.summary::<D>(&buffer),
-            end: pending.selection.end.summary::<D>(&buffer),
-            reversed: pending.selection.reversed,
-            goal: pending.selection.goal,
-        })
+        self.pending_selection
+            .as_ref()
+            .map(|pending| self.resolve_selection(&pending.selection, &snapshot, cx))
+    }
+
+    fn resolve_selection<D: TextDimension + Ord + Sub<D, Output = D>>(
+        &self,
+        selection: &Selection<Anchor>,
+        buffer: &MultiBufferSnapshot,
+        cx: &AppContext,
+    ) -> Selection<D> {
+        Selection {
+            id: selection.id,
+            start: selection.start.summary::<D>(&buffer),
+            end: selection.end.summary::<D>(&buffer),
+            reversed: selection.reversed,
+            goal: selection.goal,
+        }
     }
 
     fn selection_count<'a>(&self, cx: &'a AppContext) -> usize {
-        let mut selection_count = self.selection_set(cx).len();
+        let mut count = self.selections.len();
         if self.pending_selection.is_some() {
-            selection_count += 1;
+            count += 1;
         }
-        selection_count
+        count
     }
 
     pub fn oldest_selection<D: TextDimension + Ord + Sub<D, Output = D>>(
@@ -3113,31 +3118,29 @@ impl Editor {
         snapshot: &MultiBufferSnapshot,
         cx: &AppContext,
     ) -> Selection<D> {
-        self.selection_set(cx)
-            .oldest_selection(snapshot)
-            .or_else(|| self.pending_selection(cx))
+        self.selections
+            .iter()
+            .min_by_key(|s| s.id)
+            .map(|selection| self.resolve_selection(selection, snapshot, cx))
+            .or_else(|| self.pending_selection(snapshot, cx))
             .unwrap()
     }
 
     pub fn newest_selection<D: TextDimension + Ord + Sub<D, Output = D>>(
         &self,
+        snapshot: &MultiBufferSnapshot,
         cx: &AppContext,
     ) -> Selection<D> {
-        self.pending_selection(cx)
+        self.pending_selection(snapshot, cx)
             .or_else(|| {
-                self.selection_set(cx)
-                    .newest_selection(&self.buffer.read(cx).read(cx))
+                self.selections
+                    .iter()
+                    .min_by_key(|s| s.id)
+                    .map(|selection| self.resolve_selection(selection, snapshot, cx))
             })
             .unwrap()
     }
 
-    fn selection_set<'a>(&self, cx: &'a AppContext) -> &'a SelectionSet {
-        self.buffer
-            .read(cx)
-            .selection_set(self.selection_set_id, cx)
-            .unwrap()
-    }
-
     pub fn update_selections<T>(
         &mut self,
         mut selections: Vec<Selection<T>>,
@@ -3193,11 +3196,13 @@ impl Editor {
         }
         self.pause_cursor_blinking(cx);
 
-        self.buffer.update(cx, |buffer, cx| {
-            buffer
-                .update_selection_set(self.selection_set_id, &selections, cx)
-                .unwrap();
-        });
+        self.selections = Arc::from_iter(selections.into_iter().map(|selection| Selection {
+            id: selection.id,
+            start: buffer.anchor_before(selection.start),
+            end: buffer.anchor_before(selection.end),
+            reversed: selection.reversed,
+            goal: selection.goal,
+        }));
     }
 
     fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
@@ -3208,13 +3213,13 @@ impl Editor {
     fn start_transaction(&mut self, cx: &mut ViewContext<Self>) {
         self.end_selection(cx);
         self.buffer.update(cx, |buffer, cx| {
-            buffer.start_transaction([self.selection_set_id], cx);
+            buffer.start_transaction(cx);
         });
     }
 
     fn end_transaction(&self, cx: &mut ViewContext<Self>) {
         self.buffer.update(cx, |buffer, cx| {
-            buffer.end_transaction([self.selection_set_id], cx);
+            buffer.end_transaction(cx);
         });
     }
 
@@ -3549,14 +3554,6 @@ pub enum Event {
 
 impl Entity for Editor {
     type Event = Event;
-
-    fn release(&mut self, cx: &mut MutableAppContext) {
-        self.buffer.update(cx, |buffer, cx| {
-            buffer
-                .remove_selection_set(self.selection_set_id, cx)
-                .unwrap();
-        });
-    }
 }
 
 impl View for Editor {
@@ -3579,19 +3576,11 @@ impl View for Editor {
     fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
         self.focused = true;
         self.blink_cursors(self.blink_epoch, cx);
-        self.buffer.update(cx, |buffer, cx| {
-            buffer
-                .set_active_selection_set(Some(self.selection_set_id), cx)
-                .unwrap();
-        });
     }
 
     fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
         self.focused = false;
         self.show_local_cursors = false;
-        self.buffer.update(cx, |buffer, cx| {
-            buffer.set_active_selection_set(None, cx).unwrap();
-        });
         cx.emit(Event::Blurred);
         cx.notify();
     }
@@ -3710,6 +3699,8 @@ pub fn diagnostic_style(
 
 #[cfg(test)]
 mod tests {
+    use std::mem;
+
     use super::*;
     use language::LanguageConfig;
     use text::Point;
@@ -5670,20 +5661,18 @@ mod tests {
 
     impl Editor {
         fn selection_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
-            self.intersecting_selections(
-                self.selection_set_id,
-                DisplayPoint::zero()..self.max_point(cx),
-                cx,
-            )
-            .into_iter()
-            .map(|s| {
-                if s.reversed {
-                    s.end..s.start
-                } else {
-                    s.start..s.end
-                }
-            })
-            .collect()
+            let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+            self.selections
+                .iter()
+                .map(|s| {
+                    let mut range =
+                        s.start.to_display_point(&snapshot)..s.end.to_display_point(&snapshot);
+                    if s.reversed {
+                        mem::swap(&mut range.start, &mut range.end);
+                    }
+                    range
+                })
+                .collect()
         }
     }
 

crates/editor/src/element.rs 🔗

@@ -733,34 +733,37 @@ impl Element for EditorElement {
         let scroll_top = scroll_position.y() * line_height;
         let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
 
-        let mut selections = HashMap::new();
-        let mut active_rows = BTreeMap::new();
+        let selections = HashMap::new();
+        let active_rows = BTreeMap::new();
         let mut highlighted_row = None;
         self.update_view(cx.app, |view, cx| {
             highlighted_row = view.highlighted_row();
-            for selection_set_id in view.active_selection_sets(cx).collect::<Vec<_>>() {
-                let replica_selections = view.intersecting_selections(
-                    selection_set_id,
-                    DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
-                    cx,
-                );
-                for selection in &replica_selections {
-                    if selection_set_id == view.selection_set_id {
-                        let is_empty = selection.start == selection.end;
-                        let selection_start = snapshot.prev_row_boundary(selection.start).0;
-                        let selection_end = snapshot.next_row_boundary(selection.end).0;
-                        for row in cmp::max(selection_start.row(), start_row)
-                            ..=cmp::min(selection_end.row(), end_row)
-                        {
-                            let contains_non_empty_selection =
-                                active_rows.entry(row).or_insert(!is_empty);
-                            *contains_non_empty_selection |= !is_empty;
-                        }
-                    }
-                }
 
-                selections.insert(selection_set_id.replica_id, replica_selections);
-            }
+            // TODO: Get this working with editors owning their own selections
+
+            // for selection_set_id in view.active_selection_sets(cx).collect::<Vec<_>>() {
+            //     let replica_selections = view.intersecting_selections(
+            //         selection_set_id,
+            //         DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
+            //         cx,
+            //     );
+            //     for selection in &replica_selections {
+            //         if selection_set_id == view.selection_set_id {
+            //             let is_empty = selection.start == selection.end;
+            //             let selection_start = snapshot.prev_row_boundary(selection.start).0;
+            //             let selection_end = snapshot.next_row_boundary(selection.end).0;
+            //             for row in cmp::max(selection_start.row(), start_row)
+            //                 ..=cmp::min(selection_end.row(), end_row)
+            //             {
+            //                 let contains_non_empty_selection =
+            //                     active_rows.entry(row).or_insert(!is_empty);
+            //                 *contains_non_empty_selection |= !is_empty;
+            //             }
+            //         }
+            //     }
+
+            //     selections.insert(selection_set_id.replica_id, replica_selections);
+            // }
         });
 
         let line_number_layouts = self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx);

crates/editor/src/items.rs 🔗

@@ -322,8 +322,10 @@ impl DiagnosticMessage {
 
     fn update(&mut self, editor: ViewHandle<Editor>, cx: &mut ViewContext<Self>) {
         let editor = editor.read(cx);
-        let cursor_position = editor.newest_selection::<usize>(cx).head();
         let buffer = editor.buffer().read(cx);
+        let cursor_position = editor
+            .newest_selection::<usize>(&buffer.read(cx), cx)
+            .head();
         let new_diagnostic = buffer
             .read(cx)
             .diagnostics_in_range::<_, usize>(cursor_position..cursor_position)

crates/editor/src/multi_buffer.rs 🔗

@@ -24,7 +24,7 @@ use text::{
     locator::Locator,
     rope::TextDimension,
     subscription::{Subscription, Topic},
-    AnchorRangeExt as _, Edit, Point, PointUtf16, Selection, SelectionSetId, TextSummary,
+    AnchorRangeExt as _, Edit, Point, PointUtf16, SelectionSetId, TextSummary,
 };
 use theme::SyntaxTheme;
 
@@ -113,7 +113,7 @@ impl MultiBuffer {
     pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
         let mut this = Self::new(buffer.read(cx).replica_id());
         this.singleton = true;
-        this.push(
+        this.push_excerpt(
             ExcerptProperties {
                 buffer: &buffer,
                 range: text::Anchor::min()..text::Anchor::max(),
@@ -202,26 +202,18 @@ impl MultiBuffer {
         });
     }
 
-    pub fn start_transaction(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-        cx: &mut ModelContext<Self>,
-    ) -> Option<TransactionId> {
+    pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
         // TODO
         self.as_singleton()
             .unwrap()
-            .update(cx, |buffer, _| buffer.start_transaction(selection_set_ids))
+            .update(cx, |buffer, _| buffer.start_transaction())
     }
 
-    pub fn end_transaction(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-        cx: &mut ModelContext<Self>,
-    ) -> Option<TransactionId> {
+    pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
         // TODO
-        self.as_singleton().unwrap().update(cx, |buffer, cx| {
-            buffer.end_transaction(selection_set_ids, cx)
-        })
+        self.as_singleton()
+            .unwrap()
+            .update(cx, |buffer, cx| buffer.end_transaction(cx))
     }
 
     pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
@@ -238,153 +230,11 @@ impl MultiBuffer {
             .update(cx, |buffer, cx| buffer.redo(cx))
     }
 
-    pub fn selection_set(&self, set_id: SelectionSetId, cx: &AppContext) -> Result<&SelectionSet> {
-        // TODO
-        let set = self
-            .as_singleton()
-            .unwrap()
-            .read(cx)
-            .selection_set(set_id)?;
-        let excerpt_id = self.snapshot.borrow().excerpts.first().unwrap().id.clone();
-
-        let selection_sets: &mut HashMap<SelectionSetId, SelectionSet> =
-            unsafe { &mut *(&self.selection_sets as *const _ as *mut _) };
-        selection_sets.insert(
-            set_id,
-            SelectionSet {
-                id: set.id,
-                active: set.active,
-                selections: set
-                    .selections
-                    .iter()
-                    .map(|selection| Selection {
-                        id: selection.id,
-                        start: Anchor {
-                            excerpt_id: excerpt_id.clone(),
-                            text_anchor: selection.start.clone(),
-                        },
-                        end: Anchor {
-                            excerpt_id: excerpt_id.clone(),
-                            text_anchor: selection.end.clone(),
-                        },
-                        reversed: selection.reversed,
-                        goal: selection.goal,
-                    })
-                    .collect(),
-            },
-        );
-        Ok(self.selection_sets.get(&set.id).unwrap())
-    }
-
-    pub fn add_selection_set<T: ToOffset>(
-        &mut self,
-        selections: &[Selection<T>],
-        cx: &mut ModelContext<Self>,
-    ) -> SelectionSetId {
-        // TODO
-        let snapshot = self.read(cx);
-        self.as_singleton().unwrap().update(cx, |buffer, cx| {
-            buffer.add_selection_set(
-                &selections
-                    .iter()
-                    .map(|selection| Selection {
-                        id: selection.id,
-                        start: selection.start.to_offset(&snapshot),
-                        end: selection.end.to_offset(&snapshot),
-                        reversed: selection.reversed,
-                        goal: selection.goal,
-                    })
-                    .collect::<Vec<_>>(),
-                cx,
-            )
-        })
-    }
-
-    pub fn remove_selection_set(
-        &mut self,
-        set_id: SelectionSetId,
-        cx: &mut ModelContext<Self>,
-    ) -> Result<()> {
-        // TODO
-        self.as_singleton()
-            .unwrap()
-            .update(cx, |buffer, cx| buffer.remove_selection_set(set_id, cx))
-    }
-
-    pub fn update_selection_set<T: ToOffset>(
-        &mut self,
-        set_id: SelectionSetId,
-        selections: &[Selection<T>],
-        cx: &mut ModelContext<Self>,
-    ) -> Result<()> {
-        // TODO
-        let snapshot = self.read(cx);
-        self.as_singleton().unwrap().update(cx, |buffer, cx| {
-            buffer.update_selection_set(
-                set_id,
-                &selections
-                    .iter()
-                    .map(|selection| Selection {
-                        id: selection.id,
-                        start: selection.start.to_offset(&snapshot),
-                        end: selection.end.to_offset(&snapshot),
-                        reversed: selection.reversed,
-                        goal: selection.goal,
-                    })
-                    .collect::<Vec<_>>(),
-                cx,
-            )
-        })
-    }
-
-    pub fn set_active_selection_set(
+    pub fn push_excerpt<O>(
         &mut self,
-        set_id: Option<SelectionSetId>,
+        props: ExcerptProperties<O>,
         cx: &mut ModelContext<Self>,
-    ) -> Result<()> {
-        self.as_singleton()
-            .unwrap()
-            .update(cx, |buffer, cx| buffer.set_active_selection_set(set_id, cx))
-    }
-
-    pub fn selection_sets(
-        &self,
-        cx: &AppContext,
-    ) -> impl Iterator<Item = (&SelectionSetId, &SelectionSet)> {
-        let excerpt_id = self.snapshot.borrow().excerpts.first().unwrap().id.clone();
-        let selection_sets: &mut HashMap<SelectionSetId, SelectionSet> =
-            unsafe { &mut *(&self.selection_sets as *const _ as *mut _) };
-        selection_sets.clear();
-        for (selection_set_id, set) in self.as_singleton().unwrap().read(cx).selection_sets() {
-            selection_sets.insert(
-                *selection_set_id,
-                SelectionSet {
-                    id: set.id,
-                    active: set.active,
-                    selections: set
-                        .selections
-                        .iter()
-                        .map(|selection| Selection {
-                            id: selection.id,
-                            start: Anchor {
-                                excerpt_id: excerpt_id.clone(),
-                                text_anchor: selection.start.clone(),
-                            },
-                            end: Anchor {
-                                excerpt_id: excerpt_id.clone(),
-                                text_anchor: selection.end.clone(),
-                            },
-                            reversed: selection.reversed,
-                            goal: selection.goal,
-                        })
-                        .collect(),
-                },
-            );
-        }
-        self.selection_sets.iter()
-    }
-
-    pub fn push<O>(&mut self, props: ExcerptProperties<O>, cx: &mut ModelContext<Self>) -> ExcerptId
+    ) -> ExcerptId
     where
         O: text::ToOffset,
     {
@@ -555,13 +405,6 @@ impl MultiBuffer {
             .update(cx, |buffer, cx| buffer.randomly_edit(rng, count, cx));
         self.sync(cx);
     }
-
-    pub fn randomly_mutate<R: rand::Rng>(&mut self, rng: &mut R, cx: &mut ModelContext<Self>) {
-        self.as_singleton()
-            .unwrap()
-            .update(cx, |buffer, cx| buffer.randomly_mutate(rng, cx));
-        self.sync(cx);
-    }
 }
 
 impl Entity for MultiBuffer {
@@ -1389,7 +1232,7 @@ mod tests {
 
         let subscription = multibuffer.update(cx, |multibuffer, cx| {
             let subscription = multibuffer.subscribe();
-            multibuffer.push(
+            multibuffer.push_excerpt(
                 ExcerptProperties {
                     buffer: &buffer_1,
                     range: Point::new(1, 2)..Point::new(2, 5),
@@ -1405,7 +1248,7 @@ mod tests {
                 }]
             );
 
-            multibuffer.push(
+            multibuffer.push_excerpt(
                 ExcerptProperties {
                     buffer: &buffer_1,
                     range: Point::new(3, 3)..Point::new(4, 4),
@@ -1413,7 +1256,7 @@ mod tests {
                 },
                 cx,
             );
-            multibuffer.push(
+            multibuffer.push_excerpt(
                 ExcerptProperties {
                     buffer: &buffer_2,
                     range: Point::new(3, 1)..Point::new(3, 3),
@@ -1529,7 +1372,7 @@ mod tests {
                     );
 
                     let excerpt_id = list.update(cx, |list, cx| {
-                        list.push(
+                        list.push_excerpt(
                             ExcerptProperties {
                                 buffer: &buffer_handle,
                                 range: start_ix..end_ix,

crates/language/src/buffer.rs 🔗

@@ -178,7 +178,6 @@ struct SyntaxTree {
 
 #[derive(Clone)]
 struct AutoindentRequest {
-    selection_set_ids: HashSet<SelectionSetId>,
     before_edit: BufferSnapshot,
     edited: Vec<Anchor>,
     inserted: Option<Vec<Range<Anchor>>>,
@@ -277,10 +276,6 @@ impl Buffer {
             .into_iter()
             .map(|op| text::Operation::Edit(proto::deserialize_edit_operation(op)));
         buffer.apply_ops(ops)?;
-        for set in message.selections {
-            let set = proto::deserialize_selection_set(set);
-            buffer.add_raw_selection_set(set.id, set);
-        }
         let mut this = Self::build(buffer, file);
         this.apply_diagnostic_update(
             Arc::from(proto::deserialize_diagnostics(message.diagnostics)),
@@ -299,10 +294,7 @@ impl Buffer {
                 .history()
                 .map(proto::serialize_edit_operation)
                 .collect(),
-            selections: self
-                .selection_sets()
-                .map(|(_, set)| proto::serialize_selection_set(set))
-                .collect(),
+            selections: Vec::new(),
             diagnostics: proto::serialize_diagnostics(self.diagnostics.iter()),
         }
     }
@@ -971,49 +963,11 @@ impl Buffer {
         indent_columns: BTreeMap<u32, u32>,
         cx: &mut ModelContext<Self>,
     ) {
-        let selection_set_ids = self
-            .autoindent_requests
-            .drain(..)
-            .flat_map(|req| req.selection_set_ids.clone())
-            .collect::<HashSet<_>>();
-
-        self.start_transaction(selection_set_ids.iter().copied());
+        self.start_transaction();
         for (row, indent_column) in &indent_columns {
             self.set_indent_column_for_line(*row, *indent_column, cx);
         }
-
-        for selection_set_id in &selection_set_ids {
-            if let Ok(set) = self.selection_set(*selection_set_id) {
-                let new_selections = set
-                    .selections::<Point>(&*self)
-                    .map(|selection| {
-                        if selection.start.column == 0 {
-                            let delta = Point::new(
-                                0,
-                                indent_columns
-                                    .get(&selection.start.row)
-                                    .copied()
-                                    .unwrap_or(0),
-                            );
-                            if delta.column > 0 {
-                                return Selection {
-                                    id: selection.id,
-                                    goal: selection.goal,
-                                    reversed: selection.reversed,
-                                    start: selection.start + delta,
-                                    end: selection.end + delta,
-                                };
-                            }
-                        }
-                        selection
-                    })
-                    .collect::<Vec<_>>();
-                self.update_selection_set(*selection_set_id, &new_selections, cx)
-                    .unwrap();
-            }
-        }
-
-        self.end_transaction(selection_set_ids.iter().copied(), cx);
+        self.end_transaction(cx);
     }
 
     fn set_indent_column_for_line(&mut self, row: u32, column: u32, cx: &mut ModelContext<Self>) {
@@ -1053,7 +1007,7 @@ impl Buffer {
 
     pub(crate) fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext<Self>) -> bool {
         if self.version == diff.base_version {
-            self.start_transaction(None);
+            self.start_transaction();
             let mut offset = 0;
             for (tag, len) in diff.changes {
                 let range = offset..(offset + len);
@@ -1066,7 +1020,7 @@ impl Buffer {
                     }
                 }
             }
-            self.end_transaction(None, cx);
+            self.end_transaction(cx);
             true
         } else {
             false
@@ -1090,38 +1044,24 @@ impl Buffer {
         self.text.subscribe()
     }
 
-    pub fn start_transaction(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-    ) -> Option<TransactionId> {
-        self.start_transaction_at(selection_set_ids, Instant::now())
+    pub fn start_transaction(&mut self) -> Option<TransactionId> {
+        self.start_transaction_at(Instant::now())
     }
 
-    pub(crate) fn start_transaction_at(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-        now: Instant,
-    ) -> Option<TransactionId> {
-        self.text.start_transaction_at(selection_set_ids, now)
+    pub(crate) fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
+        self.text.start_transaction_at(now)
     }
 
-    pub fn end_transaction(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-        cx: &mut ModelContext<Self>,
-    ) -> Option<TransactionId> {
-        self.end_transaction_at(selection_set_ids, Instant::now(), cx)
+    pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
+        self.end_transaction_at(Instant::now(), cx)
     }
 
     pub(crate) fn end_transaction_at(
         &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
         now: Instant,
         cx: &mut ModelContext<Self>,
     ) -> Option<TransactionId> {
-        if let Some((transaction_id, start_version)) =
-            self.text.end_transaction_at(selection_set_ids, now)
-        {
+        if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
             let was_dirty = start_version != self.saved_version;
             self.did_edit(&start_version, was_dirty, cx);
             Some(transaction_id)
@@ -1212,7 +1152,7 @@ impl Buffer {
             return;
         }
 
-        self.start_transaction(None);
+        self.start_transaction();
         self.pending_autoindent.take();
         let autoindent_request = if autoindent && self.language.is_some() {
             let before_edit = self.snapshot();
@@ -1256,21 +1196,14 @@ impl Buffer {
                 );
             }
 
-            let selection_set_ids = self
-                .text
-                .peek_undo_stack()
-                .unwrap()
-                .starting_selection_set_ids()
-                .collect();
             self.autoindent_requests.push(Arc::new(AutoindentRequest {
-                selection_set_ids,
                 before_edit,
                 edited,
                 inserted,
             }));
         }
 
-        self.end_transaction(None, cx);
+        self.end_transaction(cx);
         self.send_operation(Operation::Buffer(text::Operation::Edit(edit)), cx);
     }
 
@@ -1298,55 +1231,6 @@ impl Buffer {
         self.language.as_ref().and_then(|l| l.grammar.as_ref())
     }
 
-    pub fn add_selection_set<T: ToOffset>(
-        &mut self,
-        selections: &[Selection<T>],
-        cx: &mut ModelContext<Self>,
-    ) -> SelectionSetId {
-        let operation = self.text.add_selection_set(selections);
-        if let text::Operation::UpdateSelections { set_id, .. } = &operation {
-            let set_id = *set_id;
-            cx.notify();
-            self.send_operation(Operation::Buffer(operation), cx);
-            set_id
-        } else {
-            unreachable!()
-        }
-    }
-
-    pub fn update_selection_set<T: ToOffset>(
-        &mut self,
-        set_id: SelectionSetId,
-        selections: &[Selection<T>],
-        cx: &mut ModelContext<Self>,
-    ) -> Result<()> {
-        let operation = self.text.update_selection_set(set_id, selections)?;
-        cx.notify();
-        self.send_operation(Operation::Buffer(operation), cx);
-        Ok(())
-    }
-
-    pub fn set_active_selection_set(
-        &mut self,
-        set_id: Option<SelectionSetId>,
-        cx: &mut ModelContext<Self>,
-    ) -> Result<()> {
-        let operation = self.text.set_active_selection_set(set_id)?;
-        self.send_operation(Operation::Buffer(operation), cx);
-        Ok(())
-    }
-
-    pub fn remove_selection_set(
-        &mut self,
-        set_id: SelectionSetId,
-        cx: &mut ModelContext<Self>,
-    ) -> Result<()> {
-        let operation = self.text.remove_selection_set(set_id)?;
-        cx.notify();
-        self.send_operation(Operation::Buffer(operation), cx);
-        Ok(())
-    }
-
     pub fn apply_ops<I: IntoIterator<Item = Operation>>(
         &mut self,
         ops: I,
@@ -1447,10 +1331,8 @@ impl Buffer {
         let was_dirty = self.is_dirty();
         let old_version = self.version.clone();
 
-        if let Some((transaction_id, operations)) = self.text.undo() {
-            for operation in operations {
-                self.send_operation(Operation::Buffer(operation), cx);
-            }
+        if let Some((transaction_id, operation)) = self.text.undo() {
+            self.send_operation(Operation::Buffer(operation), cx);
             self.did_edit(&old_version, was_dirty, cx);
             Some(transaction_id)
         } else {
@@ -1462,10 +1344,8 @@ impl Buffer {
         let was_dirty = self.is_dirty();
         let old_version = self.version.clone();
 
-        if let Some((transaction_id, operations)) = self.text.redo() {
-            for operation in operations {
-                self.send_operation(Operation::Buffer(operation), cx);
-            }
+        if let Some((transaction_id, operation)) = self.text.redo() {
+            self.send_operation(Operation::Buffer(operation), cx);
             self.did_edit(&old_version, was_dirty, cx);
             Some(transaction_id)
         } else {
@@ -1484,18 +1364,9 @@ impl Buffer {
     ) where
         T: rand::Rng,
     {
-        self.start_transaction(None);
+        self.start_transaction();
         self.text.randomly_edit(rng, old_range_count);
-        self.end_transaction(None, cx);
-    }
-
-    pub fn randomly_mutate<T>(&mut self, rng: &mut T, cx: &mut ModelContext<Self>)
-    where
-        T: rand::Rng,
-    {
-        self.start_transaction(None);
-        self.text.randomly_mutate(rng);
-        self.end_transaction(None, cx);
+        self.end_transaction(cx);
     }
 }
 

crates/language/src/tests.rs 🔗

@@ -92,15 +92,15 @@ fn test_edit_events(cx: &mut gpui::MutableAppContext) {
         buffer.edit(Some(2..4), "XYZ", cx);
 
         // An empty transaction does not emit any events.
-        buffer.start_transaction(None);
-        buffer.end_transaction(None, cx);
+        buffer.start_transaction();
+        buffer.end_transaction(cx);
 
         // A transaction containing two edits emits one edited event.
         now += Duration::from_secs(1);
-        buffer.start_transaction_at(None, now);
+        buffer.start_transaction_at(now);
         buffer.edit(Some(5..5), "u", cx);
         buffer.edit(Some(6..6), "w", cx);
-        buffer.end_transaction_at(None, now, cx);
+        buffer.end_transaction_at(now, cx);
 
         // Undoing a transaction emits one edited event.
         buffer.undo(cx);
@@ -167,7 +167,7 @@ async fn test_reparse(mut cx: gpui::TestAppContext) {
     // Perform some edits (add parameter and variable reference)
     // Parsing doesn't begin until the transaction is complete
     buffer.update(&mut cx, |buf, cx| {
-        buf.start_transaction(None);
+        buf.start_transaction();
 
         let offset = buf.text().find(")").unwrap();
         buf.edit(vec![offset..offset], "b: C", cx);
@@ -177,7 +177,7 @@ async fn test_reparse(mut cx: gpui::TestAppContext) {
         buf.edit(vec![offset..offset], " d; ", cx);
         assert!(!buf.is_parsing());
 
-        buf.end_transaction(None, cx);
+        buf.end_transaction(cx);
         assert_eq!(buf.text(), "fn a(b: C) { d; }");
         assert!(buf.is_parsing());
     });
@@ -333,59 +333,62 @@ fn test_edit_with_autoindent(cx: &mut MutableAppContext) {
     });
 }
 
-#[gpui::test]
-fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
-    cx.add_model(|cx| {
-        let text = "fn a() {}";
-
-        let mut buffer =
-            Buffer::new(0, text, cx).with_language(Some(Arc::new(rust_lang())), None, cx);
-
-        let selection_set_id = buffer.add_selection_set::<usize>(&[], cx);
-        buffer.start_transaction(Some(selection_set_id));
-        buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx);
-        buffer
-            .update_selection_set(
-                selection_set_id,
-                &[
-                    Selection {
-                        id: 0,
-                        start: Point::new(1, 0),
-                        end: Point::new(1, 0),
-                        reversed: false,
-                        goal: SelectionGoal::None,
-                    },
-                    Selection {
-                        id: 1,
-                        start: Point::new(4, 0),
-                        end: Point::new(4, 0),
-                        reversed: false,
-                        goal: SelectionGoal::None,
-                    },
-                ],
-                cx,
-            )
-            .unwrap();
-        assert_eq!(buffer.text(), "fn a(\n\n) {}\n\n");
-
-        // Ending the transaction runs the auto-indent. The selection
-        // at the start of the auto-indented row is pushed to the right.
-        buffer.end_transaction(Some(selection_set_id), cx);
-        assert_eq!(buffer.text(), "fn a(\n    \n) {}\n\n");
-        let selection_ranges = buffer
-            .selection_set(selection_set_id)
-            .unwrap()
-            .selections::<Point>(&buffer)
-            .map(|selection| selection.start.to_point(&buffer)..selection.end.to_point(&buffer))
-            .collect::<Vec<_>>();
-
-        assert_eq!(selection_ranges[0], empty(Point::new(1, 4)));
-        assert_eq!(selection_ranges[1], empty(Point::new(4, 0)));
-
-        buffer
-    });
-}
-
+// We need another approach to managing selections with auto-indent
+
+// #[gpui::test]
+// fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
+//     cx.add_model(|cx| {
+//         let text = "fn a() {}";
+
+//         let mut buffer =
+//             Buffer::new(0, text, cx).with_language(Some(Arc::new(rust_lang())), None, cx);
+
+//         let selection_set_id = buffer.add_selection_set::<usize>(&[], cx);
+//         buffer.start_transaction();
+//         buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx);
+//         buffer
+//             .update_selection_set(
+//                 selection_set_id,
+//                 &[
+//                     Selection {
+//                         id: 0,
+//                         start: Point::new(1, 0),
+//                         end: Point::new(1, 0),
+//                         reversed: false,
+//                         goal: SelectionGoal::None,
+//                     },
+//                     Selection {
+//                         id: 1,
+//                         start: Point::new(4, 0),
+//                         end: Point::new(4, 0),
+//                         reversed: false,
+//                         goal: SelectionGoal::None,
+//                     },
+//                 ],
+//                 cx,
+//             )
+//             .unwrap();
+//         assert_eq!(buffer.text(), "fn a(\n\n) {}\n\n");
+
+//         // TODO! Come up with a different approach to moving selections now that we don't manage selection sets in the buffer
+
+//         // Ending the transaction runs the auto-indent. The selection
+//         // at the start of the auto-indented row is pushed to the right.
+//         buffer.end_transaction(cx);
+//         assert_eq!(buffer.text(), "fn a(\n    \n) {}\n\n");
+//         let selection_ranges = buffer
+//             .selection_set(selection_set_id)
+//             .unwrap()
+//             .selections::<Point>(&buffer)
+//             .map(|selection| selection.start.to_point(&buffer)..selection.end.to_point(&buffer))
+//             .collect::<Vec<_>>();
+
+//         assert_eq!(selection_ranges[0], empty(Point::new(1, 4)));
+//         assert_eq!(selection_ranges[1], empty(Point::new(4, 0)));
+
+//         buffer
+//     });
+// }
 #[gpui::test]
 fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
     cx.add_model(|cx| {

crates/project/src/worktree.rs 🔗

@@ -3559,7 +3559,6 @@ mod tests {
     #[gpui::test]
     async fn test_buffer_file_changes_on_disk(mut cx: gpui::TestAppContext) {
         use std::fs;
-        use text::{Point, Selection, SelectionGoal};
 
         let initial_contents = "aaa\nbbbbb\nc\n";
         let dir = temp_tree(json!({ "the-file": initial_contents }));
@@ -3588,22 +3587,23 @@ mod tests {
             .await
             .unwrap();
 
+        // TODO
         // Add a cursor on each row.
-        let selection_set_id = buffer.update(&mut cx, |buffer, cx| {
-            assert!(!buffer.is_dirty());
-            buffer.add_selection_set(
-                &(0..3)
-                    .map(|row| Selection {
-                        id: row as usize,
-                        start: Point::new(row, 1),
-                        end: Point::new(row, 1),
-                        reversed: false,
-                        goal: SelectionGoal::None,
-                    })
-                    .collect::<Vec<_>>(),
-                cx,
-            )
-        });
+        // let selection_set_id = buffer.update(&mut cx, |buffer, cx| {
+        //     assert!(!buffer.is_dirty());
+        //     buffer.add_selection_set(
+        //         &(0..3)
+        //             .map(|row| Selection {
+        //                 id: row as usize,
+        //                 start: Point::new(row, 1),
+        //                 end: Point::new(row, 1),
+        //                 reversed: false,
+        //                 goal: SelectionGoal::None,
+        //             })
+        //             .collect::<Vec<_>>(),
+        //         cx,
+        //     )
+        // });
 
         // Change the file on disk, adding two new lines of text, and removing
         // one line.
@@ -3626,19 +3626,20 @@ mod tests {
             assert!(!buffer.is_dirty());
             assert!(!buffer.has_conflict());
 
-            let cursor_positions = buffer
-                .selection_set(selection_set_id)
-                .unwrap()
-                .selections::<Point>(&*buffer)
-                .map(|selection| {
-                    assert_eq!(selection.start, selection.end);
-                    selection.start
-                })
-                .collect::<Vec<_>>();
-            assert_eq!(
-                cursor_positions,
-                [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)]
-            );
+            // TODO
+            // let cursor_positions = buffer
+            //     .selection_set(selection_set_id)
+            //     .unwrap()
+            //     .selections::<Point>(&*buffer)
+            //     .map(|selection| {
+            //         assert_eq!(selection.start, selection.end);
+            //         selection.start
+            //     })
+            //     .collect::<Vec<_>>();
+            // assert_eq!(
+            //     cursor_positions,
+            //     [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)]
+            // );
         });
 
         // Modify the buffer

crates/server/src/rpc.rs 🔗

@@ -1045,13 +1045,14 @@ mod tests {
             .await
             .unwrap();
 
-        // Create a selection set as client B and see that selection set as client A.
         let editor_b = cx_b.add_view(window_b, |cx| {
             Editor::for_buffer(buffer_b, |cx| EditorSettings::test(cx), cx)
         });
-        buffer_a
-            .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 1)
-            .await;
+        // TODO
+        // // Create a selection set as client B and see that selection set as client A.
+        // buffer_a
+        //     .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 1)
+        //     .await;
 
         // Edit the buffer as client B and see that edit as client A.
         editor_b.update(&mut cx_b, |editor, cx| {
@@ -1061,11 +1062,12 @@ mod tests {
             .condition(&cx_a, |buffer, _| buffer.text() == "ok, b-contents")
             .await;
 
-        // Remove the selection set as client B, see those selections disappear as client A.
-        cx_b.update(move |_| drop(editor_b));
-        buffer_a
-            .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 0)
-            .await;
+        // TODO
+        // // Remove the selection set as client B, see those selections disappear as client A.
+        // cx_b.update(move |_| drop(editor_b));
+        // buffer_a
+        //     .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 0)
+        //     .await;
 
         // Close the buffer as client A, see that the buffer is closed.
         cx_a.update(move |_| drop(buffer_a));

crates/text/src/tests.rs 🔗

@@ -460,63 +460,41 @@ fn test_history() {
     let mut now = Instant::now();
     let mut buffer = Buffer::new(0, 0, History::new("123456".into()));
 
-    let set_id = if let Operation::UpdateSelections { set_id, .. } =
-        buffer.add_selection_set(&buffer.selections_from_ranges(vec![4..4]).unwrap())
-    {
-        set_id
-    } else {
-        unreachable!()
-    };
-    buffer.start_transaction_at(Some(set_id), now);
+    buffer.start_transaction_at(now);
     buffer.edit(vec![2..4], "cd");
-    buffer.end_transaction_at(Some(set_id), now);
+    buffer.end_transaction_at(now);
     assert_eq!(buffer.text(), "12cd56");
-    assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]);
 
-    buffer.start_transaction_at(Some(set_id), now);
-    buffer
-        .update_selection_set(set_id, &buffer.selections_from_ranges(vec![1..3]).unwrap())
-        .unwrap();
+    buffer.start_transaction_at(now);
     buffer.edit(vec![4..5], "e");
-    buffer.end_transaction_at(Some(set_id), now).unwrap();
+    buffer.end_transaction_at(now).unwrap();
     assert_eq!(buffer.text(), "12cde6");
-    assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
 
     now += buffer.history.group_interval + Duration::from_millis(1);
-    buffer.start_transaction_at(Some(set_id), now);
-    buffer
-        .update_selection_set(set_id, &buffer.selections_from_ranges(vec![2..2]).unwrap())
-        .unwrap();
+    buffer.start_transaction_at(now);
     buffer.edit(vec![0..1], "a");
     buffer.edit(vec![1..1], "b");
-    buffer.end_transaction_at(Some(set_id), now).unwrap();
+    buffer.end_transaction_at(now).unwrap();
     assert_eq!(buffer.text(), "ab2cde6");
-    assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]);
 
-    // Last transaction happened past the group interval, undo it on its
-    // own.
+    // Last transaction happened past the group interval, undo it on its own.
     buffer.undo();
     assert_eq!(buffer.text(), "12cde6");
-    assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
 
-    // First two transactions happened within the group interval, undo them
-    // together.
+    // First two transactions happened within the group interval, undo them together.
     buffer.undo();
     assert_eq!(buffer.text(), "123456");
-    assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]);
 
     // Redo the first two transactions together.
     buffer.redo();
     assert_eq!(buffer.text(), "12cde6");
-    assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]);
 
     // Redo the last transaction on its own.
     buffer.redo();
     assert_eq!(buffer.text(), "ab2cde6");
-    assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]);
 
-    buffer.start_transaction_at(None, now);
-    assert!(buffer.end_transaction_at(None, now).is_none());
+    buffer.start_transaction_at(now);
+    assert!(buffer.end_transaction_at(now).is_none());
     buffer.undo();
     assert_eq!(buffer.text(), "12cde6");
 }
@@ -582,8 +560,8 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
         let buffer = &mut buffers[replica_index];
         match rng.gen_range(0..=100) {
             0..=50 if mutation_count != 0 => {
-                let ops = buffer.randomly_mutate(&mut rng);
-                network.broadcast(buffer.replica_id, ops);
+                let op = buffer.randomly_edit(&mut rng, 5).2;
+                network.broadcast(buffer.replica_id, vec!(op));
                 log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text());
                 mutation_count -= 1;
             }
@@ -620,18 +598,6 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
             "Replica {} text != Replica 0 text",
             buffer.replica_id
         );
-        assert_eq!(
-            buffer.selection_sets().collect::<HashMap<_, _>>(),
-            first_buffer.selection_sets().collect::<HashMap<_, _>>()
-        );
-        assert_eq!(
-            buffer
-                .all_selection_ranges::<usize>()
-                .collect::<HashMap<_, _>>(),
-            first_buffer
-                .all_selection_ranges::<usize>()
-                .collect::<HashMap<_, _>>()
-        );
         buffer.check_invariants();
     }
 }

crates/text/src/text.rs 🔗

@@ -13,7 +13,7 @@ pub mod subscription;
 mod tests;
 
 pub use anchor::*;
-use anyhow::{anyhow, Result};
+use anyhow::Result;
 use clock::ReplicaId;
 use collections::{HashMap, HashSet};
 use locator::Locator;
@@ -71,17 +71,11 @@ pub struct Transaction {
     end: clock::Global,
     edits: Vec<clock::Local>,
     ranges: Vec<Range<FullOffset>>,
-    selections_before: HashMap<SelectionSetId, Arc<[Selection<Anchor>]>>,
-    selections_after: HashMap<SelectionSetId, Arc<[Selection<Anchor>]>>,
     first_edit_at: Instant,
     last_edit_at: Instant,
 }
 
 impl Transaction {
-    pub fn starting_selection_set_ids<'a>(&'a self) -> impl Iterator<Item = SelectionSetId> + 'a {
-        self.selections_before.keys().copied()
-    }
-
     fn push_edit(&mut self, edit: &EditOperation) {
         self.edits.push(edit.timestamp.local());
         self.end.observe(edit.timestamp.local());
@@ -158,12 +152,7 @@ impl History {
         self.ops.insert(op.timestamp.local(), op);
     }
 
-    fn start_transaction(
-        &mut self,
-        start: clock::Global,
-        selections_before: HashMap<SelectionSetId, Arc<[Selection<Anchor>]>>,
-        now: Instant,
-    ) -> Option<TransactionId> {
+    fn start_transaction(&mut self, start: clock::Global, now: Instant) -> Option<TransactionId> {
         self.transaction_depth += 1;
         if self.transaction_depth == 1 {
             let id = self.next_transaction_id;
@@ -174,8 +163,6 @@ impl History {
                 end: start,
                 edits: Vec::new(),
                 ranges: Vec::new(),
-                selections_before,
-                selections_after: Default::default(),
                 first_edit_at: now,
                 last_edit_at: now,
             });
@@ -185,11 +172,7 @@ impl History {
         }
     }
 
-    fn end_transaction(
-        &mut self,
-        selections_after: HashMap<SelectionSetId, Arc<[Selection<Anchor>]>>,
-        now: Instant,
-    ) -> Option<&Transaction> {
+    fn end_transaction(&mut self, now: Instant) -> Option<&Transaction> {
         assert_ne!(self.transaction_depth, 0);
         self.transaction_depth -= 1;
         if self.transaction_depth == 0 {
@@ -198,7 +181,6 @@ impl History {
                 None
             } else {
                 let transaction = self.undo_stack.last_mut().unwrap();
-                transaction.selections_after = selections_after;
                 transaction.last_edit_at = now;
                 Some(transaction)
             }
@@ -234,9 +216,6 @@ impl History {
 
             if let Some(transaction) = transactions_to_merge.last_mut() {
                 last_transaction.last_edit_at = transaction.last_edit_at;
-                last_transaction
-                    .selections_after
-                    .extend(transaction.selections_after.drain());
                 last_transaction.end = transaction.end.clone();
             }
         }
@@ -558,7 +537,7 @@ impl Buffer {
             None
         };
 
-        self.start_transaction(None);
+        self.start_transaction();
         let timestamp = InsertionTimestamp {
             replica_id: self.replica_id,
             local: self.local_clock.tick().value,
@@ -570,7 +549,7 @@ impl Buffer {
         self.history.push_undo(edit.timestamp.local());
         self.last_edit = edit.timestamp.local();
         self.snapshot.version.observe(edit.timestamp.local());
-        self.end_transaction(None);
+        self.end_transaction();
         edit
     }
 
@@ -1149,56 +1128,20 @@ impl Buffer {
         self.history.undo_stack.last()
     }
 
-    pub fn start_transaction(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-    ) -> Option<TransactionId> {
-        self.start_transaction_at(selection_set_ids, Instant::now())
+    pub fn start_transaction(&mut self) -> Option<TransactionId> {
+        self.start_transaction_at(Instant::now())
     }
 
-    pub fn start_transaction_at(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-        now: Instant,
-    ) -> Option<TransactionId> {
-        let selections = selection_set_ids
-            .into_iter()
-            .map(|set_id| {
-                let set = self
-                    .selection_sets
-                    .get(&set_id)
-                    .expect("invalid selection set id");
-                (set_id, set.selections.clone())
-            })
-            .collect();
-        self.history
-            .start_transaction(self.version.clone(), selections, now)
+    pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
+        self.history.start_transaction(self.version.clone(), now)
     }
 
-    pub fn end_transaction(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-    ) -> Option<(TransactionId, clock::Global)> {
-        self.end_transaction_at(selection_set_ids, Instant::now())
+    pub fn end_transaction(&mut self) -> Option<(TransactionId, clock::Global)> {
+        self.end_transaction_at(Instant::now())
     }
 
-    pub fn end_transaction_at(
-        &mut self,
-        selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
-        now: Instant,
-    ) -> Option<(TransactionId, clock::Global)> {
-        let selections = selection_set_ids
-            .into_iter()
-            .map(|set_id| {
-                let set = self
-                    .selection_sets
-                    .get(&set_id)
-                    .expect("invalid selection set id");
-                (set_id, set.selections.clone())
-            })
-            .collect();
-
-        if let Some(transaction) = self.history.end_transaction(selections, now) {
+    pub fn end_transaction_at(&mut self, now: Instant) -> Option<(TransactionId, clock::Global)> {
+        if let Some(transaction) = self.history.end_transaction(now) {
             let id = transaction.id;
             let since = transaction.start.clone();
             self.history.group();
@@ -1221,31 +1164,21 @@ impl Buffer {
         self.history.ops.values()
     }
 
-    pub fn undo(&mut self) -> Option<(TransactionId, Vec<Operation>)> {
+    pub fn undo(&mut self) -> Option<(TransactionId, Operation)> {
         if let Some(transaction) = self.history.pop_undo().cloned() {
             let transaction_id = transaction.id;
-            let selections = transaction.selections_before.clone();
-            let mut ops = Vec::new();
-            ops.push(self.undo_or_redo(transaction).unwrap());
-            for (set_id, selections) in selections {
-                ops.extend(self.restore_selection_set(set_id, selections));
-            }
-            Some((transaction_id, ops))
+            let op = self.undo_or_redo(transaction).unwrap();
+            Some((transaction_id, op))
         } else {
             None
         }
     }
 
-    pub fn redo(&mut self) -> Option<(TransactionId, Vec<Operation>)> {
+    pub fn redo(&mut self) -> Option<(TransactionId, Operation)> {
         if let Some(transaction) = self.history.pop_redo().cloned() {
             let transaction_id = transaction.id;
-            let selections = transaction.selections_after.clone();
-            let mut ops = Vec::new();
-            ops.push(self.undo_or_redo(transaction).unwrap());
-            for (set_id, selections) in selections {
-                ops.extend(self.restore_selection_set(set_id, selections));
-            }
-            Some((transaction_id, ops))
+            let op = self.undo_or_redo(transaction).unwrap();
+            Some((transaction_id, op))
         } else {
             None
         }
@@ -1275,125 +1208,6 @@ impl Buffer {
     pub fn subscribe(&mut self) -> Subscription {
         self.subscriptions.subscribe()
     }
-
-    pub fn selection_set(&self, set_id: SelectionSetId) -> Result<&SelectionSet> {
-        self.selection_sets
-            .get(&set_id)
-            .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))
-    }
-
-    pub fn selection_sets(&self) -> impl Iterator<Item = (&SelectionSetId, &SelectionSet)> {
-        self.selection_sets.iter()
-    }
-
-    fn build_anchor_selection_set<T: ToOffset>(
-        &self,
-        selections: &[Selection<T>],
-    ) -> Arc<[Selection<Anchor>]> {
-        Arc::from(
-            selections
-                .iter()
-                .map(|selection| Selection {
-                    id: selection.id,
-                    start: self.anchor_before(&selection.start),
-                    end: self.anchor_before(&selection.end),
-                    reversed: selection.reversed,
-                    goal: selection.goal,
-                })
-                .collect::<Vec<_>>(),
-        )
-    }
-
-    pub fn update_selection_set<T: ToOffset>(
-        &mut self,
-        set_id: SelectionSetId,
-        selections: &[Selection<T>],
-    ) -> Result<Operation> {
-        let selections = self.build_anchor_selection_set(selections);
-        let set = self
-            .selection_sets
-            .get_mut(&set_id)
-            .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
-        set.selections = selections.clone();
-        Ok(Operation::UpdateSelections {
-            set_id,
-            selections,
-            lamport_timestamp: self.lamport_clock.tick(),
-        })
-    }
-
-    pub fn restore_selection_set(
-        &mut self,
-        set_id: SelectionSetId,
-        selections: Arc<[Selection<Anchor>]>,
-    ) -> Result<Operation> {
-        let set = self
-            .selection_sets
-            .get_mut(&set_id)
-            .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
-        set.selections = selections.clone();
-        Ok(Operation::UpdateSelections {
-            set_id,
-            selections,
-            lamport_timestamp: self.lamport_clock.tick(),
-        })
-    }
-
-    pub fn add_selection_set<T: ToOffset>(&mut self, selections: &[Selection<T>]) -> Operation {
-        let selections = self.build_anchor_selection_set(selections);
-        let set_id = self.lamport_clock.tick();
-        self.selection_sets.insert(
-            set_id,
-            SelectionSet {
-                id: set_id,
-                selections: selections.clone(),
-                active: false,
-            },
-        );
-        Operation::UpdateSelections {
-            set_id,
-            selections,
-            lamport_timestamp: set_id,
-        }
-    }
-
-    pub fn add_raw_selection_set(&mut self, id: SelectionSetId, selections: SelectionSet) {
-        self.selection_sets.insert(id, selections);
-    }
-
-    pub fn set_active_selection_set(
-        &mut self,
-        set_id: Option<SelectionSetId>,
-    ) -> Result<Operation> {
-        if let Some(set_id) = set_id {
-            assert_eq!(set_id.replica_id, self.replica_id());
-        }
-
-        for (id, set) in &mut self.selection_sets {
-            if id.replica_id == self.local_clock.replica_id {
-                if Some(*id) == set_id {
-                    set.active = true;
-                } else {
-                    set.active = false;
-                }
-            }
-        }
-
-        Ok(Operation::SetActiveSelections {
-            set_id,
-            lamport_timestamp: self.lamport_clock.tick(),
-        })
-    }
-
-    pub fn remove_selection_set(&mut self, set_id: SelectionSetId) -> Result<Operation> {
-        self.selection_sets
-            .remove(&set_id)
-            .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
-        Ok(Operation::RemoveSelections {
-            set_id,
-            lamport_timestamp: self.lamport_clock.tick(),
-        })
-    }
 }
 
 #[cfg(any(test, feature = "test-support"))]
@@ -1434,42 +1248,6 @@ impl Buffer {
         (old_ranges, new_text, Operation::Edit(op))
     }
 
-    pub fn randomly_mutate<T>(&mut self, rng: &mut T) -> Vec<Operation>
-    where
-        T: rand::Rng,
-    {
-        use rand::prelude::*;
-
-        let mut ops = vec![self.randomly_edit(rng, 5).2];
-
-        // Randomly add, remove or mutate selection sets.
-        let replica_selection_sets = &self
-            .selection_sets()
-            .map(|(set_id, _)| *set_id)
-            .filter(|set_id| self.replica_id == set_id.replica_id)
-            .collect::<Vec<_>>();
-        let set_id = replica_selection_sets.choose(rng);
-        if set_id.is_some() && rng.gen_bool(1.0 / 6.0) {
-            ops.push(self.remove_selection_set(*set_id.unwrap()).unwrap());
-        } else {
-            let mut ranges = Vec::new();
-            for _ in 0..5 {
-                ranges.push(self.random_byte_range(0, rng));
-            }
-            let new_selections = self.selections_from_ranges(ranges).unwrap();
-
-            let op = if set_id.is_none() || rng.gen_bool(1.0 / 5.0) {
-                self.add_selection_set(&new_selections)
-            } else {
-                self.update_selection_set(*set_id.unwrap(), &new_selections)
-                    .unwrap()
-            };
-            ops.push(op);
-        }
-
-        ops
-    }
-
     pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng) -> Vec<Operation> {
         use rand::prelude::*;
 
@@ -1486,73 +1264,6 @@ impl Buffer {
         }
         ops
     }
-
-    fn selections_from_ranges<I>(&self, ranges: I) -> Result<Vec<Selection<usize>>>
-    where
-        I: IntoIterator<Item = Range<usize>>,
-    {
-        use std::sync::atomic::{self, AtomicUsize};
-
-        static NEXT_SELECTION_ID: AtomicUsize = AtomicUsize::new(0);
-
-        let mut ranges = ranges.into_iter().collect::<Vec<_>>();
-        ranges.sort_unstable_by_key(|range| range.start);
-
-        let mut selections = Vec::<Selection<usize>>::with_capacity(ranges.len());
-        for mut range in ranges {
-            let mut reversed = false;
-            if range.start > range.end {
-                reversed = true;
-                std::mem::swap(&mut range.start, &mut range.end);
-            }
-
-            if let Some(selection) = selections.last_mut() {
-                if selection.end >= range.start {
-                    selection.end = range.end;
-                    continue;
-                }
-            }
-
-            selections.push(Selection {
-                id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst),
-                start: range.start,
-                end: range.end,
-                reversed,
-                goal: SelectionGoal::None,
-            });
-        }
-        Ok(selections)
-    }
-
-    #[cfg(test)]
-    pub fn selection_ranges<'a, D>(&'a self, set_id: SelectionSetId) -> Result<Vec<Range<D>>>
-    where
-        D: TextDimension,
-    {
-        Ok(self
-            .selection_set(set_id)?
-            .selections(self)
-            .map(move |selection| {
-                if selection.reversed {
-                    selection.end..selection.start
-                } else {
-                    selection.start..selection.end
-                }
-            })
-            .collect())
-    }
-
-    #[cfg(test)]
-    pub fn all_selection_ranges<'a, D>(
-        &'a self,
-    ) -> impl 'a + Iterator<Item = (SelectionSetId, Vec<Range<usize>>)>
-    where
-        D: TextDimension,
-    {
-        self.selection_sets
-            .keys()
-            .map(move |set_id| (*set_id, self.selection_ranges(*set_id).unwrap()))
-    }
 }
 
 impl Deref for Buffer {