1use crate::Anchor;
2use crate::{rope::TextDimension, BufferSnapshot, ToOffset, ToPoint};
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<[Selection<Anchor>]>,
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: Clone> Selection<T> {
40 pub fn head(&self) -> T {
41 if self.reversed {
42 self.start.clone()
43 } else {
44 self.end.clone()
45 }
46 }
47
48 pub fn tail(&self) -> T {
49 if self.reversed {
50 self.end.clone()
51 } else {
52 self.start.clone()
53 }
54 }
55}
56
57impl<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
58 pub fn is_empty(&self) -> bool {
59 self.start == self.end
60 }
61
62 pub fn set_head(&mut self, head: T) {
63 if head.cmp(&self.tail()) < Ordering::Equal {
64 if !self.reversed {
65 self.end = self.start;
66 self.reversed = true;
67 }
68 self.start = head;
69 } else {
70 if self.reversed {
71 self.start = self.end;
72 self.reversed = false;
73 }
74 self.end = head;
75 }
76 }
77}
78
79impl Selection<Anchor> {
80 pub fn resolve<'a, D: 'a + TextDimension>(
81 &'a self,
82 snapshot: &'a BufferSnapshot,
83 ) -> Selection<D> {
84 Selection {
85 id: self.id,
86 start: snapshot.summary_for_anchor(&self.start),
87 end: snapshot.summary_for_anchor(&self.end),
88 reversed: self.reversed,
89 goal: self.goal,
90 }
91 }
92}
93
94impl SelectionSet {
95 pub fn len(&self) -> usize {
96 self.selections.len()
97 }
98
99 pub fn selections<'a, D>(
100 &'a self,
101 snapshot: &'a BufferSnapshot,
102 ) -> impl 'a + Iterator<Item = Selection<D>>
103 where
104 D: TextDimension,
105 {
106 let anchors = self
107 .selections
108 .iter()
109 .flat_map(|selection| [&selection.start, &selection.end].into_iter());
110 let mut positions = snapshot.summaries_for_anchors::<D, _>(anchors);
111 self.selections.iter().map(move |selection| Selection {
112 start: positions.next().unwrap(),
113 end: positions.next().unwrap(),
114 goal: selection.goal,
115 reversed: selection.reversed,
116 id: selection.id,
117 })
118 }
119
120 pub fn intersecting_selections<'a, D, I>(
121 &'a self,
122 range: Range<(I, Bias)>,
123 snapshot: &'a BufferSnapshot,
124 ) -> impl 'a + Iterator<Item = Selection<D>>
125 where
126 D: TextDimension,
127 I: 'a + ToOffset,
128 {
129 let start = snapshot.anchor_at(range.start.0, range.start.1);
130 let end = snapshot.anchor_at(range.end.0, range.end.1);
131 let start_ix = match self
132 .selections
133 .binary_search_by(|probe| probe.end.cmp(&start, snapshot).unwrap())
134 {
135 Ok(ix) | Err(ix) => ix,
136 };
137 let end_ix = match self
138 .selections
139 .binary_search_by(|probe| probe.start.cmp(&end, snapshot).unwrap())
140 {
141 Ok(ix) | Err(ix) => ix,
142 };
143 self.selections[start_ix..end_ix]
144 .iter()
145 .map(|s| s.resolve(snapshot))
146 }
147
148 pub fn oldest_selection<'a, D>(&'a self, snapshot: &'a BufferSnapshot) -> Option<Selection<D>>
149 where
150 D: TextDimension,
151 {
152 self.selections
153 .iter()
154 .min_by_key(|s| s.id)
155 .map(|s| s.resolve(snapshot))
156 }
157
158 pub fn newest_selection<'a, D>(&'a self, snapshot: &'a BufferSnapshot) -> Option<Selection<D>>
159 where
160 D: TextDimension,
161 {
162 self.selections
163 .iter()
164 .max_by_key(|s| s.id)
165 .map(|s| s.resolve(snapshot))
166 }
167}