.gitignore 🔗
@@ -4,3 +4,4 @@
/script/node_modules
/server/.env.toml
/server/static/styles.css
+/vendor/bin
Max Brunsfeld created
Represent selection sets as anchor range maps
.gitignore | 1
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 +-
11 files changed, 762 insertions(+), 624 deletions(-)
@@ -4,3 +4,4 @@
/script/node_modules
/server/.env.toml
/server/static/styles.css
+/vendor/bin
@@ -1,8 +1,10 @@
-use crate::Point;
-
-use super::{Buffer, Content};
+use super::{Buffer, Content, Point};
use anyhow::Result;
-use std::{cmp::Ordering, ops::Range};
+use std::{
+ cmp::Ordering,
+ fmt::{Debug, Formatter},
+ ops::Range,
+};
use sum_tree::Bias;
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
@@ -83,7 +85,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 {
@@ -92,23 +112,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<(usize, Bias)>, T)>) -> Self {
+ Self { version, entries }
+ }
+
+ pub fn raw_entries(&self) -> &[(Range<(usize, 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 {
@@ -118,22 +165,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)
+ }
}
pub trait AnchorRangeExt {
@@ -20,7 +20,7 @@ use rpc::proto;
pub use selection::*;
use std::{
cmp,
- convert::{TryFrom, TryInto},
+ convert::TryFrom,
iter::Iterator,
ops::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<usize>>,
- 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);
@@ -414,7 +408,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 {
@@ -488,20 +486,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)
@@ -513,16 +499,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(),
}
}
@@ -562,6 +539,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)
}
@@ -855,23 +839,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,
@@ -1133,16 +1121,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))
}
@@ -1223,7 +1204,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
@@ -1235,7 +1216,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
@@ -1272,12 +1253,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)
@@ -1285,25 +1286,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,
}
}
@@ -1335,9 +1354,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(),
})
}
@@ -1430,9 +1448,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);
@@ -1458,7 +1476,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>>,
{
@@ -1469,25 +1487,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)
}
@@ -1495,15 +1516,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())
@@ -2136,6 +2154,9 @@ impl Operation {
Operation::UpdateSelections {
lamport_timestamp, ..
} => *lamport_timestamp,
+ Operation::RemoveSelections {
+ lamport_timestamp, ..
+ } => *lamport_timestamp,
Operation::SetActiveSelections {
lamport_timestamp, ..
} => *lamport_timestamp,
@@ -2192,9 +2213,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 as u64,
+ end: range.end.0 as u64,
+ 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 {
@@ -2235,30 +2274,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.offset as u64,
- 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;
@@ -2301,16 +2316,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 = (selection.start as usize, Bias::Left)
+ ..(selection.end as usize, 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,
@@ -2320,7 +2342,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) => {
@@ -2360,52 +2394,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 {
- offset: message.offset as usize,
- 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;
}
@@ -2449,3 +2437,9 @@ impl ToPoint for usize {
content.into().visible_text.to_point(*self)
}
}
+
+impl ToPoint for Point {
+ fn to_point<'a>(&self, _: impl Into<Content<'a>>) -> Point {
+ *self
+ }
+}
@@ -1,5 +1,7 @@
-use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _};
-use std::{cmp::Ordering, mem, ops::Range};
+use crate::{AnchorRangeMap, Buffer, Content, 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 as u64,
+ end: range.end.0 as u64,
+ 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 = (selection.start as usize, Bias::Left)
+ ..(selection.end as usize, Bias::Right);
+ let state = SelectionState {
+ id: selection.id as usize,
+ reversed: selection.reversed,
+ goal: SelectionGoal::None,
+ };
+ (range, state)
+ })
+ .collect(),
+ )),
+ }
+ }
+}
@@ -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");
@@ -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()
@@ -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);
}
@@ -522,9 +522,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();
@@ -585,7 +585,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,
);
@@ -633,31 +633,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();
}
}
@@ -936,9 +935,9 @@ impl Buffer {
}
}
- 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);
@@ -952,10 +951,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)?;
@@ -275,24 +275,24 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
let text = History::new("fn a() {}".into());
let mut buffer = Buffer::from_history(0, text, None, Some(rust_lang()), 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,
},
@@ -309,8 +309,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<_>>();
@@ -3323,7 +3323,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";
@@ -3348,20 +3348,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,
@@ -3381,7 +3378,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, _| {
@@ -3389,18 +3386,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)]
);
});
@@ -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 {