1use crate::{AnchorRangeMap, Buffer, Content, 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 head(&self) -> T {
41 if self.reversed {
42 self.start
43 } else {
44 self.end
45 }
46 }
47
48 pub fn set_head(&mut self, head: T) {
49 if head.cmp(&self.tail()) < Ordering::Equal {
50 if !self.reversed {
51 self.end = self.start;
52 self.reversed = true;
53 }
54 self.start = head;
55 } else {
56 if self.reversed {
57 self.start = self.end;
58 self.reversed = false;
59 }
60 self.end = head;
61 }
62 }
63
64 pub fn tail(&self) -> T {
65 if self.reversed {
66 self.end
67 } else {
68 self.start
69 }
70 }
71
72 pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
73 let start = self.start.to_point(buffer);
74 let end = self.end.to_point(buffer);
75 if self.reversed {
76 end..start
77 } else {
78 start..end
79 }
80 }
81
82 pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
83 let start = self.start.to_offset(buffer);
84 let end = self.end.to_offset(buffer);
85 if self.reversed {
86 end..start
87 } else {
88 start..end
89 }
90 }
91}
92
93impl SelectionSet {
94 pub fn len(&self) -> usize {
95 self.selections.len()
96 }
97
98 pub fn offset_selections<'a>(
99 &'a self,
100 content: impl Into<Content<'a>> + 'a,
101 ) -> impl 'a + Iterator<Item = Selection<usize>> {
102 self.selections
103 .offset_ranges(content)
104 .map(|(range, state)| Selection {
105 id: state.id,
106 start: range.start,
107 end: range.end,
108 reversed: state.reversed,
109 goal: state.goal,
110 })
111 }
112
113 pub fn point_selections<'a>(
114 &'a self,
115 content: impl Into<Content<'a>> + 'a,
116 ) -> impl 'a + Iterator<Item = Selection<Point>> {
117 self.selections
118 .point_ranges(content)
119 .map(|(range, state)| Selection {
120 id: state.id,
121 start: range.start,
122 end: range.end,
123 reversed: state.reversed,
124 goal: state.goal,
125 })
126 }
127}
128
129impl<'a> Into<proto::SelectionSet> for &'a SelectionSet {
130 fn into(self) -> proto::SelectionSet {
131 let version = self.selections.version();
132 let entries = self.selections.raw_entries();
133 proto::SelectionSet {
134 replica_id: self.id.replica_id as u32,
135 lamport_timestamp: self.id.value as u32,
136 is_active: self.active,
137 version: version.into(),
138 selections: entries
139 .iter()
140 .map(|(range, state)| proto::Selection {
141 id: state.id as u64,
142 start: range.start.0 as u64,
143 end: range.end.0 as u64,
144 reversed: state.reversed,
145 })
146 .collect(),
147 }
148 }
149}
150
151impl From<proto::SelectionSet> for SelectionSet {
152 fn from(set: proto::SelectionSet) -> Self {
153 Self {
154 id: clock::Lamport {
155 replica_id: set.replica_id as u16,
156 value: set.lamport_timestamp,
157 },
158 active: set.is_active,
159 selections: Arc::new(AnchorRangeMap::from_raw(
160 set.version.into(),
161 set.selections
162 .into_iter()
163 .map(|selection| {
164 let range = (selection.start as usize, Bias::Left)
165 ..(selection.end as usize, Bias::Right);
166 let state = SelectionState {
167 id: selection.id as usize,
168 reversed: selection.reversed,
169 goal: SelectionGoal::None,
170 };
171 (range, state)
172 })
173 .collect(),
174 )),
175 }
176 }
177}