Merge branch 'anchor-map-selections' into lsp

Max Brunsfeld created

Change summary

crates/buffer/src/anchor.rs    | 129 ++++++-
crates/buffer/src/lib.rs       | 360 ++++++++++----------
crates/buffer/src/selection.rs | 142 +++++++-
crates/buffer/src/tests.rs     |   6 
crates/clock/src/lib.rs        |   6 
crates/editor/src/lib.rs       | 614 ++++++++++++++++-------------------
crates/language/src/lib.rs     |  37 +-
crates/language/src/tests.rs   |  15 
crates/project/src/worktree.rs |  35 -
crates/rpc/proto/zed.proto     |  41 +-
crates/sum_tree/src/cursor.rs  |   2 
11 files changed, 762 insertions(+), 625 deletions(-)

Detailed changes

crates/buffer/src/anchor.rs 🔗

@@ -1,8 +1,10 @@
-use crate::FullOffset;
-
-use super::{Buffer, Content, FromAnchor, Point, ToOffset};
+use super::{Buffer, Content, FromAnchor, FullOffset, Point, ToOffset};
 use anyhow::Result;
-use std::{cmp::Ordering, ops::Range};
+use std::{
+    cmp::Ordering,
+    fmt::{Debug, Formatter},
+    ops::Range,
+};
 use sum_tree::{Bias, SumTree};
 
 #[derive(Clone, Eq, PartialEq, Debug, Hash)]
@@ -112,7 +114,25 @@ impl Anchor {
 }
 
 impl<T> AnchorMap<T> {
-    pub fn to_points<'a>(
+    pub fn version(&self) -> &clock::Global {
+        &self.version
+    }
+
+    pub fn len(&self) -> usize {
+        self.entries.len()
+    }
+
+    pub fn offsets<'a>(
+        &'a self,
+        content: impl Into<Content<'a>> + 'a,
+    ) -> impl Iterator<Item = (usize, &'a T)> + 'a {
+        let content = content.into();
+        content
+            .summaries_for_anchors(self)
+            .map(move |(sum, value)| (sum.bytes, value))
+    }
+
+    pub fn points<'a>(
         &'a self,
         content: impl Into<Content<'a>> + 'a,
     ) -> impl Iterator<Item = (Point, &'a T)> + 'a {
@@ -121,23 +141,50 @@ impl<T> AnchorMap<T> {
             .summaries_for_anchors(self)
             .map(move |(sum, value)| (sum.lines, value))
     }
+}
 
+impl AnchorSet {
     pub fn version(&self) -> &clock::Global {
-        &self.version
+        &self.0.version
     }
-}
 
-impl AnchorSet {
-    pub fn to_points<'a>(
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    pub fn offsets<'a>(
+        &'a self,
+        content: impl Into<Content<'a>> + 'a,
+    ) -> impl Iterator<Item = usize> + 'a {
+        self.0.offsets(content).map(|(offset, _)| offset)
+    }
+
+    pub fn points<'a>(
         &'a self,
         content: impl Into<Content<'a>> + 'a,
     ) -> impl Iterator<Item = Point> + 'a {
-        self.0.to_points(content).map(move |(point, _)| point)
+        self.0.points(content).map(|(point, _)| point)
     }
 }
 
 impl<T> AnchorRangeMap<T> {
-    pub fn to_point_ranges<'a>(
+    pub fn version(&self) -> &clock::Global {
+        &self.version
+    }
+
+    pub fn len(&self) -> usize {
+        self.entries.len()
+    }
+
+    pub fn from_raw(version: clock::Global, entries: Vec<(Range<(FullOffset, Bias)>, T)>) -> Self {
+        Self { version, entries }
+    }
+
+    pub fn raw_entries(&self) -> &[(Range<(FullOffset, Bias)>, T)] {
+        &self.entries
+    }
+
+    pub fn point_ranges<'a>(
         &'a self,
         content: impl Into<Content<'a>> + 'a,
     ) -> impl Iterator<Item = (Range<Point>, &'a T)> + 'a {
@@ -147,22 +194,68 @@ impl<T> AnchorRangeMap<T> {
             .map(move |(range, value)| ((range.start.lines..range.end.lines), value))
     }
 
-    pub fn version(&self) -> &clock::Global {
-        &self.version
+    pub fn offset_ranges<'a>(
+        &'a self,
+        content: impl Into<Content<'a>> + 'a,
+    ) -> impl Iterator<Item = (Range<usize>, &'a T)> + 'a {
+        let content = content.into();
+        content
+            .summaries_for_anchor_ranges(self)
+            .map(move |(range, value)| ((range.start.bytes..range.end.bytes), value))
+    }
+}
+
+impl<T: PartialEq> PartialEq for AnchorRangeMap<T> {
+    fn eq(&self, other: &Self) -> bool {
+        self.version == other.version && self.entries == other.entries
+    }
+}
+
+impl<T: Eq> Eq for AnchorRangeMap<T> {}
+
+impl<T: Debug> Debug for AnchorRangeMap<T> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+        let mut f = f.debug_map();
+        for (range, value) in &self.entries {
+            f.key(range);
+            f.value(value);
+        }
+        f.finish()
+    }
+}
+
+impl Debug for AnchorRangeSet {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        let mut f = f.debug_set();
+        for (range, _) in &self.0.entries {
+            f.entry(range);
+        }
+        f.finish()
     }
 }
 
 impl AnchorRangeSet {
-    pub fn to_point_ranges<'a>(
-        &'a self,
-        content: impl Into<Content<'a>> + 'a,
-    ) -> impl Iterator<Item = Range<Point>> + 'a {
-        self.0.to_point_ranges(content).map(|(range, _)| range)
+    pub fn len(&self) -> usize {
+        self.0.len()
     }
 
     pub fn version(&self) -> &clock::Global {
         self.0.version()
     }
+
+    pub fn offset_ranges<'a>(
+        &'a self,
+        content: impl Into<Content<'a>> + 'a,
+    ) -> impl Iterator<Item = Range<usize>> + 'a {
+        self.0.offset_ranges(content).map(|(range, _)| range)
+    }
+
+    pub fn point_ranges<'a>(
+        &'a self,
+        content: impl Into<Content<'a>> + 'a,
+    ) -> impl Iterator<Item = Range<Point>> + 'a {
+        self.0.point_ranges(content).map(|(range, _)| range)
+    }
 }
 
 impl<T: Clone> Default for AnchorRangeMultimap<T> {

crates/buffer/src/lib.rs 🔗

@@ -20,7 +20,7 @@ use rpc::proto;
 pub use selection::*;
 use std::{
     cmp::{self, Reverse},
-    convert::{TryFrom, TryInto},
+    convert::TryFrom,
     iter::Iterator,
     ops::{self, Range},
     str,
@@ -73,20 +73,14 @@ pub struct Buffer {
     lamport_clock: clock::Lamport,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct SelectionSet {
-    pub selections: Arc<[Selection]>,
-    pub active: bool,
-}
-
 #[derive(Clone, Debug)]
 pub struct Transaction {
     start: clock::Global,
     end: clock::Global,
     edits: Vec<clock::Local>,
     ranges: Vec<Range<FullOffset>>,
-    selections_before: HashMap<SelectionSetId, Arc<[Selection]>>,
-    selections_after: HashMap<SelectionSetId, Arc<[Selection]>>,
+    selections_before: HashMap<SelectionSetId, Arc<AnchorRangeMap<SelectionState>>>,
+    selections_after: HashMap<SelectionSetId, Arc<AnchorRangeMap<SelectionState>>>,
     first_edit_at: Instant,
     last_edit_at: Instant,
 }
@@ -173,7 +167,7 @@ impl History {
     fn start_transaction(
         &mut self,
         start: clock::Global,
-        selections_before: HashMap<SelectionSetId, Arc<[Selection]>>,
+        selections_before: HashMap<SelectionSetId, Arc<AnchorRangeMap<SelectionState>>>,
         now: Instant,
     ) {
         self.transaction_depth += 1;
@@ -193,7 +187,7 @@ impl History {
 
     fn end_transaction(
         &mut self,
-        selections_after: HashMap<SelectionSetId, Arc<[Selection]>>,
+        selections_after: HashMap<SelectionSetId, Arc<AnchorRangeMap<SelectionState>>>,
         now: Instant,
     ) -> Option<&Transaction> {
         assert_ne!(self.transaction_depth, 0);
@@ -415,7 +409,11 @@ pub enum Operation {
     },
     UpdateSelections {
         set_id: SelectionSetId,
-        selections: Option<Arc<[Selection]>>,
+        selections: Arc<AnchorRangeMap<SelectionState>>,
+        lamport_timestamp: clock::Lamport,
+    },
+    RemoveSelections {
+        set_id: SelectionSetId,
         lamport_timestamp: clock::Lamport,
     },
     SetActiveSelections {
@@ -489,20 +487,8 @@ impl Buffer {
             .selections
             .into_iter()
             .map(|set| {
-                let set_id = clock::Lamport {
-                    replica_id: set.replica_id as ReplicaId,
-                    value: set.local_timestamp,
-                };
-                let selections: Vec<Selection> = set
-                    .selections
-                    .into_iter()
-                    .map(TryFrom::try_from)
-                    .collect::<Result<_, _>>()?;
-                let set = SelectionSet {
-                    selections: Arc::from(selections),
-                    active: set.is_active,
-                };
-                Result::<_, anyhow::Error>::Ok((set_id, set))
+                let set = SelectionSet::try_from(set)?;
+                Result::<_, anyhow::Error>::Ok((set.id, set))
             })
             .collect::<Result<_, _>>()?;
         Ok(buffer)
@@ -514,16 +500,7 @@ impl Buffer {
             id: self.remote_id,
             content: self.history.base_text.to_string(),
             history: ops,
-            selections: self
-                .selections
-                .iter()
-                .map(|(set_id, set)| proto::SelectionSetSnapshot {
-                    replica_id: set_id.replica_id as u32,
-                    local_timestamp: set_id.value,
-                    selections: set.selections.iter().map(Into::into).collect(),
-                    is_active: set.active,
-                })
-                .collect(),
+            selections: self.selections.iter().map(|(_, set)| set.into()).collect(),
         }
     }
 
@@ -565,6 +542,13 @@ impl Buffer {
         self.content().anchor_at(position, bias)
     }
 
+    pub fn anchor_range_set<E>(&self, entries: E) -> AnchorRangeSet
+    where
+        E: IntoIterator<Item = Range<(usize, Bias)>>,
+    {
+        self.content().anchor_range_set(entries)
+    }
+
     pub fn point_for_offset(&self, offset: usize) -> Result<Point> {
         self.content().point_for_offset(offset)
     }
@@ -858,23 +842,27 @@ impl Buffer {
                 selections,
                 lamport_timestamp,
             } => {
-                if let Some(selections) = selections {
-                    if let Some(set) = self.selections.get_mut(&set_id) {
-                        set.selections = selections;
-                    } else {
-                        self.selections.insert(
-                            set_id,
-                            SelectionSet {
-                                selections,
-                                active: false,
-                            },
-                        );
-                    }
+                if let Some(set) = self.selections.get_mut(&set_id) {
+                    set.selections = selections;
                 } else {
-                    self.selections.remove(&set_id);
+                    self.selections.insert(
+                        set_id,
+                        SelectionSet {
+                            id: set_id,
+                            selections,
+                            active: false,
+                        },
+                    );
                 }
                 self.lamport_clock.observe(lamport_timestamp);
             }
+            Operation::RemoveSelections {
+                set_id,
+                lamport_timestamp,
+            } => {
+                self.selections.remove(&set_id);
+                self.lamport_clock.observe(lamport_timestamp);
+            }
             Operation::SetActiveSelections {
                 set_id,
                 lamport_timestamp,
@@ -1142,16 +1130,9 @@ impl Buffer {
                 Operation::Edit(edit) => self.version >= edit.version,
                 Operation::Undo { undo, .. } => self.version >= undo.version,
                 Operation::UpdateSelections { selections, .. } => {
-                    if let Some(selections) = selections {
-                        selections.iter().all(|selection| {
-                            let contains_start = self.version >= selection.start.version;
-                            let contains_end = self.version >= selection.end.version;
-                            contains_start && contains_end
-                        })
-                    } else {
-                        true
-                    }
+                    self.version >= *selections.version()
                 }
+                Operation::RemoveSelections { .. } => true,
                 Operation::SetActiveSelections { set_id, .. } => {
                     set_id.map_or(true, |set_id| self.selections.contains_key(&set_id))
                 }
@@ -1232,7 +1213,7 @@ impl Buffer {
             let selections = transaction.selections_before.clone();
             ops.push(self.undo_or_redo(transaction).unwrap());
             for (set_id, selections) in selections {
-                ops.extend(self.update_selection_set(set_id, selections));
+                ops.extend(self.restore_selection_set(set_id, selections));
             }
         }
         ops
@@ -1244,7 +1225,7 @@ impl Buffer {
             let selections = transaction.selections_after.clone();
             ops.push(self.undo_or_redo(transaction).unwrap());
             for (set_id, selections) in selections {
-                ops.extend(self.update_selection_set(set_id, selections));
+                ops.extend(self.restore_selection_set(set_id, selections));
             }
         }
         ops
@@ -1281,12 +1262,32 @@ impl Buffer {
         self.selections.iter()
     }
 
-    pub fn update_selection_set(
+    fn build_selection_anchor_range_map<T: ToOffset>(
+        &self,
+        selections: &[Selection<T>],
+    ) -> Arc<AnchorRangeMap<SelectionState>> {
+        Arc::new(
+            self.content()
+                .anchor_range_map(selections.iter().map(|selection| {
+                    let start = selection.start.to_offset(self);
+                    let end = selection.end.to_offset(self);
+                    let range = (start, Bias::Left)..(end, Bias::Left);
+                    let state = SelectionState {
+                        id: selection.id,
+                        reversed: selection.reversed,
+                        goal: selection.goal,
+                    };
+                    (range, state)
+                })),
+        )
+    }
+
+    pub fn update_selection_set<T: ToOffset>(
         &mut self,
         set_id: SelectionSetId,
-        selections: impl Into<Arc<[Selection]>>,
+        selections: &[Selection<T>],
     ) -> Result<Operation> {
-        let selections = selections.into();
+        let selections = self.build_selection_anchor_range_map(selections);
         let set = self
             .selections
             .get_mut(&set_id)
@@ -1294,25 +1295,43 @@ impl Buffer {
         set.selections = selections.clone();
         Ok(Operation::UpdateSelections {
             set_id,
-            selections: Some(selections),
+            selections,
             lamport_timestamp: self.lamport_clock.tick(),
         })
     }
 
-    pub fn add_selection_set(&mut self, selections: impl Into<Arc<[Selection]>>) -> Operation {
-        let selections = selections.into();
-        let lamport_timestamp = self.lamport_clock.tick();
+    pub fn restore_selection_set(
+        &mut self,
+        set_id: SelectionSetId,
+        selections: Arc<AnchorRangeMap<SelectionState>>,
+    ) -> Result<Operation> {
+        let set = self
+            .selections
+            .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_selection_anchor_range_map(selections);
+        let set_id = self.lamport_clock.tick();
         self.selections.insert(
-            lamport_timestamp,
+            set_id,
             SelectionSet {
+                id: set_id,
                 selections: selections.clone(),
                 active: false,
             },
         );
         Operation::UpdateSelections {
-            set_id: lamport_timestamp,
-            selections: Some(selections),
-            lamport_timestamp,
+            set_id,
+            selections,
+            lamport_timestamp: set_id,
         }
     }
 
@@ -1344,9 +1363,8 @@ impl Buffer {
         self.selections
             .remove(&set_id)
             .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
-        Ok(Operation::UpdateSelections {
+        Ok(Operation::RemoveSelections {
             set_id,
-            selections: None,
             lamport_timestamp: self.lamport_clock.tick(),
         })
     }
@@ -1419,9 +1437,9 @@ impl Buffer {
             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)
+                self.add_selection_set(&new_selections)
             } else {
-                self.update_selection_set(*set_id.unwrap(), new_selections)
+                self.update_selection_set(*set_id.unwrap(), &new_selections)
                     .unwrap()
             };
             ops.push(op);
@@ -1447,7 +1465,7 @@ impl Buffer {
         ops
     }
 
-    fn selections_from_ranges<I>(&self, ranges: I) -> Result<Vec<Selection>>
+    fn selections_from_ranges<I>(&self, ranges: I) -> Result<Vec<Selection<usize>>>
     where
         I: IntoIterator<Item = Range<usize>>,
     {
@@ -1458,25 +1476,28 @@ impl Buffer {
         let mut ranges = ranges.into_iter().collect::<Vec<_>>();
         ranges.sort_unstable_by_key(|range| range.start);
 
-        let mut selections = Vec::with_capacity(ranges.len());
-        for range in ranges {
+        let mut selections = Vec::<Selection<usize>>::with_capacity(ranges.len());
+        for mut range in ranges {
+            let mut reversed = false;
             if range.start > range.end {
-                selections.push(Selection {
-                    id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst),
-                    start: self.anchor_before(range.end),
-                    end: self.anchor_before(range.start),
-                    reversed: true,
-                    goal: SelectionGoal::None,
-                });
-            } else {
-                selections.push(Selection {
-                    id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst),
-                    start: self.anchor_after(range.start),
-                    end: self.anchor_before(range.end),
-                    reversed: false,
-                    goal: SelectionGoal::None,
-                });
+                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)
     }
@@ -1484,15 +1505,12 @@ impl Buffer {
     pub fn selection_ranges<'a>(&'a self, set_id: SelectionSetId) -> Result<Vec<Range<usize>>> {
         Ok(self
             .selection_set(set_id)?
-            .selections
-            .iter()
+            .offset_selections(self)
             .map(move |selection| {
-                let start = selection.start.to_offset(self);
-                let end = selection.end.to_offset(self);
                 if selection.reversed {
-                    end..start
+                    selection.end..selection.start
                 } else {
-                    start..end
+                    selection.start..selection.end
                 }
             })
             .collect())
@@ -2259,6 +2277,9 @@ impl Operation {
             Operation::UpdateSelections {
                 lamport_timestamp, ..
             } => *lamport_timestamp,
+            Operation::RemoveSelections {
+                lamport_timestamp, ..
+            } => *lamport_timestamp,
             Operation::SetActiveSelections {
                 lamport_timestamp, ..
             } => *lamport_timestamp,
@@ -2315,9 +2336,27 @@ impl<'a> Into<proto::Operation> for &'a Operation {
                         replica_id: set_id.replica_id as u32,
                         local_timestamp: set_id.value,
                         lamport_timestamp: lamport_timestamp.value,
-                        set: selections.as_ref().map(|selections| proto::SelectionSet {
-                            selections: selections.iter().map(Into::into).collect(),
-                        }),
+                        version: selections.version().into(),
+                        selections: selections
+                            .raw_entries()
+                            .iter()
+                            .map(|(range, state)| proto::Selection {
+                                id: state.id as u64,
+                                start: range.start.0.to_proto(),
+                                end: range.end.0.to_proto(),
+                                reversed: state.reversed,
+                            })
+                            .collect(),
+                    },
+                ),
+                Operation::RemoveSelections {
+                    set_id,
+                    lamport_timestamp,
+                } => proto::operation::Variant::RemoveSelections(
+                    proto::operation::RemoveSelections {
+                        replica_id: set_id.replica_id as u32,
+                        local_timestamp: set_id.value,
+                        lamport_timestamp: lamport_timestamp.value,
                     },
                 ),
                 Operation::SetActiveSelections {
@@ -2358,30 +2397,6 @@ impl<'a> Into<proto::operation::Edit> for &'a EditOperation {
     }
 }
 
-impl<'a> Into<proto::Anchor> for &'a Anchor {
-    fn into(self) -> proto::Anchor {
-        proto::Anchor {
-            version: (&self.version).into(),
-            offset: self.full_offset.to_proto(),
-            bias: match self.bias {
-                Bias::Left => proto::anchor::Bias::Left as i32,
-                Bias::Right => proto::anchor::Bias::Right as i32,
-            },
-        }
-    }
-}
-
-impl<'a> Into<proto::Selection> for &'a Selection {
-    fn into(self) -> proto::Selection {
-        proto::Selection {
-            id: self.id as u64,
-            start: Some((&self.start).into()),
-            end: Some((&self.end).into()),
-            reversed: self.reversed,
-        }
-    }
-}
-
 impl TryFrom<proto::Operation> for Operation {
     type Error = anyhow::Error;
 
@@ -2424,16 +2439,23 @@ impl TryFrom<proto::Operation> for Operation {
                     },
                 },
                 proto::operation::Variant::UpdateSelections(message) => {
-                    let selections: Option<Vec<Selection>> = if let Some(set) = message.set {
-                        Some(
-                            set.selections
-                                .into_iter()
-                                .map(TryFrom::try_from)
-                                .collect::<Result<_, _>>()?,
-                        )
-                    } else {
-                        None
-                    };
+                    let version = message.version.into();
+                    let entries = message
+                        .selections
+                        .iter()
+                        .map(|selection| {
+                            let range = (FullOffset::from_proto(selection.start), Bias::Left)
+                                ..(FullOffset::from_proto(selection.end), Bias::Right);
+                            let state = SelectionState {
+                                id: selection.id as usize,
+                                reversed: selection.reversed,
+                                goal: SelectionGoal::None,
+                            };
+                            (range, state)
+                        })
+                        .collect();
+                    let selections = AnchorRangeMap::from_raw(version, entries);
+
                     Operation::UpdateSelections {
                         set_id: clock::Lamport {
                             replica_id: message.replica_id as ReplicaId,
@@ -2443,7 +2465,19 @@ impl TryFrom<proto::Operation> for Operation {
                             replica_id: message.replica_id as ReplicaId,
                             value: message.lamport_timestamp,
                         },
-                        selections: selections.map(Arc::from),
+                        selections: Arc::from(selections),
+                    }
+                }
+                proto::operation::Variant::RemoveSelections(message) => {
+                    Operation::RemoveSelections {
+                        set_id: clock::Lamport {
+                            replica_id: message.replica_id as ReplicaId,
+                            value: message.local_timestamp,
+                        },
+                        lamport_timestamp: clock::Lamport {
+                            replica_id: message.replica_id as ReplicaId,
+                            value: message.lamport_timestamp,
+                        },
                     }
                 }
                 proto::operation::Variant::SetActiveSelections(message) => {
@@ -2483,52 +2517,6 @@ impl From<proto::operation::Edit> for EditOperation {
     }
 }
 
-impl TryFrom<proto::Anchor> for Anchor {
-    type Error = anyhow::Error;
-
-    fn try_from(message: proto::Anchor) -> Result<Self, Self::Error> {
-        let mut version = clock::Global::new();
-        for entry in message.version {
-            version.observe(clock::Local {
-                replica_id: entry.replica_id as ReplicaId,
-                value: entry.timestamp,
-            });
-        }
-
-        Ok(Self {
-            full_offset: FullOffset::from_proto(message.offset),
-            bias: if message.bias == proto::anchor::Bias::Left as i32 {
-                Bias::Left
-            } else if message.bias == proto::anchor::Bias::Right as i32 {
-                Bias::Right
-            } else {
-                Err(anyhow!("invalid anchor bias {}", message.bias))?
-            },
-            version,
-        })
-    }
-}
-
-impl TryFrom<proto::Selection> for Selection {
-    type Error = anyhow::Error;
-
-    fn try_from(selection: proto::Selection) -> Result<Self, Self::Error> {
-        Ok(Selection {
-            id: selection.id as usize,
-            start: selection
-                .start
-                .ok_or_else(|| anyhow!("missing selection start"))?
-                .try_into()?,
-            end: selection
-                .end
-                .ok_or_else(|| anyhow!("missing selection end"))?
-                .try_into()?,
-            reversed: selection.reversed,
-            goal: SelectionGoal::None,
-        })
-    }
-}
-
 pub trait ToOffset {
     fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize;
 
@@ -2582,6 +2570,12 @@ impl ToPoint for usize {
     }
 }
 
+impl ToPoint for Point {
+    fn to_point<'a>(&self, _: impl Into<Content<'a>>) -> Point {
+        *self
+    }
+}
+
 pub trait FromAnchor {
     fn from_anchor<'a>(anchor: &Anchor, content: &Content<'a>) -> Self;
 }

crates/buffer/src/selection.rs 🔗

@@ -1,5 +1,7 @@
-use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _};
-use std::{cmp::Ordering, mem, ops::Range};
+use super::{AnchorRangeMap, Buffer, Content, FullOffset, Point, ToOffset, ToPoint};
+use rpc::proto;
+use std::{cmp::Ordering, ops::Range, sync::Arc};
+use sum_tree::Bias;
 
 pub type SelectionSetId = clock::Lamport;
 pub type SelectionsVersion = usize;
@@ -12,44 +14,62 @@ pub enum SelectionGoal {
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
-pub struct Selection {
+pub struct Selection<T> {
     pub id: usize,
-    pub start: Anchor,
-    pub end: Anchor,
+    pub start: T,
+    pub end: T,
     pub reversed: bool,
     pub goal: SelectionGoal,
 }
 
-impl Selection {
-    pub fn head(&self) -> &Anchor {
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct SelectionSet {
+    pub id: SelectionSetId,
+    pub active: bool,
+    pub selections: Arc<AnchorRangeMap<SelectionState>>,
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub struct SelectionState {
+    pub id: usize,
+    pub reversed: bool,
+    pub goal: SelectionGoal,
+}
+
+impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
+    pub fn is_empty(&self) -> bool {
+        self.start == self.end
+    }
+
+    pub fn head(&self) -> T {
         if self.reversed {
-            &self.start
+            self.start
         } else {
-            &self.end
+            self.end
         }
     }
 
-    pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) {
-        if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal {
+    pub fn set_head(&mut self, head: T) {
+        if head.cmp(&self.tail()) < Ordering::Equal {
             if !self.reversed {
-                mem::swap(&mut self.start, &mut self.end);
+                self.end = self.start;
                 self.reversed = true;
             }
-            self.start = cursor;
+            self.start = head;
         } else {
             if self.reversed {
-                mem::swap(&mut self.start, &mut self.end);
+                self.start = self.end;
                 self.reversed = false;
             }
-            self.end = cursor;
+            self.end = head;
         }
     }
 
-    pub fn tail(&self) -> &Anchor {
+    pub fn tail(&self) -> T {
         if self.reversed {
-            &self.end
+            self.end
         } else {
-            &self.start
+            self.start
         }
     }
 
@@ -73,3 +93,89 @@ impl Selection {
         }
     }
 }
+
+impl SelectionSet {
+    pub fn len(&self) -> usize {
+        self.selections.len()
+    }
+
+    pub fn offset_selections<'a>(
+        &'a self,
+        content: impl Into<Content<'a>> + 'a,
+    ) -> impl 'a + Iterator<Item = Selection<usize>> {
+        self.selections
+            .offset_ranges(content)
+            .map(|(range, state)| Selection {
+                id: state.id,
+                start: range.start,
+                end: range.end,
+                reversed: state.reversed,
+                goal: state.goal,
+            })
+    }
+
+    pub fn point_selections<'a>(
+        &'a self,
+        content: impl Into<Content<'a>> + 'a,
+    ) -> impl 'a + Iterator<Item = Selection<Point>> {
+        self.selections
+            .point_ranges(content)
+            .map(|(range, state)| Selection {
+                id: state.id,
+                start: range.start,
+                end: range.end,
+                reversed: state.reversed,
+                goal: state.goal,
+            })
+    }
+}
+
+impl<'a> Into<proto::SelectionSet> for &'a SelectionSet {
+    fn into(self) -> proto::SelectionSet {
+        let version = self.selections.version();
+        let entries = self.selections.raw_entries();
+        proto::SelectionSet {
+            replica_id: self.id.replica_id as u32,
+            lamport_timestamp: self.id.value as u32,
+            is_active: self.active,
+            version: version.into(),
+            selections: entries
+                .iter()
+                .map(|(range, state)| proto::Selection {
+                    id: state.id as u64,
+                    start: range.start.0.to_proto(),
+                    end: range.end.0.to_proto(),
+                    reversed: state.reversed,
+                })
+                .collect(),
+        }
+    }
+}
+
+impl From<proto::SelectionSet> for SelectionSet {
+    fn from(set: proto::SelectionSet) -> Self {
+        Self {
+            id: clock::Lamport {
+                replica_id: set.replica_id as u16,
+                value: set.lamport_timestamp,
+            },
+            active: set.is_active,
+            selections: Arc::new(AnchorRangeMap::from_raw(
+                set.version.into(),
+                set.selections
+                    .into_iter()
+                    .map(|selection| {
+                        let range = (FullOffset::from_proto(selection.start), Bias::Left)
+                            ..(FullOffset::from_proto(selection.end), Bias::Right);
+                        let state = SelectionState {
+                            id: selection.id as usize,
+                            reversed: selection.reversed,
+                            goal: SelectionGoal::None,
+                        };
+                        (range, state)
+                    })
+                    .collect(),
+            )),
+        }
+    }
+}

crates/buffer/src/tests.rs 🔗

@@ -408,7 +408,7 @@ fn test_history() {
     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())
+        buffer.add_selection_set(&buffer.selections_from_ranges(vec![4..4]).unwrap())
     {
         set_id
     } else {
@@ -422,7 +422,7 @@ fn test_history() {
 
     buffer.start_transaction_at(Some(set_id), now).unwrap();
     buffer
-        .update_selection_set(set_id, buffer.selections_from_ranges(vec![1..3]).unwrap())
+        .update_selection_set(set_id, &buffer.selections_from_ranges(vec![1..3]).unwrap())
         .unwrap();
     buffer.edit(vec![4..5], "e");
     buffer.end_transaction_at(Some(set_id), now).unwrap();
@@ -432,7 +432,7 @@ fn test_history() {
     now += buffer.history.group_interval + Duration::from_millis(1);
     buffer.start_transaction_at(Some(set_id), now).unwrap();
     buffer
-        .update_selection_set(set_id, buffer.selections_from_ranges(vec![2..2]).unwrap())
+        .update_selection_set(set_id, &buffer.selections_from_ranges(vec![2..2]).unwrap())
         .unwrap();
     buffer.edit(vec![0..1], "a");
     buffer.edit(vec![1..1], "b");

crates/clock/src/lib.rs 🔗

@@ -86,6 +86,12 @@ impl<'a> From<&'a Global> for Vec<rpc::proto::VectorClockEntry> {
     }
 }
 
+impl From<Global> for Vec<rpc::proto::VectorClockEntry> {
+    fn from(version: Global) -> Self {
+        (&version).into()
+    }
+}
+
 impl Global {
     pub fn new() -> Self {
         Self::default()

crates/editor/src/lib.rs 🔗

@@ -10,9 +10,9 @@ pub use display_map::DisplayPoint;
 use display_map::*;
 pub use element::*;
 use gpui::{
-    action, color::Color, fonts::TextStyle, geometry::vector::Vector2F, keymap::Binding,
-    text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle,
-    MutableAppContext, RenderContext, View, ViewContext, WeakViewHandle,
+    action, geometry::vector::Vector2F, keymap::Binding, text_layout, AppContext, ClipboardItem,
+    Element, ElementBox, Entity, ModelHandle, MutableAppContext, RenderContext, View, ViewContext,
+    WeakViewHandle,
 };
 use language::*;
 use serde::{Deserialize, Serialize};
@@ -20,8 +20,7 @@ use smallvec::SmallVec;
 use smol::Timer;
 use std::{
     cell::RefCell,
-    cmp::{self, Ordering},
-    iter, mem,
+    cmp, iter, mem,
     ops::{Range, RangeInclusive},
     rc::Rc,
     sync::Arc,
@@ -293,11 +292,11 @@ pub struct Editor {
     buffer: ModelHandle<Buffer>,
     display_map: ModelHandle<DisplayMap>,
     selection_set_id: SelectionSetId,
-    pending_selection: Option<Selection>,
+    pending_selection: Option<Selection<Point>>,
     next_selection_id: usize,
     add_selections_state: Option<AddSelectionsState>,
     autoclose_stack: Vec<BracketPairState>,
-    select_larger_syntax_node_stack: Vec<Arc<[Selection]>>,
+    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
     scroll_position: Vector2F,
     scroll_top_anchor: Anchor,
     autoscroll_requested: bool,
@@ -324,8 +323,9 @@ struct AddSelectionsState {
     stack: Vec<usize>,
 }
 
+#[derive(Debug)]
 struct BracketPairState {
-    ranges: SmallVec<[Range<Anchor>; 32]>,
+    ranges: AnchorRangeSet,
     pair: BracketPair,
 }
 
@@ -396,10 +396,10 @@ impl Editor {
         let mut next_selection_id = 0;
         let selection_set_id = buffer.update(cx, |buffer, cx| {
             buffer.add_selection_set(
-                vec![Selection {
+                &[Selection {
                     id: post_inc(&mut next_selection_id),
-                    start: buffer.anchor_before(0),
-                    end: buffer.anchor_before(0),
+                    start: 0,
+                    end: 0,
                     reversed: false,
                     goal: SelectionGoal::None,
                 }],
@@ -512,9 +512,9 @@ impl Editor {
             return false;
         }
 
-        let selections = self.selections(cx);
+        let mut selections = self.point_selections(cx).peekable();
         let first_cursor_top = selections
-            .first()
+            .peek()
             .unwrap()
             .head()
             .to_display_point(&display_map, Bias::Left)
@@ -563,11 +563,11 @@ impl Editor {
         layouts: &[text_layout::Line],
         cx: &mut ViewContext<Self>,
     ) -> bool {
-        let selections = self.selections(cx);
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+        let selections = self.point_selections(cx);
         let mut target_left = std::f32::INFINITY;
         let mut target_right = 0.0_f32;
-        for selection in selections.iter() {
+        for selection in selections {
             let head = selection.head().to_display_point(&display_map, Bias::Left);
             let start_column = head.column().saturating_sub(3);
             let end_column = cmp::min(display_map.line_len(head.row()), head.column() + 3);
@@ -617,17 +617,17 @@ impl Editor {
         }
 
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let cursor = display_map.anchor_before(position, Bias::Left);
+        let cursor = position.to_buffer_point(&display_map, Bias::Left);
         let selection = Selection {
             id: post_inc(&mut self.next_selection_id),
-            start: cursor.clone(),
+            start: cursor,
             end: cursor,
             reversed: false,
             goal: SelectionGoal::None,
         };
 
         if !add {
-            self.update_selections(Vec::new(), false, cx);
+            self.update_selections::<usize>(Vec::new(), false, cx);
         }
         self.pending_selection = Some(selection);
 
@@ -641,10 +641,9 @@ impl Editor {
         cx: &mut ViewContext<Self>,
     ) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let buffer = self.buffer.read(cx);
-        let cursor = display_map.anchor_before(position, Bias::Left);
+        let cursor = position.to_buffer_point(&display_map, Bias::Left);
         if let Some(selection) = self.pending_selection.as_mut() {
-            selection.set_head(buffer, cursor);
+            selection.set_head(cursor);
         } else {
             log::error!("update_selection dispatched with no pending selection");
             return;
@@ -656,8 +655,8 @@ impl Editor {
 
     fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
         if let Some(selection) = self.pending_selection.take() {
-            let mut selections = self.selections(cx).to_vec();
-            let ix = self.selection_insertion_index(&selections, &selection.start, cx.as_ref());
+            let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+            let ix = self.selection_insertion_index(&selections, selection.start);
             selections.insert(ix, selection);
             self.update_selections(selections, false, cx);
         }
@@ -669,14 +668,14 @@ impl Editor {
 
     pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
         if let Some(pending_selection) = self.pending_selection.take() {
-            let selections = self.selections(cx);
-            if selections.is_empty() {
+            if self.point_selections(cx).next().is_none() {
                 self.update_selections(vec![pending_selection], true, cx);
             }
         } else {
-            let selections = self.selections(cx);
-            let mut oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
-            if selections.len() == 1 {
+            let selection_count = self.selection_count(cx);
+            let selections = self.point_selections(cx);
+            let mut oldest_selection = selections.min_by_key(|s| s.id).unwrap().clone();
+            if selection_count == 1 {
                 oldest_selection.start = oldest_selection.head().clone();
                 oldest_selection.end = oldest_selection.head().clone();
             }
@@ -690,24 +689,26 @@ impl Editor {
         T: ToOffset,
     {
         let buffer = self.buffer.read(cx);
-        let mut selections = Vec::new();
-        for range in ranges {
-            let mut start = range.start.to_offset(buffer);
-            let mut end = range.end.to_offset(buffer);
-            let reversed = if start > end {
-                mem::swap(&mut start, &mut end);
-                true
-            } else {
-                false
-            };
-            selections.push(Selection {
-                id: post_inc(&mut self.next_selection_id),
-                start: buffer.anchor_before(start),
-                end: buffer.anchor_before(end),
-                reversed,
-                goal: SelectionGoal::None,
-            });
-        }
+        let selections = ranges
+            .into_iter()
+            .map(|range| {
+                let mut start = range.start.to_offset(buffer);
+                let mut end = range.end.to_offset(buffer);
+                let reversed = if start > end {
+                    mem::swap(&mut start, &mut end);
+                    true
+                } else {
+                    false
+                };
+                Selection {
+                    id: post_inc(&mut self.next_selection_id),
+                    start: start,
+                    end: end,
+                    reversed,
+                    goal: SelectionGoal::None,
+                }
+            })
+            .collect();
         self.update_selections(selections, autoscroll, cx);
     }
 
@@ -720,26 +721,27 @@ impl Editor {
     where
         T: IntoIterator<Item = &'a Range<DisplayPoint>>,
     {
-        let mut selections = Vec::new();
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        for range in ranges {
-            let mut start = range.start;
-            let mut end = range.end;
-            let reversed = if start > end {
-                mem::swap(&mut start, &mut end);
-                true
-            } else {
-                false
-            };
-
-            selections.push(Selection {
-                id: post_inc(&mut self.next_selection_id),
-                start: display_map.anchor_before(start, Bias::Left),
-                end: display_map.anchor_before(end, Bias::Left),
-                reversed,
-                goal: SelectionGoal::None,
-            });
-        }
+        let selections = ranges
+            .into_iter()
+            .map(|range| {
+                let mut start = range.start;
+                let mut end = range.end;
+                let reversed = if start > end {
+                    mem::swap(&mut start, &mut end);
+                    true
+                } else {
+                    false
+                };
+                Selection {
+                    id: post_inc(&mut self.next_selection_id),
+                    start: start.to_buffer_point(&display_map, Bias::Left),
+                    end: end.to_buffer_point(&display_map, Bias::Left),
+                    reversed,
+                    goal: SelectionGoal::None,
+                }
+            })
+            .collect();
         self.update_selections(selections, false, cx);
         Ok(())
     }
@@ -758,10 +760,10 @@ impl Editor {
         self.start_transaction(cx);
         let mut old_selections = SmallVec::<[_; 32]>::new();
         {
-            let selections = self.selections(cx);
+            let selections = self.point_selections(cx).collect::<Vec<_>>();
             let buffer = self.buffer.read(cx);
             for selection in selections.iter() {
-                let start_point = selection.start.to_point(buffer);
+                let start_point = selection.start;
                 let indent = buffer
                     .indent_column_for_line(start_point.row)
                     .min(start_point.column);
@@ -848,7 +850,7 @@ impl Editor {
                     let start = (range.start as isize + delta) as usize;
                     let end = (range.end as isize + delta) as usize;
                     let text_before_cursor_len = indent as usize + 1;
-                    let anchor = buffer.anchor_before(start + text_before_cursor_len);
+                    let cursor = start + text_before_cursor_len;
                     let text_len = if insert_extra_newline {
                         text_before_cursor_len * 2
                     } else {
@@ -857,8 +859,8 @@ impl Editor {
                     delta += text_len as isize - (end - start) as isize;
                     Selection {
                         id,
-                        start: anchor.clone(),
-                        end: anchor,
+                        start: cursor,
+                        end: cursor,
                         reversed: false,
                         goal: SelectionGoal::None,
                     }
@@ -880,35 +882,25 @@ impl Editor {
 
     fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
-        let mut old_selections = SmallVec::<[_; 32]>::new();
-        {
-            let selections = self.selections(cx);
-            let buffer = self.buffer.read(cx);
-            for selection in selections.iter() {
-                let start = selection.start.to_offset(buffer);
-                let end = selection.end.to_offset(buffer);
-                old_selections.push((selection.id, start..end));
-            }
-        }
-
+        let old_selections = self.offset_selections(cx).collect::<SmallVec<[_; 32]>>();
         let mut new_selections = Vec::new();
         self.buffer.update(cx, |buffer, cx| {
-            let edit_ranges = old_selections.iter().map(|(_, range)| range.clone());
+            let edit_ranges = old_selections.iter().map(|s| s.start..s.end);
             buffer.edit_with_autoindent(edit_ranges, text, cx);
             let text_len = text.len() as isize;
             let mut delta = 0_isize;
             new_selections = old_selections
                 .into_iter()
-                .map(|(id, range)| {
-                    let start = range.start as isize;
-                    let end = range.end as isize;
-                    let anchor = buffer.anchor_before((start + delta + text_len) as usize);
+                .map(|selection| {
+                    let start = selection.start as isize;
+                    let end = selection.end as isize;
+                    let cursor = (start + delta + text_len) as usize;
                     let deleted_count = end - start;
                     delta += text_len - deleted_count;
                     Selection {
-                        id,
-                        start: anchor.clone(),
-                        end: anchor,
+                        id: selection.id,
+                        start: cursor,
+                        end: cursor,
                         reversed: false,
                         goal: SelectionGoal::None,
                     }
@@ -921,10 +913,10 @@ impl Editor {
     }
 
     fn autoclose_pairs(&mut self, cx: &mut ViewContext<Self>) {
-        let selections = self.selections(cx);
+        let selections = self.offset_selections(cx).collect::<Vec<_>>();
         let new_autoclose_pair_state = self.buffer.update(cx, |buffer, cx| {
             let autoclose_pair = buffer.language().and_then(|language| {
-                let first_selection_start = selections.first().unwrap().start.to_offset(&*buffer);
+                let first_selection_start = selections.first().unwrap().start;
                 let pair = language.brackets().iter().find(|pair| {
                     buffer.contains_str_at(
                         first_selection_start.saturating_sub(pair.start.len()),
@@ -933,9 +925,8 @@ impl Editor {
                 });
                 pair.and_then(|pair| {
                     let should_autoclose = selections[1..].iter().all(|selection| {
-                        let selection_start = selection.start.to_offset(&*buffer);
                         buffer.contains_str_at(
-                            selection_start.saturating_sub(pair.start.len()),
+                            selection.start.saturating_sub(pair.start.len()),
                             &pair.start,
                         )
                     });
@@ -960,14 +951,13 @@ impl Editor {
                 buffer.edit(selection_ranges, &pair.end, cx);
 
                 if pair.end.len() == 1 {
+                    let mut delta = 0;
                     Some(BracketPairState {
-                        ranges: selections
-                            .iter()
-                            .map(|selection| {
-                                selection.start.bias_left(buffer)
-                                    ..selection.start.bias_right(buffer)
-                            })
-                            .collect(),
+                        ranges: buffer.anchor_range_set(selections.iter().map(move |selection| {
+                            let offset = selection.start + delta;
+                            delta += 1;
+                            (offset, Bias::Left)..(offset, Bias::Right)
+                        })),
                         pair,
                     })
                 } else {
@@ -979,7 +969,8 @@ impl Editor {
     }
 
     fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext<Self>) -> bool {
-        let old_selections = self.selections(cx);
+        let old_selection_count = self.selection_count(cx);
+        let old_selections = self.offset_selections(cx).collect::<Vec<_>>();
         let autoclose_pair_state = if let Some(autoclose_pair_state) = self.autoclose_stack.last() {
             autoclose_pair_state
         } else {
@@ -989,29 +980,25 @@ impl Editor {
             return false;
         }
 
-        debug_assert_eq!(old_selections.len(), autoclose_pair_state.ranges.len());
+        debug_assert_eq!(old_selection_count, autoclose_pair_state.ranges.len());
 
         let buffer = self.buffer.read(cx);
-        let old_selection_ranges: SmallVec<[_; 32]> = old_selections
+        if old_selections
             .iter()
-            .map(|selection| (selection.id, selection.offset_range(buffer)))
-            .collect();
-        if old_selection_ranges
-            .iter()
-            .zip(&autoclose_pair_state.ranges)
-            .all(|((_, selection_range), autoclose_range)| {
+            .zip(autoclose_pair_state.ranges.offset_ranges(buffer))
+            .all(|(selection, autoclose_range)| {
                 let autoclose_range_end = autoclose_range.end.to_offset(buffer);
-                selection_range.is_empty() && selection_range.start == autoclose_range_end
+                selection.is_empty() && selection.start == autoclose_range_end
             })
         {
-            let new_selections = old_selection_ranges
+            let new_selections = old_selections
                 .into_iter()
-                .map(|(id, range)| {
-                    let new_head = buffer.anchor_before(range.start + 1);
+                .map(|selection| {
+                    let cursor = selection.start + 1;
                     Selection {
-                        id,
-                        start: new_head.clone(),
-                        end: new_head,
+                        id: selection.id,
+                        start: cursor,
+                        end: cursor,
                         reversed: false,
                         goal: SelectionGoal::None,
                     }
@@ -1034,22 +1021,18 @@ impl Editor {
 
     pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
-        let mut selections = self.selections(cx).to_vec();
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        {
-            let buffer = self.buffer.read(cx);
-            for selection in &mut selections {
-                let range = selection.point_range(buffer);
-                if range.start == range.end {
-                    let head = selection.head().to_display_point(&display_map, Bias::Left);
-                    let cursor = display_map
-                        .anchor_before(movement::left(&display_map, head).unwrap(), Bias::Left);
-                    selection.set_head(&buffer, cursor);
-                    selection.goal = SelectionGoal::None;
-                }
+        for selection in &mut selections {
+            if selection.is_empty() {
+                let head = selection.head().to_display_point(&display_map, Bias::Left);
+                let cursor = movement::left(&display_map, head)
+                    .unwrap()
+                    .to_buffer_point(&display_map, Bias::Left);
+                selection.set_head(cursor);
+                selection.goal = SelectionGoal::None;
             }
         }
-
         self.update_selections(selections, true, cx);
         self.insert("", cx);
         self.end_transaction(cx);
@@ -1058,21 +1041,17 @@ impl Editor {
     pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections(cx).to_vec();
-        {
-            let buffer = self.buffer.read(cx);
-            for selection in &mut selections {
-                let range = selection.point_range(buffer);
-                if range.start == range.end {
-                    let head = selection.head().to_display_point(&display_map, Bias::Left);
-                    let cursor = display_map
-                        .anchor_before(movement::right(&display_map, head).unwrap(), Bias::Right);
-                    selection.set_head(&buffer, cursor);
-                    selection.goal = SelectionGoal::None;
-                }
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            if selection.is_empty() {
+                let head = selection.head().to_display_point(&display_map, Bias::Left);
+                let cursor = movement::right(&display_map, head)
+                    .unwrap()
+                    .to_buffer_point(&display_map, Bias::Right);
+                selection.set_head(cursor);
+                selection.goal = SelectionGoal::None;
             }
         }
-
         self.update_selections(selections, true, cx);
         self.insert(&"", cx);
         self.end_transaction(cx);
@@ -1081,28 +1060,24 @@ impl Editor {
     pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
         let tab_size = self.build_settings.borrow()(cx).tab_size;
-        let mut selections = self.selections(cx).to_vec();
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
         self.buffer.update(cx, |buffer, cx| {
             let mut last_indented_row = None;
             for selection in &mut selections {
-                let mut range = selection.point_range(buffer);
-                if range.is_empty() {
+                if selection.is_empty() {
                     let char_column = buffer
-                        .chars_for_range(Point::new(range.start.row, 0)..range.start)
+                        .chars_for_range(Point::new(selection.start.row, 0)..selection.start)
                         .count();
                     let chars_to_next_tab_stop = tab_size - (char_column % tab_size);
                     buffer.edit(
-                        [range.start..range.start],
+                        [selection.start..selection.start],
                         " ".repeat(chars_to_next_tab_stop),
                         cx,
                     );
-                    range.start.column += chars_to_next_tab_stop as u32;
-
-                    let head = buffer.anchor_before(range.start);
-                    selection.start = head.clone();
-                    selection.end = head;
+                    selection.start.column += chars_to_next_tab_stop as u32;
+                    selection.end = selection.start;
                 } else {
-                    for row in range.start.row..=range.end.row {
+                    for row in selection.start.row..=selection.end.row {
                         if last_indented_row != Some(row) {
                             let char_column = buffer.indent_column_for_line(row) as usize;
                             let chars_to_next_tab_stop = tab_size - (char_column % tab_size);
@@ -1126,13 +1101,13 @@ impl Editor {
     pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
 
-        let selections = self.selections(cx);
+        let selections = self.point_selections(cx).collect::<Vec<_>>();
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let buffer = self.buffer.read(cx);
 
+        let mut row_delta = 0;
         let mut new_cursors = Vec::new();
         let mut edit_ranges = Vec::new();
-
         let mut selections = selections.iter().peekable();
         while let Some(selection) = selections.next() {
             let mut rows = selection.spanned_rows(false, &display_map).buffer_rows;
@@ -1159,7 +1134,7 @@ impl Editor {
                 // If there's a line after the range, delete the \n from the end of the row range
                 // and position the cursor on the next line.
                 edit_end = Point::new(rows.end, 0).to_offset(buffer);
-                cursor_buffer_row = rows.end;
+                cursor_buffer_row = rows.start;
             } else {
                 // If there isn't a line after the range, delete the \n from the line before the
                 // start of the row range and position the cursor there.
@@ -1168,10 +1143,11 @@ impl Editor {
                 cursor_buffer_row = rows.start.saturating_sub(1);
             }
 
-            let mut cursor =
-                Point::new(cursor_buffer_row, 0).to_display_point(&display_map, Bias::Left);
+            let mut cursor = Point::new(cursor_buffer_row - row_delta, 0)
+                .to_display_point(&display_map, Bias::Left);
             *cursor.column_mut() =
                 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
+            row_delta += rows.len() as u32;
 
             new_cursors.push((
                 selection.id,
@@ -1180,18 +1156,15 @@ impl Editor {
             edit_ranges.push(edit_start..edit_end);
         }
 
-        new_cursors.sort_unstable_by_key(|(_, range)| range.clone());
+        new_cursors.sort_unstable_by_key(|(_, point)| point.clone());
         let new_selections = new_cursors
             .into_iter()
-            .map(|(id, cursor)| {
-                let anchor = buffer.anchor_before(cursor);
-                Selection {
-                    id,
-                    start: anchor.clone(),
-                    end: anchor,
-                    reversed: false,
-                    goal: SelectionGoal::None,
-                }
+            .map(|(id, cursor)| Selection {
+                id,
+                start: cursor,
+                end: cursor,
+                reversed: false,
+                goal: SelectionGoal::None,
             })
             .collect();
         self.buffer
@@ -1203,26 +1176,16 @@ impl Editor {
     pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
 
-        let mut selections = self.selections(cx).to_vec();
-        {
-            // Temporarily bias selections right to allow newly duplicate lines to push them down
-            // when the selections are at the beginning of a line.
-            let buffer = self.buffer.read(cx);
-            for selection in &mut selections {
-                selection.start = selection.start.bias_right(buffer);
-                selection.end = selection.end.bias_right(buffer);
-            }
-        }
-        self.update_selections(selections.clone(), false, cx);
-
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let buffer = self.buffer.read(cx);
 
         let mut edits = Vec::new();
-        let mut selections_iter = selections.iter_mut().peekable();
+        let mut selections_iter = selections.iter().peekable();
         while let Some(selection) = selections_iter.next() {
             // Avoid duplicating the same lines twice.
             let mut rows = selection.spanned_rows(false, &display_map).buffer_rows;
+
             while let Some(next_selection) = selections_iter.peek() {
                 let next_rows = next_selection.spanned_rows(false, &display_map).buffer_rows;
                 if next_rows.start <= rows.end - 1 {
@@ -1240,30 +1203,38 @@ impl Editor {
                 .text_for_range(start..end)
                 .chain(Some("\n"))
                 .collect::<String>();
-            edits.push((start, text));
+            edits.push((start, text, rows.len() as u32));
+        }
+
+        let mut edits_iter = edits.iter().peekable();
+        let mut row_delta = 0;
+        for selection in selections.iter_mut() {
+            while let Some((point, _, line_count)) = edits_iter.peek() {
+                if *point <= selection.start {
+                    row_delta += line_count;
+                    edits_iter.next();
+                } else {
+                    break;
+                }
+            }
+            selection.start.row += row_delta;
+            selection.end.row += row_delta;
         }
 
         self.buffer.update(cx, |buffer, cx| {
-            for (offset, text) in edits.into_iter().rev() {
-                buffer.edit(Some(offset..offset), text, cx);
+            for (point, text, _) in edits.into_iter().rev() {
+                buffer.edit(Some(point..point), text, cx);
             }
         });
 
-        // Restore bias on selections.
-        let buffer = self.buffer.read(cx);
-        for selection in &mut selections {
-            selection.start = selection.start.bias_left(buffer);
-            selection.end = selection.end.bias_left(buffer);
-        }
         self.update_selections(selections, true, cx);
-
         self.end_transaction(cx);
     }
 
     pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
 
-        let selections = self.selections(cx);
+        let selections = self.point_selections(cx).collect::<Vec<_>>();
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let buffer = self.buffer.read(cx);
 
@@ -1353,7 +1324,7 @@ impl Editor {
     pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
 
-        let selections = self.selections(cx);
+        let selections = self.point_selections(cx).collect::<Vec<_>>();
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let buffer = self.buffer.read(cx);
 
@@ -1440,23 +1411,19 @@ impl Editor {
     pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
         self.start_transaction(cx);
         let mut text = String::new();
-        let mut selections = self.selections(cx).to_vec();
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
         let mut clipboard_selections = Vec::with_capacity(selections.len());
         {
             let buffer = self.buffer.read(cx);
             let max_point = buffer.max_point();
             for selection in &mut selections {
-                let mut start = selection.start.to_point(buffer);
-                let mut end = selection.end.to_point(buffer);
-                let is_entire_line = start == end;
+                let is_entire_line = selection.is_empty();
                 if is_entire_line {
-                    start = Point::new(start.row, 0);
-                    end = cmp::min(max_point, Point::new(start.row + 1, 0));
-                    selection.start = buffer.anchor_before(start);
-                    selection.end = buffer.anchor_before(end);
+                    selection.start = Point::new(selection.start.row, 0);
+                    selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
                 }
                 let mut len = 0;
-                for chunk in buffer.text_for_range(start..end) {
+                for chunk in buffer.text_for_range(selection.start..selection.end) {
                     text.push_str(chunk);
                     len += chunk.len();
                 }
@@ -1475,15 +1442,15 @@ impl Editor {
     }
 
     pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
-        let selections = self.selections(cx);
+        let selections = self.point_selections(cx).collect::<Vec<_>>();
         let buffer = self.buffer.read(cx);
         let max_point = buffer.max_point();
         let mut text = String::new();
         let mut clipboard_selections = Vec::with_capacity(selections.len());
         for selection in selections.iter() {
-            let mut start = selection.start.to_point(buffer);
-            let mut end = selection.end.to_point(buffer);
-            let is_entire_line = start == end;
+            let mut start = selection.start;
+            let mut end = selection.end;
+            let is_entire_line = selection.is_empty();
             if is_entire_line {
                 start = Point::new(start.row, 0);
                 end = cmp::min(max_point, Point::new(start.row + 1, 0));
@@ -1507,16 +1474,16 @@ impl Editor {
         if let Some(item) = cx.as_mut().read_from_clipboard() {
             let clipboard_text = item.text();
             if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
-                let selections = self.selections(cx);
+                let mut selections = self.offset_selections(cx).collect::<Vec<_>>();
                 let all_selections_were_entire_line =
                     clipboard_selections.iter().all(|s| s.is_entire_line);
                 if clipboard_selections.len() != selections.len() {
                     clipboard_selections.clear();
                 }
 
+                let mut delta = 0_isize;
                 let mut start_offset = 0;
-                let mut new_selections = Vec::with_capacity(selections.len());
-                for (i, selection) in selections.iter().enumerate() {
+                for (i, selection) in selections.iter_mut().enumerate() {
                     let to_insert;
                     let entire_line;
                     if let Some(clipboard_selection) = clipboard_selections.get(i) {
@@ -1529,33 +1496,29 @@ impl Editor {
                         entire_line = all_selections_were_entire_line;
                     }
 
-                    self.buffer.update(cx, |buffer, cx| {
-                        let selection_start = selection.start.to_point(&*buffer);
-                        let selection_end = selection.end.to_point(&*buffer);
+                    selection.start = (selection.start as isize + delta) as usize;
+                    selection.end = (selection.end as isize + delta) as usize;
 
+                    self.buffer.update(cx, |buffer, cx| {
                         // If the corresponding selection was empty when this slice of the
                         // clipboard text was written, then the entire line containing the
                         // selection was copied. If this selection is also currently empty,
                         // then paste the line before the current line of the buffer.
-                        let new_selection_start = selection.end.bias_right(buffer);
-                        if selection_start == selection_end && entire_line {
-                            let line_start = Point::new(selection_start.row, 0);
-                            buffer.edit(Some(line_start..line_start), to_insert, cx);
+                        let range = if selection.is_empty() && entire_line {
+                            let column = selection.start.to_point(&*buffer).column as usize;
+                            let line_start = selection.start - column;
+                            line_start..line_start
                         } else {
-                            buffer.edit(Some(&selection.start..&selection.end), to_insert, cx);
+                            selection.start..selection.end
                         };
 
-                        let new_selection_start = new_selection_start.bias_left(buffer);
-                        new_selections.push(Selection {
-                            id: selection.id,
-                            start: new_selection_start.clone(),
-                            end: new_selection_start,
-                            reversed: false,
-                            goal: SelectionGoal::None,
-                        });
+                        delta += to_insert.len() as isize - range.len() as isize;
+                        buffer.edit([range], to_insert, cx);
+                        selection.start += to_insert.len();
+                        selection.end = selection.start;
                     });
                 }
-                self.update_selections(new_selections, true, cx);
+                self.update_selections(selections, true, cx);
             } else {
                 self.insert(clipboard_text, cx);
             }
@@ -1572,121 +1535,110 @@ impl Editor {
 
     pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections(cx).to_vec();
-        {
-            for selection in &mut selections {
-                let start = selection.start.to_display_point(&display_map, Bias::Left);
-                let end = selection.end.to_display_point(&display_map, Bias::Left);
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            let start = selection.start.to_display_point(&display_map, Bias::Left);
+            let end = selection.end.to_display_point(&display_map, Bias::Left);
 
-                if start != end {
-                    selection.end = selection.start.clone();
-                } else {
-                    let cursor = display_map
-                        .anchor_before(movement::left(&display_map, start).unwrap(), Bias::Left);
-                    selection.start = cursor.clone();
-                    selection.end = cursor;
-                }
-                selection.reversed = false;
-                selection.goal = SelectionGoal::None;
+            if start != end {
+                selection.end = selection.start.clone();
+            } else {
+                let cursor = movement::left(&display_map, start)
+                    .unwrap()
+                    .to_buffer_point(&display_map, Bias::Left);
+                selection.start = cursor.clone();
+                selection.end = cursor;
             }
+            selection.reversed = false;
+            selection.goal = SelectionGoal::None;
         }
         self.update_selections(selections, true, cx);
     }
 
     pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections(cx).to_vec();
-        {
-            let buffer = self.buffer.read(cx);
-            for selection in &mut selections {
-                let head = selection.head().to_display_point(&display_map, Bias::Left);
-                let cursor = display_map
-                    .anchor_before(movement::left(&display_map, head).unwrap(), Bias::Left);
-                selection.set_head(&buffer, cursor);
-                selection.goal = SelectionGoal::None;
-            }
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            let head = selection.head().to_display_point(&display_map, Bias::Left);
+            let cursor = movement::left(&display_map, head)
+                .unwrap()
+                .to_buffer_point(&display_map, Bias::Left);
+            selection.set_head(cursor);
+            selection.goal = SelectionGoal::None;
         }
         self.update_selections(selections, true, cx);
     }
 
     pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections(cx).to_vec();
-        {
-            for selection in &mut selections {
-                let start = selection.start.to_display_point(&display_map, Bias::Left);
-                let end = selection.end.to_display_point(&display_map, Bias::Left);
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            let start = selection.start.to_display_point(&display_map, Bias::Left);
+            let end = selection.end.to_display_point(&display_map, Bias::Left);
 
-                if start != end {
-                    selection.start = selection.end.clone();
-                } else {
-                    let cursor = display_map
-                        .anchor_before(movement::right(&display_map, end).unwrap(), Bias::Right);
-                    selection.start = cursor.clone();
-                    selection.end = cursor;
-                }
-                selection.reversed = false;
-                selection.goal = SelectionGoal::None;
+            if start != end {
+                selection.start = selection.end.clone();
+            } else {
+                let cursor = movement::right(&display_map, end)
+                    .unwrap()
+                    .to_buffer_point(&display_map, Bias::Right);
+                selection.start = cursor;
+                selection.end = cursor;
             }
+            selection.reversed = false;
+            selection.goal = SelectionGoal::None;
         }
         self.update_selections(selections, true, cx);
     }
 
     pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections(cx).to_vec();
-        {
-            let app = cx.as_ref();
-            let buffer = self.buffer.read(app);
-            for selection in &mut selections {
-                let head = selection.head().to_display_point(&display_map, Bias::Left);
-                let cursor = display_map
-                    .anchor_before(movement::right(&display_map, head).unwrap(), Bias::Right);
-                selection.set_head(&buffer, cursor);
-                selection.goal = SelectionGoal::None;
-            }
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            let head = selection.head().to_display_point(&display_map, Bias::Left);
+            let cursor = movement::right(&display_map, head)
+                .unwrap()
+                .to_buffer_point(&display_map, Bias::Right);
+            selection.set_head(cursor);
+            selection.goal = SelectionGoal::None;
         }
         self.update_selections(selections, true, cx);
     }
 
     pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
-        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         if matches!(self.mode, EditorMode::SingleLine) {
             cx.propagate_action();
-        } else {
-            let mut selections = self.selections(cx).to_vec();
-            {
-                for selection in &mut selections {
-                    let start = selection.start.to_display_point(&display_map, Bias::Left);
-                    let end = selection.end.to_display_point(&display_map, Bias::Left);
-                    if start != end {
-                        selection.goal = SelectionGoal::None;
-                    }
+            return;
+        }
 
-                    let (start, goal) = movement::up(&display_map, start, selection.goal).unwrap();
-                    let cursor = display_map.anchor_before(start, Bias::Left);
-                    selection.start = cursor.clone();
-                    selection.end = cursor;
-                    selection.goal = goal;
-                    selection.reversed = false;
-                }
+        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            let start = selection.start.to_display_point(&display_map, Bias::Left);
+            let end = selection.end.to_display_point(&display_map, Bias::Left);
+            if start != end {
+                selection.goal = SelectionGoal::None;
             }
-            self.update_selections(selections, true, cx);
+
+            let (start, goal) = movement::up(&display_map, start, selection.goal).unwrap();
+            let cursor = start.to_buffer_point(&display_map, Bias::Left);
+            selection.start = cursor;
+            selection.end = cursor;
+            selection.goal = goal;
+            selection.reversed = false;
         }
+        self.update_selections(selections, true, cx);
     }
 
     pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections(cx).to_vec();
-        {
-            let app = cx.as_ref();
-            let buffer = self.buffer.read(app);
-            for selection in &mut selections {
-                let head = selection.head().to_display_point(&display_map, Bias::Left);
-                let (head, goal) = movement::up(&display_map, head, selection.goal).unwrap();
-                selection.set_head(&buffer, display_map.anchor_before(head, Bias::Left));
-                selection.goal = goal;
-            }
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            let head = selection.head().to_display_point(&display_map, Bias::Left);
+            let (head, goal) = movement::up(&display_map, head, selection.goal).unwrap();
+            let cursor = head.to_buffer_point(&display_map, Bias::Left);
+            selection.set_head(cursor);
+            selection.goal = goal;
         }
         self.update_selections(selections, true, cx);
     }
@@ -1694,41 +1646,37 @@ impl Editor {
     pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
         if matches!(self.mode, EditorMode::SingleLine) {
             cx.propagate_action();
-        } else {
-            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-            let mut selections = self.selections(cx).to_vec();
-            {
-                for selection in &mut selections {
-                    let start = selection.start.to_display_point(&display_map, Bias::Left);
-                    let end = selection.end.to_display_point(&display_map, Bias::Left);
-                    if start != end {
-                        selection.goal = SelectionGoal::None;
-                    }
+            return;
+        }
 
-                    let (start, goal) = movement::down(&display_map, end, selection.goal).unwrap();
-                    let cursor = display_map.anchor_before(start, Bias::Right);
-                    selection.start = cursor.clone();
-                    selection.end = cursor;
-                    selection.goal = goal;
-                    selection.reversed = false;
-                }
+        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            let start = selection.start.to_display_point(&display_map, Bias::Left);
+            let end = selection.end.to_display_point(&display_map, Bias::Left);
+            if start != end {
+                selection.goal = SelectionGoal::None;
             }
-            self.update_selections(selections, true, cx);
+
+            let (start, goal) = movement::down(&display_map, end, selection.goal).unwrap();
+            let cursor = start.to_buffer_point(&display_map, Bias::Right);
+            selection.start = cursor;
+            selection.end = cursor;
+            selection.goal = goal;
+            selection.reversed = false;
         }
+        self.update_selections(selections, true, cx);
     }
 
     pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let mut selections = self.selections(cx).to_vec();
-        {
-            let app = cx.as_ref();
-            let buffer = self.buffer.read(app);
-            for selection in &mut selections {
-                let head = selection.head().to_display_point(&display_map, Bias::Left);
-                let (head, goal) = movement::down(&display_map, head, selection.goal).unwrap();
-                selection.set_head(&buffer, display_map.anchor_before(head, Bias::Right));
-                selection.goal = goal;
-            }
+        let mut selections = self.point_selections(cx).collect::<Vec<_>>();
+        for selection in &mut selections {
+            let head = selection.head().to_display_point(&display_map, Bias::Left);
+            let (head, goal) = movement::down(&display_map, head, selection.goal).unwrap();
+            let cursor = head.to_buffer_point(&display_map, Bias::Right);
+            selection.set_head(cursor);
+            selection.goal = goal;
         }
         self.update_selections(selections, true, cx);
     }

crates/language/src/lib.rs 🔗

@@ -790,9 +790,9 @@ impl Buffer {
             for request in autoindent_requests {
                 let old_to_new_rows = request
                     .edited
-                    .to_points(&request.before_edit)
+                    .points(&request.before_edit)
                     .map(|point| point.row)
-                    .zip(request.edited.to_points(&snapshot).map(|point| point.row))
+                    .zip(request.edited.points(&snapshot).map(|point| point.row))
                     .collect::<BTreeMap<u32, u32>>();
 
                 let mut old_suggestions = HashMap::<u32, u32>::default();
@@ -853,7 +853,7 @@ impl Buffer {
                 if let Some(inserted) = request.inserted.as_ref() {
                     let inserted_row_ranges = contiguous_ranges(
                         inserted
-                            .to_point_ranges(&snapshot)
+                            .point_ranges(&snapshot)
                             .flat_map(|range| range.start.row..range.end.row + 1),
                         max_rows_between_yields,
                     );
@@ -901,31 +901,30 @@ impl Buffer {
         for selection_set_id in &selection_set_ids {
             if let Ok(set) = self.selection_set(*selection_set_id) {
                 let new_selections = set
-                    .selections
-                    .iter()
+                    .point_selections(&*self)
                     .map(|selection| {
-                        let start_point = selection.start.to_point(&self.text);
-                        if start_point.column == 0 {
-                            let end_point = selection.end.to_point(&self.text);
+                        if selection.start.column == 0 {
                             let delta = Point::new(
                                 0,
-                                indent_columns.get(&start_point.row).copied().unwrap_or(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: self
-                                        .anchor_at(start_point + delta, selection.start.bias),
-                                    end: self.anchor_at(end_point + delta, selection.end.bias),
+                                    start: selection.start + delta,
+                                    end: selection.end + delta,
                                 };
                             }
                         }
-                        selection.clone()
+                        selection
                     })
-                    .collect::<Arc<[_]>>();
-                self.update_selection_set(*selection_set_id, new_selections, cx)
+                    .collect::<Vec<_>>();
+                self.update_selection_set(*selection_set_id, &new_selections, cx)
                     .unwrap();
             }
         }
@@ -1239,9 +1238,9 @@ impl Buffer {
         cx.notify();
     }
 
-    pub fn add_selection_set(
+    pub fn add_selection_set<T: ToOffset>(
         &mut self,
-        selections: impl Into<Arc<[Selection]>>,
+        selections: &[Selection<T>],
         cx: &mut ModelContext<Self>,
     ) -> SelectionSetId {
         let operation = self.text.add_selection_set(selections);
@@ -1255,10 +1254,10 @@ impl Buffer {
         }
     }
 
-    pub fn update_selection_set(
+    pub fn update_selection_set<T: ToOffset>(
         &mut self,
         set_id: SelectionSetId,
-        selections: impl Into<Arc<[Selection]>>,
+        selections: &[Selection<T>],
         cx: &mut ModelContext<Self>,
     ) -> Result<()> {
         let operation = self.text.update_selection_set(set_id, selections)?;

crates/language/src/tests.rs 🔗

@@ -274,24 +274,24 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
 
         let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx);
 
-        let selection_set_id = buffer.add_selection_set(Vec::new(), cx);
+        let selection_set_id = buffer.add_selection_set::<usize>(&[], cx);
         buffer.start_transaction(Some(selection_set_id)).unwrap();
         buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx);
         buffer
             .update_selection_set(
                 selection_set_id,
-                vec![
+                &[
                     Selection {
                         id: 0,
-                        start: buffer.anchor_before(Point::new(1, 0)),
-                        end: buffer.anchor_before(Point::new(1, 0)),
+                        start: Point::new(1, 0),
+                        end: Point::new(1, 0),
                         reversed: false,
                         goal: SelectionGoal::None,
                     },
                     Selection {
                         id: 1,
-                        start: buffer.anchor_before(Point::new(4, 0)),
-                        end: buffer.anchor_before(Point::new(4, 0)),
+                        start: Point::new(4, 0),
+                        end: Point::new(4, 0),
                         reversed: false,
                         goal: SelectionGoal::None,
                     },
@@ -308,8 +308,7 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
         let selection_ranges = buffer
             .selection_set(selection_set_id)
             .unwrap()
-            .selections
-            .iter()
+            .point_selections(&buffer)
             .map(|selection| selection.point_range(&buffer))
             .collect::<Vec<_>>();
 

crates/project/src/worktree.rs 🔗

@@ -3410,7 +3410,7 @@ mod tests {
 
     #[gpui::test]
     async fn test_buffer_file_changes_on_disk(mut cx: gpui::TestAppContext) {
-        use buffer::{Point, Selection, SelectionGoal, ToPoint};
+        use buffer::{Point, Selection, SelectionGoal};
         use std::fs;
 
         let initial_contents = "aaa\nbbbbb\nc\n";
@@ -3436,20 +3436,17 @@ mod tests {
             .await
             .unwrap();
 
-        // Add a cursor at the start of each row.
+        // 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| {
-                        let anchor = buffer.anchor_at(Point::new(row, 0), Bias::Right);
-                        Selection {
-                            id: row as usize,
-                            start: anchor.clone(),
-                            end: anchor,
-                            reversed: false,
-                            goal: SelectionGoal::None,
-                        }
+                &(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,
@@ -3469,7 +3466,7 @@ mod tests {
         // contents are edited according to the diff between the old and new
         // file contents.
         buffer
-            .condition(&cx, |buffer, _| buffer.text() != initial_contents)
+            .condition(&cx, |buffer, _| buffer.text() == new_contents)
             .await;
 
         buffer.update(&mut cx, |buffer, _| {
@@ -3477,18 +3474,18 @@ mod tests {
             assert!(!buffer.is_dirty());
             assert!(!buffer.has_conflict());
 
-            let set = buffer.selection_set(selection_set_id).unwrap();
-            let cursor_positions = set
-                .selections
-                .iter()
+            let cursor_positions = buffer
+                .selection_set(selection_set_id)
+                .unwrap()
+                .point_selections(&*buffer)
                 .map(|selection| {
                     assert_eq!(selection.start, selection.end);
-                    selection.start.to_point(&*buffer)
+                    selection.start
                 })
                 .collect::<Vec<_>>();
             assert_eq!(
                 cursor_positions,
-                &[Point::new(1, 0), Point::new(3, 0), Point::new(4, 0),]
+                [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)]
             );
         });
 

crates/rpc/proto/zed.proto 🔗

@@ -227,43 +227,31 @@ message Buffer {
     uint64 id = 1;
     string content = 2;
     repeated Operation.Edit history = 3;
-    repeated SelectionSetSnapshot selections = 4;
-}
-
-message SelectionSetSnapshot {
-    uint32 replica_id = 1;
-    uint32 local_timestamp = 2;
-    repeated Selection selections = 3;
-    bool is_active = 4;
+    repeated SelectionSet selections = 4;
 }
 
 message SelectionSet {
-    repeated Selection selections = 1;
+    uint32 replica_id = 1;
+    uint32 lamport_timestamp = 2;
+    bool is_active = 3;
+    repeated VectorClockEntry version = 4;
+    repeated Selection selections = 5;
 }
 
 message Selection {
     uint64 id = 1;
-    Anchor start = 2;
-    Anchor end = 3;
+    uint64 start = 2;
+    uint64 end = 3;
     bool reversed = 4;
 }
 
-message Anchor {
-    repeated VectorClockEntry version = 1;
-    uint64 offset = 2;
-    Bias bias = 3;
-    enum Bias {
-        LEFT = 0;
-        Right = 1;
-    }
-}
-
 message Operation {
     oneof variant {
         Edit edit = 1;
         Undo undo = 2;
         UpdateSelections update_selections = 3;
-        SetActiveSelections set_active_selections = 4;
+        RemoveSelections remove_selections = 4;
+        SetActiveSelections set_active_selections = 5;
     }
 
     message Edit {
@@ -294,7 +282,14 @@ message Operation {
         uint32 replica_id = 1;
         uint32 local_timestamp = 2;
         uint32 lamport_timestamp = 3;
-        SelectionSet set = 4;
+        repeated VectorClockEntry version = 4;
+        repeated Selection selections = 5;
+    }
+
+    message RemoveSelections {
+        uint32 replica_id = 1;
+        uint32 local_timestamp = 2;
+        uint32 lamport_timestamp = 3;
     }
 
     message SetActiveSelections {

crates/sum_tree/src/cursor.rs 🔗

@@ -509,7 +509,7 @@ where
     }
 }
 
-pub struct FilterCursor<'a, F: FnMut(&T::Summary) -> bool, T: Item, D> {
+pub struct FilterCursor<'a, F, T: Item, D> {
     cursor: Cursor<'a, T, D>,
     filter_node: F,
 }