1use super::{AnchorRangeMap, Buffer, Content, FullOffset, Point, ToOffset, ToPoint};
2use rpc::proto;
3use std::{cmp::Ordering, ops::Range, sync::Arc};
4use sum_tree::Bias;
5
6pub type SelectionSetId = clock::Lamport;
7pub type SelectionsVersion = usize;
8
9#[derive(Copy, Clone, Debug, Eq, PartialEq)]
10pub enum SelectionGoal {
11 None,
12 Column(u32),
13 ColumnRange { start: u32, end: u32 },
14}
15
16#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct Selection<T> {
18 pub id: usize,
19 pub start: T,
20 pub end: T,
21 pub reversed: bool,
22 pub goal: SelectionGoal,
23}
24
25#[derive(Clone, Debug, Eq, PartialEq)]
26pub struct SelectionSet {
27 pub id: SelectionSetId,
28 pub active: bool,
29 pub selections: Arc<AnchorRangeMap<SelectionState>>,
30}
31
32#[derive(Debug, Eq, PartialEq)]
33pub struct SelectionState {
34 pub id: usize,
35 pub reversed: bool,
36 pub goal: SelectionGoal,
37}
38
39impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
40 pub fn is_empty(&self) -> bool {
41 self.start == self.end
42 }
43
44 pub fn head(&self) -> T {
45 if self.reversed {
46 self.start
47 } else {
48 self.end
49 }
50 }
51
52 pub fn set_head(&mut self, head: T) {
53 if head.cmp(&self.tail()) < Ordering::Equal {
54 if !self.reversed {
55 self.end = self.start;
56 self.reversed = true;
57 }
58 self.start = head;
59 } else {
60 if self.reversed {
61 self.start = self.end;
62 self.reversed = false;
63 }
64 self.end = head;
65 }
66 }
67
68 pub fn tail(&self) -> T {
69 if self.reversed {
70 self.end
71 } else {
72 self.start
73 }
74 }
75
76 pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
77 let start = self.start.to_point(buffer);
78 let end = self.end.to_point(buffer);
79 if self.reversed {
80 end..start
81 } else {
82 start..end
83 }
84 }
85
86 pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
87 let start = self.start.to_offset(buffer);
88 let end = self.end.to_offset(buffer);
89 if self.reversed {
90 end..start
91 } else {
92 start..end
93 }
94 }
95}
96
97impl SelectionSet {
98 pub fn len(&self) -> usize {
99 self.selections.len()
100 }
101
102 pub fn offset_selections<'a>(
103 &'a self,
104 content: impl Into<Content<'a>> + 'a,
105 ) -> impl 'a + Iterator<Item = Selection<usize>> {
106 self.selections
107 .offset_ranges(content)
108 .map(|(range, state)| Selection {
109 id: state.id,
110 start: range.start,
111 end: range.end,
112 reversed: state.reversed,
113 goal: state.goal,
114 })
115 }
116
117 pub fn point_selections<'a>(
118 &'a self,
119 content: impl Into<Content<'a>> + 'a,
120 ) -> impl 'a + Iterator<Item = Selection<Point>> {
121 self.selections
122 .point_ranges(content)
123 .map(|(range, state)| Selection {
124 id: state.id,
125 start: range.start,
126 end: range.end,
127 reversed: state.reversed,
128 goal: state.goal,
129 })
130 }
131}
132
133impl<'a> Into<proto::SelectionSet> for &'a SelectionSet {
134 fn into(self) -> proto::SelectionSet {
135 let version = self.selections.version();
136 let entries = self.selections.raw_entries();
137 proto::SelectionSet {
138 replica_id: self.id.replica_id as u32,
139 lamport_timestamp: self.id.value as u32,
140 is_active: self.active,
141 version: version.into(),
142 selections: entries
143 .iter()
144 .map(|(range, state)| proto::Selection {
145 id: state.id as u64,
146 start: range.start.0.to_proto(),
147 end: range.end.0.to_proto(),
148 reversed: state.reversed,
149 })
150 .collect(),
151 }
152 }
153}
154
155impl From<proto::SelectionSet> for SelectionSet {
156 fn from(set: proto::SelectionSet) -> Self {
157 Self {
158 id: clock::Lamport {
159 replica_id: set.replica_id as u16,
160 value: set.lamport_timestamp,
161 },
162 active: set.is_active,
163 selections: Arc::new(AnchorRangeMap::from_raw(
164 set.version.into(),
165 set.selections
166 .into_iter()
167 .map(|selection| {
168 let range = (FullOffset::from_proto(selection.start), Bias::Left)
169 ..(FullOffset::from_proto(selection.end), Bias::Right);
170 let state = SelectionState {
171 id: selection.id as usize,
172 reversed: selection.reversed,
173 goal: SelectionGoal::None,
174 };
175 (range, state)
176 })
177 .collect(),
178 )),
179 }
180 }
181}