1#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
9pub struct Selection {
10 pub anchor: usize,
11 pub head: usize,
12}
13
14impl Selection {
15 pub fn cursor(at: usize) -> Self {
16 Self {
17 anchor: at,
18 head: at,
19 }
20 }
21
22 pub fn collapsed(self) -> bool {
23 self.anchor == self.head
24 }
25
26 pub fn range(self) -> (usize, usize) {
28 (self.anchor.min(self.head), self.anchor.max(self.head))
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
36pub struct SelectionSet {
37 primary: Selection,
38 extras: Vec<Selection>,
39}
40
41impl Default for SelectionSet {
42 fn default() -> Self {
43 Self {
44 primary: Selection::cursor(0),
45 extras: Vec::new(),
46 }
47 }
48}
49
50impl SelectionSet {
51 pub fn primary(&self) -> Selection {
52 self.primary
53 }
54
55 pub fn heads(&self) -> Vec<usize> {
57 std::iter::once(self.primary.head)
58 .chain(self.extras.iter().map(|s| s.head))
59 .collect()
60 }
61
62 pub fn extra_heads(&self) -> &[Selection] {
63 &self.extras
64 }
65
66 pub fn count(&self) -> usize {
67 1 + self.extras.len()
68 }
69
70 pub fn set_head(&mut self, head: usize) {
72 self.primary.head = head;
73 }
74
75 pub fn collapse_primary(&mut self, at: usize) {
77 self.primary = Selection::cursor(at);
78 }
79
80 pub fn stretch_primary(&mut self, anchor: usize, head: usize) {
82 self.primary = Selection { anchor, head };
83 }
84
85 pub fn toggle_extra(&mut self) {
87 if let Some(i) = self.extras.iter().position(|s| s.head == self.primary.head) {
88 self.extras.remove(i);
89 } else {
90 self.extras.push(self.primary);
91 }
92 self.normalize();
93 }
94
95 pub fn plant_extra(&mut self, at: usize) {
99 if at != self.primary.head && !self.extras.iter().any(|s| s.head == at) {
100 self.extras.push(Selection::cursor(at));
101 }
102 self.normalize();
103 }
104
105 pub fn normalize(&mut self) {
108 self.extras.sort_by_key(|s| s.head);
109 self.extras.dedup();
110 }
111
112 pub fn collapse_extras(&mut self) {
114 self.extras.clear();
115 }
116
117 pub fn set_extras(&mut self, heads: impl IntoIterator<Item = usize>) {
121 self.extras = heads.into_iter().map(Selection::cursor).collect();
122 self.normalize();
123 }
124
125 pub fn plant_extra_selection(&mut self, anchor: usize, head: usize) {
129 let selection = Selection { anchor, head };
130 if selection.range() == self.primary.range()
131 || self
132 .extras
133 .iter()
134 .any(|extra| extra.range() == selection.range())
135 {
136 return;
137 }
138 self.extras.push(selection);
139 self.normalize();
140 }
141
142 pub fn set_extra_selections(&mut self, selections: impl IntoIterator<Item = Selection>) {
147 self.extras = selections.into_iter().collect();
148 self.normalize();
149 }
150
151 pub fn remove_extra(&mut self, selection: Selection) -> Option<Selection> {
154 let at = self.extras.iter().position(|extra| *extra == selection)?;
155 Some(self.extras.remove(at))
156 }
157
158 pub fn map_positions(&mut self, mut map: impl FnMut(usize) -> usize) {
160 self.primary.anchor = map(self.primary.anchor);
161 self.primary.head = map(self.primary.head);
162 for selection in &mut self.extras {
163 selection.anchor = map(selection.anchor);
164 selection.head = map(selection.head);
165 }
166 self.normalize();
167 }
168
169 pub fn remap(&mut self, at: usize, delta: isize) {
172 let shift = |p: &mut usize| {
173 if *p >= at {
174 *p = (*p as isize + delta).max(0) as usize;
175 }
176 };
177 shift(&mut self.primary.head);
178 shift(&mut self.primary.anchor);
179 for s in &mut self.extras {
180 shift(&mut s.head);
181 shift(&mut s.anchor);
182 }
183 self.normalize();
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn invariants_hold() {
193 let mut s = SelectionSet::default();
194 s.set_head(5);
195 s.toggle_extra(); assert_eq!(s.count(), 2);
197 s.plant_extra(2);
198 s.plant_extra(2); assert_eq!(s.count(), 3);
200 assert_eq!(s.heads(), vec![5, 2, 5]);
201 s.toggle_extra(); assert_eq!(s.count(), 2);
203 assert_eq!(s.heads(), vec![5, 2]);
204 s.collapse_extras();
205 assert_eq!(s.count(), 1);
206 }
207
208 #[test]
209 fn remap_shifts_past_the_edit() {
210 let mut s = SelectionSet::default();
211 s.collapse_primary(10);
212 s.plant_extra(20);
213 s.remap(5, 3); assert_eq!(s.heads(), vec![13, 23]);
215 s.remap(5, -3);
216 assert_eq!(s.heads(), vec![10, 20]);
217 }
218}