floem_editor_core/
selection.rs

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;
8
9/// Indicate whether a delta should be applied inside, outside non-caret selection or
10/// after a caret selection (see [`Selection::apply_delta`].
11#[derive(Copy, Clone)]
12pub enum InsertDrift {
13    /// Indicates this edit should happen within any (non-caret) selections if possible.
14    Inside,
15    /// Indicates this edit should happen outside any selections if possible.
16    Outside,
17    /// Indicates to do whatever the `after` bool says to do
18    Default,
19}
20
21#[derive(Clone, Copy, PartialEq, Debug)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23pub struct SelRegion {
24    /// Region start offset
25    pub start: usize,
26    /// Region end offset
27    pub end: usize,
28    /// Horizontal rules for multiple selection
29    pub horiz: Option<ColPosition>,
30}
31
32/// A selection holding one or more [`SelRegion`].
33/// Regions are kept in order from the leftmost selection to the rightmost selection.
34#[derive(Clone, PartialEq, Debug)]
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36pub struct Selection {
37    regions: Vec<SelRegion>,
38    last_inserted: usize,
39}
40
41impl AsRef<Selection> for Selection {
42    fn as_ref(&self) -> &Selection {
43        self
44    }
45}
46
47impl SelRegion {
48    /// Creates new [`SelRegion`] from `start` and `end` offset.
49    pub fn new(start: usize, end: usize, horiz: Option<ColPosition>) -> SelRegion {
50        SelRegion { start, end, horiz }
51    }
52
53    /// Creates a caret [`SelRegion`],
54    /// i.e. `start` and `end` position are both set to `offset` value.
55    pub fn caret(offset: usize) -> SelRegion {
56        SelRegion {
57            start: offset,
58            end: offset,
59            horiz: None,
60        }
61    }
62
63    /// Return the minimum value between region's start and end position
64    ///
65    /// **Example:**
66    ///
67    /// ```rust
68    /// # use floem_editor_core::selection::SelRegion;
69    /// let  region = SelRegion::new(1, 10, None);
70    /// assert_eq!(region.min(), region.start);
71    /// let  region = SelRegion::new(42, 1, None);
72    /// assert_eq!(region.min(), region.end);
73    /// ```
74    pub fn min(self) -> usize {
75        min(self.start, self.end)
76    }
77
78    /// Return the maximum value between region's start and end position.
79    ///
80    /// **Example:**
81    ///
82    /// ```rust
83    /// # use floem_editor_core::selection::SelRegion;
84    /// let  region = SelRegion::new(1, 10, None);
85    /// assert_eq!(region.max(), region.end);
86    /// let  region = SelRegion::new(42, 1, None);
87    /// assert_eq!(region.max(), region.start);
88    /// ```
89    pub fn max(self) -> usize {
90        max(self.start, self.end)
91    }
92
93    /// A [`SelRegion`] is considered to be a caret when its start and end position are equal.
94    ///
95    /// **Example:**
96    ///
97    /// ```rust
98    /// # use floem_editor_core::selection::SelRegion;
99    /// let  region = SelRegion::new(1, 1, None);
100    /// assert!(region.is_caret());
101    /// ```
102    pub fn is_caret(self) -> bool {
103        self.start == self.end
104    }
105
106    /// Merge two [`SelRegion`] into a single one.
107    ///
108    /// **Example:**
109    ///
110    /// ```rust
111    /// # use floem_editor_core::selection::SelRegion;
112    /// let  region = SelRegion::new(1, 2, None);
113    /// let  other = SelRegion::new(3, 4, None);
114    /// assert_eq!(region.merge_with(other), SelRegion::new(1, 4, None));
115    /// ```
116    pub fn merge_with(self, other: SelRegion) -> SelRegion {
117        let is_forward = self.end >= self.start;
118        let new_min = min(self.min(), other.min());
119        let new_max = max(self.max(), other.max());
120        let (start, end) = if is_forward {
121            (new_min, new_max)
122        } else {
123            (new_max, new_min)
124        };
125        SelRegion::new(start, end, None)
126    }
127
128    fn should_merge(self, other: SelRegion) -> bool {
129        other.min() < self.max()
130            || ((self.is_caret() || other.is_caret()) && other.min() == self.max())
131    }
132
133    fn contains(&self, offset: usize) -> bool {
134        self.min() <= offset && offset <= self.max()
135    }
136}
137
138impl Selection {
139    /// Creates a new empty [`Selection`]
140    pub fn new() -> Selection {
141        Selection {
142            regions: Vec::new(),
143            last_inserted: 0,
144        }
145    }
146
147    /// Creates a caret [`Selection`], i.e. a selection with a single caret [`SelRegion`]
148    pub fn caret(offset: usize) -> Selection {
149        Selection {
150            regions: vec![SelRegion::caret(offset)],
151            last_inserted: 0,
152        }
153    }
154
155    /// Creates a region [`Selection`], i.e. a selection with a single [`SelRegion`]
156    /// from `start` to `end` position
157    pub fn region(start: usize, end: usize) -> Self {
158        Self::sel_region(SelRegion {
159            start,
160            end,
161            horiz: None,
162        })
163    }
164
165    /// Creates a [`Selection`], with a single [`SelRegion`] equal to `region`.
166    pub fn sel_region(region: SelRegion) -> Self {
167        Self {
168            regions: vec![region],
169            last_inserted: 0,
170        }
171    }
172
173    /// Returns whether this [`Selection`], contains the given `offset` position or not.
174    ///
175    /// **Example:**
176    ///
177    /// ```rust
178    /// # use floem_editor_core::selection::Selection;
179    /// let  selection = Selection::region(0, 2);
180    /// assert!(selection.contains(0));
181    /// assert!(selection.contains(1));
182    /// assert!(selection.contains(2));
183    /// assert!(!selection.contains(3));
184    /// ```
185    pub fn contains(&self, offset: usize) -> bool {
186        for region in self.regions.iter() {
187            if region.contains(offset) {
188                return true;
189            }
190        }
191        false
192    }
193
194    /// Returns this selection regions
195    pub fn regions(&self) -> &[SelRegion] {
196        &self.regions
197    }
198
199    /// Returns a mutable reference to this selection regions
200    pub fn regions_mut(&mut self) -> &mut [SelRegion] {
201        &mut self.regions
202    }
203
204    /// Returns a copy of [`self`] with all regions converted to caret region at their respective
205    /// [`SelRegion::min`] offset.
206    ///
207    /// **Examples:**
208    ///
209    /// ```rust
210    /// # use floem_editor_core::selection::{Selection, SelRegion};
211    /// let mut selection = Selection::new();
212    /// selection.add_region(SelRegion::new(1, 3, None));
213    /// selection.add_region(SelRegion::new(6, 12, None));
214    /// selection.add_region(SelRegion::new(24, 48, None));
215    ///
216    /// assert_eq!(selection.min().regions(), vec![
217    ///     SelRegion::caret(1),
218    ///     SelRegion::caret(6),
219    ///     SelRegion::caret(24)
220    /// ]);
221    pub fn min(&self) -> Selection {
222        let mut selection = Self::new();
223        for region in &self.regions {
224            let new_region = SelRegion::new(region.min(), region.min(), None);
225            selection.add_region(new_region);
226        }
227        selection
228    }
229
230    /// Get the leftmost [`SelRegion`] in this selection if present.
231    pub fn first(&self) -> Option<&SelRegion> {
232        self.regions.first()
233    }
234
235    /// Get the rightmost [`SelRegion`] in this selection if present.
236    pub fn last(&self) -> Option<&SelRegion> {
237        self.regions.get(self.len() - 1)
238    }
239
240    /// Get the last inserted [`SelRegion`] in this selection if present.
241    pub fn last_inserted(&self) -> Option<&SelRegion> {
242        self.regions.get(self.last_inserted)
243    }
244
245    /// Get a mutable reference to the last inserted [`SelRegion`] in this selection if present.
246    pub fn last_inserted_mut(&mut self) -> Option<&mut SelRegion> {
247        self.regions.get_mut(self.last_inserted)
248    }
249
250    /// The number of [`SelRegion`] in this selection.
251    pub fn len(&self) -> usize {
252        self.regions.len()
253    }
254
255    /// A [`Selection`] is considered to be a caret if it contains
256    /// only caret [`SelRegion`] (see [`SelRegion::is_caret`])
257    pub fn is_caret(&self) -> bool {
258        self.regions.iter().all(|region| region.is_caret())
259    }
260
261    pub fn current_caret(&self) -> Option<usize> {
262        if self.regions.len() == 1 {
263            if self.regions[0].is_caret() {
264                Some(self.regions[0].start)
265            } else {
266                None
267            }
268        } else {
269            None
270        }
271    }
272
273    /// Returns `true` if `self` has zero [`SelRegion`]
274    pub fn is_empty(&self) -> bool {
275        self.len() == 0
276    }
277
278    /// Returns the minimal offset across all region of this selection.
279    ///
280    /// This function panics if the selection is empty.
281    ///
282    /// **Example:**
283    ///
284    /// ```rust
285    /// # use floem_editor_core::selection::{Selection, SelRegion};
286    /// let mut selection = Selection::new();
287    /// selection.add_region(SelRegion::caret(4));
288    /// selection.add_region(SelRegion::new(0, 12, None));
289    /// selection.add_region(SelRegion::new(24, 48, None));
290    /// assert_eq!(selection.min_offset(), 0);
291    /// ```
292    pub fn min_offset(&self) -> usize {
293        let mut offset = self.regions()[0].min();
294        for region in &self.regions {
295            offset = offset.min(region.min());
296        }
297        offset
298    }
299
300    /// Returns the maximal offset across all region of this selection.
301    ///
302    /// This function panics if the selection is empty.
303    ///
304    /// **Example:**
305    ///
306    /// ```rust
307    /// # use floem_editor_core::selection::{Selection, SelRegion};
308    /// let mut selection = Selection::new();
309    /// selection.add_region(SelRegion::caret(4));
310    /// selection.add_region(SelRegion::new(0, 12, None));
311    /// selection.add_region(SelRegion::new(24, 48, None));
312    /// assert_eq!(selection.max_offset(), 48);
313    /// ```
314    pub fn max_offset(&self) -> usize {
315        let mut offset = self.regions()[0].max();
316        for region in &self.regions {
317            offset = offset.max(region.max());
318        }
319        offset
320    }
321
322    /// Returns regions in [`self`] overlapping or fully enclosed in the provided
323    /// `start` to `end` range.
324    ///
325    /// **Example:**
326    ///
327    /// ```rust
328    /// # use floem_editor_core::selection::{Selection, SelRegion};
329    /// let mut selection = Selection::new();
330    /// selection.add_region(SelRegion::new(0, 3, None));
331    /// selection.add_region(SelRegion::new(3, 6, None));
332    /// selection.add_region(SelRegion::new(7, 8, None));
333    /// selection.add_region(SelRegion::new(9, 11, None));
334    /// let regions = selection.regions_in_range(5, 10);
335    /// assert_eq!(regions, vec![
336    ///     SelRegion::new(3, 6, None),
337    ///     SelRegion::new(7, 8, None),
338    ///     SelRegion::new(9, 11, None)
339    /// ]);
340    /// ```
341    pub fn regions_in_range(&self, start: usize, end: usize) -> &[SelRegion] {
342        let first = self.search(start);
343        let mut last = self.search(end);
344        if last < self.regions.len() && self.regions[last].min() <= end {
345            last += 1;
346        }
347        &self.regions[first..last]
348    }
349
350    /// Returns regions in [`self`] starting between `start` to `end` range.
351    ///
352    /// **Example:**
353    ///
354    /// ```rust
355    /// # use floem_editor_core::selection::{Selection, SelRegion};
356    /// let mut selection = Selection::new();
357    /// selection.add_region(SelRegion::new(0, 3, None));
358    /// selection.add_region(SelRegion::new(3, 6, None));
359    /// selection.add_region(SelRegion::new(7, 8, None));
360    /// selection.add_region(SelRegion::new(9, 11, None));
361    /// let regions = selection.full_regions_in_range(5, 10);
362    /// assert_eq!(regions, vec![
363    ///     SelRegion::new(7, 8, None),
364    ///     SelRegion::new(9, 11, None)
365    /// ]);
366    /// ```
367    pub fn full_regions_in_range(&self, start: usize, end: usize) -> &[SelRegion] {
368        let first = self.search_min(start);
369        let mut last = self.search_min(end);
370        if last < self.regions.len() && self.regions[last].min() <= end {
371            last += 1;
372        }
373        &self.regions[first..last]
374    }
375
376    /// Deletes regions in [`self`] overlapping or enclosing in `start` to `end` range.
377    ///
378    /// **Example:**
379    ///
380    /// ```rust
381    /// # use floem_editor_core::selection::{Selection, SelRegion};
382    /// let mut selection = Selection::new();
383    /// selection.add_region(SelRegion::new(0, 3, None));
384    /// selection.add_region(SelRegion::new(3, 6, None));
385    /// selection.add_region(SelRegion::new(7, 8, None));
386    /// selection.add_region(SelRegion::new(9, 11, None));
387    /// selection.delete_range(5, 10);
388    /// assert_eq!(selection.regions(), vec![SelRegion::new(0, 3, None)]);
389    /// ```
390    pub fn delete_range(&mut self, start: usize, end: usize) {
391        let mut first = self.search(start);
392        let mut last = self.search(end);
393        if first >= self.regions.len() {
394            return;
395        }
396        if self.regions[first].max() == start {
397            first += 1;
398        }
399        if last < self.regions.len() && self.regions[last].min() < end {
400            last += 1;
401        }
402        remove_n_at(&mut self.regions, first, last - first);
403    }
404
405    /// Add a regions to [`self`]. Note that if provided region overlap
406    /// on of the selection regions they will be merged in a single region.
407    ///
408    /// **Example:**
409    ///
410    /// ```rust
411    /// # use floem_editor_core::selection::{Selection, SelRegion};
412    /// let mut selection = Selection::new();
413    /// // Overlapping
414    /// selection.add_region(SelRegion::new(0, 4, None));
415    /// selection.add_region(SelRegion::new(3, 6, None));
416    /// assert_eq!(selection.regions(), vec![SelRegion::new(0, 6, None)]);
417    /// // Non-overlapping
418    /// let mut selection = Selection::new();
419    /// selection.add_region(SelRegion::new(0, 3, None));
420    /// selection.add_region(SelRegion::new(3, 6, None));
421    /// assert_eq!(selection.regions(), vec![
422    ///     SelRegion::new(0, 3, None),
423    ///     SelRegion::new(3, 6, None)
424    /// ]);
425    /// ```
426    pub fn add_region(&mut self, region: SelRegion) {
427        let mut ix = self.search(region.min());
428        if ix == self.regions.len() {
429            self.regions.push(region);
430            self.last_inserted = self.regions.len() - 1;
431            return;
432        }
433        let mut region = region;
434        let mut end_ix = ix;
435        if self.regions[ix].min() <= region.min() {
436            if self.regions[ix].should_merge(region) {
437                region = self.regions[ix].merge_with(region);
438            } else {
439                ix += 1;
440            }
441            end_ix += 1;
442        }
443        while end_ix < self.regions.len() && region.should_merge(self.regions[end_ix]) {
444            region = self.regions[end_ix].merge_with(region);
445            end_ix += 1;
446        }
447        if ix == end_ix {
448            self.regions.insert(ix, region);
449            self.last_inserted = ix;
450        } else {
451            self.regions[ix] = region;
452            remove_n_at(&mut self.regions, ix + 1, end_ix - ix - 1);
453        }
454    }
455
456    /// Add a region to the selection. This method does not merge regions and does not allow
457    /// ambiguous regions (regions that overlap).
458    ///
459    /// On ambiguous regions, the region with the lower start position wins. That is, in such a
460    /// case, the new region is either not added at all, because there is an ambiguous region with
461    /// a lower start position, or existing regions that intersect with the new region but do
462    /// not start before the new region, are deleted.
463    pub fn add_range_distinct(&mut self, region: SelRegion) -> (usize, usize) {
464        let mut ix = self.search(region.min());
465
466        if ix < self.regions.len() && self.regions[ix].max() == region.min() {
467            ix += 1;
468        }
469
470        if ix < self.regions.len() {
471            // in case of ambiguous regions the region closer to the left wins
472            let occ = &self.regions[ix];
473            let is_eq = occ.min() == region.min() && occ.max() == region.max();
474            let is_intersect_before = region.min() >= occ.min() && occ.max() > region.min();
475            if is_eq || is_intersect_before {
476                return (occ.min(), occ.max());
477            }
478        }
479
480        // delete ambiguous regions to the right
481        let mut last = self.search(region.max());
482        if last < self.regions.len() && self.regions[last].min() < region.max() {
483            last += 1;
484        }
485        remove_n_at(&mut self.regions, ix, last - ix);
486
487        if ix == self.regions.len() {
488            self.regions.push(region);
489        } else {
490            self.regions.insert(ix, region);
491        }
492
493        (self.regions[ix].min(), self.regions[ix].max())
494    }
495
496    /// Apply [`lapce_xi_rope::RopeDelta`] to this selection.
497    /// Typically used to apply an edit to a buffer and update its selections
498    /// **Parameters*:*
499    /// - `delta`[`lapce_xi_rope::RopeDelta`]
500    /// - `after` parameter indicate if the delta should be applied before or after the selection
501    /// - `drift` see [`InsertDrift`]
502    pub fn apply_delta(&self, delta: &RopeDelta, after: bool, drift: InsertDrift) -> Selection {
503        let mut result = Selection::new();
504        let mut transformer = Transformer::new(delta);
505        for region in self.regions() {
506            let is_region_forward = region.start < region.end;
507
508            let (start_after, end_after) = match (drift, region.is_caret()) {
509                (InsertDrift::Inside, false) => (!is_region_forward, is_region_forward),
510                (InsertDrift::Outside, false) => (is_region_forward, !is_region_forward),
511                _ => (after, after),
512            };
513
514            let new_region = SelRegion::new(
515                transformer.transform(region.start, start_after),
516                transformer.transform(region.end, end_after),
517                None,
518            );
519            result.add_region(new_region);
520        }
521        result
522    }
523
524    /// Returns cursor position, which corresponds to last inserted region `end` offset,
525    pub fn get_cursor_offset(&self) -> usize {
526        if self.is_empty() {
527            return 0;
528        }
529        self.regions[self.last_inserted].end
530    }
531
532    /// Replaces last inserted [`SelRegion`] of this selection with the provided one.
533    pub fn replace_last_inserted_region(&mut self, region: SelRegion) {
534        if self.is_empty() {
535            self.add_region(region);
536            return;
537        }
538
539        self.regions.remove(self.last_inserted);
540        self.add_region(region);
541    }
542
543    fn search(&self, offset: usize) -> usize {
544        if self.regions.is_empty() || offset > self.regions.last().unwrap().max() {
545            return self.regions.len();
546        }
547        match self.regions.binary_search_by(|r| r.max().cmp(&offset)) {
548            Ok(ix) => ix,
549            Err(ix) => ix,
550        }
551    }
552
553    fn search_min(&self, offset: usize) -> usize {
554        if self.regions.is_empty() || offset > self.regions.last().unwrap().max() {
555            return self.regions.len();
556        }
557        match self
558            .regions
559            .binary_search_by(|r| r.min().cmp(&(offset + 1)))
560        {
561            Ok(ix) => ix,
562            Err(ix) => ix,
563        }
564    }
565}
566
567impl Default for Selection {
568    fn default() -> Self {
569        Self::new()
570    }
571}
572
573fn remove_n_at<T>(v: &mut Vec<T>, index: usize, n: usize) {
574    match n.cmp(&1) {
575        Ordering::Equal => {
576            v.remove(index);
577        }
578        Ordering::Greater => {
579            v.drain(index..index + n);
580        }
581        _ => (),
582    };
583}
584
585#[cfg(test)]
586mod test {
587    use crate::{
588        buffer::Buffer,
589        editor::EditType,
590        selection::{InsertDrift, SelRegion, Selection},
591    };
592
593    #[test]
594    fn should_return_selection_region_min() {
595        let region = SelRegion::new(1, 10, None);
596        assert_eq!(region.min(), region.start);
597
598        let region = SelRegion::new(42, 1, None);
599        assert_eq!(region.min(), region.end);
600    }
601
602    #[test]
603    fn should_return_selection_region_max() {
604        let region = SelRegion::new(1, 10, None);
605        assert_eq!(region.max(), region.end);
606
607        let region = SelRegion::new(42, 1, None);
608        assert_eq!(region.max(), region.start);
609    }
610
611    #[test]
612    fn is_caret_should_return_true() {
613        let region = SelRegion::new(1, 10, None);
614        assert!(!region.is_caret());
615    }
616
617    #[test]
618    fn is_caret_should_return_false() {
619        let region = SelRegion::new(1, 1, None);
620        assert!(region.is_caret());
621    }
622
623    #[test]
624    fn should_merge_regions() {
625        let region = SelRegion::new(1, 2, None);
626        let other = SelRegion::new(3, 4, None);
627        assert_eq!(region.merge_with(other), SelRegion::new(1, 4, None));
628
629        let region = SelRegion::new(2, 1, None);
630        let other = SelRegion::new(4, 3, None);
631        assert_eq!(region.merge_with(other), SelRegion::new(4, 1, None));
632
633        let region = SelRegion::new(1, 1, None);
634        let other = SelRegion::new(6, 6, None);
635        assert_eq!(region.merge_with(other), SelRegion::new(1, 6, None));
636    }
637
638    #[test]
639    fn selection_should_be_caret() {
640        let mut selection = Selection::new();
641        selection.add_region(SelRegion::caret(1));
642        selection.add_region(SelRegion::caret(6));
643        assert!(selection.is_caret());
644    }
645
646    #[test]
647    fn selection_should_not_be_caret() {
648        let mut selection = Selection::new();
649        selection.add_region(SelRegion::caret(1));
650        selection.add_region(SelRegion::new(4, 6, None));
651        assert!(!selection.is_caret());
652    }
653
654    #[test]
655    fn should_return_min_selection() {
656        let mut selection = Selection::new();
657        selection.add_region(SelRegion::new(1, 3, None));
658        selection.add_region(SelRegion::new(4, 6, None));
659        assert_eq!(
660            selection.min().regions,
661            vec![SelRegion::caret(1), SelRegion::caret(4)]
662        );
663    }
664
665    #[test]
666    fn selection_should_contains_region() {
667        let selection = Selection::region(0, 2);
668        assert!(selection.contains(0));
669        assert!(selection.contains(1));
670        assert!(selection.contains(2));
671        assert!(!selection.contains(3));
672    }
673
674    #[test]
675    fn should_return_last_inserted_region() {
676        let mut selection = Selection::region(5, 6);
677        selection.add_region(SelRegion::caret(1));
678        assert_eq!(selection.last_inserted(), Some(&SelRegion::caret(1)));
679    }
680
681    #[test]
682    fn should_return_last_region() {
683        let mut selection = Selection::region(5, 6);
684        selection.add_region(SelRegion::caret(1));
685        assert_eq!(selection.last(), Some(&SelRegion::new(5, 6, None)));
686    }
687
688    #[test]
689    fn should_return_first_region() {
690        let mut selection = Selection::region(5, 6);
691        selection.add_region(SelRegion::caret(1));
692        assert_eq!(selection.first(), Some(&SelRegion::caret(1)));
693    }
694
695    #[test]
696    fn should_return_regions_in_range() {
697        let mut selection = Selection::new();
698        selection.add_region(SelRegion::new(0, 3, None));
699        selection.add_region(SelRegion::new(3, 6, None));
700        selection.add_region(SelRegion::new(7, 8, None));
701        selection.add_region(SelRegion::new(9, 11, None));
702
703        let regions = selection.regions_in_range(5, 10);
704
705        assert_eq!(
706            regions,
707            vec![
708                SelRegion::new(3, 6, None),
709                SelRegion::new(7, 8, None),
710                SelRegion::new(9, 11, None),
711            ]
712        );
713    }
714
715    #[test]
716    fn should_return_regions_in_full_range() {
717        let mut selection = Selection::new();
718        selection.add_region(SelRegion::new(0, 3, None));
719        selection.add_region(SelRegion::new(3, 6, None));
720        selection.add_region(SelRegion::new(7, 8, None));
721        selection.add_region(SelRegion::new(9, 11, None));
722
723        let regions = selection.full_regions_in_range(5, 10);
724
725        assert_eq!(
726            regions,
727            vec![SelRegion::new(7, 8, None), SelRegion::new(9, 11, None),]
728        );
729    }
730
731    #[test]
732    fn should_delete_regions() {
733        let mut selection = Selection::new();
734        selection.add_region(SelRegion::new(0, 3, None));
735        selection.add_region(SelRegion::new(3, 6, None));
736        selection.add_region(SelRegion::new(7, 8, None));
737        selection.add_region(SelRegion::new(9, 11, None));
738        selection.delete_range(5, 10);
739        assert_eq!(selection.regions(), vec![SelRegion::new(0, 3, None)]);
740    }
741
742    #[test]
743    fn should_add_regions() {
744        let mut selection = Selection::new();
745        selection.add_region(SelRegion::new(0, 3, None));
746        selection.add_region(SelRegion::new(3, 6, None));
747        assert_eq!(
748            selection.regions(),
749            vec![SelRegion::new(0, 3, None), SelRegion::new(3, 6, None),]
750        );
751    }
752
753    #[test]
754    fn should_add_and_merge_regions() {
755        let mut selection = Selection::new();
756
757        selection.add_region(SelRegion::new(0, 4, None));
758        selection.add_region(SelRegion::new(3, 6, None));
759        assert_eq!(selection.regions(), vec![SelRegion::new(0, 6, None)]);
760    }
761
762    #[test]
763    fn should_apply_delta_after_insertion() {
764        let selection = Selection::caret(0);
765
766        let (_, mock_delta, _) = {
767            let mut buffer = Buffer::new("");
768            buffer.edit(&[(selection.clone(), "Hello")], EditType::InsertChars)
769        };
770
771        assert_eq!(
772            selection.apply_delta(&mock_delta, true, InsertDrift::Inside),
773            Selection::caret(5)
774        );
775    }
776}