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