1use crate::{Anchor, AnchorRangeMap, Buffer, Point, ToOffset as _, ToPoint as _};
2use rpc::proto;
3use std::{cmp::Ordering, mem, 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 {
18 pub id: usize,
19 pub start: Anchor,
20 pub end: Anchor,
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 Selection {
40 pub fn head(&self) -> &Anchor {
41 if self.reversed {
42 &self.start
43 } else {
44 &self.end
45 }
46 }
47
48 pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) {
49 if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal {
50 if !self.reversed {
51 mem::swap(&mut self.start, &mut self.end);
52 self.reversed = true;
53 }
54 self.start = cursor;
55 } else {
56 if self.reversed {
57 mem::swap(&mut self.start, &mut self.end);
58 self.reversed = false;
59 }
60 self.end = cursor;
61 }
62 }
63
64 pub fn tail(&self) -> &Anchor {
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<'a> Into<proto::SelectionSet> for &'a SelectionSet {
94 fn into(self) -> proto::SelectionSet {
95 let version = self.selections.version();
96 let entries = self.selections.raw_entries();
97 proto::SelectionSet {
98 replica_id: self.id.replica_id as u32,
99 lamport_timestamp: self.id.value as u32,
100 is_active: self.active,
101 version: version.into(),
102 selections: entries
103 .iter()
104 .map(|(range, state)| proto::Selection {
105 id: state.id as u64,
106 start: range.start.0 as u64,
107 end: range.end.0 as u64,
108 reversed: state.reversed,
109 })
110 .collect(),
111 }
112 }
113}
114
115impl From<proto::SelectionSet> for SelectionSet {
116 fn from(set: proto::SelectionSet) -> Self {
117 Self {
118 id: clock::Lamport {
119 replica_id: set.replica_id as u16,
120 value: set.lamport_timestamp,
121 },
122 active: set.is_active,
123 selections: Arc::new(AnchorRangeMap::from_raw(
124 set.version.into(),
125 set.selections
126 .into_iter()
127 .map(|selection| {
128 let range = (selection.start as usize, Bias::Left)
129 ..(selection.end as usize, Bias::Right);
130 let state = SelectionState {
131 id: selection.id as usize,
132 reversed: selection.reversed,
133 goal: SelectionGoal::None,
134 };
135 (range, state)
136 })
137 .collect(),
138 )),
139 }
140 }
141}