1use std::cell::RefCell;
15
16use crate::coords::Bias;
17use crate::patch::Patch;
18
19type RebaseScratch = (Vec<(u32, Bias)>, Vec<u32>);
22
23#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
26pub struct SelectionId(pub usize);
27
28#[derive(Copy, Clone, PartialEq, Eq, Debug)]
31pub struct Selection {
32 pub id: SelectionId,
34 start: u32,
35 end: u32,
36 reversed: bool,
37 pub goal: Option<u32>,
41}
42
43impl Selection {
44 #[must_use]
46 pub fn caret(id: SelectionId, offset: u32) -> Self {
47 Self { id, start: offset, end: offset, reversed: false, goal: None }
48 }
49
50 #[must_use]
53 pub fn from_anchor(id: SelectionId, anchor: u32, head: u32) -> Self {
54 Self {
55 id,
56 start: anchor.min(head),
57 end: anchor.max(head),
58 reversed: head < anchor,
59 goal: None,
60 }
61 }
62
63 #[must_use]
65 pub fn start(&self) -> u32 {
66 self.start
67 }
68
69 #[must_use]
71 pub fn end(&self) -> u32 {
72 self.end
73 }
74
75 #[must_use]
77 pub fn head(&self) -> u32 {
78 if self.reversed {
79 self.start
80 } else {
81 self.end
82 }
83 }
84
85 #[must_use]
87 pub fn tail(&self) -> u32 {
88 if self.reversed {
89 self.end
90 } else {
91 self.start
92 }
93 }
94
95 #[must_use]
97 pub fn is_empty(&self) -> bool {
98 self.start == self.end
99 }
100
101 pub fn set_head(&mut self, offset: u32) {
105 let tail = self.tail();
106 self.start = tail.min(offset);
107 self.end = tail.max(offset);
108 self.reversed = offset < tail;
109 self.goal = None;
110 }
111
112 pub fn collapse_to_head(&mut self) {
114 let h = self.head();
115 self.start = h;
116 self.end = h;
117 self.reversed = false;
118 }
119
120 pub fn move_to_caret(&mut self, offset: u32) {
123 self.start = offset;
124 self.end = offset;
125 self.reversed = false;
126 self.goal = None;
127 }
128}
129
130#[derive(Clone, Debug)]
133pub struct SelectionSet {
134 selections: Vec<Selection>,
135 next_id: usize,
136}
137
138impl SelectionSet {
139 #[must_use]
141 pub fn new(offset: u32) -> Self {
142 Self { selections: vec![Selection::caret(SelectionId(0), offset)], next_id: 1 }
143 }
144
145 #[must_use]
149 pub fn from_offsets(offsets: &[u32]) -> Self {
150 assert!(!offsets.is_empty(), "a selection set is never empty");
151 let mut set = Self { selections: Vec::new(), next_id: 0 };
152 for &o in offsets {
153 let id = set.mint();
154 set.selections.push(Selection::caret(id, o));
155 }
156 set.normalize();
157 set
158 }
159
160 #[must_use]
165 pub fn from_ranges(ranges: &[(u32, u32)], newest: usize) -> Self {
166 assert!(!ranges.is_empty(), "a selection set is never empty");
167 assert!(newest < ranges.len(), "newest index out of bounds");
168 let mut set = Self { selections: Vec::new(), next_id: 0 };
169 for (i, &(anchor, head)) in ranges.iter().enumerate() {
171 if i != newest {
172 let id = set.mint();
173 set.selections.push(Selection::from_anchor(id, anchor, head));
174 }
175 }
176 let id = set.mint();
177 let (anchor, head) = ranges[newest];
178 set.selections.push(Selection::from_anchor(id, anchor, head));
179 set.normalize();
180 set
181 }
182
183 #[must_use]
185 pub fn all(&self) -> &[Selection] {
186 &self.selections
187 }
188
189 #[must_use]
191 pub fn len(&self) -> usize {
192 self.selections.len()
193 }
194
195 #[must_use]
198 pub fn is_empty(&self) -> bool {
199 false
200 }
201
202 #[must_use]
204 pub fn newest(&self) -> &Selection {
205 self.selections.iter().max_by_key(|s| s.id).expect("set is non-empty")
206 }
207
208 fn mint(&mut self) -> SelectionId {
210 let id = SelectionId(self.next_id);
211 self.next_id += 1;
212 id
213 }
214
215 pub fn add_caret(&mut self, offset: u32) {
217 let id = self.mint();
218 self.selections.push(Selection::caret(id, offset));
219 self.normalize();
220 }
221
222 pub fn add_selection(&mut self, anchor: u32, head: u32) {
224 let id = self.mint();
225 self.selections.push(Selection::from_anchor(id, anchor, head));
226 self.normalize();
227 }
228
229 pub fn set_single(&mut self, sel: Selection) {
232 self.selections = vec![sel];
233 }
234
235 pub fn collapse_to_newest(&mut self) {
238 let mut n = *self.newest();
239 n.collapse_to_head();
240 self.selections = vec![n];
241 }
242
243 pub fn collapse_to_primary(&mut self) {
247 let mut primary = *self.selections.iter().min_by_key(|s| s.id).expect("set is non-empty");
248 primary.collapse_to_head();
249 self.selections = vec![primary];
250 }
251
252 pub fn map_each(&mut self, mut f: impl FnMut(&mut Selection)) {
255 for s in &mut self.selections {
256 f(s);
257 }
258 self.normalize();
259 }
260
261 pub fn rebase(&mut self, patch: &Patch) {
267 thread_local! {
279 static SCRATCH: RefCell<RebaseScratch> =
280 const { RefCell::new((Vec::new(), Vec::new())) };
281 }
282 SCRATCH.with(|cell| {
283 let (queries, mapped) = &mut *cell.borrow_mut();
284 queries.clear();
285 for s in &self.selections {
286 if s.start == s.end {
287 queries.push((s.start, Bias::Right));
290 } else {
291 queries.push((s.start, Bias::Left));
292 queries.push((s.end, Bias::Right));
293 }
294 }
295 patch.map_many(&queries[..], mapped);
296 let mut mi = 0;
297 for s in &mut self.selections {
298 if s.start == s.end {
299 let o = mapped[mi];
300 mi += 1;
301 s.start = o;
302 s.end = o;
303 } else {
304 let (ns, ne) = (mapped[mi], mapped[mi + 1]);
305 mi += 2;
306 s.start = ns.min(ne);
307 s.end = ne.max(ns);
308 }
309 s.goal = None;
310 }
311 queries.clear(); });
313 self.normalize();
314 }
315
316 fn normalize(&mut self) {
323 self.selections.sort_by_key(|s| (s.start, s.end));
324 let mut w = 0;
331 for r in 1..self.selections.len() {
332 let s = self.selections[r];
333 if should_merge(&self.selections[w], &s) {
334 let prev = self.selections[w];
335 let newer = if s.id > prev.id { s } else { prev };
337 let dst = &mut self.selections[w];
338 dst.start = prev.start.min(s.start);
339 dst.end = prev.end.max(s.end);
340 dst.id = newer.id;
341 dst.reversed = newer.reversed;
342 dst.goal = newer.goal;
343 } else {
344 w += 1;
345 self.selections[w] = s;
346 }
347 }
348 self.selections.truncate(w + 1);
349 }
350}
351
352fn should_merge(a: &Selection, b: &Selection) -> bool {
354 debug_assert!(a.start <= b.start);
355 if b.start < a.end {
356 return true; }
358 if a.start == b.start {
359 return true; }
361 if b.start == a.end {
362 return a.is_empty() || b.is_empty();
364 }
365 false
366}
367
368#[cfg(test)]
369mod tests {
370 use super::*;
371 use crate::patch::Edit;
372
373 #[test]
374 fn head_tail_and_direction() {
375 let s = Selection::from_anchor(SelectionId(0), 2, 8);
376 assert_eq!((s.start(), s.end(), s.head(), s.tail()), (2, 8, 8, 2));
377 let r = Selection::from_anchor(SelectionId(0), 8, 2); assert_eq!((r.start(), r.end(), r.head(), r.tail()), (2, 8, 2, 8));
379 }
380
381 #[test]
382 fn set_head_flips_when_crossing_tail() {
383 let mut s = Selection::from_anchor(SelectionId(0), 5, 8); s.set_head(2); assert_eq!((s.start(), s.end(), s.head(), s.tail()), (2, 5, 2, 5));
386 }
387
388 #[test]
389 fn overlapping_selections_merge() {
390 let mut set = SelectionSet::new(0);
391 set.set_single(Selection::from_anchor(SelectionId(0), 0, 5));
392 set.add_selection(3, 9); assert_eq!(set.len(), 1);
394 assert_eq!((set.all()[0].start(), set.all()[0].end()), (0, 9));
395 }
396
397 #[test]
398 fn nonempty_touching_selections_do_not_merge() {
399 let mut set = SelectionSet::new(0);
400 set.set_single(Selection::from_anchor(SelectionId(0), 0, 3));
401 set.add_selection(3, 6); assert_eq!(set.len(), 2, "non-empty touching selections stay separate");
403 }
404
405 #[test]
406 fn caret_touching_a_boundary_merges() {
407 let mut set = SelectionSet::new(0);
408 set.set_single(Selection::from_anchor(SelectionId(0), 0, 3));
409 set.add_caret(3); assert_eq!(set.len(), 1);
411 }
412
413 #[test]
414 fn newest_wins_identity_on_merge() {
415 let mut set = SelectionSet::new(0);
416 set.set_single(Selection::from_anchor(SelectionId(0), 0, 5));
417 set.add_selection(3, 9); assert_eq!(set.all()[0].id, SelectionId(1));
419 }
420
421 #[test]
422 fn rebase_follows_an_insertion() {
423 let mut set = SelectionSet::new(0);
424 set.set_single(Selection::from_anchor(SelectionId(0), 5, 10));
425 let patch = Patch::single(Edit { old: 0..0, new: 0..3 });
427 set.rebase(&patch);
428 assert_eq!((set.all()[0].start(), set.all()[0].end()), (8, 13));
429 }
430
431 #[test]
432 fn rebase_collapses_a_selection_inside_a_deletion() {
433 let mut set = SelectionSet::new(0);
434 set.set_single(Selection::from_anchor(SelectionId(0), 3, 7));
435 let patch = Patch::single(Edit { old: 0..10, new: 0..0 });
437 set.rebase(&patch);
438 assert!(set.all()[0].is_empty());
439 assert_eq!(set.all()[0].start(), 0);
440 }
441
442 #[test]
443 fn from_ranges_installs_a_box_with_the_chosen_newest() {
444 let set = SelectionSet::from_ranges(&[(0, 3), (10, 13), (20, 23)], 2);
446 assert_eq!(set.len(), 3);
447 assert_eq!((set.newest().start(), set.newest().end()), (20, 23));
448 }
449
450 #[test]
451 fn collapse_to_primary_keeps_the_oldest_as_a_caret() {
452 let mut set = SelectionSet::new(0); set.add_selection(5, 9); set.add_caret(20); assert!(set.len() >= 2);
456 set.collapse_to_primary();
457 assert_eq!(set.len(), 1);
458 assert_eq!(set.all()[0].id, SelectionId(0), "the oldest cursor is kept");
459 assert!(set.all()[0].is_empty());
460 assert_eq!(set.all()[0].head(), 0);
461 }
462
463 #[test]
464 fn collapse_to_newest_keeps_one_caret() {
465 let mut set = SelectionSet::new(0);
466 set.add_selection(5, 9);
467 set.add_caret(20);
468 assert!(set.len() >= 2);
469 set.collapse_to_newest();
470 assert_eq!(set.len(), 1);
471 assert!(set.all()[0].is_empty());
472 }
473}