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() || first == last {
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 remove_n_at(&mut self.regions, first, last - first);
455 }
456
457 pub fn add_region(&mut self, region: SelRegion) {
480 let mut ix = self.search(region.min());
481 if ix == self.regions.len() {
482 self.regions.push(region);
483 self.last_inserted = self.regions.len() - 1;
484 return;
485 }
486 let mut region = region;
487 let mut end_ix = ix;
488 if self.regions[ix].min() <= region.min() {
489 if self.regions[ix].should_merge(region) {
490 region = self.regions[ix].merge_with(region);
491 } else {
492 ix += 1;
493 }
494 end_ix += 1;
495 }
496 while end_ix < self.regions.len() && region.should_merge(self.regions[end_ix]) {
497 region = self.regions[end_ix].merge_with(region);
498 end_ix += 1;
499 }
500 if ix == end_ix {
501 self.regions.insert(ix, region);
502 } else {
503 self.regions[ix] = region;
504 remove_n_at(&mut self.regions, ix + 1, end_ix - ix - 1);
505 }
506 self.last_inserted = ix;
507 }
508
509 pub fn add_range_distinct(&mut self, region: SelRegion) -> (usize, usize) {
517 let mut ix = self.search(region.min());
518
519 if ix < self.regions.len() && self.regions[ix].max() == region.min() {
520 ix += 1;
521 }
522
523 if ix < self.regions.len() {
524 let occ = &self.regions[ix];
526 let is_eq = occ.min() == region.min() && occ.max() == region.max();
527 let is_intersect_before = region.min() >= occ.min() && occ.max() > region.min();
528 if is_eq || is_intersect_before {
529 return (occ.min(), occ.max());
530 }
531 }
532
533 let mut last = self.search(region.max());
535 if last < self.regions.len() && self.regions[last].min() < region.max() {
536 last += 1;
537 }
538 remove_n_at(&mut self.regions, ix, last - ix);
539
540 if ix == self.regions.len() {
541 self.regions.push(region);
542 } else {
543 self.regions.insert(ix, region);
544 }
545
546 (self.regions[ix].min(), self.regions[ix].max())
547 }
548
549 pub fn apply_delta(&self, delta: &RopeDelta, after: bool, drift: InsertDrift) -> Selection {
556 let mut result = Selection::new();
557 let mut transformer = Transformer::new(delta);
558 for region in self.regions() {
559 let is_region_forward = region.start < region.end;
560
561 let (start_after, end_after) = match (drift, region.is_caret()) {
562 (InsertDrift::Inside, false) => (!is_region_forward, is_region_forward),
563 (InsertDrift::Outside, false) => (is_region_forward, !is_region_forward),
564 _ => (after, after),
565 };
566
567 let new_region = SelRegion::new(
568 transformer.transform(region.start, start_after),
569 transformer.transform(region.end, end_after),
570 region.affinity,
571 None,
572 );
573 result.add_region(new_region);
574 }
575 result
576 }
577
578 pub fn get_cursor_offset(&self) -> usize {
580 if self.is_empty() {
581 return 0;
582 }
583 self.regions[self.last_inserted].end
584 }
585
586 pub fn get_cursor_affinity(&self) -> CursorAffinity {
588 if self.is_empty() {
589 return CursorAffinity::Backward;
590 }
591 self.regions[self.last_inserted].affinity
592 }
593
594 pub fn replace_last_inserted_region(&mut self, region: SelRegion) {
596 if self.is_empty() {
597 self.add_region(region);
598 return;
599 }
600
601 self.regions.remove(self.last_inserted);
602 self.add_region(region);
603 }
604
605 fn search(&self, offset: usize) -> usize {
606 if self.regions.is_empty() || offset > self.regions.last().unwrap().max() {
607 return self.regions.len();
608 }
609 match self.regions.binary_search_by(|r| r.max().cmp(&offset)) {
610 Ok(ix) => ix,
611 Err(ix) => ix,
612 }
613 }
614
615 fn search_min(&self, offset: usize) -> usize {
616 if self.regions.is_empty() || offset > self.regions.last().unwrap().max() {
617 return self.regions.len();
618 }
619 match self
620 .regions
621 .binary_search_by(|r| r.min().cmp(&(offset + 1)))
622 {
623 Ok(ix) => ix,
624 Err(ix) => ix,
625 }
626 }
627}
628
629impl Default for Selection {
630 fn default() -> Self {
631 Self::new()
632 }
633}
634
635fn remove_n_at<T>(v: &mut Vec<T>, index: usize, n: usize) {
636 match n.cmp(&1) {
637 Ordering::Equal => {
638 v.remove(index);
639 }
640 Ordering::Greater => {
641 v.drain(index..index + n);
642 }
643 _ => (),
644 };
645}
646
647#[cfg(test)]
648mod test {
649 use crate::{
650 buffer::Buffer,
651 cursor::CursorAffinity,
652 editor::EditType,
653 selection::{InsertDrift, SelRegion, Selection},
654 };
655
656 #[test]
657 fn should_return_selection_region_min() {
658 let region = SelRegion::new(1, 10, CursorAffinity::Backward, None);
659 assert_eq!(region.min(), region.start);
660
661 let region = SelRegion::new(42, 1, CursorAffinity::Backward, None);
662 assert_eq!(region.min(), region.end);
663 }
664
665 #[test]
666 fn should_return_selection_region_max() {
667 let region = SelRegion::new(1, 10, CursorAffinity::Backward, None);
668 assert_eq!(region.max(), region.end);
669
670 let region = SelRegion::new(42, 1, CursorAffinity::Backward, None);
671 assert_eq!(region.max(), region.start);
672 }
673
674 #[test]
675 fn is_caret_should_return_true() {
676 let region = SelRegion::new(1, 10, CursorAffinity::Backward, None);
677 assert!(!region.is_caret());
678 }
679
680 #[test]
681 fn is_caret_should_return_false() {
682 let region = SelRegion::new(1, 1, CursorAffinity::Backward, None);
683 assert!(region.is_caret());
684 }
685
686 #[test]
687 fn should_merge_regions() {
688 let region = SelRegion::new(1, 2, CursorAffinity::Backward, None);
689 let other = SelRegion::new(3, 4, CursorAffinity::Backward, None);
690 assert_eq!(
691 region.merge_with(other),
692 SelRegion::new(1, 4, CursorAffinity::Backward, None)
693 );
694
695 let region = SelRegion::new(2, 1, CursorAffinity::Backward, None);
696 let other = SelRegion::new(4, 3, CursorAffinity::Backward, None);
697 assert_eq!(
698 region.merge_with(other),
699 SelRegion::new(4, 1, CursorAffinity::Backward, None)
700 );
701
702 let region = SelRegion::new(1, 1, CursorAffinity::Backward, None);
703 let other = SelRegion::new(6, 6, CursorAffinity::Backward, None);
704 assert_eq!(
705 region.merge_with(other),
706 SelRegion::new(1, 6, CursorAffinity::Backward, None)
707 );
708 }
709
710 #[test]
711 fn selection_should_be_caret() {
712 let mut selection = Selection::new();
713 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
714 selection.add_region(SelRegion::caret(6, CursorAffinity::Backward));
715 assert!(selection.is_caret());
716 }
717
718 #[test]
719 fn selection_should_not_be_caret() {
720 let mut selection = Selection::new();
721 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
722 selection.add_region(SelRegion::new(4, 6, CursorAffinity::Backward, None));
723 assert!(!selection.is_caret());
724 }
725
726 #[test]
727 fn should_return_min_selection() {
728 let mut selection = Selection::new();
729 selection.add_region(SelRegion::new(1, 3, CursorAffinity::Backward, None));
730 selection.add_region(SelRegion::new(4, 6, CursorAffinity::Backward, None));
731 assert_eq!(
732 selection.min().regions,
733 vec![
734 SelRegion::caret(1, CursorAffinity::Backward),
735 SelRegion::caret(4, CursorAffinity::Backward)
736 ]
737 );
738 }
739
740 #[test]
741 fn selection_should_contains_region() {
742 let selection = Selection::region(0, 2, CursorAffinity::Backward);
743 assert!(selection.contains(0));
744 assert!(selection.contains(1));
745 assert!(selection.contains(2));
746 assert!(!selection.contains(3));
747 }
748
749 #[test]
750 fn should_return_last_inserted_region() {
751 let mut selection = Selection::region(5, 6, CursorAffinity::Backward);
752 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
753 assert_eq!(
754 selection.last_inserted(),
755 Some(&SelRegion::caret(1, CursorAffinity::Backward))
756 );
757 }
758
759 #[test]
760 fn should_return_last_region() {
761 let mut selection = Selection::region(5, 6, CursorAffinity::Backward);
762 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
763 assert_eq!(
764 selection.last(),
765 Some(&SelRegion::new(5, 6, CursorAffinity::Backward, None))
766 );
767 }
768
769 #[test]
770 fn should_return_first_region() {
771 let mut selection = Selection::region(5, 6, CursorAffinity::Backward);
772 selection.add_region(SelRegion::caret(1, CursorAffinity::Backward));
773 assert_eq!(
774 selection.first(),
775 Some(&SelRegion::caret(1, CursorAffinity::Backward))
776 );
777 }
778
779 #[test]
780 fn should_return_regions_in_range() {
781 let mut selection = Selection::new();
782 selection.add_region(SelRegion::new(0, 3, CursorAffinity::Backward, None));
783 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
784 selection.add_region(SelRegion::new(7, 8, CursorAffinity::Backward, None));
785 selection.add_region(SelRegion::new(9, 11, CursorAffinity::Backward, None));
786
787 let regions = selection.regions_in_range(5, 10);
788
789 assert_eq!(
790 regions,
791 vec![
792 SelRegion::new(3, 6, CursorAffinity::Backward, None),
793 SelRegion::new(7, 8, CursorAffinity::Backward, None),
794 SelRegion::new(9, 11, CursorAffinity::Backward, None),
795 ]
796 );
797 }
798
799 #[test]
800 fn should_return_regions_in_full_range() {
801 let mut selection = Selection::new();
802 selection.add_region(SelRegion::new(0, 3, CursorAffinity::Backward, None));
803 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
804 selection.add_region(SelRegion::new(7, 8, CursorAffinity::Backward, None));
805 selection.add_region(SelRegion::new(9, 11, CursorAffinity::Backward, None));
806
807 let regions = selection.full_regions_in_range(5, 10);
808
809 assert_eq!(
810 regions,
811 vec![
812 SelRegion::new(7, 8, CursorAffinity::Backward, None),
813 SelRegion::new(9, 11, CursorAffinity::Backward, None),
814 ]
815 );
816 }
817
818 #[test]
819 fn should_delete_regions() {
820 let mut selection = Selection::new();
821 selection.add_region(SelRegion::new(0, 3, CursorAffinity::Backward, None));
822 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
823 selection.add_region(SelRegion::new(7, 8, CursorAffinity::Backward, None));
824 selection.add_region(SelRegion::new(9, 11, CursorAffinity::Backward, None));
825 selection.delete_range(5, 10);
826 assert_eq!(
827 selection.regions(),
828 vec![SelRegion::new(0, 3, CursorAffinity::Backward, None)]
829 );
830 }
831
832 #[test]
833 fn should_add_regions() {
834 let mut selection = Selection::new();
835 selection.add_region(SelRegion::new(0, 3, CursorAffinity::Backward, None));
836 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
837 assert_eq!(
838 selection.regions(),
839 vec![
840 SelRegion::new(0, 3, CursorAffinity::Backward, None),
841 SelRegion::new(3, 6, CursorAffinity::Backward, None),
842 ]
843 );
844 }
845
846 #[test]
847 fn should_add_and_merge_regions() {
848 let mut selection = Selection::new();
849
850 selection.add_region(SelRegion::new(0, 4, CursorAffinity::Backward, None));
851 selection.add_region(SelRegion::new(3, 6, CursorAffinity::Backward, None));
852 assert_eq!(
853 selection.regions(),
854 vec![SelRegion::new(0, 6, CursorAffinity::Backward, None)]
855 );
856 }
857
858 #[test]
859 fn should_apply_delta_after_insertion() {
860 let selection = Selection::caret(0, CursorAffinity::Backward);
861
862 let (_, mock_delta, _) = {
863 let mut buffer = Buffer::new("");
864 buffer.edit(&[(selection.clone(), "Hello")], EditType::InsertChars)
865 };
866
867 assert_eq!(
868 selection.apply_delta(&mock_delta, true, InsertDrift::Inside),
869 Selection::caret(5, CursorAffinity::Backward)
870 );
871 }
872}