Skip to main content

duat_core/mode/cursor/
selections.rs

1//! The [`Selections`] and [`Selection`] structs
2//!
3//! This module just defines the underlying [`Selections`] struct, as
4//! well as all of its components. This struct is used by [`Handle`]s
5//! in order to modify [`Text`]s by manipulating [`Cursor`]s, which
6//! are ultimately backed by the [`Selection`] struct.
7//!
8//! This module also defines [`VPoint`], which is essentially a
9//! [`Point`] with more information inbued into it, most notably
10//! various column distances, as well as their "desired values".
11//!
12//! [`Handle`]: crate::context::Handle
13//! [`Text`]: crate::text::Text
14//! [`Cursor`]: super::Cursor
15use std::sync::Mutex;
16
17use gap_buf::{GapBuffer, gap_buffer};
18
19pub use self::cursor::{Selection, VPoint};
20use crate::{
21    buffer::Change,
22    text::{Point, Strs, TextRange},
23    utils::{add_shifts, merging_range_by_guess_and_lazy_shift},
24};
25
26/// The list of [`Selection`]s in a [`Text`]
27///
28/// This list can contain any number of [`Selection`]s, and they
29/// should be usable in whatever order the end user may want, without
30/// breaking from, for example, modifications that should move cursors
31/// backwards or ahead. If that is not the case, report it as a bug.
32///
33/// they are primarily meant to be interacted with from the
34/// [`Handle`], with its [`edit_`] methods meant to efficiently
35/// handle a large number of [`Selection`]s in an efficient manner,
36/// although you can interact with them separately.
37///
38/// [`Handle`]: crate::context::Handle
39/// [`edit_`]: crate::context::Handle::edit_all
40/// [`Text`]: crate::text::Text
41pub struct Selections {
42    buf: GapBuffer<Selection>,
43    main_i: usize,
44    shift: Mutex<Shift>,
45}
46
47impl Selections {
48    /// A new `Selections` with a set main [`Selection`]
49    pub(crate) fn new(main: Selection) -> Self {
50        Self {
51            buf: gap_buffer![main],
52            main_i: 0,
53            shift: Mutex::default(),
54        }
55    }
56
57    /// Returns a new empty `Selections`
58    pub(crate) const fn new_empty() -> Self {
59        Self {
60            buf: GapBuffer::new(),
61            main_i: 0,
62            shift: Mutex::new(Shift { from: 0, by: [0; 3] }),
63        }
64    }
65
66    ////////// Modification functions
67
68    /// Sets the main [`Selection`]
69    pub fn set_main(&mut self, new: usize) {
70        self.main_i = new.min(self.buf.len().saturating_sub(1));
71    }
72
73    /// Rotates the main [`Selection`] by an amount
74    pub fn rotate_main(&mut self, amount: i32) {
75        self.main_i = (self.main_i as i32 + amount).rem_euclid(self.buf.len() as i32) as usize
76    }
77
78    /// Removes all [`Selection`]s
79    pub fn clear(&mut self) {
80        self.buf = GapBuffer::new();
81        *self.shift.get_mut().unwrap() = Shift::default();
82    }
83
84    /// Removes all [`Selection`]s and adds a [default `Selection`] as
85    /// main
86    ///
87    /// [default `Selection`]: Selection::default
88    pub fn reset(&mut self) {
89        self.remove_extras();
90        self.buf[self.main_i] = Selection::default();
91    }
92
93    /// Removes all but the main [`Selection`]
94    pub fn remove_extras(&mut self) {
95        if !self.is_empty() {
96            let cursor = self.buf.remove(self.main_i);
97            let shift = std::mem::take(self.shift.get_mut().unwrap());
98            if shift.from <= self.main_i && shift.by != [0; 3] {
99                cursor.shift_by(shift.by);
100            }
101            self.buf = gap_buffer![cursor];
102        }
103        self.main_i = 0;
104    }
105
106    /// Corrects all [`Selection`]s, so that they no longer reference
107    /// outdated data
108    pub(crate) fn correct_all(&mut self, strs: &Strs) {
109        for selection in &mut self.buf {
110            selection.correct(strs)
111        }
112    }
113
114    ////////// Querying functions
115
116    /// Gets the main [`Selection`]
117    ///
118    /// # Panics
119    ///
120    /// This method will panic if there are no `Selection`s. If you
121    /// want a non-panicking method, see [`Selections::get_main`].
122    #[track_caller]
123    pub fn main(&self) -> &Selection {
124        match self.get(self.main_i) {
125            Some(main) => main,
126            None => panic!("No main selection"),
127        }
128    }
129
130    /// Gets the main [`Selection`], if there is one
131    ///
132    /// If you want a method that doesn't return an [`Option`] (for
133    /// convenience), see [`Selections::main`].
134    pub fn get_main(&self) -> Option<&Selection> {
135        self.get(self.main_i)
136    }
137
138    /// Gets the `n`th [`Selection`] if there is one
139    pub fn get(&self, n: usize) -> Option<&Selection> {
140        if n >= self.len() {
141            return None;
142        }
143        let mut shift = self.shift.lock().unwrap();
144        if n >= shift.from && shift.by != [0; 3] {
145            for cursor in self.buf.range(shift.from..n + 1).iter() {
146                cursor.shift_by(shift.by);
147            }
148            if n + 1 < self.buf.len() {
149                shift.from = n + 1;
150            } else {
151                *shift = Shift::default();
152            }
153        }
154
155        self.buf.get(n)
156    }
157
158    /// Iterates over all [`Selection`]s in order
159    ///
160    /// Also tells you wether the [`Selection`] is the main selection
161    /// or not.
162    pub fn iter(&self) -> impl Iterator<Item = (&Selection, bool)> {
163        let mut shift = *self.shift.lock().unwrap();
164
165        self.buf.iter().enumerate().map(move |(i, selection)| {
166            if i >= shift.from && shift.by != [0; 3] {
167                selection.shift_by(shift.by);
168                if i + 1 < self.buf.len() {
169                    self.shift.lock().unwrap().from = i + 1;
170                    shift.from = i + 1;
171                } else {
172                    *self.shift.lock().unwrap() = Shift::default();
173                }
174            }
175
176            (selection, i == self.main_i)
177        })
178    }
179
180    /// Iterates over all [`Selection`]s in a given [`TextRange`]
181    ///
182    /// Also tells you the index of the [`Selection`], as well as if
183    /// it is the main selection or not.
184    ///
185    /// This [`Iterator`] *will* include [`Selection`]s that are
186    /// partially contained.
187    pub fn iter_within(
188        &self,
189        range: impl TextRange,
190    ) -> impl Iterator<Item = (usize, &Selection, bool)> {
191        let shift = *self.shift.lock().unwrap();
192        let range = range.to_range(u32::MAX as usize);
193
194        let m_range = merging_range_by_guess_and_lazy_shift(
195            (&self.buf, self.buf.len()),
196            (0, [range.start, range.end]),
197            (shift.from, shift.by[0], 0, |byte, shift| {
198                (byte as i32 + shift) as usize
199            }),
200            (
201                |sel| sel.start_point().byte(),
202                |sel| sel.end_point_excl().byte(),
203            ),
204        );
205
206        let (s0, s1) = self.buf.range(m_range.clone()).as_slices();
207        let iter = [s0, s1].into_iter().flatten().enumerate();
208        iter.map(move |(i, selection)| {
209            let i = i + m_range.start;
210            if i >= shift.from && shift.by != [0; 3] {
211                selection.shift_by(shift.by);
212                if i + 1 < self.buf.len() {
213                    self.shift.lock().unwrap().from = i + 1;
214                } else {
215                    *self.shift.lock().unwrap() = Shift::default();
216                }
217            }
218
219            (i, selection, i == self.main_i)
220        })
221    }
222
223    /// The index of the main [`Selection`]
224    pub fn main_index(&self) -> usize {
225        self.main_i
226    }
227
228    /// How many [`Selection`]s there are in the list
229    pub fn len(&self) -> usize {
230        self.buf.len()
231    }
232
233    /// Returns [`true`] when there are no [`Selection`]s
234    #[must_use]
235    pub fn is_empty(&self) -> bool {
236        self.len() == 0
237    }
238
239    ////////// Internal modification functions
240
241    /// Inserts a [`Selection`] back from editing
242    pub(crate) fn insert(
243        &mut self,
244        guess_i: usize,
245        sel: Selection,
246        main: bool,
247    ) -> ([usize; 2], bool) {
248        let mut shift = self.shift.lock().unwrap();
249        let shift_from = shift.from.min(self.len());
250
251        // The range of cursors that will be drained
252        let m_range = merging_range_by_guess_and_lazy_shift(
253            (&self.buf, self.buf.len()),
254            (guess_i, [sel.start_point(), sel.end_point_excl()]),
255            (shift_from, shift.by, [0; 3], Point::shift_by),
256            (Selection::start_point, Selection::end_point_excl),
257        );
258
259        // Shift all ranges that preceed the end of the cursor's range.
260        if shift_from < m_range.end && shift.by != [0; 3] {
261            for cursor in self.buf.range(shift_from..m_range.end).into_iter() {
262                cursor.shift_by(shift.by);
263            }
264        }
265
266        // Get the minimum and maximum Points in the taken range, designate
267        // those as the new Selection's bounds.
268        let (caret, anchor, last_cursor_overhangs) = {
269            let mut c_range = m_range.clone();
270            let first = c_range.next().and_then(|i| self.buf.get(i));
271            let last = c_range.last().and_then(|i| self.buf.get(i)).or(first);
272            let start = first
273                .map(|first| first.lazy_v_start().min(sel.lazy_v_start()))
274                .unwrap_or(sel.lazy_v_start());
275            let (end, last_sel_overhangs) = if let Some(last) = last
276                && last.lazy_v_end() >= sel.lazy_v_end()
277            {
278                (last.lazy_v_end(), true)
279            } else {
280                (sel.lazy_v_end(), false)
281            };
282
283            if let Some(anchor) = sel.anchor() {
284                match sel.caret() < anchor {
285                    true => (start, Some(end), last_sel_overhangs),
286                    false => (end, Some(start), last_sel_overhangs),
287                }
288            } else {
289                (end, (start != end).then_some(start), last_sel_overhangs)
290            }
291        };
292
293        let selection = Selection::from_v(caret, anchor, sel.change_i);
294        self.buf.splice(m_range.clone(), [selection]);
295
296        if main {
297            self.main_i = m_range.start;
298        } else if self.main_i >= m_range.start {
299            self.main_i = (self.main_i + 1 - m_range.clone().count()).max(m_range.start)
300        }
301
302        // If there are no more Selections after this, don't set the
303        // shift_state.
304        let cursors_taken = m_range.clone().count();
305        let new_shift_from = shift_from.saturating_sub(cursors_taken).max(m_range.start) + 1;
306        if new_shift_from < self.buf.len() {
307            shift.from = new_shift_from;
308        } else {
309            *shift = Shift::default()
310        }
311
312        ([m_range.start, cursors_taken], last_cursor_overhangs)
313    }
314
315    /// Applies a [`Change`] to the [`Selection`]s list
316    ///
317    /// Returns the number of [`Selection`]s that were removed
318    pub(crate) fn apply_change(&mut self, guess_i: usize, change: Change<&str>) -> usize {
319        let mut shift = self.shift.lock().unwrap();
320        let shift_from = shift.from.min(self.len());
321
322        // The range of cursors that will be drained
323        let c_range = merging_range_by_guess_and_lazy_shift(
324            (&self.buf, self.buf.len()),
325            (guess_i, [change.start(), change.taken_end()]),
326            (shift_from, shift.by, [0; 3], Point::shift_by),
327            (Selection::start_point, Selection::end_point_excl),
328        );
329
330        // Since applied changes don't remove Selections, we need to shift all
331        // Selections in the whole range. First by the original shift, in
332        // order to update them to the latest shift leve, then by the
333        // change.
334        if c_range.end > shift_from && shift.by != [0; 3] {
335            for cursor in self.buf.range(shift_from..c_range.end).into_iter() {
336                cursor.shift_by(shift.by);
337            }
338        }
339        let range = c_range.start..c_range.end.max(shift_from);
340        for cursor in self.buf.range(range).into_iter() {
341            cursor.shift_by_change(change);
342        }
343
344        let (cursors_taken, cursors_added) = {
345            let mut cursors_taken = self.buf.splice(c_range.clone(), []);
346            if let Some(first) = cursors_taken.next() {
347                let last = cursors_taken.next_back().unwrap_or(first.clone());
348                let (start, end) = (first.start_point(), last.end_point_excl());
349                let merged = Selection::new(start, (start < end).then_some(end));
350                drop(cursors_taken);
351                self.buf.insert(c_range.start, merged);
352
353                (c_range.len(), 1)
354            } else {
355                (0, 0)
356            }
357        };
358
359        let from = shift_from.saturating_sub(cursors_taken).max(c_range.start) + cursors_added;
360        if from < self.buf.len() {
361            *shift = Shift {
362                from,
363                by: add_shifts(shift.by, change.shift()),
364            };
365        } else {
366            *shift = Shift::default()
367        }
368
369        cursors_taken - cursors_added
370    }
371
372    /// Removes a [`Selection`], which might be brought back
373    pub(crate) fn remove(&mut self, i: usize) -> Option<(Selection, bool)> {
374        if i >= self.buf.len() {
375            return None;
376        }
377        let shift = self.shift.get_mut().unwrap();
378
379        if i >= shift.from && shift.by != [0; 3] {
380            for cursor in self.buf.range(shift.from..i + 1).iter() {
381                cursor.shift_by(shift.by);
382            }
383            if i + 1 < self.buf.len() {
384                // i here, instead of i + 1, since this Selection is about to be
385                // removed.
386                shift.from = i;
387            } else {
388                *shift = Shift::default()
389            }
390        } else if i < shift.from {
391            // If I am removing before shift_from, obviously the index of the
392            // first unshifted Selection is moved back.
393            shift.from -= 1;
394        }
395
396        let was_main = self.main_i == i;
397        if self.main_i >= i {
398            self.main_i = self.main_i.saturating_sub(1);
399        }
400        Some((self.buf.remove(i), was_main))
401    }
402
403    /// Ensures that there is at least one [`Selection`] on the list
404    pub(crate) fn populate(&mut self) {
405        if self.buf.is_empty() {
406            self.main_i = 0;
407            self.buf = gap_buffer![Selection::default()];
408        }
409    }
410}
411
412impl Clone for Selections {
413    fn clone(&self) -> Self {
414        Self {
415            buf: self.buf.clone(),
416            main_i: self.main_i,
417            shift: Mutex::new(*self.shift.lock().unwrap()),
418        }
419    }
420}
421
422mod cursor {
423    use std::{cmp::Ordering, ops::Range, sync::Mutex};
424
425    use bincode::{Decode, Encode};
426
427    use crate::{
428        buffer::Change,
429        opts::PrintOpts,
430        text::{Point, Strs, Text, TextIndex},
431        ui::Area,
432    };
433
434    /// A cursor in the text buffer. This is an editing cursor, -(not
435    /// a printing cursor.
436    #[derive(Default, Encode, Decode)]
437    pub struct Selection {
438        caret: Mutex<LazyVPoint>,
439        anchor: Mutex<Option<LazyVPoint>>,
440        pub(in crate::mode::cursor) change_i: Option<u32>,
441    }
442
443    impl Selection {
444        /// Returns a new instance of [`Selection`].
445        pub(crate) fn new(caret: Point, anchor: Option<Point>) -> Self {
446            Self {
447                caret: Mutex::new(LazyVPoint::Unknown(caret)),
448                anchor: Mutex::new(anchor.map(LazyVPoint::Unknown)),
449                change_i: None,
450            }
451        }
452
453        pub(super) fn from_v(
454            caret: LazyVPoint,
455            anchor: Option<LazyVPoint>,
456            change_i: Option<u32>,
457        ) -> Self {
458            Self {
459                caret: Mutex::new(caret),
460                anchor: Mutex::new(anchor),
461                change_i,
462            }
463        }
464
465        /// Moves to specific, pre calculated [`Point`].
466        #[track_caller]
467        pub fn move_to(&mut self, idx: impl TextIndex, text: &Text) {
468            let byte = idx.to_byte_index();
469            if byte == self.caret().byte() {
470                return;
471            }
472            *self.caret.get_mut().unwrap() =
473                LazyVPoint::Unknown(text.point_at_byte(byte.min(text.len() - 1)));
474        }
475
476        /// Internal horizontal movement function
477        ///
478        /// Returns `true` if the caret was moved
479        pub fn move_hor(&mut self, by: i32, text: &Text) -> i32 {
480            let by = by as isize;
481            if by == 0 {
482                return 0;
483            };
484
485            let caret = self.caret.get_mut().unwrap();
486
487            // We move in chars, not bytes, but calculating char index can be
488            // expensive, so do a rough estimate assuming that the text is ascii
489            // only.
490            let target_char = caret.point().char().saturating_add_signed(by);
491
492            let point = if target_char == 0 {
493                Point::default()
494            } else if target_char >= text.last_point().char() {
495                text.last_point()
496            } else if by.abs() < 500 {
497                if by > 0 {
498                    text[caret.point()..]
499                        .chars()
500                        .take(by as usize)
501                        .fold(caret.point(), |point, char| point.fwd(char))
502                } else {
503                    text[..caret.point()]
504                        .chars()
505                        .rev()
506                        .take(by.unsigned_abs())
507                        .fold(caret.point(), |point, char| point.rev(char))
508                }
509            } else {
510                text.point_at_char(target_char)
511            };
512
513            let moved = point.char() as i32 - caret.point().char() as i32;
514            *caret = LazyVPoint::Unknown(point);
515            moved
516        }
517
518        /// Internal vertical movement function.
519        ///
520        /// Returns `true` if the caret actually moved at all.
521        pub fn move_ver(&mut self, by: i32, text: &Text, area: &Area, opts: PrintOpts) -> bool {
522            if by == 0 {
523                return false;
524            }
525            let caret = self.caret.get_mut().unwrap();
526            let point = caret.point();
527
528            let desired_col = match *caret {
529                LazyVPoint::Unknown(_) => None,
530                LazyVPoint::Known(vpoint) => Some(vpoint.desired_visual_col()),
531                LazyVPoint::Desired { dvcol, .. } => Some(dvcol as usize),
532            };
533
534            let vpoint = area.move_ver(by, text, point, desired_col, opts);
535            *caret = LazyVPoint::Known(vpoint);
536
537            vpoint.point != point
538        }
539
540        /// Internal vertical movement function.
541        ///
542        /// Returns `true` if the caret actually moved at all.
543        pub fn move_ver_wrapped(
544            &mut self,
545            by: i32,
546            text: &Text,
547            area: &Area,
548            opts: PrintOpts,
549        ) -> bool {
550            if by == 0 {
551                return false;
552            };
553
554            let caret = self.caret.get_mut().unwrap();
555            let point = caret.point();
556
557            let desired_col = match *caret {
558                LazyVPoint::Unknown(_) => None,
559                LazyVPoint::Known(vpoint) => Some(vpoint.desired_wrapped_col()),
560                LazyVPoint::Desired { dwcol, .. } => Some(dwcol as usize),
561            };
562
563            let vpoint = area.move_ver_wrapped(by, text, point, desired_col, opts);
564            *caret = LazyVPoint::Known(vpoint);
565
566            vpoint.point != point
567        }
568
569        pub(crate) fn shift_by_change(&self, change: Change<&str>) {
570            let mut caret = self.caret.lock().unwrap();
571
572            let (shift, taken) = (change.shift(), change.taken_end());
573            if caret.point() >= change.start() {
574                let shifted_caret = caret.point().max(taken).shift_by(shift);
575                *caret = LazyVPoint::Unknown(shifted_caret);
576            }
577
578            let mut anchor = self.anchor.lock().unwrap();
579            if let Some(anchor) = &mut *anchor
580                && anchor.point() >= change.start()
581            {
582                let shifted_anchor = anchor.point().max(taken).shift_by(shift);
583                *anchor = LazyVPoint::Unknown(shifted_anchor);
584            }
585        }
586
587        /// Assumes that both parts of the cursor are ahead of the
588        /// shift
589        pub(crate) fn shift_by(&self, shift: [i32; 3]) {
590            let mut caret = self.caret.lock().unwrap();
591            *caret = LazyVPoint::Unknown(caret.point().shift_by(shift));
592
593            let mut anchor = self.anchor.lock().unwrap();
594            if let Some(anchor) = &mut *anchor {
595                *anchor = LazyVPoint::Unknown(anchor.point().shift_by(shift));
596            }
597        }
598
599        /// Corrects this [`Selection`], so that it no longer assumes
600        /// to be in the correct position
601        pub(crate) fn correct(&mut self, strs: &Strs) {
602            let mut caret = self.caret.lock().unwrap();
603            *caret = LazyVPoint::Unknown(strs.point_at_byte(caret.point().byte()));
604
605            let mut anchor = self.anchor.lock().unwrap();
606            if let Some(anchor) = &mut *anchor {
607                *anchor = LazyVPoint::Unknown(strs.point_at_byte(anchor.point().byte()));
608            }
609        }
610
611        ////////// Public movement functions
612
613        /// Sets the position of the anchor to be the same as the
614        /// current cursor position in the buffer
615        ///
616        /// The `anchor` and `current` act as a range of text on the
617        /// buffer.
618        pub fn set_anchor(&mut self) {
619            *self.anchor.get_mut().unwrap() = Some(*self.caret.get_mut().unwrap())
620        }
621
622        /// Unsets the anchor, returning its byte index if it existed
623        ///
624        /// This is done so the cursor no longer has a valid
625        /// selection.
626        pub fn unset_anchor(&mut self) -> Option<Point> {
627            self.anchor.get_mut().unwrap().take().map(|a| a.point())
628        }
629
630        /// Switches the position of the anchor and caret
631        pub fn swap_ends(&mut self) {
632            if let Some(anchor) = self.anchor.get_mut().unwrap() {
633                std::mem::swap(self.caret.get_mut().unwrap(), anchor);
634            }
635        }
636
637        /// Returns the byte index of this `Selection`'s `caret`
638        pub fn caret(&self) -> Point {
639            self.caret.lock().unwrap().point()
640        }
641
642        /// Returns the byte index of this `Selection`'s `anchor`, if
643        /// there is one
644        pub fn anchor(&self) -> Option<Point> {
645            self.anchor.lock().unwrap().map(|lazy| lazy.point())
646        }
647
648        ////////// Range functions
649
650        /// Returns the byte index range between the `caret` and
651        /// `anchor`
652        ///
653        /// If `anchor` isn't set, returns an empty range on `caret`.
654        ///
655        /// # Note
656        ///
657        /// This range is _inclusive_, that is, it will include the
658        /// character at the end. If you use it to replace a range in
659        /// the [`Text`], know that this range will be truncated to
660        /// not include the last `\n`, since it is not allowed to be
661        /// removed.
662        pub fn byte_range(&self, text: &Text) -> Range<usize> {
663            self.start_point().byte()..self.end_point(text).byte()
664        }
665
666        /// The starting [`Point`] of this [`Selection`]
667        pub fn start_point(&self) -> Point {
668            if let Some(anchor) = *self.anchor.lock().unwrap() {
669                anchor.point().min(self.caret.lock().unwrap().point())
670            } else {
671                self.caret.lock().unwrap().point()
672            }
673        }
674
675        /// The ending [`Point`] of this [`Selection`]
676        pub fn end_point(&self, text: &Text) -> Point {
677            self.end_point_excl()
678                .fwd(text.char_at(self.end_point_excl()).unwrap())
679        }
680
681        pub(super) fn end_point_excl(&self) -> Point {
682            if let Some(anchor) = *self.anchor.lock().unwrap() {
683                anchor.point().max(self.caret.lock().unwrap().point())
684            } else {
685                self.caret.lock().unwrap().point()
686            }
687        }
688
689        /// Returns the range between `caret` and `anchor`.
690        ///
691        /// If `anchor` isn't set, returns a range that contains only
692        /// the `caret`'s current `char`.
693        pub fn point_range(&self, text: &Text) -> Range<Point> {
694            self.start_point()..self.end_point(text)
695        }
696
697        /// Returns an exclusive range between `caret` and `anchor`
698        ///
699        /// If `anchor` isn't set, both [`Point`]s will be the same.
700        pub fn point_range_excl(&self) -> Range<Point> {
701            self.start_point()..self.end_point_excl()
702        }
703
704        ////////// VPoint functions
705
706        /// Sets both the desired visual column, as well as the
707        /// desired wrapped column
708        pub fn set_desired_cols(&mut self, v: usize, w: usize) {
709            let (v, w) = (v as u16, w as u16);
710            let caret = self.caret.get_mut().unwrap();
711            match caret {
712                LazyVPoint::Known(vp) => {
713                    vp.dvcol = v;
714                    vp.dwcol = w;
715                }
716                LazyVPoint::Unknown(point) => {
717                    *caret = LazyVPoint::Desired { point: *point, dvcol: v, dwcol: w }
718                }
719                LazyVPoint::Desired { dvcol, dwcol, .. } => (*dvcol, *dwcol) = (v, w),
720            }
721        }
722
723        /// The visual caret of this [`Selection`]
724        ///
725        /// [`VPoint`]s include a lot more information than regular
726        /// [`Point`]s, like visual distance form the left edge, what
727        /// the desired distance is, etc.
728        pub fn v_caret(&self, text: &Text, area: &Area, opts: PrintOpts) -> VPoint {
729            let mut caret = self.caret.lock().unwrap();
730            let vp = caret.calculate(text, area, opts);
731            *caret = LazyVPoint::Known(vp);
732            vp
733        }
734
735        /// The visual anchor of this [`Selection`], if it exists
736        ///
737        /// [`VPoint`]s include a lot more information than regular
738        /// [`Point`]s, like visual distance form the left edge, what
739        /// the desired distance is, etc.
740        pub fn v_anchor(&self, text: &Text, area: &Area, opts: PrintOpts) -> Option<VPoint> {
741            self.anchor.lock().unwrap().as_mut().map(|anchor| {
742                let vp = anchor.calculate(text, area, opts);
743                *anchor = LazyVPoint::Known(vp);
744                vp
745            })
746        }
747
748        /// The visual range between the caret and anchor of this
749        /// [`Selection`]
750        ///
751        /// [`VPoint`]s include a lot more information than regular
752        /// [`Point`]s, like visual distance form the left edge, what
753        /// the desired distance is, etc.
754        pub fn v_range(&self, text: &Text, area: &Area, opts: PrintOpts) -> [VPoint; 2] {
755            let v_caret = self.v_caret(text, area, opts);
756            let v_anchor = self.v_anchor(text, area, opts).unwrap_or(v_caret);
757            [v_caret.min(v_anchor), v_caret.max(v_anchor)]
758        }
759
760        /// The starting [`LazyVPoint`]
761        pub(super) fn lazy_v_start(&self) -> LazyVPoint {
762            match *self.anchor.lock().unwrap() {
763                Some(anchor) => self.caret.lock().unwrap().min(anchor),
764                None => *self.caret.lock().unwrap(),
765            }
766        }
767
768        /// The ending [`LazyVPoint`]
769        pub(super) fn lazy_v_end(&self) -> LazyVPoint {
770            match *self.anchor.lock().unwrap() {
771                Some(anchor) => self.caret.lock().unwrap().max(anchor),
772                None => *self.caret.lock().unwrap(),
773            }
774        }
775    }
776
777    impl Clone for Selection {
778        fn clone(&self) -> Self {
779            Self {
780                caret: Mutex::new(*self.caret.lock().unwrap()),
781                anchor: Mutex::new(*self.anchor.lock().unwrap()),
782                change_i: self.change_i,
783            }
784        }
785    }
786
787    /// A struct meant to minimize calculations on very large numbers
788    /// of [`Selection`]s
789    #[derive(Clone, Copy, Eq, Encode, Decode)]
790    pub(super) enum LazyVPoint {
791        Unknown(Point),
792        Known(VPoint),
793        Desired {
794            point: Point,
795            dvcol: u16,
796            dwcol: u16,
797        },
798    }
799
800    impl LazyVPoint {
801        fn point(&self) -> Point {
802            match *self {
803                LazyVPoint::Unknown(point) | LazyVPoint::Desired { point, .. } => point,
804                LazyVPoint::Known(vp) => vp.point,
805            }
806        }
807
808        /// Calculates the [`VPoint`], to be used sparingly
809        fn calculate(self, text: &Text, area: &Area, opts: PrintOpts) -> VPoint {
810            match self {
811                Self::Known(vp) => vp,
812                Self::Unknown(point) => area.move_ver(0, text, point, None, opts),
813                Self::Desired { point, dvcol, dwcol } => {
814                    let mut vp = area.move_ver(0, text, point, Some(dvcol as usize), opts);
815                    vp.dvcol = dvcol;
816                    vp.dwcol = dwcol;
817                    vp
818                }
819            }
820        }
821    }
822
823    impl Default for LazyVPoint {
824        fn default() -> Self {
825            Self::Desired {
826                point: Point::default(),
827                dvcol: 0,
828                dwcol: 0,
829            }
830        }
831    }
832
833    #[allow(clippy::non_canonical_partial_ord_impl)]
834    impl PartialOrd for LazyVPoint {
835        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
836            Some(self.point().cmp(&other.point()))
837        }
838    }
839
840    impl Ord for LazyVPoint {
841        fn cmp(&self, other: &Self) -> Ordering {
842            self.partial_cmp(other).unwrap()
843        }
844    }
845
846    impl PartialEq for LazyVPoint {
847        fn eq(&self, other: &Self) -> bool {
848            self.point() == other.point()
849        }
850    }
851
852    /// A visual [`Point`], which includes more information
853    ///
854    /// Alongside the byte, char, and line of the [`Point`], this
855    /// struct has:
856    ///
857    /// - Number of [`char`]s from the left edge
858    /// - Number of visual cells from the left edge
859    /// - Desired number of visual cells from the left edge
860    /// - Number of wrapped cells from the left edge
861    /// - Desired number of wrapped cells from the left edge
862    ///
863    /// The difference between visual cells and wrapped cells is that
864    /// visual cells are essentially "The distance a [`Point`] would
865    /// be if this line were not wrapped"
866    ///
867    /// Desired cells are used when moving vertically, since when you
868    /// move a [`Selection`] up or down to a shorter line, then to a
869    /// longer one, you expect the horizontal position to hold. This
870    /// is applied both in [full line] and [wrapped line] vertical
871    /// movement.
872    ///
873    /// [full line]: crate::mode::Cursor::move_ver
874    /// [wrapped line]: crate::mode::Cursor::move_ver_wrapped
875    #[derive(Default, Clone, Copy, Debug, Eq, Encode, Decode)]
876    pub struct VPoint {
877        point: Point,
878        // No plan to support lines that are far too long
879        ccol: u16,
880        vcol: u16,
881        dvcol: u16,
882        wcol: u16,
883        dwcol: u16,
884    }
885
886    impl VPoint {
887        /// Returns a new `VPoint` from scratch
888        pub fn new(point: Point, ccol: u16, vcol: u16, dvcol: u16, wcol: u16, dwcol: u16) -> Self {
889            Self { point, ccol, vcol, dvcol, wcol, dwcol }
890        }
891
892        /// The byte index of this [`VPoint`]
893        pub fn byte(&self) -> usize {
894            self.point.byte()
895        }
896
897        /// The char index of this [`VPoint`]
898        pub fn char(&self) -> usize {
899            self.point.char()
900        }
901
902        /// The line index of this [`VPoint`]
903        pub fn line(&self) -> usize {
904            self.point.line()
905        }
906
907        /// Number of characters from the start of the line
908        pub fn char_col(&self) -> usize {
909            self.ccol as usize
910        }
911
912        /// Total space from the start of the line
913        pub fn visual_col(&self) -> usize {
914            self.vcol as usize
915        }
916
917        /// How much space there should be from the start of the line
918        pub fn desired_visual_col(&self) -> usize {
919            self.dvcol as usize
920        }
921
922        /// Total space from the left edge
923        pub fn wrapped_col(&self) -> usize {
924            self.wcol as usize
925        }
926
927        /// How much space there should be from the left edge
928        pub fn desired_wrapped_col(&self) -> usize {
929            self.dwcol as usize
930        }
931    }
932
933    #[allow(clippy::non_canonical_partial_ord_impl)]
934    impl PartialOrd for VPoint {
935        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
936            Some(self.point.cmp(&other.point))
937        }
938    }
939
940    impl Ord for VPoint {
941        fn cmp(&self, other: &Self) -> Ordering {
942            self.partial_cmp(other).unwrap()
943        }
944    }
945
946    impl PartialEq for VPoint {
947        fn eq(&self, other: &Self) -> bool {
948            self.point == other.point
949        }
950    }
951
952    impl std::fmt::Debug for Selection {
953        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
954            f.debug_struct("Selection")
955                .field("caret", &*self.caret.lock().unwrap())
956                .field("anchor", &*self.anchor.lock().unwrap())
957                .field("change_i", &self.change_i)
958                .finish()
959        }
960    }
961
962    impl std::fmt::Debug for LazyVPoint {
963        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
964            match self {
965                Self::Known(vp) => write!(f, "Known({:?}, {})", vp.point, vp.dwcol),
966                Self::Unknown(p_or_b) => write!(f, "Unknown({p_or_b:?}"),
967                Self::Desired { point, dvcol, dwcol } => {
968                    write!(f, "Desired({point:?}, {dvcol}, {dwcol})")
969                }
970            }
971        }
972    }
973}
974
975impl std::fmt::Debug for Selections {
976    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
977        struct DebugShiftState(Shift);
978        impl std::fmt::Debug for DebugShiftState {
979            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
980                write!(f, "{:?}", self.0)
981            }
982        }
983
984        f.debug_struct("Selections")
985            .field("buf", &self.buf)
986            .field("main_i", &self.main_i)
987            .field("shift_sate", &DebugShiftState(*self.shift.lock().unwrap()))
988            .finish()
989    }
990}
991
992#[derive(Default, Debug, Clone, Copy)]
993struct Shift {
994    from: usize,
995    by: [i32; 3],
996}