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 map_positions(&mut self, mut map: impl FnMut(usize) -> usize) {
127 self.primary.anchor = map(self.primary.anchor);
128 self.primary.head = map(self.primary.head);
129 for selection in &mut self.extras {
130 selection.anchor = map(selection.anchor);
131 selection.head = map(selection.head);
132 }
133 self.normalize();
134 }
135
136 pub fn remap(&mut self, at: usize, delta: isize) {
139 let shift = |p: &mut usize| {
140 if *p >= at {
141 *p = (*p as isize + delta).max(0) as usize;
142 }
143 };
144 shift(&mut self.primary.head);
145 shift(&mut self.primary.anchor);
146 for s in &mut self.extras {
147 shift(&mut s.head);
148 shift(&mut s.anchor);
149 }
150 self.normalize();
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn invariants_hold() {
160 let mut s = SelectionSet::default();
161 s.set_head(5);
162 s.toggle_extra(); assert_eq!(s.count(), 2);
164 s.plant_extra(2);
165 s.plant_extra(2); assert_eq!(s.count(), 3);
167 assert_eq!(s.heads(), vec![5, 2, 5]);
168 s.toggle_extra(); assert_eq!(s.count(), 2);
170 assert_eq!(s.heads(), vec![5, 2]);
171 s.collapse_extras();
172 assert_eq!(s.count(), 1);
173 }
174
175 #[test]
176 fn remap_shifts_past_the_edit() {
177 let mut s = SelectionSet::default();
178 s.collapse_primary(10);
179 s.plant_extra(20);
180 s.remap(5, 3); assert_eq!(s.heads(), vec![13, 23]);
182 s.remap(5, -3);
183 assert_eq!(s.heads(), vec![10, 20]);
184 }
185}