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