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