From 087ff28d0d78471c48a2947f35083f28990c7274 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 22 Oct 2021 09:56:47 +0200 Subject: [PATCH 01/14] Move SelectionSet and Into impl to selection module --- crates/buffer/src/lib.rs | 17 ----------------- crates/buffer/src/selection.rs | 21 ++++++++++++++++++++- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index a5771ad4c0..eec7da424b 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -73,12 +73,6 @@ 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, @@ -2248,17 +2242,6 @@ impl<'a> Into for &'a Anchor { } } -impl<'a> Into 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 for Operation { type Error = anyhow::Error; diff --git a/crates/buffer/src/selection.rs b/crates/buffer/src/selection.rs index 98f34865f5..df0834b67f 100644 --- a/crates/buffer/src/selection.rs +++ b/crates/buffer/src/selection.rs @@ -1,5 +1,7 @@ +use rpc::proto; + use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _}; -use std::{cmp::Ordering, mem, ops::Range}; +use std::{cmp::Ordering, mem, ops::Range, sync::Arc}; pub type SelectionSetId = clock::Lamport; pub type SelectionsVersion = usize; @@ -20,6 +22,12 @@ pub struct Selection { pub goal: SelectionGoal, } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SelectionSet { + pub selections: Arc<[Selection]>, + pub active: bool, +} + impl Selection { pub fn head(&self) -> &Anchor { if self.reversed { @@ -73,3 +81,14 @@ impl Selection { } } } + +impl<'a> Into 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, + } + } +} From 401bdf0ba105613ae68642bbc09a7a59d0a3409a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 22 Oct 2021 12:35:29 -0600 Subject: [PATCH 02/14] Simplify protocol messages related to selection sets This prepares the way to switch to using AnchorRangeMaps to store and transmit selection sets. --- crates/buffer/src/lib.rs | 109 ++++++++++++++++++++++--------------- crates/rpc/proto/zed.proto | 25 +++++---- 2 files changed, 79 insertions(+), 55 deletions(-) diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index eec7da424b..4511531cf4 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -408,7 +408,11 @@ pub enum Operation { }, UpdateSelections { set_id: SelectionSetId, - selections: Option>, + selections: Arc<[Selection]>, + lamport_timestamp: clock::Lamport, + }, + RemoveSelections { + set_id: SelectionSetId, lamport_timestamp: clock::Lamport, }, SetActiveSelections { @@ -484,7 +488,7 @@ impl Buffer { .map(|set| { let set_id = clock::Lamport { replica_id: set.replica_id as ReplicaId, - value: set.local_timestamp, + value: set.lamport_timestamp, }; let selections: Vec = set .selections @@ -510,9 +514,9 @@ impl Buffer { selections: self .selections .iter() - .map(|(set_id, set)| proto::SelectionSetSnapshot { + .map(|(set_id, set)| proto::SelectionSet { replica_id: set_id.replica_id as u32, - local_timestamp: set_id.value, + lamport_timestamp: set_id.value, selections: set.selections.iter().map(Into::into).collect(), is_active: set.active, }) @@ -849,23 +853,26 @@ 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 { + 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, @@ -1127,16 +1134,13 @@ 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 - } + selections.iter().all(|selection| { + let contains_start = self.version >= selection.start.version; + let contains_end = self.version >= selection.end.version; + contains_start && contains_end + }) } + Operation::RemoveSelections { .. } => true, Operation::SetActiveSelections { set_id, .. } => { set_id.map_or(true, |set_id| self.selections.contains_key(&set_id)) } @@ -1279,7 +1283,7 @@ impl Buffer { set.selections = selections.clone(); Ok(Operation::UpdateSelections { set_id, - selections: Some(selections), + selections, lamport_timestamp: self.lamport_clock.tick(), }) } @@ -1296,7 +1300,7 @@ impl Buffer { ); Operation::UpdateSelections { set_id: lamport_timestamp, - selections: Some(selections), + selections, lamport_timestamp, } } @@ -1329,9 +1333,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(), }) } @@ -2130,6 +2133,9 @@ impl Operation { Operation::UpdateSelections { lamport_timestamp, .. } => *lamport_timestamp, + Operation::RemoveSelections { + lamport_timestamp, .. + } => *lamport_timestamp, Operation::SetActiveSelections { lamport_timestamp, .. } => *lamport_timestamp, @@ -2186,9 +2192,17 @@ impl<'a> Into 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(), - }), + selections: selections.iter().map(Into::into).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 { @@ -2284,16 +2298,11 @@ impl TryFrom for Operation { }, }, proto::operation::Variant::UpdateSelections(message) => { - let selections: Option> = if let Some(set) = message.set { - Some( - set.selections - .into_iter() - .map(TryFrom::try_from) - .collect::>()?, - ) - } else { - None - }; + let selections: Vec = message + .selections + .into_iter() + .map(TryFrom::try_from) + .collect::>()?; Operation::UpdateSelections { set_id: clock::Lamport { replica_id: message.replica_id as ReplicaId, @@ -2303,7 +2312,19 @@ impl TryFrom 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) => { diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 0f0ea69261..939c39829b 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -227,18 +227,14 @@ 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; + repeated Selection selections = 3; + bool is_active = 4; } message Selection { @@ -263,7 +259,8 @@ message Operation { 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 +291,13 @@ message Operation { uint32 replica_id = 1; uint32 local_timestamp = 2; uint32 lamport_timestamp = 3; - SelectionSet set = 4; + repeated Selection selections = 4; + } + + message RemoveSelections { + uint32 replica_id = 1; + uint32 local_timestamp = 2; + uint32 lamport_timestamp = 3; } message SetActiveSelections { From 3ae5ba09fdc0b111f3c6200da2c8c1e2a9c6c30f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 22 Oct 2021 12:46:02 -0600 Subject: [PATCH 03/14] Implement TryFrom on SelectionSet More prep work for changing the selection set representation. --- crates/buffer/src/lib.rs | 48 ++++++----------------------- crates/buffer/src/selection.rs | 55 +++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 43 deletions(-) diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 4511531cf4..6deaf228a1 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -20,7 +20,7 @@ use rpc::proto; pub use selection::*; use std::{ cmp, - convert::{TryFrom, TryInto}, + convert::TryFrom, iter::Iterator, ops::Range, str, @@ -486,20 +486,8 @@ impl Buffer { .selections .into_iter() .map(|set| { - let set_id = clock::Lamport { - replica_id: set.replica_id as ReplicaId, - value: set.lamport_timestamp, - }; - let selections: Vec = set - .selections - .into_iter() - .map(TryFrom::try_from) - .collect::>()?; - 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::>()?; Ok(buffer) @@ -859,6 +847,7 @@ impl Buffer { self.selections.insert( set_id, SelectionSet { + id: set_id, selections, active: false, }, @@ -1290,18 +1279,19 @@ impl Buffer { pub fn add_selection_set(&mut self, selections: impl Into>) -> Operation { let selections = selections.into(); - let lamport_timestamp = self.lamport_clock.tick(); + 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, + set_id, selections, - lamport_timestamp, + lamport_timestamp: set_id, } } @@ -2390,26 +2380,6 @@ impl TryFrom for Anchor { } } -impl TryFrom for Selection { - type Error = anyhow::Error; - - fn try_from(selection: proto::Selection) -> Result { - 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>) -> usize; } diff --git a/crates/buffer/src/selection.rs b/crates/buffer/src/selection.rs index df0834b67f..589746803b 100644 --- a/crates/buffer/src/selection.rs +++ b/crates/buffer/src/selection.rs @@ -1,7 +1,13 @@ -use rpc::proto; - use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _}; -use std::{cmp::Ordering, mem, ops::Range, sync::Arc}; +use anyhow::anyhow; +use rpc::proto; +use std::{ + cmp::Ordering, + convert::{TryFrom, TryInto}, + mem, + ops::Range, + sync::Arc, +}; pub type SelectionSetId = clock::Lamport; pub type SelectionsVersion = usize; @@ -24,8 +30,9 @@ pub struct Selection { #[derive(Clone, Debug, Eq, PartialEq)] pub struct SelectionSet { - pub selections: Arc<[Selection]>, + pub id: SelectionSetId, pub active: bool, + pub selections: Arc<[Selection]>, } impl Selection { @@ -92,3 +99,43 @@ impl<'a> Into for &'a Selection { } } } + +impl TryFrom for Selection { + type Error = anyhow::Error; + + fn try_from(selection: proto::Selection) -> Result { + 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, + }) + } +} + +impl TryFrom for SelectionSet { + type Error = anyhow::Error; + + fn try_from(set: proto::SelectionSet) -> Result { + Ok(Self { + id: clock::Lamport { + replica_id: set.replica_id as u16, + value: set.lamport_timestamp, + }, + active: set.is_active, + selections: Arc::from( + set.selections + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?, + ), + }) + } +} From 6ba4af3e260b68bec2ba20003085b38c940041bb Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 22 Oct 2021 13:19:19 -0600 Subject: [PATCH 04/14] WIP: Start converting SelectionSet to use AnchorRangeMap --- crates/buffer/src/anchor.rs | 33 +++++++++++- crates/buffer/src/lib.rs | 19 ++----- crates/buffer/src/selection.rs | 94 +++++++++++++++++----------------- crates/clock/src/lib.rs | 6 +++ crates/rpc/proto/zed.proto | 12 +++-- 5 files changed, 97 insertions(+), 67 deletions(-) diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index 1ac82727df..58673a3301 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -2,7 +2,11 @@ use crate::Point; use super::{Buffer, Content}; 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)] @@ -108,6 +112,14 @@ impl AnchorSet { } impl AnchorRangeMap { + 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 to_point_ranges<'a>( &'a self, content: impl Into> + 'a, @@ -123,6 +135,25 @@ impl AnchorRangeMap { } } +impl PartialEq for AnchorRangeMap { + fn eq(&self, other: &Self) -> bool { + self.version == other.version && self.entries == other.entries + } +} + +impl Eq for AnchorRangeMap {} + +impl Debug for AnchorRangeMap { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let f = f.debug_map(); + for (range, value) in &self.entries { + f.key(range); + f.value(value); + } + f.finish() + } +} + impl AnchorRangeSet { pub fn to_point_ranges<'a>( &'a self, diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 6deaf228a1..f780d2590c 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -408,7 +408,7 @@ pub enum Operation { }, UpdateSelections { set_id: SelectionSetId, - selections: Arc<[Selection]>, + selections: Arc>, lamport_timestamp: clock::Lamport, }, RemoveSelections { @@ -502,12 +502,7 @@ impl Buffer { selections: self .selections .iter() - .map(|(set_id, set)| proto::SelectionSet { - replica_id: set_id.replica_id as u32, - lamport_timestamp: set_id.value, - selections: set.selections.iter().map(Into::into).collect(), - is_active: set.active, - }) + .map(|(set_id, set)| set.into()) .collect(), } } @@ -1123,11 +1118,7 @@ impl Buffer { Operation::Edit(edit) => self.version >= edit.version, Operation::Undo { undo, .. } => self.version >= undo.version, Operation::UpdateSelections { 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 - }) + self.version >= *selections.version() } Operation::RemoveSelections { .. } => true, Operation::SetActiveSelections { set_id, .. } => { @@ -1262,14 +1253,14 @@ impl Buffer { pub fn update_selection_set( &mut self, set_id: SelectionSetId, - selections: impl Into>, + selections: &[Selection], ) -> Result { let selections = selections.into(); let set = self .selections .get_mut(&set_id) .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - set.selections = selections.clone(); + set.selections = todo!(); Ok(Operation::UpdateSelections { set_id, selections, diff --git a/crates/buffer/src/selection.rs b/crates/buffer/src/selection.rs index 589746803b..03b394252b 100644 --- a/crates/buffer/src/selection.rs +++ b/crates/buffer/src/selection.rs @@ -1,13 +1,7 @@ -use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _}; -use anyhow::anyhow; +use crate::{Anchor, AnchorRangeMap, Buffer, Point, ToOffset as _, ToPoint as _}; use rpc::proto; -use std::{ - cmp::Ordering, - convert::{TryFrom, TryInto}, - mem, - ops::Range, - sync::Arc, -}; +use std::{cmp::Ordering, mem, ops::Range, sync::Arc}; +use sum_tree::Bias; pub type SelectionSetId = clock::Lamport; pub type SelectionsVersion = usize; @@ -32,7 +26,14 @@ pub struct Selection { pub struct SelectionSet { pub id: SelectionSetId, pub active: bool, - pub selections: Arc<[Selection]>, + pub selections: Arc>, +} + +#[derive(Debug, Eq, PartialEq)] +pub struct SelectionState { + pub id: usize, + pub reversed: bool, + pub goal: SelectionGoal, } impl Selection { @@ -89,53 +90,52 @@ impl Selection { } } -impl<'a> Into 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<'a> Into 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 TryFrom for Selection { - type Error = anyhow::Error; - - fn try_from(selection: proto::Selection) -> Result { - 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, - }) - } -} - -impl TryFrom for SelectionSet { - type Error = anyhow::Error; - - fn try_from(set: proto::SelectionSet) -> Result { - Ok(Self { +impl From 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::from( + selections: Arc::new(AnchorRangeMap::from_raw( + set.version.into(), set.selections .into_iter() - .map(TryInto::try_into) - .collect::, _>>()?, - ), - }) + .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(), + )), + } } } diff --git a/crates/clock/src/lib.rs b/crates/clock/src/lib.rs index ee5c0dba03..b3158d99dd 100644 --- a/crates/clock/src/lib.rs +++ b/crates/clock/src/lib.rs @@ -86,6 +86,12 @@ impl<'a> From<&'a Global> for Vec { } } +impl From for Vec { + fn from(version: Global) -> Self { + (&version).into() + } +} + impl Global { pub fn new() -> Self { Self::default() diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 939c39829b..0678215ef8 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -233,14 +233,15 @@ message Buffer { message SelectionSet { uint32 replica_id = 1; uint32 lamport_timestamp = 2; - repeated Selection selections = 3; - bool is_active = 4; + 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; } @@ -291,7 +292,8 @@ message Operation { uint32 replica_id = 1; uint32 local_timestamp = 2; uint32 lamport_timestamp = 3; - repeated Selection selections = 4; + repeated VectorClockEntry version = 4; + repeated Selection selections = 5; } message RemoveSelections { From 60a8e7443070226943504a8303752dea99e9e74b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 22 Oct 2021 14:12:16 -0600 Subject: [PATCH 05/14] Get buffer compiling with new SelectionSets based on AnchorRangeMap One test is failing however. --- crates/buffer/src/anchor.rs | 22 ++++-- crates/buffer/src/lib.rs | 122 +++++++++++++++++++++++---------- crates/buffer/src/selection.rs | 68 +++++++++++++----- crates/buffer/src/tests.rs | 6 +- 4 files changed, 156 insertions(+), 62 deletions(-) diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index 58673a3301..3162dcd28f 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -87,7 +87,7 @@ impl Anchor { } impl AnchorMap { - pub fn to_points<'a>( + pub fn points<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { @@ -103,11 +103,11 @@ impl AnchorMap { } impl AnchorSet { - pub fn to_points<'a>( + pub fn points<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { - self.0.to_points(content).map(move |(point, _)| point) + self.0.points(content).map(move |(point, _)| point) } } @@ -120,7 +120,7 @@ impl AnchorRangeMap { &self.entries } - pub fn to_point_ranges<'a>( + pub fn point_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator, &'a T)> + 'a { @@ -130,6 +130,16 @@ impl AnchorRangeMap { .map(move |(range, value)| ((range.start.lines..range.end.lines), value)) } + pub fn offset_ranges<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl Iterator, &'a T)> + 'a { + let content = content.into(); + content + .summaries_for_anchor_ranges(self) + .map(move |(range, value)| ((range.start.bytes..range.end.bytes), value)) + } + pub fn version(&self) -> &clock::Global { &self.version } @@ -145,7 +155,7 @@ impl Eq for AnchorRangeMap {} impl Debug for AnchorRangeMap { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - let f = f.debug_map(); + let mut f = f.debug_map(); for (range, value) in &self.entries { f.key(range); f.value(value); @@ -159,7 +169,7 @@ impl AnchorRangeSet { &'a self, content: impl Into> + 'a, ) -> impl Iterator> + 'a { - self.0.to_point_ranges(content).map(|(range, _)| range) + self.0.point_ranges(content).map(|(range, _)| range) } pub fn version(&self) -> &clock::Global { diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index f780d2590c..a5dd062570 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -79,8 +79,8 @@ pub struct Transaction { end: clock::Global, edits: Vec, ranges: Vec>, - selections_before: HashMap>, - selections_after: HashMap>, + selections_before: HashMap>>, + selections_after: HashMap>>, first_edit_at: Instant, last_edit_at: Instant, } @@ -167,7 +167,7 @@ impl History { fn start_transaction( &mut self, start: clock::Global, - selections_before: HashMap>, + selections_before: HashMap>>, now: Instant, ) { self.transaction_depth += 1; @@ -187,7 +187,7 @@ impl History { fn end_transaction( &mut self, - selections_after: HashMap>, + selections_after: HashMap>>, now: Instant, ) -> Option<&Transaction> { assert_ne!(self.transaction_depth, 0); @@ -499,11 +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)| set.into()) - .collect(), + selections: self.selections.iter().map(|(_, set)| set.into()).collect(), } } @@ -1201,7 +1197,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 @@ -1213,7 +1209,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 @@ -1250,17 +1246,37 @@ impl Buffer { self.selections.iter() } - pub fn update_selection_set( + fn build_selection_anchor_range_map( + &self, + selections: &[Selection], + ) -> Arc> { + 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( &mut self, set_id: SelectionSetId, - selections: &[Selection], + selections: &[Selection], ) -> Result { - let selections = selections.into(); + let selections = self.build_selection_anchor_range_map(selections); let set = self .selections .get_mut(&set_id) .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - set.selections = todo!(); + set.selections = selections.clone(); Ok(Operation::UpdateSelections { set_id, selections, @@ -1268,8 +1284,25 @@ impl Buffer { }) } - pub fn add_selection_set(&mut self, selections: impl Into>) -> Operation { - let selections = selections.into(); + pub fn restore_selection_set( + &mut self, + set_id: SelectionSetId, + selections: Arc>, + ) -> Result { + 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(&mut self, selections: &[Selection]) -> Operation { + let selections = self.build_selection_anchor_range_map(selections); let set_id = self.lamport_clock.tick(); self.selections.insert( set_id, @@ -1408,9 +1441,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); @@ -1436,7 +1469,7 @@ impl Buffer { ops } - fn selections_from_ranges(&self, ranges: I) -> Result> + fn selections_from_ranges(&self, ranges: I) -> Result>> where I: IntoIterator>, { @@ -1452,16 +1485,16 @@ impl Buffer { 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), + start: range.end, + end: 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), + start: range.start, + end: range.end, reversed: false, goal: SelectionGoal::None, }); @@ -1473,15 +1506,12 @@ impl Buffer { pub fn selection_ranges<'a>(&'a self, set_id: SelectionSetId) -> Result>> { 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()) @@ -2173,7 +2203,17 @@ impl<'a> Into for &'a Operation { replica_id: set_id.replica_id as u32, local_timestamp: set_id.value, lamport_timestamp: lamport_timestamp.value, - 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 { @@ -2279,11 +2319,23 @@ impl TryFrom for Operation { }, }, proto::operation::Variant::UpdateSelections(message) => { - let selections: Vec = message + let version = message.version.into(); + let entries = message .selections - .into_iter() - .map(TryFrom::try_from) - .collect::>()?; + .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, diff --git a/crates/buffer/src/selection.rs b/crates/buffer/src/selection.rs index 03b394252b..f582aa199f 100644 --- a/crates/buffer/src/selection.rs +++ b/crates/buffer/src/selection.rs @@ -1,6 +1,6 @@ -use crate::{Anchor, AnchorRangeMap, Buffer, Point, ToOffset as _, ToPoint as _}; +use crate::{AnchorRangeMap, Buffer, Content, Point, ToOffset, ToPoint}; use rpc::proto; -use std::{cmp::Ordering, mem, ops::Range, sync::Arc}; +use std::{cmp::Ordering, ops::Range, sync::Arc}; use sum_tree::Bias; pub type SelectionSetId = clock::Lamport; @@ -14,10 +14,10 @@ pub enum SelectionGoal { } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Selection { +pub struct Selection { pub id: usize, - pub start: Anchor, - pub end: Anchor, + pub start: T, + pub end: T, pub reversed: bool, pub goal: SelectionGoal, } @@ -36,36 +36,36 @@ pub struct SelectionState { pub goal: SelectionGoal, } -impl Selection { - pub fn head(&self) -> &Anchor { +impl Selection { + 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 } } @@ -90,6 +90,38 @@ impl Selection { } } +impl SelectionSet { + pub fn offset_selections<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl 'a + Iterator> { + 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> + 'a, + ) -> impl 'a + Iterator> { + 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 for &'a SelectionSet { fn into(self) -> proto::SelectionSet { let version = self.selections.version(); diff --git a/crates/buffer/src/tests.rs b/crates/buffer/src/tests.rs index bb29f7de98..bce08ebf73 100644 --- a/crates/buffer/src/tests.rs +++ b/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"); From ab4f90a20a4f7f6adcff20ddcd0d3336285a3ae6 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 25 Oct 2021 09:26:36 -0600 Subject: [PATCH 06/14] Get language and project compiling --- crates/buffer/src/lib.rs | 6 ++++++ crates/language/src/lib.rs | 32 ++++++++++++++------------------ crates/language/src/tests.rs | 15 +++++++-------- crates/project/src/worktree.rs | 22 +++++++++------------- 4 files changed, 36 insertions(+), 39 deletions(-) diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index a5dd062570..a3d841db3f 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -2466,3 +2466,9 @@ impl ToPoint for usize { content.into().visible_text.to_point(*self) } } + +impl ToPoint for Point { + fn to_point<'a>(&self, _: impl Into>) -> Point { + *self + } +} diff --git a/crates/language/src/lib.rs b/crates/language/src/lib.rs index b80eed7e33..8d0f06a648 100644 --- a/crates/language/src/lib.rs +++ b/crates/language/src/lib.rs @@ -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::>(); let mut old_suggestions = HashMap::::default(); @@ -633,31 +633,27 @@ 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::>(); - self.update_selection_set(*selection_set_id, new_selections, cx) + .collect::>(); + self.update_selection_set(*selection_set_id, &new_selections, cx) .unwrap(); } } @@ -936,9 +932,9 @@ impl Buffer { } } - pub fn add_selection_set( + pub fn add_selection_set( &mut self, - selections: impl Into>, + selections: &[Selection], cx: &mut ModelContext, ) -> SelectionSetId { let operation = self.text.add_selection_set(selections); @@ -952,10 +948,10 @@ impl Buffer { } } - pub fn update_selection_set( + pub fn update_selection_set( &mut self, set_id: SelectionSetId, - selections: impl Into>, + selections: &[Selection], cx: &mut ModelContext, ) -> Result<()> { let operation = self.text.update_selection_set(set_id, selections)?; diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index 23cdced4c7..7237fd3b80 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -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::(&[], 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::>(); diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 0ef60a7408..f763a57699 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -3352,16 +3352,13 @@ mod tests { 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, 0), + end: Point::new(row, 0), + reversed: false, + goal: SelectionGoal::None, }) .collect::>(), cx, @@ -3391,11 +3388,10 @@ mod tests { let set = buffer.selection_set(selection_set_id).unwrap(); let cursor_positions = set - .selections - .iter() + .point_selections(&*buffer) .map(|selection| { assert_eq!(selection.start, selection.end); - selection.start.to_point(&*buffer) + selection.start }) .collect::>(); assert_eq!( From 1a92a199543cd405a54704a1d3334164e2848943 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 26 Oct 2021 12:04:04 -0600 Subject: [PATCH 07/14] Remove Anchor from protocol --- crates/rpc/proto/zed.proto | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 0678215ef8..2986ab9451 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -245,16 +245,6 @@ message Selection { 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; From 9c74be3bf2ad6d857980cc675299c8db5cb64a66 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 28 Oct 2021 19:36:43 +0200 Subject: [PATCH 08/14] Start fixing compilation errors on `Editor` Co-Authored-By: Max Brunsfeld --- crates/buffer/src/anchor.rs | 32 +++++++ crates/buffer/src/lib.rs | 46 ++-------- crates/buffer/src/selection.rs | 4 + crates/editor/src/lib.rs | 149 ++++++++++++++++----------------- 4 files changed, 117 insertions(+), 114 deletions(-) diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index 3162dcd28f..40ed74089e 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -87,6 +87,16 @@ impl Anchor { } impl AnchorMap { + pub fn offsets<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl Iterator + '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> + 'a, @@ -103,6 +113,13 @@ impl AnchorMap { } impl AnchorSet { + pub fn offsets<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl Iterator + 'a { + self.0.offsets(content).map(move |(offset, _)| offset) + } + pub fn points<'a>( &'a self, content: impl Into> + 'a, @@ -120,6 +137,10 @@ impl AnchorRangeMap { &self.entries } + pub fn len(&self) -> usize { + self.entries.len() + } + pub fn point_ranges<'a>( &'a self, content: impl Into> + 'a, @@ -165,6 +186,17 @@ impl Debug for AnchorRangeMap { } impl AnchorRangeSet { + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn to_offset_ranges<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl Iterator> + 'a { + self.0.offset_ranges(content).map(|(range, _)| range) + } + pub fn to_point_ranges<'a>( &'a self, content: impl Into> + 'a, diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index a3d841db3f..ffee9d5736 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -539,6 +539,13 @@ impl Buffer { self.content().anchor_at(position, bias) } + pub fn anchor_range_set(&self, entries: E) -> AnchorRangeSet + where + E: IntoIterator>, + { + self.content().anchor_range_set(entries) + } + pub fn point_for_offset(&self, offset: usize) -> Result { self.content().point_for_offset(offset) } @@ -2264,19 +2271,6 @@ impl<'a> Into for &'a EditOperation { } } -impl<'a> Into 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 TryFrom for Operation { type Error = anyhow::Error; @@ -2397,32 +2391,6 @@ impl From for EditOperation { } } -impl TryFrom for Anchor { - type Error = anyhow::Error; - - fn try_from(message: proto::Anchor) -> Result { - 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, - }) - } -} - pub trait ToOffset { fn to_offset<'a>(&self, content: impl Into>) -> usize; } diff --git a/crates/buffer/src/selection.rs b/crates/buffer/src/selection.rs index f582aa199f..858ffad3fb 100644 --- a/crates/buffer/src/selection.rs +++ b/crates/buffer/src/selection.rs @@ -91,6 +91,10 @@ impl Selection { } impl SelectionSet { + pub fn len(&self) -> usize { + self.selections.len() + } + pub fn offset_selections<'a>( &'a self, content: impl Into> + 'a, diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 61414d5dc7..0efe14e777 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -293,11 +293,11 @@ pub struct Editor { buffer: ModelHandle, display_map: ModelHandle, selection_set_id: SelectionSetId, - pending_selection: Option, + pending_selection: Option>, next_selection_id: usize, add_selections_state: Option, autoclose_stack: Vec, - select_larger_syntax_node_stack: Vec>, + select_larger_syntax_node_stack: Vec]>>, scroll_position: Vector2F, scroll_top_anchor: Anchor, autoscroll_requested: bool, @@ -325,7 +325,7 @@ struct AddSelectionsState { } struct BracketPairState { - ranges: SmallVec<[Range; 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 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, ) -> 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::(Vec::new(), false, cx); } self.pending_selection = Some(selection); @@ -642,9 +642,9 @@ impl Editor { ) { 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 +656,8 @@ impl Editor { fn end_selection(&mut self, cx: &mut ViewContext) { 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::>(); + let ix = self.selection_insertion_index(&selections, selection.start, cx.as_ref()); selections.insert(ix, selection); self.update_selections(selections, false, cx); } @@ -669,14 +669,14 @@ impl Editor { pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { 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(); } @@ -758,10 +758,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::>(); 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); @@ -880,35 +880,25 @@ impl Editor { fn insert(&mut self, text: &str, cx: &mut ViewContext) { 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::>(); 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 +911,10 @@ impl Editor { } fn autoclose_pairs(&mut self, cx: &mut ViewContext) { - let selections = self.selections(cx); + let selections = self.offset_selections(cx).collect::>(); 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 +923,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, ) }); @@ -961,13 +950,9 @@ impl Editor { if pair.end.len() == 1 { 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(|selection| { + (selection.start, Bias::Left)..(selection.start, Bias::Right) + })), pair, }) } else { @@ -979,7 +964,8 @@ impl Editor { } fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext) -> bool { - let old_selections = self.selections(cx); + let old_selection_count = self.selection_count(cx); + let old_selections = self.offset_selections(cx); let autoclose_pair_state = if let Some(autoclose_pair_state) = self.autoclose_stack.last() { autoclose_pair_state } else { @@ -989,16 +975,11 @@ 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 - .iter() - .map(|selection| (selection.id, selection.offset_range(buffer))) - .collect(); - if old_selection_ranges - .iter() - .zip(&autoclose_pair_state.ranges) + if old_selections + .zip(&autoclose_pair_state.ranges.to_offset_ranges(buffer)) .all(|((_, selection_range), autoclose_range)| { let autoclose_range_end = autoclose_range.end.to_offset(buffer); selection_range.is_empty() && selection_range.start == autoclose_range_end @@ -2273,7 +2254,7 @@ impl Editor { row: u32, columns: &Range, reversed: bool, - ) -> Option { + ) -> Option> { let is_empty = columns.start == columns.end; let line_len = display_map.line_len(row); if columns.start < line_len || (is_empty && columns.start == line_len) { @@ -2340,17 +2321,15 @@ impl Editor { fn selection_insertion_index( &self, - selections: &[Selection], - start: &Anchor, + selections: &[Selection], + start: Point, cx: &AppContext, ) -> usize { let buffer = self.buffer.read(cx); - match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) { + match selections.binary_search_by_key(&start, |probe| probe.start) { Ok(index) => index, Err(index) => { - if index > 0 - && selections[index - 1].end.cmp(&start, buffer).unwrap() == Ordering::Greater - { + if index > 0 && selections[index - 1].end > start { index - 1 } else { index @@ -2359,19 +2338,39 @@ impl Editor { } } - fn selections(&mut self, cx: &mut ViewContext) -> Arc<[Selection]> { + fn point_selections<'a>( + &mut self, + cx: &'a mut ViewContext, + ) -> impl 'a + Iterator> { self.end_selection(cx); let buffer = self.buffer.read(cx); buffer .selection_set(self.selection_set_id) .unwrap() - .selections - .clone() + .point_selections(buffer) } - fn update_selections( + fn offset_selections<'a>( &mut self, - mut selections: Vec, + cx: &'a mut ViewContext, + ) -> impl 'a + Iterator> { + self.end_selection(cx); + let buffer = self.buffer.read(cx); + buffer + .selection_set(self.selection_set_id) + .unwrap() + .offset_selections(buffer) + } + + fn selection_count(&mut self, cx: &mut ViewContext) -> usize { + self.end_selection(cx); + let buffer = self.buffer.read(cx); + buffer.selection_set(self.selection_set_id).unwrap().len() + } + + fn update_selections( + &mut self, + mut selections: Vec>, autoscroll: bool, cx: &mut ViewContext, ) { From efc85d1b75f9034117a4d6b8cc46f3e276bdcd98 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 28 Oct 2021 15:42:24 -0700 Subject: [PATCH 09/14] Get the Editor crate compiling --- crates/buffer/src/anchor.rs | 10 + crates/buffer/src/selection.rs | 4 + crates/editor/src/lib.rs | 902 +++++++++++++++------------------ 3 files changed, 425 insertions(+), 491 deletions(-) diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index 40ed74089e..4a420de21f 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -185,6 +185,16 @@ impl Debug for AnchorRangeMap { } } +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 len(&self) -> usize { self.0.len() diff --git a/crates/buffer/src/selection.rs b/crates/buffer/src/selection.rs index 858ffad3fb..e25bea5ff7 100644 --- a/crates/buffer/src/selection.rs +++ b/crates/buffer/src/selection.rs @@ -37,6 +37,10 @@ pub struct SelectionState { } impl Selection { + pub fn is_empty(&self) -> bool { + self.start == self.end + } + pub fn head(&self) -> T { if self.reversed { self.start diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 0efe14e777..50f446c5e8 100644 --- a/crates/editor/src/lib.rs +++ b/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, @@ -297,7 +296,7 @@ pub struct Editor { next_selection_id: usize, add_selections_state: Option, autoclose_stack: Vec, - select_larger_syntax_node_stack: Vec]>>, + select_larger_syntax_node_stack: Vec]>>, scroll_position: Vector2F, scroll_top_anchor: Anchor, autoscroll_requested: bool, @@ -324,6 +323,7 @@ struct AddSelectionsState { stack: Vec, } +#[derive(Debug)] struct BracketPairState { ranges: AnchorRangeSet, pair: BracketPair, @@ -512,7 +512,7 @@ impl Editor { return false; } - let selections = self.point_selections(cx).peekable(); + let mut selections = self.point_selections(cx).peekable(); let first_cursor_top = selections .peek() .unwrap() @@ -641,7 +641,6 @@ impl Editor { cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let buffer = self.buffer.read(cx); let cursor = position.to_buffer_point(&display_map, Bias::Left); if let Some(selection) = self.pending_selection.as_mut() { selection.set_head(cursor); @@ -657,7 +656,7 @@ impl Editor { fn end_selection(&mut self, cx: &mut ViewContext) { if let Some(selection) = self.pending_selection.take() { let mut selections = self.point_selections(cx).collect::>(); - let ix = self.selection_insertion_index(&selections, selection.start, cx.as_ref()); + let ix = self.selection_insertion_index(&selections, selection.start); selections.insert(ix, selection); self.update_selections(selections, false, cx); } @@ -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>, { - 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(()) } @@ -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, } @@ -949,9 +951,12 @@ impl Editor { buffer.edit(selection_ranges, &pair.end, cx); if pair.end.len() == 1 { + let mut delta = 0; Some(BracketPairState { - ranges: buffer.anchor_range_set(selections.iter().map(|selection| { - (selection.start, Bias::Left)..(selection.start, Bias::Right) + ranges: buffer.anchor_range_set(selections.iter().map(move |selection| { + let offset = selection.start + delta; + delta += 1; + (offset, Bias::Left)..(offset, Bias::Right) })), pair, }) @@ -965,7 +970,7 @@ impl Editor { fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext) -> bool { let old_selection_count = self.selection_count(cx); - let old_selections = self.offset_selections(cx); + let old_selections = self.offset_selections(cx).collect::>(); let autoclose_pair_state = if let Some(autoclose_pair_state) = self.autoclose_stack.last() { autoclose_pair_state } else { @@ -979,20 +984,21 @@ impl Editor { let buffer = self.buffer.read(cx); if old_selections - .zip(&autoclose_pair_state.ranges.to_offset_ranges(buffer)) - .all(|((_, selection_range), autoclose_range)| { + .iter() + .zip(autoclose_pair_state.ranges.to_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, } @@ -1015,22 +1021,18 @@ impl Editor { pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext) { self.start_transaction(cx); - let mut selections = self.selections(cx).to_vec(); + let mut selections = self.point_selections(cx).collect::>(); 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); @@ -1039,21 +1041,17 @@ impl Editor { pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext) { 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::>(); + 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); @@ -1062,28 +1060,24 @@ impl Editor { pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext) { 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::>(); 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); @@ -1107,13 +1101,13 @@ impl Editor { pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext) { self.start_transaction(cx); - let selections = self.selections(cx); + let selections = self.point_selections(cx).collect::>(); 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; @@ -1140,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. @@ -1149,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, @@ -1161,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 @@ -1184,26 +1176,16 @@ impl Editor { pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext) { 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::>(); 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 { @@ -1221,30 +1203,38 @@ impl Editor { .text_for_range(start..end) .chain(Some("\n")) .collect::(); - 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.start_transaction(cx); - let selections = self.selections(cx); + let selections = self.point_selections(cx).collect::>(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); @@ -1334,7 +1324,7 @@ impl Editor { pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext) { self.start_transaction(cx); - let selections = self.selections(cx); + let selections = self.point_selections(cx).collect::>(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); @@ -1421,23 +1411,19 @@ impl Editor { pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext) { 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::>(); 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(); } @@ -1456,15 +1442,15 @@ impl Editor { } pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext) { - let selections = self.selections(cx); + let selections = self.point_selections(cx).collect::>(); 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)); @@ -1488,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::>() { - let selections = self.selections(cx); + let mut selections = self.offset_selections(cx).collect::>(); 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) { @@ -1510,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); } @@ -1553,121 +1535,110 @@ impl Editor { pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { 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::>(); + 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) { 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::>(); + 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) { 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::>(); + 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) { 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::>(); + 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) { - 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; - } - - 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; - } - } - self.update_selections(selections, true, cx); + return; } + + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + let mut selections = self.point_selections(cx).collect::>(); + 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; + } + + 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) { 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::>(); + 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); } @@ -1675,41 +1646,37 @@ impl Editor { pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { 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; - } - - 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; - } - } - self.update_selections(selections, true, cx); + return; } + + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + let mut selections = self.point_selections(cx).collect::>(); + 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; + } + + 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) { 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::>(); + 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); } @@ -1720,17 +1687,15 @@ impl Editor { cx: &mut ViewContext, ) { 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 head = selection.head().to_display_point(&display_map, Bias::Left); - let new_head = movement::prev_word_boundary(&display_map, head).unwrap(); - let anchor = display_map.anchor_before(new_head, Bias::Left); - selection.start = anchor.clone(); - selection.end = anchor; - selection.reversed = false; - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::prev_word_boundary(&display_map, head).unwrap(); + let cursor = new_head.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); } @@ -1741,16 +1706,13 @@ impl Editor { cx: &mut ViewContext, ) { 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 new_head = movement::prev_word_boundary(&display_map, head).unwrap(); - let anchor = display_map.anchor_before(new_head, Bias::Left); - selection.set_head(buffer, anchor); - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::prev_word_boundary(&display_map, head).unwrap(); + let cursor = new_head.to_buffer_point(&display_map, Bias::Left); + selection.set_head(cursor); + selection.goal = SelectionGoal::None; } self.update_selections(selections, true, cx); } @@ -1762,23 +1724,16 @@ impl Editor { ) { 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::prev_word_boundary(&display_map, head).unwrap(), - Bias::Right, - ); - selection.set_head(&buffer, cursor); - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + if selection.is_empty() { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::prev_word_boundary(&display_map, head).unwrap(); + let cursor = new_head.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); @@ -1790,17 +1745,15 @@ impl Editor { cx: &mut ViewContext, ) { 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 head = selection.head().to_display_point(&display_map, Bias::Left); - let new_head = movement::next_word_boundary(&display_map, head).unwrap(); - let anchor = display_map.anchor_before(new_head, Bias::Left); - selection.start = anchor.clone(); - selection.end = anchor; - selection.reversed = false; - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::next_word_boundary(&display_map, head).unwrap(); + let cursor = new_head.to_buffer_point(&display_map, Bias::Left); + selection.start = cursor; + selection.end = cursor; + selection.reversed = false; + selection.goal = SelectionGoal::None; } self.update_selections(selections, true, cx); } @@ -1811,16 +1764,13 @@ impl Editor { cx: &mut ViewContext, ) { 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 new_head = movement::next_word_boundary(&display_map, head).unwrap(); - let anchor = display_map.anchor_before(new_head, Bias::Left); - selection.set_head(buffer, anchor); - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::next_word_boundary(&display_map, head).unwrap(); + let cursor = new_head.to_buffer_point(&display_map, Bias::Left); + selection.set_head(cursor); + selection.goal = SelectionGoal::None; } self.update_selections(selections, true, cx); } @@ -1832,23 +1782,16 @@ impl Editor { ) { 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::next_word_boundary(&display_map, head).unwrap(), - Bias::Right, - ); - selection.set_head(&buffer, cursor); - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + if selection.is_empty() { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::next_word_boundary(&display_map, head).unwrap(); + let cursor = new_head.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); @@ -1860,17 +1803,15 @@ impl Editor { cx: &mut ViewContext, ) { 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 head = selection.head().to_display_point(&display_map, Bias::Left); - let new_head = movement::line_beginning(&display_map, head, true).unwrap(); - let anchor = display_map.anchor_before(new_head, Bias::Left); - selection.start = anchor.clone(); - selection.end = anchor; - selection.reversed = false; - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::line_beginning(&display_map, head, true).unwrap(); + let cursor = new_head.to_buffer_point(&display_map, Bias::Left); + selection.start = cursor; + selection.end = cursor; + selection.reversed = false; + selection.goal = SelectionGoal::None; } self.update_selections(selections, true, cx); } @@ -1881,17 +1822,12 @@ impl Editor { cx: &mut ViewContext, ) { 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 new_head = - movement::line_beginning(&display_map, head, *toggle_indent).unwrap(); - let anchor = display_map.anchor_before(new_head, Bias::Left); - selection.set_head(buffer, anchor); - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::line_beginning(&display_map, head, *toggle_indent).unwrap(); + selection.set_head(new_head.to_buffer_point(&display_map, Bias::Left)); + selection.goal = SelectionGoal::None; } self.update_selections(selections, true, cx); } @@ -1909,12 +1845,12 @@ impl Editor { pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections(cx).to_vec(); + let mut selections = self.point_selections(cx).collect::>(); { for selection in &mut selections { let head = selection.head().to_display_point(&display_map, Bias::Left); let new_head = movement::line_end(&display_map, head).unwrap(); - let anchor = display_map.anchor_before(new_head, Bias::Left); + let anchor = new_head.to_buffer_point(&display_map, Bias::Left); selection.start = anchor.clone(); selection.end = anchor; selection.reversed = false; @@ -1926,16 +1862,12 @@ impl Editor { pub fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext) { 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 new_head = movement::line_end(&display_map, head).unwrap(); - let anchor = display_map.anchor_before(new_head, Bias::Left); - selection.set_head(buffer, anchor); - selection.goal = SelectionGoal::None; - } + let mut selections = self.point_selections(cx).collect::>(); + for selection in &mut selections { + let head = selection.head().to_display_point(&display_map, Bias::Left); + let new_head = movement::line_end(&display_map, head).unwrap(); + selection.set_head(new_head.to_buffer_point(&display_map, Bias::Left)); + selection.goal = SelectionGoal::None; } self.update_selections(selections, true, cx); } @@ -1955,12 +1887,10 @@ impl Editor { } pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext) { - let buffer = self.buffer.read(cx); - let cursor = buffer.anchor_before(Point::new(0, 0)); let selection = Selection { id: post_inc(&mut self.next_selection_id), - start: cursor.clone(), - end: cursor, + start: 0, + end: 0, reversed: false, goal: SelectionGoal::None, }; @@ -1968,17 +1898,17 @@ impl Editor { } pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext) { - let mut selection = self.selections(cx).last().unwrap().clone(); - selection.set_head(self.buffer.read(cx), Anchor::min()); + let mut selection = self.point_selections(cx).last().unwrap().clone(); + selection.set_head(Point::zero()); self.update_selections(vec![selection], true, cx); } pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext) { let buffer = self.buffer.read(cx); - let cursor = buffer.anchor_before(buffer.max_point()); + let cursor = buffer.len(); let selection = Selection { id: post_inc(&mut self.next_selection_id), - start: cursor.clone(), + start: cursor, end: cursor, reversed: false, goal: SelectionGoal::None, @@ -1987,16 +1917,16 @@ impl Editor { } pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext) { - let mut selection = self.selections(cx).last().unwrap().clone(); - selection.set_head(self.buffer.read(cx), Anchor::max()); + let mut selection = self.offset_selections(cx).last().unwrap().clone(); + selection.set_head(self.buffer.read(cx).len()); self.update_selections(vec![selection], true, cx); } pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext) { let selection = Selection { id: post_inc(&mut self.next_selection_id), - start: Anchor::min(), - end: Anchor::max(), + start: 0, + end: self.buffer.read(cx).len(), reversed: false, goal: SelectionGoal::None, }; @@ -2005,13 +1935,13 @@ impl Editor { pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections(cx).to_vec(); + let mut selections = self.point_selections(cx).collect::>(); let buffer = self.buffer.read(cx); let max_point = buffer.max_point(); for selection in &mut selections { let rows = selection.spanned_rows(true, &display_map).buffer_rows; - selection.start = buffer.anchor_before(Point::new(rows.start, 0)); - selection.end = buffer.anchor_before(cmp::min(max_point, Point::new(rows.end, 0))); + selection.start = Point::new(rows.start, 0); + selection.end = cmp::min(max_point, Point::new(rows.end, 0)); selection.reversed = false; } self.update_selections(selections, true, cx); @@ -2022,27 +1952,26 @@ impl Editor { _: &SplitSelectionIntoLines, cx: &mut ViewContext, ) { - let selections = self.selections(cx); + let selections = self.point_selections(cx).collect::>(); let buffer = self.buffer.read(cx); let mut to_unfold = Vec::new(); let mut new_selections = Vec::new(); for selection in selections.iter() { - let range = selection.point_range(buffer).sorted(); - if range.start.row != range.end.row { + if selection.start.row != selection.end.row { new_selections.push(Selection { id: post_inc(&mut self.next_selection_id), - start: selection.start.clone(), - end: selection.start.clone(), + start: selection.start, + end: selection.start, reversed: false, goal: SelectionGoal::None, }); } - for row in range.start.row + 1..range.end.row { - let cursor = buffer.anchor_before(Point::new(row, buffer.line_len(row))); + for row in selection.start.row + 1..selection.end.row { + let cursor = Point::new(row, buffer.line_len(row)); new_selections.push(Selection { id: post_inc(&mut self.next_selection_id), - start: cursor.clone(), + start: cursor, end: cursor, reversed: false, goal: SelectionGoal::None, @@ -2050,12 +1979,12 @@ impl Editor { } new_selections.push(Selection { id: selection.id, - start: selection.end.clone(), - end: selection.end.clone(), + start: selection.end, + end: selection.end, reversed: false, goal: SelectionGoal::None, }); - to_unfold.push(range); + to_unfold.push(selection.start..selection.end); } self.unfold_ranges(to_unfold, cx); self.update_selections(new_selections, true, cx); @@ -2071,7 +2000,7 @@ impl Editor { fn add_selection(&mut self, above: bool, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections(cx).to_vec(); + let mut selections = self.point_selections(cx).collect::>(); let mut state = self.add_selections_state.take().unwrap_or_else(|| { let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); let range = oldest_selection.display_range(&display_map).sorted(); @@ -2167,42 +2096,42 @@ impl Editor { _: &SelectLargerSyntaxNode, cx: &mut ViewContext, ) { - let old_selections = self.selections(cx); + let old_selections = self.offset_selections(cx).collect::>(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); let mut selected_larger_node = false; - let mut new_selection_ranges = Vec::new(); - for selection in old_selections.iter() { - let old_range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer); - let mut new_range = old_range.clone(); - while let Some(containing_range) = buffer.range_for_syntax_ancestor(new_range.clone()) { - new_range = containing_range; - if !display_map.intersects_fold(new_range.start) - && !display_map.intersects_fold(new_range.end) + let mut new_selections = old_selections + .iter() + .map(|selection| { + let old_range = selection.start..selection.end; + let mut new_range = old_range.clone(); + while let Some(containing_range) = + buffer.range_for_syntax_ancestor(new_range.clone()) { - break; + new_range = containing_range; + if !display_map.intersects_fold(new_range.start) + && !display_map.intersects_fold(new_range.end) + { + break; + } } - } - selected_larger_node |= new_range != old_range; - new_selection_ranges.push((selection.id, new_range, selection.reversed)); - } + selected_larger_node |= new_range != old_range; + Selection { + id: selection.id, + start: new_range.start, + end: new_range.end, + goal: SelectionGoal::None, + reversed: selection.reversed, + } + }) + .collect::>(); if selected_larger_node { stack.push(old_selections); - new_selection_ranges.sort_unstable_by_key(|(_, range, _)| range.start.clone()); - let new_selections = new_selection_ranges - .into_iter() - .map(|(id, range, reversed)| Selection { - id, - start: buffer.anchor_before(range.start), - end: buffer.anchor_before(range.end), - reversed, - goal: SelectionGoal::None, - }) - .collect(); + new_selections.sort_unstable_by_key(|selection| selection.start); self.update_selections(new_selections, true, cx); } self.select_larger_syntax_node_stack = stack; @@ -2225,23 +2154,22 @@ impl Editor { _: &MoveToEnclosingBracket, cx: &mut ViewContext, ) { - let mut selections = self.selections(cx).to_vec(); + let mut selections = self.offset_selections(cx).collect::>(); let buffer = self.buffer.read(cx.as_ref()); for selection in &mut selections { - let selection_range = selection.offset_range(buffer); if let Some((open_range, close_range)) = - buffer.enclosing_bracket_ranges(selection_range.clone()) + buffer.enclosing_bracket_ranges(selection.start..selection.end) { let close_range = close_range.to_inclusive(); - let destination = if close_range.contains(&selection_range.start) - && close_range.contains(&selection_range.end) + let destination = if close_range.contains(&selection.start) + && close_range.contains(&selection.end) { open_range.end } else { *close_range.start() }; - selection.start = buffer.anchor_before(destination); - selection.end = selection.start.clone(); + selection.start = destination; + selection.end = destination; } } @@ -2262,8 +2190,8 @@ impl Editor { let end = DisplayPoint::new(row, cmp::min(columns.end, line_len)); Some(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), + start: start.to_buffer_point(display_map, Bias::Left), + end: end.to_buffer_point(display_map, Bias::Left), reversed, goal: SelectionGoal::ColumnRange { start: columns.start, @@ -2297,9 +2225,13 @@ impl Editor { ) -> impl 'a + Iterator> { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); - let selections = &buffer.selection_set(set_id).unwrap().selections; - let start = display_map.anchor_before(range.start, Bias::Left); - let start_index = self.selection_insertion_index(selections, &start, cx); + let selections = buffer + .selection_set(set_id) + .unwrap() + .point_selections(buffer) + .collect::>(); + let start = range.start.to_buffer_point(&display_map, Bias::Left); + let start_index = self.selection_insertion_index(&selections, start); let pending_selection = if set_id.replica_id == self.buffer.read(cx).replica_id() { self.pending_selection.as_ref().and_then(|s| { let selection_range = s.display_range(&display_map); @@ -2312,20 +2244,15 @@ impl Editor { } else { None }; - selections[start_index..] - .iter() + selections + .into_iter() + .skip(start_index) .map(move |s| s.display_range(&display_map)) .take_while(move |r| r.start <= range.end || r.end <= range.end) .chain(pending_selection) } - fn selection_insertion_index( - &self, - selections: &[Selection], - start: Point, - cx: &AppContext, - ) -> usize { - let buffer = self.buffer.read(cx); + fn selection_insertion_index(&self, selections: &[Selection], start: Point) -> usize { match selections.binary_search_by_key(&start, |probe| probe.start) { Ok(index) => index, Err(index) => { @@ -2368,27 +2295,24 @@ impl Editor { buffer.selection_set(self.selection_set_id).unwrap().len() } - fn update_selections( + fn update_selections( &mut self, mut selections: Vec>, autoscroll: bool, cx: &mut ViewContext, - ) { + ) where + T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug, + { // Merge overlapping selections. let buffer = self.buffer.read(cx); let mut i = 1; while i < selections.len() { - if selections[i - 1] - .end - .cmp(&selections[i].start, buffer) - .unwrap() - >= Ordering::Equal - { + if selections[i - 1].end >= selections[i].start { let removed = selections.remove(i); - if removed.start.cmp(&selections[i - 1].start, buffer).unwrap() < Ordering::Equal { + if removed.start < selections[i - 1].start { selections[i - 1].start = removed.start; } - if removed.end.cmp(&selections[i - 1].end, buffer).unwrap() > Ordering::Equal { + if removed.end > selections[i - 1].end { selections[i - 1].end = removed.end; } } else { @@ -2401,13 +2325,13 @@ impl Editor { while let Some(autoclose_pair_state) = self.autoclose_stack.last() { let all_selections_inside_autoclose_ranges = if selections.len() == autoclose_pair_state.ranges.len() { - selections.iter().zip(&autoclose_pair_state.ranges).all( - |(selection, autoclose_range)| { - let head = selection.head(); - autoclose_range.start.cmp(head, buffer).unwrap() <= Ordering::Equal - && autoclose_range.end.cmp(head, buffer).unwrap() >= Ordering::Equal - }, - ) + selections + .iter() + .zip(autoclose_pair_state.ranges.to_point_ranges(buffer)) + .all(|(selection, autoclose_range)| { + let head = selection.head().to_point(&*buffer); + autoclose_range.start <= head && autoclose_range.end >= head + }) } else { false }; @@ -2428,7 +2352,7 @@ impl Editor { self.buffer.update(cx, |buffer, cx| { buffer - .update_selection_set(self.selection_set_id, selections, cx) + .update_selection_set(self.selection_set_id, &selections, cx) .unwrap(); }); } @@ -2460,9 +2384,9 @@ impl Editor { pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext) { let mut fold_ranges = Vec::new(); - let selections = self.selections(cx); + let selections = self.point_selections(cx).collect::>(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - for selection in selections.iter() { + for selection in selections { let range = selection.display_range(&display_map).sorted(); let buffer_start_row = range.start.to_buffer_point(&display_map, Bias::Left).row; @@ -2483,7 +2407,7 @@ impl Editor { } pub fn unfold(&mut self, _: &Unfold, cx: &mut ViewContext) { - let selections = self.selections(cx); + let selections = self.point_selections(cx).collect::>(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let ranges = selections @@ -2544,12 +2468,8 @@ impl Editor { } pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext) { - let selections = self.selections(cx); - let buffer = self.buffer.read(cx); - let ranges = selections - .iter() - .map(|s| s.point_range(buffer).sorted()) - .collect(); + let selections = self.point_selections(cx); + let ranges = selections.map(|s| s.start..s.end).collect(); self.fold_ranges(ranges, cx); } @@ -2755,12 +2675,12 @@ impl EditorSettings { .select_font(font_family_id, &font_properties) .unwrap(); EditorStyle { - text: TextStyle { + text: gpui::fonts::TextStyle { font_family_name, font_family_id, font_id, font_size: 14., - color: Color::from_u32(0xff0000ff), + color: gpui::color::Color::from_u32(0xff0000ff), font_properties, underline: false, }, @@ -2862,7 +2782,7 @@ impl View for Editor { } } -impl SelectionExt for Selection { +impl SelectionExt for Selection { fn display_range(&self, map: &DisplayMapSnapshot) -> Range { let start = self.start.to_display_point(map, Bias::Left); let end = self.end.to_display_point(map, Bias::Left); From f3cd710f216b1aa4db98c8d587fa18df472207c4 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 28 Oct 2021 16:04:16 -0700 Subject: [PATCH 10/14] Create valid disjoint selection sets in selections_in_ranges --- crates/buffer/src/lib.rs | 37 ++++++++++++++++++---------------- crates/project/src/worktree.rs | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index ffee9d5736..47e40800ed 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -1487,25 +1487,28 @@ impl Buffer { let mut ranges = ranges.into_iter().collect::>(); ranges.sort_unstable_by_key(|range| range.start); - let mut selections = Vec::with_capacity(ranges.len()); - for range in ranges { + let mut selections = Vec::>::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: range.end, - end: range.start, - reversed: true, - goal: SelectionGoal::None, - }); - } else { - selections.push(Selection { - id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), - start: range.start, - end: 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) } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index f763a57699..61e4dfc9a4 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -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"; From 9bc08e446bb6cee0f37ab28afe449d49bc2aa649 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 28 Oct 2021 16:17:07 -0700 Subject: [PATCH 11/14] Fix unit test for on-disk-changes to not rely on selection bias --- crates/language/src/lib.rs | 5 ++++- crates/project/src/worktree.rs | 15 ++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/crates/language/src/lib.rs b/crates/language/src/lib.rs index 8d0f06a648..6142b506b5 100644 --- a/crates/language/src/lib.rs +++ b/crates/language/src/lib.rs @@ -638,7 +638,10 @@ impl Buffer { if selection.start.column == 0 { let delta = Point::new( 0, - indent_columns.get(&selection.start.row).copied().unwrap_or(0), + indent_columns + .get(&selection.start.row) + .copied() + .unwrap_or(0), ); if delta.column > 0 { return Selection { diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 61e4dfc9a4..8ad4583b34 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -3348,15 +3348,15 @@ 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| Selection { id: row as usize, - start: Point::new(row, 0), - end: Point::new(row, 0), + start: Point::new(row, 1), + end: Point::new(row, 1), reversed: false, goal: SelectionGoal::None, }) @@ -3378,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, _| { @@ -3386,8 +3386,9 @@ mod tests { assert!(!buffer.is_dirty()); assert!(!buffer.has_conflict()); - let set = buffer.selection_set(selection_set_id).unwrap(); - let cursor_positions = set + let cursor_positions = buffer + .selection_set(selection_set_id) + .unwrap() .point_selections(&*buffer) .map(|selection| { assert_eq!(selection.start, selection.end); @@ -3396,7 +3397,7 @@ mod tests { .collect::>(); 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)] ); }); From a1e576343e30f840c2ce04204eec04d6292bddb4 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 28 Oct 2021 16:32:49 -0700 Subject: [PATCH 12/14] Rename AnchorRangeSet::to_point_ranges -> point_ranges --- crates/buffer/src/anchor.rs | 4 ++-- crates/editor/src/lib.rs | 4 ++-- crates/language/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index 4a420de21f..d978b76050 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -200,14 +200,14 @@ impl AnchorRangeSet { self.0.len() } - pub fn to_offset_ranges<'a>( + pub fn offset_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator> + 'a { self.0.offset_ranges(content).map(|(range, _)| range) } - pub fn to_point_ranges<'a>( + pub fn point_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator> + 'a { diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 50f446c5e8..1030cab758 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -985,7 +985,7 @@ impl Editor { let buffer = self.buffer.read(cx); if old_selections .iter() - .zip(autoclose_pair_state.ranges.to_offset_ranges(buffer)) + .zip(autoclose_pair_state.ranges.offset_ranges(buffer)) .all(|(selection, autoclose_range)| { let autoclose_range_end = autoclose_range.end.to_offset(buffer); selection.is_empty() && selection.start == autoclose_range_end @@ -2327,7 +2327,7 @@ impl Editor { if selections.len() == autoclose_pair_state.ranges.len() { selections .iter() - .zip(autoclose_pair_state.ranges.to_point_ranges(buffer)) + .zip(autoclose_pair_state.ranges.point_ranges(buffer)) .all(|(selection, autoclose_range)| { let head = selection.head().to_point(&*buffer); autoclose_range.start <= head && autoclose_range.end >= head diff --git a/crates/language/src/lib.rs b/crates/language/src/lib.rs index 6142b506b5..c86fca62b4 100644 --- a/crates/language/src/lib.rs +++ b/crates/language/src/lib.rs @@ -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, ); From acb29eb27398a367562478ad5aa52c19b5aa50d0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 28 Oct 2021 16:32:56 -0700 Subject: [PATCH 13/14] Ignore vendor/bin folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d096dc01da..379d197a5c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /script/node_modules /server/.env.toml /server/static/styles.css +/vendor/bin From 2952f2c905e17273c9fbde42bb626d0b3d62965f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 28 Oct 2021 16:48:07 -0700 Subject: [PATCH 14/14] :art: anchor.rs --- crates/buffer/src/anchor.rs | 52 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index d978b76050..2500e27e2b 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -1,6 +1,4 @@ -use crate::Point; - -use super::{Buffer, Content}; +use super::{Buffer, Content, Point}; use anyhow::Result; use std::{ cmp::Ordering, @@ -87,6 +85,14 @@ impl Anchor { } impl AnchorMap { + 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> + 'a, @@ -106,29 +112,41 @@ impl AnchorMap { .summaries_for_anchors(self) .map(move |(sum, value)| (sum.lines, value)) } - - pub fn version(&self) -> &clock::Global { - &self.version - } } impl AnchorSet { + pub fn version(&self) -> &clock::Global { + &self.0.version + } + + pub fn len(&self) -> usize { + self.0.len() + } + pub fn offsets<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { - self.0.offsets(content).map(move |(offset, _)| offset) + self.0.offsets(content).map(|(offset, _)| offset) } pub fn points<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { - self.0.points(content).map(move |(point, _)| point) + self.0.points(content).map(|(point, _)| point) } } impl AnchorRangeMap { + 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 } } @@ -137,10 +155,6 @@ impl AnchorRangeMap { &self.entries } - pub fn len(&self) -> usize { - self.entries.len() - } - pub fn point_ranges<'a>( &'a self, content: impl Into> + 'a, @@ -160,10 +174,6 @@ impl AnchorRangeMap { .summaries_for_anchor_ranges(self) .map(move |(range, value)| ((range.start.bytes..range.end.bytes), value)) } - - pub fn version(&self) -> &clock::Global { - &self.version - } } impl PartialEq for AnchorRangeMap { @@ -200,6 +210,10 @@ impl AnchorRangeSet { self.0.len() } + pub fn version(&self) -> &clock::Global { + self.0.version() + } + pub fn offset_ranges<'a>( &'a self, content: impl Into> + 'a, @@ -213,10 +227,6 @@ impl AnchorRangeSet { ) -> impl Iterator> + 'a { self.0.point_ranges(content).map(|(range, _)| range) } - - pub fn version(&self) -> &clock::Global { - self.0.version() - } } pub trait AnchorRangeExt {