1use std::cmp::{max, min, Ordering};
2
3use lapce_xi_rope::{RopeDelta, Transformer};
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use crate::cursor::{ColPosition, CursorAffinity};
8
9#[derive(Copy, Clone)]
12pub enum InsertDrift {
13 Inside,
15 Outside,
17 Default,
19}
20
21#[derive(Clone, Copy, PartialEq, Debug)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23pub struct SelRegion {
24 pub start: usize,
26 pub end: usize,
28 pub affinity: CursorAffinity,
30 pub horiz: Option<ColPosition>,
32}
33
34#[derive(Clone, PartialEq, Debug)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38pub struct Selection {
39 regions: Vec<SelRegion>,
40 last_inserted: usize,
41}
42
43impl AsRef<Selection> for Selection {
44 fn as_ref(&self) -> &Selection {
45 self
46 }
47}
48
49impl SelRegion {
50 pub fn new(
52 start: usize,
53 end: usize,
54 affinity: CursorAffinity,
55 horiz: Option<ColPosition>,
56 ) -> SelRegion {
57 SelRegion {
58 start,
59 end,
60 affinity,
61 horiz,
62 }
63 }
64
65 pub fn caret(offset: usize, affinity: CursorAffinity) -> SelRegion {
68 SelRegion {
69 start: offset,
70 end: offset,
71 affinity,
72 horiz: None,
73 }
74 }
75
76 pub(crate) fn imaginary_region(start: usize, end: usize) -> SelRegion {
78 SelRegion {
79 start,
80 end,
81 affinity: CursorAffinity::Backward,
82 horiz: None,
83 }
84 }
85
86 pub(crate) fn imaginary_caret(offset: usize) -> SelRegion {
89 SelRegion::imaginary_region(offset, offset)
90 }
91
92 pub fn min(self) -> usize {
105 min(self.start, self.end)
106 }
107
108 pub fn max(self) -> usize {
121 max(self.start, self.end)
122 }
123
124 pub fn is_caret(self) -> bool {
135 self.start == self.end
136 }
137
138 pub fn merge_with(self, other: SelRegion) -> SelRegion {
150 let is_forward = self.end >= self.start;
151 let new_min = min(self.min(), other.min());
152 let new_max = max(self.max(), other.max());
153 let (start, end) = if is_forward {
154 (new_min, new_max)
155 } else {
156 (new_max, new_min)
157 };
158 SelRegion::new(start, end, self.affinity, None)
159 }
160
161 fn should_merge(self, other: SelRegion) -> bool {
162 other.min() < self.max()
163 || ((self.is_caret() || other.is_caret()) && other.min() == self.max())
164 }
165
166 fn contains(&self, offset: usize) -> bool {
167 self.min() <= offset && offset <= self.max()
168 }
169}
170
171impl Selection {
172 pub fn new() -> Selection {
174 Selection {
175 regions: Vec::new(),
176 last_inserted: 0,
177 }
178 }
179
180 pub fn caret(offset: usize, affinity: CursorAffinity) -> Selection {
182 Selection {
183 regions: vec![SelRegion::caret(offset, affinity)],
184 last_inserted: 0,
185 }
186 }
187
188 pub fn region(start: usize, end: usize, affinity: CursorAffinity) -> Self {
191 Self::sel_region(SelRegion {
192 start,
193 end,
194 affinity,
195 horiz: None,
196 })
197 }
198
199 pub fn sel_region(region: SelRegion) -> Self {
201 Self {
202 regions: vec![region],
203 last_inserted: 0,
204 }
205 }
206
207 pub(crate) fn imaginary_region(start: usize, end: usize) -> Self {
209 Self::sel_region(SelRegion::imaginary_region(start, end))
210 }
211
212 pub(crate) fn imaginary_caret(offset: usize) -> Self {
214 Self::sel_region(SelRegion::imaginary_caret(offset))
215 }
216
217 pub fn contains(&self, offset: usize) -> bool {
231 for region in self.regions.iter() {
232 if region.contains(offset) {
233 return true;
234 }
235 }
236 false
237 }
238
239 pub fn regions(&self) -> &[SelRegion] {
241 &self.regions
242 }
243
244 pub fn regions_mut(&mut self) -> &mut [SelRegion] {
246 &mut self.regions
247 }
248
249 pub fn min(&self) -> Selection {
268 let mut selection = Self::new();
269 for region in &self.regions {
270 let new_region =
271 SelRegion::new(region.min(), region.min(), CursorAffinity::Backward, None);
272 selection.add_region(new_region);
273 }
274 selection
275 }
276
277 pub fn first(&self) -> Option<&SelRegion> {
279 self.regions.first()
280 }
281
282 pub fn last(&self) -> Option<&SelRegion> {
284 self.regions.get(self.len() - 1)
285 }
286
287 pub fn last_inserted(&self) -> Option<&SelRegion> {
289 self.regions.get(self.last_inserted)
290 }
291
292 pub fn last_inserted_mut(&mut self) -> Option<&mut SelRegion> {
294 self.regions.get_mut(self.last_inserted)
295 }
296
297 pub fn len(&self) -> usize {
299 self.regions.len()
300 }
301
302 pub fn is_caret(&self) -> bool {
305 self.regions.iter().all(|region| region.is_caret())
306 }
307
308 pub fn current_caret(&self) -> Option<usize> {
309 if self.regions.len() == 1 {
310 if self.regions[0].is_caret() {
311 Some(self.regions[0].start)
312 } else {
313 None
314 }
315 } else {
316 None
317 }
318 }
319
320 pub fn is_empty(&self) -> bool {
322 self.len() == 0
323 }
324
325 pub fn min_offset(&self) -> usize {
341 let mut offset = self.regions()[0].min();
342 for region in &self.regions {
343 offset = offset.min(region.min());
344 }
345 offset
346 }
347
348 pub fn max_offset(&self) -> usize {
364 let mut offset = self.regions()[0].max();
365 for region in &self.regions {
366 offset = offset.max(region.max());
367 }
368 offset
369 }
370
371 pub fn regions_in_range(&self, start: usize, end: usize) -> &[SelRegion] {
392 let first = self.search(start);
393 let mut last = self.search(end);
394 if last < self.regions.len() && self.regions[last].min() <= end {
395 last += 1;
396 }
397 &self.regions[first..last]
398 }
399
400 pub fn full_regions_in_range(&self, start: usize, end: usize) -> &[SelRegion] {
419 let first = self.search_min(start);
420 let mut last = self.search_min(end);
421 if last < self.regions.len() && self.regions[last].min() <= end {
422 last += 1;
423 }
424 &self.regions[first..last]
425 }
426
427 pub fn delete_range(&mut self, start: usize, end: usize) {
443 let mut first = self.search(start);
444 let mut last = self.search(end);
445 if first >= self.regions.len() {
446 return;
447 }
448 if self.regions[first].max() == start {
449 first += 1;
450 }
451 if last < self.regions.len() && self.regions[last].min() < end {
452 last += 1;
453 }
454 if first > last {
455 return;
456 }
457 let count = last - first;
458
459 remove_n_at(&mut self.regions, first, last - first);
460
461 if self.last_inserted >= last {
462 self.last_inserted -= count;
463 } else if self.last_inserted >= first {
464 self.last_inserted = first.saturating_sub(1);
465 }
466 }
467
468 pub fn add_region(&mut self, region: SelRegion) {
491 let mut ix = self.search(region.min());
492 if ix == self.regions.len() {
493 self.regions.push(region);
494 self.last_inserted = self.regions.len() - 1;
495 return;
496 }
497 let mut region = region;
498 let mut end_ix = ix;
499 if self.regions[ix].min() <= region.min() {
500 if self.regions[ix].should_merge(region) {
501 region = self.regions[ix].merge_with(region);
502 } else {
503 ix += 1;
504 }
505 end_ix += 1;
506 }
507 while end_ix < self.regions.len() && region.should_merge(self.regions[end_ix]) {
508 region = self.regions[end_ix].merge_with(region);
509 end_ix += 1;
510 }
511 if ix == end_ix {
512 self.regions.insert(ix, region);
513 } else {
514 self.regions[ix] = region;
515 remove_n_at(&mut self.regions, ix + 1, end_ix - ix - 1);
516 }
517 self.last_inserted = ix;
518 }
519
520 pub fn add_range_distinct(&mut self, region: SelRegion) -> (usize, usize) {
528 let mut ix = self.search(region.min());
529
530 if ix < self.regions.len() && self.regions[ix].max() == region.min() {
531 ix += 1;
532 }
533
534 if ix < self.regions.len() {
535 let occ = &self.regions[ix];
537 let is_eq = occ.min() == region.min() && occ.max() == region.max();
538 let is_intersect_before = region.min() >= occ.min() && occ.max() > region.min();
539 if is_eq || is_intersect_before {
540 return (occ.min(), occ.max());
541 }
542 }
543
544 let mut last = self.search(region.max());
546 if last < self.regions.len() && self.regions[last].min() < region.max() {
547 last += 1;
548 }
549 remove_n_at(&mut self.regions, ix, last - ix);
550
551 if ix == self.regions.len() {
552 self.regions.push(region);
553 } else {
554 self.regions.insert(ix, region);
555 }
556
557 (self.regions[ix].min(), self.regions[ix].max())
558 }
559
560 pub fn apply_delta(&self, delta: &RopeDelta, after: bool, drift: InsertDrift) -> Selection {
567 let mut result = Selection::new();
568 let mut transformer = Transformer::new(delta);
569 for region in self.regions() {
570 let is_region_forward = region.start < region.end;
571
572 let (start_after, end_after) = match (drift, region.is_caret()) {
573 (InsertDrift::Inside, false) => (!is_region_forward, is_region_forward),
574 (InsertDrift::Outside, false) => (is_region_forward, !is_region_forward),
575 _ => (after, after),
576 };
577
578 let new_region = SelRegion::new(
579 transformer.transform(region.start, start_after),
580 transformer.transform(region.end, end_after),
581 region.affinity,
582 None,
583 );
584 result.add_region(new_region);
585 }
586 result
587 }
588
589 pub fn get_cursor_offset(&self) -> usize {
591 if self.is_empty() {
592 return 0;
593 }
594 self.regions[self.last_inserted].end
595 }
596
597 pub fn get_cursor_affinity(&self) -> CursorAffinity {
599 if self.is_empty() {
600 return CursorAffinity::Backward;
601 }
602 self.regions[self.last_inserted].affinity
603 }
604
605 pub fn replace_last_inserted_region(&mut self, region: SelRegion) {
607 if self.is_empty() {
608 self.add_region(region);
609 return;
610 }
611
612 self.regions.remove(self.last_inserted);
613 self.add_region(region);
614 }
615
616 fn search(&self, offset: usize) -> usize {
617 if self.regions.is_empty() || offset > self.regions.last().unwrap().max() {
618 return self.regions.len();
619 }
620 match self.regions.binary_search_by(|r| r.max().cmp(&offset)) {
621 Ok(ix) => ix,
622 Err(ix) => ix,
623 }
624 }
625
626 fn search_min(&self, offset: usize) -> usize {
627 if self.regions.is_empty() || offset > self.regions.last().unwrap().max() {
628 return self.regions.len();
629 }
630 match self
631 .regions
632 .binary_search_by(|r| r.min().cmp(&(offset + 1)))
633 {
634 Ok(ix) => ix,
635 Err(ix) => ix,
636 }
637 }
638}
639
640impl Default for Selection {
641 fn default() -> Self {
642 Self::new()
643 }
644}
645
646fn remove_n_at<T>(v: &mut Vec<T>, index: usize, n: usize) {
647 match n.cmp(&1) {
648 Ordering::Equal => {
649 v.remove(index);
650 }
651 Ordering::Greater => {
652 v.drain(index..index + n);
653 }
654 _ => (),
655 };
656}
657
658#[cfg(test)]
659mod test {
660 use crate::{
661 buffer::Buffer,
662 cursor::CursorAffinity,
663 editor::EditType,
664 selection::{InsertDrift, SelRegion, Selection},
665 };
666
667 #[test]
668 fn should_return_selection_region_min() {
669 let region = SelRegion::new(1, 10, CursorAffinity::Backward, None);
670 assert_eq!(region.min(), region.start);
671
672 let region = SelRegion::new(42, 1, CursorAffinity::Backward, None);
673 assert_eq!(region.min(), region.end);
674 }
675
676 #[test]
677 fn should_return_selection_region_max() {
678 let region = SelRegion::new(1, 10, CursorAffinity::Backward, None);
679 assert_eq!(region.max(), region.end);
680
681 let region = SelRegion::new(42, 1, CursorAffinity::Backward, None);
682 assert_eq!(region.max(), region.start);
683 }
684
685 #[test]
686 fn is_caret_should_return_true() {
687 let region = SelRegion::new(1, 10, CursorAffinity::Backward, None);
688 assert!(!region.is_caret());
689 }
690
691 #[test]
692 fn is_caret_should_return_false() {
693 let region = SelRegion::new(1, 1, CursorAffinity::Backward, None);
694 assert!(region.is_caret());
695 }
696
697 #[test]
698 fn should_merge_regions() {
699 let region = SelRegion::new(1, 2, CursorAffinity::Backward, None);
700 let other = SelRegion::new(3, 4, CursorAffinity::Backward, None);
701 assert_eq!(
702 region.merge_with(other),
703 SelRegion::new(1, 4, CursorAffinity::Backward, None)
704 );
705
706 let region = SelRegion::new(2, 1, CursorAffinity::Backward, None);
707 let other = SelRegion::new(4, 3, CursorAffinity::Backward, None);
708 assert_eq!(
709 region.merge_with(other),
710 SelRegion::new(4, 1, CursorAffinity::Backward, None)
711 );
712
713 let region = SelRegion::new(1, 1, CursorAffinity::Backward, None);
714 let other = SelRegion::new(6, 6, CursorAffinity::Backward, None);
715 assert_eq!(
716 region.merge_with(other),
717 SelRegion::new(1, 6, CursorAffinity::Backward, None)
718 );
719 }
720
721 #[test]
722 fn selection_should_be_caret() {
723 let mut selection = Selection::new();
724 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
725 selection.add_region(SelRegion::caret(6, CursorAffinity::Backward));
726 assert!(selection.is_caret());
727 }
728
729 #[test]
730 fn selection_should_not_be_caret() {
731 let mut selection = Selection::new();
732 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
733 selection.add_region(SelRegion::new(4, 6, CursorAffinity::Backward, None));
734 assert!(!selection.is_caret());
735 }
736
737 #[test]
738 fn should_return_min_selection() {
739 let mut selection = Selection::new();
740 selection.add_region(SelRegion::new(1, 3, CursorAffinity::Backward, None));
741 selection.add_region(SelRegion::new(4, 6, CursorAffinity::Backward, None));
742 assert_eq!(
743 selection.min().regions,
744 vec![
745 SelRegion::caret(1, CursorAffinity::Backward),
746 SelRegion::caret(4, CursorAffinity::Backward)
747 ]
748 );
749 }
750
751 #[test]
752 fn selection_should_contains_region() {
753 let selection = Selection::region(0, 2, CursorAffinity::Backward);
754 assert!(selection.contains(0));
755 assert!(selection.contains(1));
756 assert!(selection.contains(2));
757 assert!(!selection.contains(3));
758 }
759
760 #[test]
761 fn should_return_last_inserted_region() {
762 let mut selection = Selection::region(5, 6, CursorAffinity::Backward);
763 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
764 assert_eq!(
765 selection.last_inserted(),
766 Some(&SelRegion::caret(1, CursorAffinity::Backward))
767 );
768 }
769
770 #[test]
771 fn should_return_last_region() {
772 let mut selection = Selection::region(5, 6, CursorAffinity::Backward);
773 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
774 assert_eq!(
775 selection.last(),
776 Some(&SelRegion::new(5, 6, CursorAffinity::Backward, None))
777 );
778 }
779
780 #[test]
781 fn should_return_first_region() {
782 let mut selection = Selection::region(5, 6, CursorAffinity::Backward);
783 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
784 assert_eq!(
785 selection.first(),
786 Some(&SelRegion::caret(1, CursorAffinity::Backward))
787 );
788 }
789
790 #[test]
791 fn should_return_regions_in_range() {
792 let mut selection = Selection::new();
793 selection.add_region(SelRegion::new(0, 3, CursorAffinity::Backward, None));
794 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
795 selection.add_region(SelRegion::new(7, 8, CursorAffinity::Backward, None));
796 selection.add_region(SelRegion::new(9, 11, CursorAffinity::Backward, None));
797
798 let regions = selection.regions_in_range(5, 10);
799
800 assert_eq!(
801 regions,
802 vec![
803 SelRegion::new(3, 6, CursorAffinity::Backward, None),
804 SelRegion::new(7, 8, CursorAffinity::Backward, None),
805 SelRegion::new(9, 11, CursorAffinity::Backward, None),
806 ]
807 );
808 }
809
810 #[test]
811 fn should_return_regions_in_full_range() {
812 let mut selection = Selection::new();
813 selection.add_region(SelRegion::new(0, 3, CursorAffinity::Backward, None));
814 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
815 selection.add_region(SelRegion::new(7, 8, CursorAffinity::Backward, None));
816 selection.add_region(SelRegion::new(9, 11, CursorAffinity::Backward, None));
817
818 let regions = selection.full_regions_in_range(5, 10);
819
820 assert_eq!(
821 regions,
822 vec![
823 SelRegion::new(7, 8, CursorAffinity::Backward, None),
824 SelRegion::new(9, 11, CursorAffinity::Backward, None),
825 ]
826 );
827 }
828
829 #[test]
830 fn should_delete_regions() {
831 let mut selection = Selection::new();
832 selection.add_region(SelRegion::new(0, 3, CursorAffinity::Backward, None));
833 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
834 selection.add_region(SelRegion::new(7, 8, CursorAffinity::Backward, None));
835 selection.add_region(SelRegion::new(9, 11, CursorAffinity::Backward, None));
836 selection.delete_range(5, 10);
837 assert_eq!(
838 selection.regions(),
839 vec![SelRegion::new(0, 3, CursorAffinity::Backward, None)]
840 );
841 }
842
843 #[test]
844 fn should_add_regions() {
845 let mut selection = Selection::new();
846 selection.add_region(SelRegion::new(0, 3, CursorAffinity::Backward, None));
847 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
848 assert_eq!(
849 selection.regions(),
850 vec![
851 SelRegion::new(0, 3, CursorAffinity::Backward, None),
852 SelRegion::new(3, 6, CursorAffinity::Backward, None),
853 ]
854 );
855 }
856
857 #[test]
858 fn should_add_and_merge_regions() {
859 let mut selection = Selection::new();
860
861 selection.add_region(SelRegion::new(0, 4, CursorAffinity::Backward, None));
862 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
863 assert_eq!(
864 selection.regions(),
865 vec![SelRegion::new(0, 6, CursorAffinity::Backward, None)]
866 );
867 }
868
869 #[test]
870 fn should_apply_delta_after_insertion() {
871 let selection = Selection::caret(0, CursorAffinity::Backward);
872
873 let (_, mock_delta, _) = {
874 let mut buffer = Buffer::new("");
875 buffer.edit(&[(selection.clone(), "Hello")], EditType::InsertChars)
876 };
877
878 assert_eq!(
879 selection.apply_delta(&mock_delta, true, InsertDrift::Inside),
880 Selection::caret(5, CursorAffinity::Backward)
881 );
882 }
883}