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; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum SelectionGoal { None, Column(u32), ColumnRange { start: u32, end: u32 }, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Selection { pub id: usize, pub start: T, pub end: T, pub reversed: bool, pub goal: SelectionGoal, } #[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 } else { self.end } } pub fn set_head(&mut self, head: T) { if head.cmp(&self.tail()) < Ordering::Equal { if !self.reversed { self.end = self.start; self.reversed = true; } self.start = head; } else { if self.reversed { self.start = self.end; self.reversed = false; } self.end = head; } } pub fn tail(&self) -> T { if self.reversed { self.end } else { self.start } } pub fn point_range(&self, buffer: &Buffer) -> Range { let start = self.start.to_point(buffer); let end = self.end.to_point(buffer); if self.reversed { end..start } else { start..end } } pub fn offset_range(&self, buffer: &Buffer) -> Range { let start = self.start.to_offset(buffer); let end = self.end.to_offset(buffer); if self.reversed { end..start } else { start..end } } } 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(), )), } } }