diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index c1789a933b..b4f01909bf 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -1,8 +1,10 @@ -use crate::FullOffset; - -use super::{Buffer, Content, FromAnchor, Point, ToOffset}; +use super::{Buffer, Content, FromAnchor, FullOffset, Point, ToOffset}; use anyhow::Result; -use std::{cmp::Ordering, ops::Range}; +use std::{ + cmp::Ordering, + fmt::{Debug, Formatter}, + ops::Range, +}; use sum_tree::{Bias, SumTree}; #[derive(Clone, Eq, PartialEq, Debug, Hash)] @@ -112,7 +114,25 @@ impl Anchor { } impl AnchorMap { - pub fn to_points<'a>( + pub fn version(&self) -> &clock::Global { + &self.version + } + + pub fn len(&self) -> usize { + self.entries.len() + } + + pub fn offsets<'a>( + &'a self, + content: impl Into> + '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, ) -> impl Iterator + 'a { @@ -121,23 +141,50 @@ 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 to_points<'a>( + 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(|(offset, _)| offset) + } + + 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(|(point, _)| point) } } impl AnchorRangeMap { - pub fn to_point_ranges<'a>( + pub fn version(&self) -> &clock::Global { + &self.version + } + + pub fn len(&self) -> usize { + self.entries.len() + } + + pub fn from_raw(version: clock::Global, entries: Vec<(Range<(FullOffset, Bias)>, T)>) -> Self { + Self { version, entries } + } + + pub fn raw_entries(&self) -> &[(Range<(FullOffset, Bias)>, T)] { + &self.entries + } + + pub fn point_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator, &'a T)> + 'a { @@ -147,22 +194,68 @@ impl AnchorRangeMap { .map(move |(range, value)| ((range.start.lines..range.end.lines), value)) } - pub fn version(&self) -> &clock::Global { - &self.version + pub fn offset_ranges<'a>( + &'a self, + content: impl Into> + '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)) + } +} + +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 mut f = f.debug_map(); + for (range, value) in &self.entries { + f.key(range); + f.value(value); + } + f.finish() + } +} + +impl Debug for AnchorRangeSet { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut f = f.debug_set(); + for (range, _) in &self.0.entries { + f.entry(range); + } + f.finish() } } impl AnchorRangeSet { - pub fn to_point_ranges<'a>( - &'a self, - content: impl Into> + 'a, - ) -> impl Iterator> + 'a { - self.0.to_point_ranges(content).map(|(range, _)| range) + pub fn len(&self) -> usize { + self.0.len() } pub fn version(&self) -> &clock::Global { self.0.version() } + + pub fn offset_ranges<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl Iterator> + 'a { + self.0.offset_ranges(content).map(|(range, _)| range) + } + + pub fn point_ranges<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl Iterator> + 'a { + self.0.point_ranges(content).map(|(range, _)| range) + } } impl Default for AnchorRangeMultimap { diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 2fbd050bc8..a8d4981ed7 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::{self, Reverse}, - convert::{TryFrom, TryInto}, + convert::TryFrom, iter::Iterator, ops::{self, Range}, str, @@ -73,20 +73,14 @@ pub struct Buffer { lamport_clock: clock::Lamport, } -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SelectionSet { - pub selections: Arc<[Selection]>, - pub active: bool, -} - #[derive(Clone, Debug)] pub struct Transaction { start: clock::Global, end: clock::Global, edits: Vec, ranges: Vec>, - selections_before: HashMap>, - selections_after: HashMap>, + selections_before: HashMap>>, + selections_after: HashMap>>, first_edit_at: Instant, last_edit_at: Instant, } @@ -173,7 +167,7 @@ impl History { fn start_transaction( &mut self, start: clock::Global, - selections_before: HashMap>, + selections_before: HashMap>>, now: Instant, ) { self.transaction_depth += 1; @@ -193,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); @@ -415,7 +409,11 @@ pub enum Operation { }, UpdateSelections { set_id: SelectionSetId, - selections: Option>, + selections: Arc>, + lamport_timestamp: clock::Lamport, + }, + RemoveSelections { + set_id: SelectionSetId, lamport_timestamp: clock::Lamport, }, SetActiveSelections { @@ -489,20 +487,8 @@ impl Buffer { .selections .into_iter() .map(|set| { - let set_id = clock::Lamport { - replica_id: set.replica_id as ReplicaId, - value: set.local_timestamp, - }; - let selections: Vec = 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) @@ -514,16 +500,7 @@ impl Buffer { id: self.remote_id, content: self.history.base_text.to_string(), history: ops, - selections: self - .selections - .iter() - .map(|(set_id, set)| proto::SelectionSetSnapshot { - replica_id: set_id.replica_id as u32, - local_timestamp: set_id.value, - selections: set.selections.iter().map(Into::into).collect(), - is_active: set.active, - }) - .collect(), + selections: self.selections.iter().map(|(_, set)| set.into()).collect(), } } @@ -565,6 +542,13 @@ impl Buffer { self.content().anchor_at(position, bias) } + pub fn anchor_range_set(&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) } @@ -858,23 +842,27 @@ impl Buffer { selections, lamport_timestamp, } => { - if let Some(selections) = selections { - if let Some(set) = self.selections.get_mut(&set_id) { - set.selections = selections; - } else { - self.selections.insert( - set_id, - SelectionSet { - selections, - active: false, - }, - ); - } + if let Some(set) = self.selections.get_mut(&set_id) { + set.selections = selections; } else { - self.selections.remove(&set_id); + self.selections.insert( + set_id, + SelectionSet { + id: set_id, + selections, + active: false, + }, + ); } self.lamport_clock.observe(lamport_timestamp); } + Operation::RemoveSelections { + set_id, + lamport_timestamp, + } => { + self.selections.remove(&set_id); + self.lamport_clock.observe(lamport_timestamp); + } Operation::SetActiveSelections { set_id, lamport_timestamp, @@ -1142,16 +1130,9 @@ impl Buffer { Operation::Edit(edit) => self.version >= edit.version, Operation::Undo { undo, .. } => self.version >= undo.version, Operation::UpdateSelections { selections, .. } => { - if let Some(selections) = selections { - selections.iter().all(|selection| { - let contains_start = self.version >= selection.start.version; - let contains_end = self.version >= selection.end.version; - contains_start && contains_end - }) - } else { - true - } + self.version >= *selections.version() } + Operation::RemoveSelections { .. } => true, Operation::SetActiveSelections { set_id, .. } => { set_id.map_or(true, |set_id| self.selections.contains_key(&set_id)) } @@ -1232,7 +1213,7 @@ impl Buffer { let selections = transaction.selections_before.clone(); ops.push(self.undo_or_redo(transaction).unwrap()); for (set_id, selections) in selections { - ops.extend(self.update_selection_set(set_id, selections)); + ops.extend(self.restore_selection_set(set_id, selections)); } } ops @@ -1244,7 +1225,7 @@ impl Buffer { let selections = transaction.selections_after.clone(); ops.push(self.undo_or_redo(transaction).unwrap()); for (set_id, selections) in selections { - ops.extend(self.update_selection_set(set_id, selections)); + ops.extend(self.restore_selection_set(set_id, selections)); } } ops @@ -1281,12 +1262,32 @@ impl Buffer { self.selections.iter() } - pub fn update_selection_set( + fn build_selection_anchor_range_map( + &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: impl Into>, + selections: &[Selection], ) -> Result { - let selections = selections.into(); + let selections = self.build_selection_anchor_range_map(selections); let set = self .selections .get_mut(&set_id) @@ -1294,25 +1295,43 @@ impl Buffer { set.selections = selections.clone(); Ok(Operation::UpdateSelections { set_id, - selections: Some(selections), + selections, lamport_timestamp: self.lamport_clock.tick(), }) } - pub fn add_selection_set(&mut self, selections: impl Into>) -> Operation { - let selections = selections.into(); - let lamport_timestamp = self.lamport_clock.tick(); + 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( - lamport_timestamp, + set_id, SelectionSet { + id: set_id, selections: selections.clone(), active: false, }, ); Operation::UpdateSelections { - set_id: lamport_timestamp, - selections: Some(selections), - lamport_timestamp, + set_id, + selections, + lamport_timestamp: set_id, } } @@ -1344,9 +1363,8 @@ impl Buffer { self.selections .remove(&set_id) .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - Ok(Operation::UpdateSelections { + Ok(Operation::RemoveSelections { set_id, - selections: None, lamport_timestamp: self.lamport_clock.tick(), }) } @@ -1419,9 +1437,9 @@ impl Buffer { let new_selections = self.selections_from_ranges(ranges).unwrap(); let op = if set_id.is_none() || rng.gen_bool(1.0 / 5.0) { - self.add_selection_set(new_selections) + self.add_selection_set(&new_selections) } else { - self.update_selection_set(*set_id.unwrap(), new_selections) + self.update_selection_set(*set_id.unwrap(), &new_selections) .unwrap() }; ops.push(op); @@ -1447,7 +1465,7 @@ impl Buffer { ops } - fn selections_from_ranges(&self, ranges: I) -> Result> + fn selections_from_ranges(&self, ranges: I) -> Result>> where I: IntoIterator>, { @@ -1458,25 +1476,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: self.anchor_before(range.end), - end: self.anchor_before(range.start), - reversed: true, - goal: SelectionGoal::None, - }); - } else { - selections.push(Selection { - id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), - start: self.anchor_after(range.start), - end: self.anchor_before(range.end), - reversed: false, - goal: SelectionGoal::None, - }); + reversed = true; + std::mem::swap(&mut range.start, &mut range.end); } + + if let Some(selection) = selections.last_mut() { + if selection.end >= range.start { + selection.end = range.end; + continue; + } + } + + selections.push(Selection { + id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), + start: range.start, + end: range.end, + reversed, + goal: SelectionGoal::None, + }); } Ok(selections) } @@ -1484,15 +1505,12 @@ impl Buffer { pub fn selection_ranges<'a>(&'a self, set_id: SelectionSetId) -> Result>> { Ok(self .selection_set(set_id)? - .selections - .iter() + .offset_selections(self) .map(move |selection| { - let start = selection.start.to_offset(self); - let end = selection.end.to_offset(self); if selection.reversed { - end..start + selection.end..selection.start } else { - start..end + selection.start..selection.end } }) .collect()) @@ -2259,6 +2277,9 @@ impl Operation { Operation::UpdateSelections { lamport_timestamp, .. } => *lamport_timestamp, + Operation::RemoveSelections { + lamport_timestamp, .. + } => *lamport_timestamp, Operation::SetActiveSelections { lamport_timestamp, .. } => *lamport_timestamp, @@ -2315,9 +2336,27 @@ impl<'a> Into for &'a Operation { replica_id: set_id.replica_id as u32, local_timestamp: set_id.value, lamport_timestamp: lamport_timestamp.value, - set: selections.as_ref().map(|selections| proto::SelectionSet { - selections: selections.iter().map(Into::into).collect(), - }), + version: selections.version().into(), + selections: selections + .raw_entries() + .iter() + .map(|(range, state)| proto::Selection { + id: state.id as u64, + start: range.start.0.to_proto(), + end: range.end.0.to_proto(), + reversed: state.reversed, + }) + .collect(), + }, + ), + Operation::RemoveSelections { + set_id, + lamport_timestamp, + } => proto::operation::Variant::RemoveSelections( + proto::operation::RemoveSelections { + replica_id: set_id.replica_id as u32, + local_timestamp: set_id.value, + lamport_timestamp: lamport_timestamp.value, }, ), Operation::SetActiveSelections { @@ -2358,30 +2397,6 @@ impl<'a> Into for &'a EditOperation { } } -impl<'a> Into for &'a Anchor { - fn into(self) -> proto::Anchor { - proto::Anchor { - version: (&self.version).into(), - offset: self.full_offset.to_proto(), - bias: match self.bias { - Bias::Left => proto::anchor::Bias::Left as i32, - Bias::Right => proto::anchor::Bias::Right as i32, - }, - } - } -} - -impl<'a> Into 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; @@ -2424,16 +2439,23 @@ 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 version = message.version.into(); + let entries = message + .selections + .iter() + .map(|selection| { + let range = (FullOffset::from_proto(selection.start), Bias::Left) + ..(FullOffset::from_proto(selection.end), Bias::Right); + let state = SelectionState { + id: selection.id as usize, + reversed: selection.reversed, + goal: SelectionGoal::None, + }; + (range, state) + }) + .collect(); + let selections = AnchorRangeMap::from_raw(version, entries); + Operation::UpdateSelections { set_id: clock::Lamport { replica_id: message.replica_id as ReplicaId, @@ -2443,7 +2465,19 @@ impl TryFrom for Operation { replica_id: message.replica_id as ReplicaId, value: message.lamport_timestamp, }, - selections: selections.map(Arc::from), + selections: Arc::from(selections), + } + } + proto::operation::Variant::RemoveSelections(message) => { + Operation::RemoveSelections { + set_id: clock::Lamport { + replica_id: message.replica_id as ReplicaId, + value: message.local_timestamp, + }, + lamport_timestamp: clock::Lamport { + replica_id: message.replica_id as ReplicaId, + value: message.lamport_timestamp, + }, } } proto::operation::Variant::SetActiveSelections(message) => { @@ -2483,52 +2517,6 @@ impl From 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 { - full_offset: FullOffset::from_proto(message.offset), - bias: if message.bias == proto::anchor::Bias::Left as i32 { - Bias::Left - } else if message.bias == proto::anchor::Bias::Right as i32 { - Bias::Right - } else { - Err(anyhow!("invalid anchor bias {}", message.bias))? - }, - version, - }) - } -} - -impl TryFrom 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; @@ -2582,6 +2570,12 @@ impl ToPoint for usize { } } +impl ToPoint for Point { + fn to_point<'a>(&self, _: impl Into>) -> Point { + *self + } +} + pub trait FromAnchor { fn from_anchor<'a>(anchor: &Anchor, content: &Content<'a>) -> Self; } diff --git a/crates/buffer/src/selection.rs b/crates/buffer/src/selection.rs index 98f34865f5..3dc84f6647 100644 --- a/crates/buffer/src/selection.rs +++ b/crates/buffer/src/selection.rs @@ -1,5 +1,7 @@ -use crate::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _}; -use std::{cmp::Ordering, mem, ops::Range}; +use super::{AnchorRangeMap, Buffer, Content, FullOffset, Point, ToOffset, ToPoint}; +use rpc::proto; +use std::{cmp::Ordering, ops::Range, sync::Arc}; +use sum_tree::Bias; pub type SelectionSetId = clock::Lamport; pub type SelectionsVersion = usize; @@ -12,44 +14,62 @@ pub enum SelectionGoal { } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Selection { +pub struct Selection { pub id: usize, - pub start: Anchor, - pub end: Anchor, + pub start: T, + pub end: T, pub reversed: bool, pub goal: SelectionGoal, } -impl Selection { - pub fn head(&self) -> &Anchor { +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SelectionSet { + pub id: SelectionSetId, + pub active: bool, + pub selections: Arc>, +} + +#[derive(Debug, Eq, PartialEq)] +pub struct SelectionState { + pub id: usize, + pub reversed: bool, + pub goal: SelectionGoal, +} + +impl Selection { + pub fn is_empty(&self) -> bool { + self.start == self.end + } + + pub fn head(&self) -> T { if self.reversed { - &self.start + self.start } else { - &self.end + self.end } } - pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) { - if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal { + pub fn set_head(&mut self, head: T) { + if head.cmp(&self.tail()) < Ordering::Equal { if !self.reversed { - mem::swap(&mut self.start, &mut self.end); + self.end = self.start; self.reversed = true; } - self.start = cursor; + self.start = head; } else { if self.reversed { - mem::swap(&mut self.start, &mut self.end); + self.start = self.end; self.reversed = false; } - self.end = cursor; + self.end = head; } } - pub fn tail(&self) -> &Anchor { + pub fn tail(&self) -> T { if self.reversed { - &self.end + self.end } else { - &self.start + self.start } } @@ -73,3 +93,89 @@ impl Selection { } } } + +impl SelectionSet { + pub fn len(&self) -> usize { + self.selections.len() + } + + pub fn offset_selections<'a>( + &'a self, + content: impl Into> + '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(); + let entries = self.selections.raw_entries(); + proto::SelectionSet { + replica_id: self.id.replica_id as u32, + lamport_timestamp: self.id.value as u32, + is_active: self.active, + version: version.into(), + selections: entries + .iter() + .map(|(range, state)| proto::Selection { + id: state.id as u64, + start: range.start.0.to_proto(), + end: range.end.0.to_proto(), + reversed: state.reversed, + }) + .collect(), + } + } +} + +impl From for SelectionSet { + fn from(set: proto::SelectionSet) -> Self { + Self { + id: clock::Lamport { + replica_id: set.replica_id as u16, + value: set.lamport_timestamp, + }, + active: set.is_active, + selections: Arc::new(AnchorRangeMap::from_raw( + set.version.into(), + set.selections + .into_iter() + .map(|selection| { + let range = (FullOffset::from_proto(selection.start), Bias::Left) + ..(FullOffset::from_proto(selection.end), Bias::Right); + let state = SelectionState { + id: selection.id as usize, + reversed: selection.reversed, + goal: SelectionGoal::None, + }; + (range, state) + }) + .collect(), + )), + } + } +} 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"); 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/editor/src/lib.rs b/crates/editor/src/lib.rs index fc28e04729..d41fbf81cb 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, @@ -293,11 +292,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, @@ -324,8 +323,9 @@ struct AddSelectionsState { stack: Vec, } +#[derive(Debug)] 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 mut selections = self.point_selections(cx).peekable(); let first_cursor_top = selections - .first() + .peek() .unwrap() .head() .to_display_point(&display_map, Bias::Left) @@ -563,11 +563,11 @@ impl Editor { layouts: &[text_layout::Line], cx: &mut ViewContext, ) -> 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); @@ -641,10 +641,9 @@ 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 = display_map.anchor_before(position, Bias::Left); + let cursor = position.to_buffer_point(&display_map, Bias::Left); if let Some(selection) = self.pending_selection.as_mut() { - selection.set_head(buffer, cursor); + selection.set_head(cursor); } else { log::error!("update_selection dispatched with no pending selection"); return; @@ -656,8 +655,8 @@ impl Editor { fn end_selection(&mut self, cx: &mut ViewContext) { 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); selections.insert(ix, selection); self.update_selections(selections, false, cx); } @@ -669,14 +668,14 @@ impl Editor { pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { if let Some(pending_selection) = self.pending_selection.take() { - let selections = self.selections(cx); - if selections.is_empty() { + if self.point_selections(cx).next().is_none() { self.update_selections(vec![pending_selection], true, cx); } } else { - let selections = self.selections(cx); - let mut oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); - if selections.len() == 1 { + let selection_count = self.selection_count(cx); + let selections = self.point_selections(cx); + let mut oldest_selection = selections.min_by_key(|s| s.id).unwrap().clone(); + if selection_count == 1 { oldest_selection.start = oldest_selection.head().clone(); oldest_selection.end = oldest_selection.head().clone(); } @@ -690,24 +689,26 @@ impl Editor { T: ToOffset, { let buffer = self.buffer.read(cx); - let mut selections = Vec::new(); - for range in ranges { - let mut start = range.start.to_offset(buffer); - let mut end = range.end.to_offset(buffer); - let reversed = if start > end { - mem::swap(&mut start, &mut end); - true - } else { - false - }; - selections.push(Selection { - id: post_inc(&mut self.next_selection_id), - start: buffer.anchor_before(start), - end: buffer.anchor_before(end), - reversed, - goal: SelectionGoal::None, - }); - } + let selections = ranges + .into_iter() + .map(|range| { + let mut start = range.start.to_offset(buffer); + let mut end = range.end.to_offset(buffer); + let reversed = if start > end { + mem::swap(&mut start, &mut end); + true + } else { + false + }; + Selection { + id: post_inc(&mut self.next_selection_id), + start: start, + end: end, + reversed, + goal: SelectionGoal::None, + } + }) + .collect(); self.update_selections(selections, autoscroll, cx); } @@ -720,26 +721,27 @@ impl Editor { where T: IntoIterator>, { - let mut selections = Vec::new(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - for range in ranges { - let mut start = range.start; - let mut end = range.end; - let reversed = if start > end { - mem::swap(&mut start, &mut end); - true - } else { - false - }; - - selections.push(Selection { - id: post_inc(&mut self.next_selection_id), - start: display_map.anchor_before(start, Bias::Left), - end: display_map.anchor_before(end, Bias::Left), - reversed, - goal: SelectionGoal::None, - }); - } + let selections = ranges + .into_iter() + .map(|range| { + let mut start = range.start; + let mut end = range.end; + let reversed = if start > end { + mem::swap(&mut start, &mut end); + true + } else { + false + }; + Selection { + id: post_inc(&mut self.next_selection_id), + start: start.to_buffer_point(&display_map, Bias::Left), + end: end.to_buffer_point(&display_map, Bias::Left), + reversed, + goal: SelectionGoal::None, + } + }) + .collect(); self.update_selections(selections, false, cx); Ok(()) } @@ -758,10 +760,10 @@ impl Editor { self.start_transaction(cx); let mut old_selections = SmallVec::<[_; 32]>::new(); { - let selections = self.selections(cx); + let selections = self.point_selections(cx).collect::>(); let buffer = self.buffer.read(cx); for selection in selections.iter() { - let start_point = selection.start.to_point(buffer); + let start_point = selection.start; let indent = buffer .indent_column_for_line(start_point.row) .min(start_point.column); @@ -848,7 +850,7 @@ impl Editor { let start = (range.start as isize + delta) as usize; let end = (range.end as isize + delta) as usize; let text_before_cursor_len = indent as usize + 1; - let anchor = buffer.anchor_before(start + text_before_cursor_len); + let cursor = start + text_before_cursor_len; let text_len = if insert_extra_newline { text_before_cursor_len * 2 } else { @@ -857,8 +859,8 @@ impl Editor { delta += text_len as isize - (end - start) as isize; Selection { id, - start: anchor.clone(), - end: anchor, + start: cursor, + end: cursor, reversed: false, goal: SelectionGoal::None, } @@ -880,35 +882,25 @@ impl Editor { fn insert(&mut self, text: &str, cx: &mut ViewContext) { self.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 +913,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 +925,8 @@ impl Editor { }); pair.and_then(|pair| { let should_autoclose = selections[1..].iter().all(|selection| { - let selection_start = selection.start.to_offset(&*buffer); buffer.contains_str_at( - selection_start.saturating_sub(pair.start.len()), + selection.start.saturating_sub(pair.start.len()), &pair.start, ) }); @@ -960,14 +951,13 @@ impl Editor { buffer.edit(selection_ranges, &pair.end, cx); if pair.end.len() == 1 { + let mut delta = 0; Some(BracketPairState { - ranges: selections - .iter() - .map(|selection| { - selection.start.bias_left(buffer) - ..selection.start.bias_right(buffer) - }) - .collect(), + ranges: buffer.anchor_range_set(selections.iter().map(move |selection| { + let offset = selection.start + delta; + delta += 1; + (offset, Bias::Left)..(offset, Bias::Right) + })), pair, }) } else { @@ -979,7 +969,8 @@ impl Editor { } fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext) -> bool { - let old_selections = self.selections(cx); + let old_selection_count = self.selection_count(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 { @@ -989,29 +980,25 @@ impl Editor { return false; } - debug_assert_eq!(old_selections.len(), autoclose_pair_state.ranges.len()); + debug_assert_eq!(old_selection_count, autoclose_pair_state.ranges.len()); let buffer = self.buffer.read(cx); - let old_selection_ranges: SmallVec<[_; 32]> = old_selections + if old_selections .iter() - .map(|selection| (selection.id, selection.offset_range(buffer))) - .collect(); - if old_selection_ranges - .iter() - .zip(&autoclose_pair_state.ranges) - .all(|((_, selection_range), autoclose_range)| { + .zip(autoclose_pair_state.ranges.offset_ranges(buffer)) + .all(|(selection, autoclose_range)| { let autoclose_range_end = autoclose_range.end.to_offset(buffer); - selection_range.is_empty() && selection_range.start == autoclose_range_end + selection.is_empty() && selection.start == autoclose_range_end }) { - let new_selections = old_selection_ranges + let new_selections = old_selections .into_iter() - .map(|(id, range)| { - let new_head = buffer.anchor_before(range.start + 1); + .map(|selection| { + let cursor = selection.start + 1; Selection { - id, - start: new_head.clone(), - end: new_head, + id: selection.id, + start: cursor, + end: cursor, reversed: false, goal: SelectionGoal::None, } @@ -1034,22 +1021,18 @@ impl Editor { pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext) { self.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); @@ -1058,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); @@ -1081,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); @@ -1126,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; @@ -1159,7 +1134,7 @@ impl Editor { // If there's a line after the range, delete the \n from the end of the row range // and position the cursor on the next line. edit_end = Point::new(rows.end, 0).to_offset(buffer); - cursor_buffer_row = rows.end; + cursor_buffer_row = rows.start; } else { // If there isn't a line after the range, delete the \n from the line before the // start of the row range and position the cursor there. @@ -1168,10 +1143,11 @@ impl Editor { cursor_buffer_row = rows.start.saturating_sub(1); } - let mut cursor = - Point::new(cursor_buffer_row, 0).to_display_point(&display_map, Bias::Left); + let mut cursor = Point::new(cursor_buffer_row - row_delta, 0) + .to_display_point(&display_map, Bias::Left); *cursor.column_mut() = cmp::min(goal_display_column, display_map.line_len(cursor.row())); + row_delta += rows.len() as u32; new_cursors.push(( selection.id, @@ -1180,18 +1156,15 @@ impl Editor { edit_ranges.push(edit_start..edit_end); } - new_cursors.sort_unstable_by_key(|(_, range)| range.clone()); + new_cursors.sort_unstable_by_key(|(_, point)| point.clone()); let new_selections = new_cursors .into_iter() - .map(|(id, cursor)| { - let anchor = buffer.anchor_before(cursor); - Selection { - id, - start: anchor.clone(), - end: anchor, - reversed: false, - goal: SelectionGoal::None, - } + .map(|(id, cursor)| Selection { + id, + start: cursor, + end: cursor, + reversed: false, + goal: SelectionGoal::None, }) .collect(); self.buffer @@ -1203,26 +1176,16 @@ impl Editor { pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext) { self.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 { @@ -1240,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); @@ -1353,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); @@ -1440,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(); } @@ -1475,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)); @@ -1507,16 +1474,16 @@ impl Editor { if let Some(item) = cx.as_mut().read_from_clipboard() { let clipboard_text = item.text(); if let Some(mut clipboard_selections) = item.metadata::>() { - 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) { @@ -1529,33 +1496,29 @@ impl Editor { entire_line = all_selections_were_entire_line; } - self.buffer.update(cx, |buffer, cx| { - let selection_start = selection.start.to_point(&*buffer); - let selection_end = selection.end.to_point(&*buffer); + selection.start = (selection.start as isize + delta) as usize; + selection.end = (selection.end as isize + delta) as usize; + self.buffer.update(cx, |buffer, cx| { // If the corresponding selection was empty when this slice of the // clipboard text was written, then the entire line containing the // selection was copied. If this selection is also currently empty, // then paste the line before the current line of the buffer. - let new_selection_start = selection.end.bias_right(buffer); - if selection_start == selection_end && entire_line { - let line_start = Point::new(selection_start.row, 0); - buffer.edit(Some(line_start..line_start), to_insert, cx); + let range = if selection.is_empty() && entire_line { + let column = selection.start.to_point(&*buffer).column as usize; + let line_start = selection.start - column; + line_start..line_start } else { - buffer.edit(Some(&selection.start..&selection.end), to_insert, cx); + selection.start..selection.end }; - let new_selection_start = new_selection_start.bias_left(buffer); - new_selections.push(Selection { - id: selection.id, - start: new_selection_start.clone(), - end: new_selection_start, - reversed: false, - goal: SelectionGoal::None, - }); + delta += to_insert.len() as isize - range.len() as isize; + buffer.edit([range], to_insert, cx); + selection.start += to_insert.len(); + selection.end = selection.start; }); } - self.update_selections(new_selections, true, cx); + self.update_selections(selections, true, cx); } else { self.insert(clipboard_text, cx); } @@ -1572,121 +1535,110 @@ impl Editor { pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { 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); } @@ -1694,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); } @@ -1739,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); } @@ -1760,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); } @@ -1781,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); @@ -1809,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); } @@ -1830,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); } @@ -1851,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); @@ -1879,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); } @@ -1900,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); } @@ -1928,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; @@ -1945,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); } @@ -1974,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, }; @@ -1987,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, @@ -2006,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, }; @@ -2024,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); @@ -2041,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, @@ -2069,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); @@ -2090,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(); @@ -2186,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; @@ -2244,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; } } @@ -2273,7 +2182,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) { @@ -2281,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, @@ -2316,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); @@ -2331,26 +2244,19 @@ 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: &Anchor, - cx: &AppContext, - ) -> usize { - let buffer = self.buffer.read(cx); - match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) { + 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) => { - 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,37 +2265,54 @@ 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, - ) { + ) 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 { @@ -2402,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.point_ranges(buffer)) + .all(|(selection, autoclose_range)| { + let head = selection.head().to_point(&*buffer); + autoclose_range.start <= head && autoclose_range.end >= head + }) } else { false }; @@ -2429,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(); }); } @@ -2461,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; @@ -2484,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 @@ -2545,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); } @@ -2756,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: None, }, @@ -2867,7 +2786,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); diff --git a/crates/language/src/lib.rs b/crates/language/src/lib.rs index 57540982d8..520358cd17 100644 --- a/crates/language/src/lib.rs +++ b/crates/language/src/lib.rs @@ -790,9 +790,9 @@ impl Buffer { for request in autoindent_requests { let old_to_new_rows = request .edited - .to_points(&request.before_edit) + .points(&request.before_edit) .map(|point| point.row) - .zip(request.edited.to_points(&snapshot).map(|point| point.row)) + .zip(request.edited.points(&snapshot).map(|point| point.row)) .collect::>(); let mut old_suggestions = HashMap::::default(); @@ -853,7 +853,7 @@ impl Buffer { if let Some(inserted) = request.inserted.as_ref() { let inserted_row_ranges = contiguous_ranges( inserted - .to_point_ranges(&snapshot) + .point_ranges(&snapshot) .flat_map(|range| range.start.row..range.end.row + 1), max_rows_between_yields, ); @@ -901,31 +901,30 @@ impl Buffer { for selection_set_id in &selection_set_ids { if let Ok(set) = self.selection_set(*selection_set_id) { let new_selections = set - .selections - .iter() + .point_selections(&*self) .map(|selection| { - let start_point = selection.start.to_point(&self.text); - if start_point.column == 0 { - let end_point = selection.end.to_point(&self.text); + if selection.start.column == 0 { let delta = Point::new( 0, - indent_columns.get(&start_point.row).copied().unwrap_or(0), + indent_columns + .get(&selection.start.row) + .copied() + .unwrap_or(0), ); if delta.column > 0 { return Selection { id: selection.id, goal: selection.goal, reversed: selection.reversed, - start: self - .anchor_at(start_point + delta, selection.start.bias), - end: self.anchor_at(end_point + delta, selection.end.bias), + start: selection.start + delta, + end: selection.end + delta, }; } } - selection.clone() + selection }) - .collect::>(); - self.update_selection_set(*selection_set_id, new_selections, cx) + .collect::>(); + self.update_selection_set(*selection_set_id, &new_selections, cx) .unwrap(); } } @@ -1239,9 +1238,9 @@ impl Buffer { cx.notify(); } - pub fn add_selection_set( + pub fn add_selection_set( &mut self, - selections: impl Into>, + selections: &[Selection], cx: &mut ModelContext, ) -> SelectionSetId { let operation = self.text.add_selection_set(selections); @@ -1255,10 +1254,10 @@ impl Buffer { } } - pub fn update_selection_set( + pub fn update_selection_set( &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 1798db9d0f..a6af0cd015 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -274,24 +274,24 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) { let mut buffer = Buffer::new(0, text, cx).with_language(rust_lang(), None, cx); - let selection_set_id = buffer.add_selection_set(Vec::new(), cx); + let selection_set_id = buffer.add_selection_set::(&[], cx); buffer.start_transaction(Some(selection_set_id)).unwrap(); buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx); buffer .update_selection_set( selection_set_id, - vec![ + &[ Selection { id: 0, - start: buffer.anchor_before(Point::new(1, 0)), - end: buffer.anchor_before(Point::new(1, 0)), + start: Point::new(1, 0), + end: Point::new(1, 0), reversed: false, goal: SelectionGoal::None, }, Selection { id: 1, - start: buffer.anchor_before(Point::new(4, 0)), - end: buffer.anchor_before(Point::new(4, 0)), + start: Point::new(4, 0), + end: Point::new(4, 0), reversed: false, goal: SelectionGoal::None, }, @@ -308,8 +308,7 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) { let selection_ranges = buffer .selection_set(selection_set_id) .unwrap() - .selections - .iter() + .point_selections(&buffer) .map(|selection| selection.point_range(&buffer)) .collect::>(); diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 2fa709c0a7..a4eb69db8f 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -3410,7 +3410,7 @@ mod tests { #[gpui::test] async fn test_buffer_file_changes_on_disk(mut cx: gpui::TestAppContext) { - use buffer::{Point, Selection, SelectionGoal, ToPoint}; + use buffer::{Point, Selection, SelectionGoal}; use std::fs; let initial_contents = "aaa\nbbbbb\nc\n"; @@ -3436,20 +3436,17 @@ mod tests { .await .unwrap(); - // Add a cursor at the start of each row. + // Add a cursor on each row. let selection_set_id = buffer.update(&mut cx, |buffer, cx| { assert!(!buffer.is_dirty()); buffer.add_selection_set( - (0..3) - .map(|row| { - let anchor = buffer.anchor_at(Point::new(row, 0), Bias::Right); - Selection { - id: row as usize, - start: anchor.clone(), - end: anchor, - reversed: false, - goal: SelectionGoal::None, - } + &(0..3) + .map(|row| Selection { + id: row as usize, + start: Point::new(row, 1), + end: Point::new(row, 1), + reversed: false, + goal: SelectionGoal::None, }) .collect::>(), cx, @@ -3469,7 +3466,7 @@ mod tests { // contents are edited according to the diff between the old and new // file contents. buffer - .condition(&cx, |buffer, _| buffer.text() != initial_contents) + .condition(&cx, |buffer, _| buffer.text() == new_contents) .await; buffer.update(&mut cx, |buffer, _| { @@ -3477,18 +3474,18 @@ mod tests { assert!(!buffer.is_dirty()); assert!(!buffer.has_conflict()); - let set = buffer.selection_set(selection_set_id).unwrap(); - let cursor_positions = set - .selections - .iter() + let cursor_positions = buffer + .selection_set(selection_set_id) + .unwrap() + .point_selections(&*buffer) .map(|selection| { assert_eq!(selection.start, selection.end); - selection.start.to_point(&*buffer) + selection.start }) .collect::>(); 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)] ); }); diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 0f0ea69261..2986ab9451 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -227,43 +227,31 @@ message Buffer { uint64 id = 1; string content = 2; repeated Operation.Edit history = 3; - repeated SelectionSetSnapshot selections = 4; -} - -message SelectionSetSnapshot { - uint32 replica_id = 1; - uint32 local_timestamp = 2; - repeated Selection selections = 3; - bool is_active = 4; + repeated SelectionSet selections = 4; } message SelectionSet { - repeated Selection selections = 1; + uint32 replica_id = 1; + uint32 lamport_timestamp = 2; + bool is_active = 3; + repeated VectorClockEntry version = 4; + repeated Selection selections = 5; } message Selection { uint64 id = 1; - Anchor start = 2; - Anchor end = 3; + uint64 start = 2; + uint64 end = 3; bool reversed = 4; } -message Anchor { - repeated VectorClockEntry version = 1; - uint64 offset = 2; - Bias bias = 3; - enum Bias { - LEFT = 0; - Right = 1; - } -} - message Operation { oneof variant { Edit edit = 1; Undo undo = 2; UpdateSelections update_selections = 3; - SetActiveSelections set_active_selections = 4; + RemoveSelections remove_selections = 4; + SetActiveSelections set_active_selections = 5; } message Edit { @@ -294,7 +282,14 @@ message Operation { uint32 replica_id = 1; uint32 local_timestamp = 2; uint32 lamport_timestamp = 3; - SelectionSet set = 4; + repeated VectorClockEntry version = 4; + repeated Selection selections = 5; + } + + message RemoveSelections { + uint32 replica_id = 1; + uint32 local_timestamp = 2; + uint32 lamport_timestamp = 3; } message SetActiveSelections { diff --git a/crates/sum_tree/src/cursor.rs b/crates/sum_tree/src/cursor.rs index 11c2847a7f..324cf0eadb 100644 --- a/crates/sum_tree/src/cursor.rs +++ b/crates/sum_tree/src/cursor.rs @@ -509,7 +509,7 @@ where } } -pub struct FilterCursor<'a, F: FnMut(&T::Summary) -> bool, T: Item, D> { +pub struct FilterCursor<'a, F, T: Item, D> { cursor: Cursor<'a, T, D>, filter_node: F, }