diff --git a/crates/buffer/src/anchor.rs b/crates/buffer/src/anchor.rs index 58673a3301..3162dcd28f 100644 --- a/crates/buffer/src/anchor.rs +++ b/crates/buffer/src/anchor.rs @@ -87,7 +87,7 @@ impl Anchor { } impl AnchorMap { - pub fn to_points<'a>( + pub fn points<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { @@ -103,11 +103,11 @@ impl AnchorMap { } impl AnchorSet { - pub fn to_points<'a>( + pub fn points<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { - self.0.to_points(content).map(move |(point, _)| point) + self.0.points(content).map(move |(point, _)| point) } } @@ -120,7 +120,7 @@ impl AnchorRangeMap { &self.entries } - pub fn to_point_ranges<'a>( + pub fn point_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator, &'a T)> + 'a { @@ -130,6 +130,16 @@ impl AnchorRangeMap { .map(move |(range, value)| ((range.start.lines..range.end.lines), value)) } + pub fn offset_ranges<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl Iterator, &'a T)> + 'a { + let content = content.into(); + content + .summaries_for_anchor_ranges(self) + .map(move |(range, value)| ((range.start.bytes..range.end.bytes), value)) + } + pub fn version(&self) -> &clock::Global { &self.version } @@ -145,7 +155,7 @@ impl Eq for AnchorRangeMap {} impl Debug for AnchorRangeMap { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - let f = f.debug_map(); + let mut f = f.debug_map(); for (range, value) in &self.entries { f.key(range); f.value(value); @@ -159,7 +169,7 @@ impl AnchorRangeSet { &'a self, content: impl Into> + 'a, ) -> impl Iterator> + 'a { - self.0.to_point_ranges(content).map(|(range, _)| range) + self.0.point_ranges(content).map(|(range, _)| range) } pub fn version(&self) -> &clock::Global { diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index f780d2590c..a5dd062570 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -79,8 +79,8 @@ pub struct Transaction { end: clock::Global, edits: Vec, ranges: Vec>, - selections_before: HashMap>, - selections_after: HashMap>, + selections_before: HashMap>>, + selections_after: HashMap>>, first_edit_at: Instant, last_edit_at: Instant, } @@ -167,7 +167,7 @@ impl History { fn start_transaction( &mut self, start: clock::Global, - selections_before: HashMap>, + selections_before: HashMap>>, now: Instant, ) { self.transaction_depth += 1; @@ -187,7 +187,7 @@ impl History { fn end_transaction( &mut self, - selections_after: HashMap>, + selections_after: HashMap>>, now: Instant, ) -> Option<&Transaction> { assert_ne!(self.transaction_depth, 0); @@ -499,11 +499,7 @@ impl Buffer { id: self.remote_id, content: self.history.base_text.to_string(), history: ops, - selections: self - .selections - .iter() - .map(|(set_id, set)| set.into()) - .collect(), + selections: self.selections.iter().map(|(_, set)| set.into()).collect(), } } @@ -1201,7 +1197,7 @@ impl Buffer { let selections = transaction.selections_before.clone(); ops.push(self.undo_or_redo(transaction).unwrap()); for (set_id, selections) in selections { - ops.extend(self.update_selection_set(set_id, selections)); + ops.extend(self.restore_selection_set(set_id, selections)); } } ops @@ -1213,7 +1209,7 @@ impl Buffer { let selections = transaction.selections_after.clone(); ops.push(self.undo_or_redo(transaction).unwrap()); for (set_id, selections) in selections { - ops.extend(self.update_selection_set(set_id, selections)); + ops.extend(self.restore_selection_set(set_id, selections)); } } ops @@ -1250,17 +1246,37 @@ impl Buffer { self.selections.iter() } - pub fn update_selection_set( + fn build_selection_anchor_range_map( + &self, + selections: &[Selection], + ) -> Arc> { + Arc::new( + self.content() + .anchor_range_map(selections.iter().map(|selection| { + let start = selection.start.to_offset(self); + let end = selection.end.to_offset(self); + let range = (start, Bias::Left)..(end, Bias::Left); + let state = SelectionState { + id: selection.id, + reversed: selection.reversed, + goal: selection.goal, + }; + (range, state) + })), + ) + } + + pub fn update_selection_set( &mut self, set_id: SelectionSetId, - selections: &[Selection], + selections: &[Selection], ) -> Result { - let selections = selections.into(); + let selections = self.build_selection_anchor_range_map(selections); let set = self .selections .get_mut(&set_id) .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - set.selections = todo!(); + set.selections = selections.clone(); Ok(Operation::UpdateSelections { set_id, selections, @@ -1268,8 +1284,25 @@ impl Buffer { }) } - pub fn add_selection_set(&mut self, selections: impl Into>) -> Operation { - let selections = selections.into(); + pub fn restore_selection_set( + &mut self, + set_id: SelectionSetId, + selections: Arc>, + ) -> Result { + let set = self + .selections + .get_mut(&set_id) + .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; + set.selections = selections.clone(); + Ok(Operation::UpdateSelections { + set_id, + selections, + lamport_timestamp: self.lamport_clock.tick(), + }) + } + + pub fn add_selection_set(&mut self, selections: &[Selection]) -> Operation { + let selections = self.build_selection_anchor_range_map(selections); let set_id = self.lamport_clock.tick(); self.selections.insert( set_id, @@ -1408,9 +1441,9 @@ impl Buffer { let new_selections = self.selections_from_ranges(ranges).unwrap(); let op = if set_id.is_none() || rng.gen_bool(1.0 / 5.0) { - self.add_selection_set(new_selections) + self.add_selection_set(&new_selections) } else { - self.update_selection_set(*set_id.unwrap(), new_selections) + self.update_selection_set(*set_id.unwrap(), &new_selections) .unwrap() }; ops.push(op); @@ -1436,7 +1469,7 @@ impl Buffer { ops } - fn selections_from_ranges(&self, ranges: I) -> Result> + fn selections_from_ranges(&self, ranges: I) -> Result>> where I: IntoIterator>, { @@ -1452,16 +1485,16 @@ impl Buffer { if range.start > range.end { selections.push(Selection { id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), - start: self.anchor_before(range.end), - end: self.anchor_before(range.start), + start: range.end, + end: range.start, reversed: true, goal: SelectionGoal::None, }); } else { selections.push(Selection { id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), - start: self.anchor_after(range.start), - end: self.anchor_before(range.end), + start: range.start, + end: range.end, reversed: false, goal: SelectionGoal::None, }); @@ -1473,15 +1506,12 @@ impl Buffer { pub fn selection_ranges<'a>(&'a self, set_id: SelectionSetId) -> Result>> { Ok(self .selection_set(set_id)? - .selections - .iter() + .offset_selections(self) .map(move |selection| { - let start = selection.start.to_offset(self); - let end = selection.end.to_offset(self); if selection.reversed { - end..start + selection.end..selection.start } else { - start..end + selection.start..selection.end } }) .collect()) @@ -2173,7 +2203,17 @@ impl<'a> Into for &'a Operation { replica_id: set_id.replica_id as u32, local_timestamp: set_id.value, lamport_timestamp: lamport_timestamp.value, - selections: selections.iter().map(Into::into).collect(), + version: selections.version().into(), + selections: selections + .raw_entries() + .iter() + .map(|(range, state)| proto::Selection { + id: state.id as u64, + start: range.start.0 as u64, + end: range.end.0 as u64, + reversed: state.reversed, + }) + .collect(), }, ), Operation::RemoveSelections { @@ -2279,11 +2319,23 @@ impl TryFrom for Operation { }, }, proto::operation::Variant::UpdateSelections(message) => { - let selections: Vec = message + let version = message.version.into(); + let entries = message .selections - .into_iter() - .map(TryFrom::try_from) - .collect::>()?; + .iter() + .map(|selection| { + let range = (selection.start as usize, Bias::Left) + ..(selection.end as usize, Bias::Right); + let state = SelectionState { + id: selection.id as usize, + reversed: selection.reversed, + goal: SelectionGoal::None, + }; + (range, state) + }) + .collect(); + let selections = AnchorRangeMap::from_raw(version, entries); + Operation::UpdateSelections { set_id: clock::Lamport { replica_id: message.replica_id as ReplicaId, diff --git a/crates/buffer/src/selection.rs b/crates/buffer/src/selection.rs index 03b394252b..f582aa199f 100644 --- a/crates/buffer/src/selection.rs +++ b/crates/buffer/src/selection.rs @@ -1,6 +1,6 @@ -use crate::{Anchor, AnchorRangeMap, Buffer, Point, ToOffset as _, ToPoint as _}; +use crate::{AnchorRangeMap, Buffer, Content, Point, ToOffset, ToPoint}; use rpc::proto; -use std::{cmp::Ordering, mem, ops::Range, sync::Arc}; +use std::{cmp::Ordering, ops::Range, sync::Arc}; use sum_tree::Bias; pub type SelectionSetId = clock::Lamport; @@ -14,10 +14,10 @@ pub enum SelectionGoal { } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Selection { +pub struct Selection { pub id: usize, - pub start: Anchor, - pub end: Anchor, + pub start: T, + pub end: T, pub reversed: bool, pub goal: SelectionGoal, } @@ -36,36 +36,36 @@ pub struct SelectionState { pub goal: SelectionGoal, } -impl Selection { - pub fn head(&self) -> &Anchor { +impl Selection { + pub fn head(&self) -> T { if self.reversed { - &self.start + self.start } else { - &self.end + self.end } } - pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) { - if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal { + pub fn set_head(&mut self, head: T) { + if head.cmp(&self.tail()) < Ordering::Equal { if !self.reversed { - mem::swap(&mut self.start, &mut self.end); + self.end = self.start; self.reversed = true; } - self.start = cursor; + self.start = head; } else { if self.reversed { - mem::swap(&mut self.start, &mut self.end); + self.start = self.end; self.reversed = false; } - self.end = cursor; + self.end = head; } } - pub fn tail(&self) -> &Anchor { + pub fn tail(&self) -> T { if self.reversed { - &self.end + self.end } else { - &self.start + self.start } } @@ -90,6 +90,38 @@ impl Selection { } } +impl SelectionSet { + pub fn offset_selections<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl 'a + Iterator> { + self.selections + .offset_ranges(content) + .map(|(range, state)| Selection { + id: state.id, + start: range.start, + end: range.end, + reversed: state.reversed, + goal: state.goal, + }) + } + + pub fn point_selections<'a>( + &'a self, + content: impl Into> + 'a, + ) -> impl 'a + Iterator> { + self.selections + .point_ranges(content) + .map(|(range, state)| Selection { + id: state.id, + start: range.start, + end: range.end, + reversed: state.reversed, + goal: state.goal, + }) + } +} + impl<'a> Into for &'a SelectionSet { fn into(self) -> proto::SelectionSet { let version = self.selections.version(); diff --git a/crates/buffer/src/tests.rs b/crates/buffer/src/tests.rs index bb29f7de98..bce08ebf73 100644 --- a/crates/buffer/src/tests.rs +++ b/crates/buffer/src/tests.rs @@ -408,7 +408,7 @@ fn test_history() { let mut buffer = Buffer::new(0, 0, History::new("123456".into())); let set_id = if let Operation::UpdateSelections { set_id, .. } = - buffer.add_selection_set(buffer.selections_from_ranges(vec![4..4]).unwrap()) + buffer.add_selection_set(&buffer.selections_from_ranges(vec![4..4]).unwrap()) { set_id } else { @@ -422,7 +422,7 @@ fn test_history() { buffer.start_transaction_at(Some(set_id), now).unwrap(); buffer - .update_selection_set(set_id, buffer.selections_from_ranges(vec![1..3]).unwrap()) + .update_selection_set(set_id, &buffer.selections_from_ranges(vec![1..3]).unwrap()) .unwrap(); buffer.edit(vec![4..5], "e"); buffer.end_transaction_at(Some(set_id), now).unwrap(); @@ -432,7 +432,7 @@ fn test_history() { now += buffer.history.group_interval + Duration::from_millis(1); buffer.start_transaction_at(Some(set_id), now).unwrap(); buffer - .update_selection_set(set_id, buffer.selections_from_ranges(vec![2..2]).unwrap()) + .update_selection_set(set_id, &buffer.selections_from_ranges(vec![2..2]).unwrap()) .unwrap(); buffer.edit(vec![0..1], "a"); buffer.edit(vec![1..1], "b");