duat_core/mode/cursor/
mod.rs

1//! A helper struct for [`Mode`]s with [`Selections`]
2//!
3//! This struct can edit [`Text`] in a declarative way, freeing the
4//! [`Mode`]s from worrying about synchronization of the
5//! selections and dealing with editing the text directly.
6//!
7//! [`Mode`]: super::Mode
8use std::{
9    cell::{Cell, RefMut},
10    ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
11    rc::Rc,
12};
13
14use lender::{Lender, Lending};
15
16pub use self::selections::{Selection, Selections, VPoint};
17use crate::{
18    cfg::PrintCfg,
19    file::{File, Parser},
20    text::{Change, Lines, Point, RegexPattern, Searcher, Strs, Text, TextRange},
21    ui::{Area, Ui, Widget},
22};
23
24/// The [`Selection`] and [`Selections`] structs
25mod selections;
26
27/// A selection that can edit [`Text`], but can't alter selections
28///
29/// This struct will be used only inside functions passed to the
30/// [`edit_*`] family of methods from the [`Handle`].
31///
32/// To make edits, you can use three different functions. You can,
33/// those being [`replace`], [`insert`], and [`append`]. [`replace`]
34/// will completely replace the [`Selection`]'s selection. [`insert`]
35/// will place text behind the `caret`, and [`append`] will place it
36/// after the `caret`.
37///
38/// You can also move the [`Selection`]'s selection in many different
39/// ways, which are described below, in the `impl` section for this
40/// struct.
41///
42/// ```rust
43/// # use duat_core::prelude::*;
44/// # fn test<U: Ui, S>(mut pa: Pass, handle: &mut Handle<File<U>, U, S>) {
45/// let sel: String = handle.edit_main(&mut pa, |mut c| {
46///     c.set_anchor();
47///     c.set_caret_on_end();
48///     c.replace("my replacement");
49///     c.append(" and my edit");
50///
51///     c.swap_ends();
52///     c.insert("This is ");
53///     c.swap_ends();
54///
55///     c.move_hor(" and my edit".chars().count() as i32);
56///     c.set_anchor();
57///     c.move_hor(-("This is my replacement and my edit".chars().count() as i32));
58///     c.selection().into_iter().collect()
59/// });
60///
61/// assert_eq!(&sel, "This is my replacement and my edit");
62/// # }
63/// ```
64///
65/// [`edit_*`]: crate::context::Handle::edit_nth
66/// [`Handle`]: crate::context::Handle
67/// [`replace`]: Cursor::replace
68/// [`insert`]: Cursor::insert
69/// [`append`]: Cursor::append
70pub struct Cursor<'a, W: Widget<A::Ui> + ?Sized, A: Area, S> {
71    initial: Selection,
72    selection: Selection,
73    n: usize,
74    was_main: bool,
75    widget: &'a mut W,
76    area: &'a A,
77    next_i: Option<Rc<Cell<usize>>>,
78    inc_searcher: &'a mut S,
79}
80
81impl<'a, W: Widget<A::Ui> + ?Sized, A: Area, S> Cursor<'a, W, A, S> {
82    /// Returns a new instance of [`Cursor`]
83    pub(crate) fn new(
84        selection: Selection,
85        n: usize,
86        was_main: bool,
87        widget: &'a mut W,
88        area: &'a A,
89        next_i: Option<Rc<Cell<usize>>>,
90        searcher: &'a mut S,
91    ) -> Self {
92        Self {
93            initial: selection.clone(),
94            selection,
95            n,
96            was_main,
97            widget,
98            area,
99            next_i,
100            inc_searcher: searcher,
101        }
102    }
103
104    ////////// Text editing
105
106    /// Replaces the entire selection with new text
107    ///
108    /// If there is a selection, then it is treated as _inclusive_,
109    /// therefore, a selection where `caret == anchor` will remove the
110    /// character where the caret is. If there is no selection, then
111    /// this has the same effect as [`insert`]. If you wish to
112    /// append to the `caret` instead, see [`append`].
113    ///
114    /// After replacing the sele tion, if the `caret` is behind the
115    /// `anchor` (or in the same spot), it will be placed on the start
116    /// of the selection, while the `anchor` will be placed on the
117    /// new end. If it is ahead, it will be placed ahead.
118    ///
119    /// [`insert`]: Self::insert
120    /// [`append`]: Self::append
121    pub fn replace(&mut self, edit: impl ToString) {
122        let change = {
123            let edit = edit.to_string();
124            let [p0, p1] = self.selection.point_range(self.widget.text());
125            let p1 = if self.anchor().is_some() { p1 } else { p0 };
126            Change::new(edit, [p0, p1], self.widget.text())
127        };
128
129        // Disconsider null changes.
130        if change.added_str().len() < 10 && change.added_str() == change.taken_str() {
131            return;
132        }
133
134        let (start, end) = (change.start(), change.added_end());
135
136        self.edit(change);
137
138        let anchor_was_on_start = self.anchor_is_start();
139        self.move_to(start..end);
140        if !anchor_was_on_start {
141            self.set_caret_on_start();
142        }
143    }
144
145    /// Inserts new text directly behind the `caret`
146    ///
147    /// If the `anchor` is ahead of the `caret`, it will move forwards
148    /// by the number of chars in the new text.
149    ///
150    /// If you wish to replace the selected text, see [`replace`], if
151    /// you want to append after the `caret` instead, see [`append`]
152    ///
153    /// [`replace`]: Self::replace
154    /// [`append`]: Self::append
155    pub fn insert(&mut self, edit: impl ToString) {
156        let range = [self.selection.caret(), self.selection.caret()];
157        let change = Change::new(edit.to_string(), range, self.widget.text());
158        let (added, taken) = (change.added_end(), change.taken_end());
159
160        self.edit(change);
161
162        if let Some(anchor) = self.selection.anchor()
163            && anchor > self.selection.caret()
164        {
165            let new_anchor = anchor + added - taken;
166            self.selection.swap_ends();
167            self.selection.move_to(new_anchor, self.widget.text());
168            self.selection.swap_ends();
169        }
170    }
171
172    /// Appends new text directly after the `caret`
173    ///
174    /// If the `anchor` is ahead of the `caret`, it will move forwards
175    /// by the number of chars in the new text.
176    ///
177    /// If you wish to replace the selected text, see [`replace`], if
178    /// you want to insert before the `caret` instead, see [`insert`]
179    ///
180    /// [`replace`]: Self::replace
181    /// [`insert`]: Self::insert
182    pub fn append(&mut self, edit: impl ToString) {
183        let caret = self.selection.caret();
184        let p = caret.fwd(self.widget.text().char_at(caret).unwrap());
185        let change = Change::new(edit.to_string(), [p, p], self.widget.text());
186        let (added, taken) = (change.added_end(), change.taken_end());
187
188        self.edit(change);
189
190        if let Some(anchor) = self.selection.anchor()
191            && anchor > p
192        {
193            let new_anchor = anchor + added - taken;
194            self.selection.swap_ends();
195            self.selection.move_to(new_anchor, self.widget.text());
196            self.selection.swap_ends();
197        }
198    }
199
200    /// Edits the file with a [`Change`]
201    fn edit(&mut self, change: Change) {
202        let text = self.widget.text_mut();
203        let (change_i, selections_taken) =
204            text.apply_change(self.selection.change_i.map(|i| i as usize), change);
205        self.selection.change_i = change_i.map(|i| i as u32);
206
207        // The Change may have happened before the index of the next curossr,
208        // so we need to account for that.
209        if let Some(change_i) = change_i
210            && let Some(next_i) = self.next_i.as_ref()
211            && change_i <= next_i.get()
212        {
213            next_i.set(next_i.get().saturating_sub(selections_taken));
214        }
215    }
216
217    ////////// Movement functions
218
219    /// Moves the selection horizontally. May cause vertical movement
220    ///
221    /// Returns the distance moved in chars.
222    pub fn move_hor(&mut self, count: i32) -> i32 {
223        self.selection.move_hor(count, self.widget.text())
224    }
225
226    /// Moves the selection vertically. May cause horizontal movement
227    ///
228    /// Returns the distance moved in lines.
229    pub fn move_ver(&mut self, count: i32) -> i32 {
230        self.selection.move_ver(
231            count,
232            self.widget.text(),
233            self.area,
234            self.widget.print_cfg(),
235        )
236    }
237
238    /// Moves the selection vertically a number of wrapped lines. May
239    /// cause horizontal movement
240    ///
241    /// Returns the distance moved in wrapped lines.
242    pub fn move_ver_wrapped(&mut self, count: i32) {
243        self.selection.move_ver_wrapped(
244            count,
245            self.widget.text(),
246            self.area,
247            self.widget.print_cfg(),
248        );
249    }
250
251    /// Moves the selection to a [`Point`] or a [range] of [`Point`]s
252    ///
253    /// If you give it just a [`Point`], it will move the caret,
254    /// without affecting the anchor. If you give it a [range] of
255    /// [`Point`]s, the anchor will be placed at the start, while the
256    /// caret will be placed at the end of said [range]. You can flip
257    /// those positions with a function like [`swap_ends`].
258    ///
259    /// If a [`Point`] is not valid, it will be corrected and clamped
260    /// to the lenght of the [`Text`].
261    ///
262    /// [range]: std::ops::RangeBounds
263    /// [`swap_ends`]: Self::swap_ends
264    pub fn move_to(&mut self, point_or_points: impl PointOrPoints) {
265        point_or_points.move_to(self);
266    }
267
268    /// Moves the selection to [`Point::default`], i.e., the start of
269    /// the [`Text`]
270    pub fn move_to_start(&mut self) {
271        self.selection.move_to(Point::default(), self.widget.text());
272    }
273
274    /// Moves the selection to a `line` and a `column`
275    ///
276    /// - If the coords isn't valid, it will move to the "maximum"
277    ///   position allowed.
278    pub fn move_to_coords(&mut self, line: usize, col: usize) {
279        let [s, e] = self
280            .text()
281            .points_of_line(line.min(self.text().last_point().line()));
282        let (p, _) = self
283            .text()
284            .chars_fwd(s..e)
285            .unwrap()
286            .take(col + 1)
287            .last()
288            .unzip();
289        self.move_to(p.unwrap_or(e));
290    }
291
292    /// Moves to a column on the current line
293    pub fn move_to_col(&mut self, col: usize) {
294        let line = self.text().point_at_line(self.caret().line()).line();
295        self.move_to_coords(line, col);
296    }
297
298    /// Returns and takes the anchor of the [`Selection`].
299    pub fn unset_anchor(&mut self) -> Option<Point> {
300        self.selection.unset_anchor()
301    }
302
303    /// Sets the `anchor` to the current `caret`
304    pub fn set_anchor(&mut self) {
305        self.selection.set_anchor()
306    }
307
308    /// Sets the `anchor` if it was not already set
309    ///
310    /// Returns `true` if the anchor was set by this command.
311    pub fn set_anchor_if_needed(&mut self) -> bool {
312        if self.anchor().is_none() {
313            self.selection.set_anchor();
314            true
315        } else {
316            false
317        }
318    }
319
320    /// Swaps the position of the `caret` and `anchor`
321    pub fn swap_ends(&mut self) {
322        self.selection.swap_ends();
323    }
324
325    /// Sets the caret of the [`Selection`] on the start of the
326    /// selection
327    ///
328    /// Returns `true` if a swap occurred
329    pub fn set_caret_on_start(&mut self) -> bool {
330        if let Some(anchor) = self.anchor()
331            && anchor < self.caret()
332        {
333            self.swap_ends();
334            true
335        } else {
336            false
337        }
338    }
339
340    /// Sets the caret of the [`Selection`] on the end of the
341    /// selection
342    ///
343    /// Returns `true` if a swap occurred
344    pub fn set_caret_on_end(&mut self) -> bool {
345        if let Some(anchor) = self.anchor()
346            && anchor > self.caret()
347        {
348            self.swap_ends();
349            true
350        } else {
351            false
352        }
353    }
354
355    ////////// Selection meta manipulation
356
357    /// Resets the [`Selection`] to how it was before being modified
358    pub fn reset(&mut self) {
359        self.selection = self.initial.clone();
360    }
361
362    /// Copies the current [`Selection`] in place
363    ///
364    /// This will leave an additional [`Selection`] with the current
365    /// selection. Do note that normal intersection rules apply, so if
366    /// at the end of the movement, this selection intersects with any
367    /// other, they will be merged into one.
368    ///
369    /// When this [`Cursor`] is dropped, like with normal [`Cursor`]s,
370    /// its [`Selection`] will be added to the [`Selections`], unless
371    /// you [destroy] it.
372    ///
373    /// [destroy]: Self::destroy
374    pub fn copy(&mut self) -> Cursor<'_, W, A, S> {
375        Cursor::new(
376            self.selection.clone(),
377            self.n,
378            false,
379            self.widget,
380            self.area,
381            self.next_i.clone(),
382            self.inc_searcher,
383        )
384    }
385
386    /// Destroys the current [`Selection`]
387    ///
388    /// Will not destroy it if it is the last [`Selection`] left
389    ///
390    /// If this was the main selection, the main selection will now be
391    /// the selection immediately behind it.
392    pub fn destroy(mut self) {
393        // If it is 1, it is actually 2, because this Selection is also part
394        // of that list.
395        if !self.widget.text().selections().is_empty() {
396            // Rc<Cell> needs to be manually dropped to reduce its counter.
397            self.next_i.take();
398            if self.was_main {
399                self.widget.text_mut().selections_mut().rotate_main(-1);
400            }
401            // The destructor is what inserts the Selection back into the list, so
402            // don't run it.
403            std::mem::forget(self);
404        } else {
405            // Just to be explicit.
406            drop(self);
407        }
408    }
409
410    /// Sets the "desired visual column"
411    ///
412    /// The desired visual column determines at what point in a line
413    /// the caret will be placed when moving [up and down] through
414    /// lines of varying lengths.
415    ///
416    /// Will also set the "desired wrapped visual column", which is
417    /// the same thing but used when moving vertically in a [wrapped]
418    /// fashion.
419    ///
420    /// [up and down]: Cursor::move_ver
421    /// [wrapped]: Cursor::move_ver_wrapped
422    pub fn set_desired_vcol(&mut self, x: usize) {
423        self.selection.set_desired_cols(x, x);
424    }
425
426    ////////// Iteration functions
427
428    /// Iterates over the [`char`]s
429    ///
430    /// This iteration will begin on the `caret`. It will also include
431    /// the [`Point`] of each `char`
432    pub fn chars_fwd(&self) -> impl Iterator<Item = (Point, char)> + '_ {
433        self.widget.text().chars_fwd(self.caret()..).unwrap()
434    }
435
436    /// Iterates over the [`char`]s, in reverse
437    ///
438    /// This iteration will begin on the `caret`. It will also include
439    /// the [`Point`] of each `char`
440    pub fn chars_rev(&self) -> impl Iterator<Item = (Point, char)> {
441        self.widget.text().chars_rev(..self.caret()).unwrap()
442    }
443
444    /// Searches the [`Text`] for a regex
445    ///
446    /// The search will begin on the `caret`, and returns the bounding
447    /// [`Point`]s, alongside the match. If an `end` is provided,
448    /// the search will stop at the given [`Point`].
449    ///
450    /// # Panics
451    ///
452    /// If the regex is not valid, this method will panic.
453    ///
454    /// ```rust
455    /// # use duat_core::prelude::*;
456    /// fn search_nth_paren<U: Ui, S>(pa: &mut Pass, handle: &mut Handle<File<U>, U, S>, n: usize) {
457    ///     handle.edit_all(pa, |mut e| {
458    ///         let mut nth = e.search_fwd('(', None).nth(n);
459    ///         if let Some([p0, p1]) = nth {
460    ///             e.move_to(p0);
461    ///             e.set_anchor();
462    ///             e.move_to(p1);
463    ///         }
464    ///     })
465    /// }
466    /// ```
467    pub fn search_fwd<R: RegexPattern>(
468        &self,
469        pat: R,
470        end: Option<Point>,
471    ) -> impl Iterator<Item = R::Match> + '_ {
472        let start = self.selection.caret();
473        let text = self.widget.text();
474        match end {
475            Some(end) => text.search_fwd(pat, start..end).unwrap(),
476            None => text.search_fwd(pat, start..text.len()).unwrap(),
477        }
478    }
479
480    /// Searches the [`Text`] for a regex, in reverse
481    ///
482    /// The search will begin on the `caret`, and returns the bounding
483    /// [`Point`]s, alongside the match. If a `start` is provided,
484    /// the search will stop at the given [`Point`].
485    ///
486    /// # Panics
487    ///
488    /// If the regex is not valid, this method will panic.
489    ///
490    /// ```rust
491    /// # use duat_core::prelude::*;
492    /// fn search_nth_paren<U: Ui, S>(
493    ///     pa: &mut Pass,
494    ///     handle: &mut Handle<File<U>, U, S>,
495    ///     s: &str,
496    ///     n: usize,
497    /// ) {
498    ///     handle.edit_all(pa, |mut e| {
499    ///         let mut nth = e.search_rev(s, None).nth(n);
500    ///         if let Some([p0, p1]) = nth {
501    ///             e.move_to(p0);
502    ///             e.set_anchor();
503    ///             e.move_to(p1);
504    ///         }
505    ///     })
506    /// }
507    /// ```
508    pub fn search_rev<R: RegexPattern>(
509        &self,
510        pat: R,
511        start: Option<Point>,
512    ) -> impl Iterator<Item = R::Match> + '_ {
513        let end = self.selection.caret();
514        let start = start.unwrap_or_default();
515        let text = self.widget.text();
516        text.search_rev(pat, start..end).unwrap()
517    }
518
519    /// Wether the current selection matches a regex pattern
520    pub fn matches<R: RegexPattern>(&self, pat: R) -> bool {
521        let range = self.selection.range(self.widget.text());
522        self.widget.text().matches(pat, range).unwrap()
523    }
524
525    ////////// Text queries
526
527    /// Returns the [`char`] in the `caret`
528    pub fn char(&self) -> char {
529        self.text()
530            .char_at(self.selection.caret())
531            .unwrap_or_else(|| panic!("{:#?}\n{:#?}", self.selection.caret(), self.text()))
532    }
533
534    /// Returns the [`char`] at a given [`Point`]
535    pub fn char_at(&self, p: Point) -> Option<char> {
536        self.text().char_at(p)
537    }
538
539    /// Returns the [`Selection`]'s selection
540    ///
541    /// The reason why this return value is `IntoIter<&str, 2>` is
542    /// because the [`Text`] utilizes an underlying [`GapBuffer`]
543    /// to store the characters. This means that the text is
544    /// always separated into two distinct chunks.
545    ///
546    /// If this [`Selection`]'s selection happens to be entirely
547    /// within one of these chunks, the other `&str` will just be
548    /// empty.
549    ///
550    /// [`GapBuffer`]: gapbuf::GapBuffer
551    pub fn selection(&self) -> Strs<'_> {
552        let range = self.selection.range(self.text());
553        self.text().strs(range).unwrap()
554    }
555
556    /// Returns the [`Strs`] for the given [`TextRange`]
557    ///
558    /// [`GapBuffer`]: gapbuf::GapBuffer
559    pub fn strs(&self, range: impl TextRange) -> Option<Strs<'_>> {
560        self.widget.text().strs(range)
561    }
562
563    /// Returns the length of the [`Text`], in [`Point`]
564    pub fn len(&self) -> Point {
565        self.text().len()
566    }
567
568    /// Returns the position of the last [`char`] if there is one
569    pub fn last_point(&self) -> Point {
570        self.text().last_point()
571    }
572
573    /// An [`Iterator`] over the lines in a given [range]
574    ///
575    /// [range]: TextRange
576    pub fn lines_on(&self, range: impl TextRange) -> Lines<'_> {
577        self.widget.text().lines(range)
578    }
579
580    /// Gets the current level of indentation
581    pub fn indent(&self) -> usize {
582        self.widget
583            .text()
584            .indent(self.caret(), self.area, self.cfg())
585    }
586
587    /// Gets the indentation level on the given [`Point`]
588    pub fn indent_on(&self, p: Point) -> usize {
589        self.widget.text().indent(p, self.area, self.cfg())
590    }
591
592    ////////// Selection queries
593
594    /// Returns the `caret`
595    pub fn caret(&self) -> Point {
596        self.selection.caret()
597    }
598
599    /// Returns the `anchor`
600    pub fn anchor(&self) -> Option<Point> {
601        self.selection.anchor()
602    }
603
604    /// The [`Point`] range of the [`Selection`]
605    pub fn range(&self) -> [Point; 2] {
606        self.selection.point_range(self.text())
607    }
608
609    /// An exclusive [`Point`] range of the [`Selection`]
610    pub fn range_excl(&self) -> [Point; 2] {
611        self.selection.point_range_excl()
612    }
613
614    /// The [`VPoint`] range of the [`Selection`]
615    ///
616    /// Use only if you need the things that the [`VPoint`] provides,
617    /// in order to preven extraneous calculations
618    pub fn v_caret(&self) -> VPoint {
619        self.selection
620            .v_caret(self.widget.text(), self.area, self.widget.print_cfg())
621    }
622
623    /// The [`VPoint`] of the anchor, if it exists
624    ///
625    /// Use only if you need the things that the [`VPoint`] provides,
626    /// in order to preven extraneous calculations
627    pub fn v_anchor(&self) -> Option<VPoint> {
628        self.selection
629            .v_anchor(self.widget.text(), self.area, self.widget.print_cfg())
630    }
631
632    /// Returns `true` if the `anchor` exists before the `caret`
633    pub fn anchor_is_start(&self) -> bool {
634        self.anchor().is_none_or(|anchor| anchor < self.caret())
635    }
636
637    /// Whether or not this is the main [`Selection`]
638    pub fn is_main(&self) -> bool {
639        self.was_main
640    }
641
642    /// The [`Text`] of the [`Widget`]
643    pub fn text(&self) -> &Text {
644        self.widget.text()
645    }
646
647    /// The [`PrintCfg`] in use
648    pub fn cfg(&self) -> PrintCfg {
649        self.widget.print_cfg()
650    }
651}
652
653impl<U: Ui, S> Cursor<'_, File<U>, U::Area, S> {
654    /// Reads the [`Bytes`] and a [`Parser`]
655    ///
656    /// [`Bytes`]: crate::text::Bytes
657    pub fn read_parser<Rd: Parser<U>, Ret>(&self, read: impl FnOnce(&Rd) -> Ret) -> Option<Ret> {
658        self.widget.read_parser(read)
659    }
660}
661
662/// Incremental search functions, only available on [`IncSearcher`]s
663///
664/// [`IncSearcher`]: https://docs.rs/duat-utils/latest/duat_utils/modes/struct.IncSearcher.html
665impl<W: Widget<A::Ui> + ?Sized, A: Area> Cursor<'_, W, A, Searcher> {
666    /// Search incrementally from an [`IncSearch`] request
667    ///
668    /// This will match the Regex pattern from the current position of
669    /// the caret. if `end` is [`Some`], the search will end at the
670    /// requested [`Point`].
671    ///
672    /// [`IncSearch`]: https://docs.rs/duat-utils/latest/duat_utils/modes/struct.IncSearch.html
673    pub fn search_inc_fwd(&mut self, end: Option<Point>) -> impl Iterator<Item = [Point; 2]> + '_ {
674        let range = if let Some(end) = end {
675            (self.selection.caret()..end).to_range(self.text().len().byte())
676        } else {
677            (self.selection.caret()..).to_range(self.text().len().byte())
678        };
679        self.inc_searcher.search_fwd(self.widget.text(), range)
680    }
681
682    /// Search incrementally from an [`IncSearch`] request in reverse
683    ///
684    /// This will match the Regex pattern from the current position of
685    /// the caret in reverse. if `start` is [`Some`], the search will
686    /// end at the requested [`Point`].
687    ///
688    /// [`IncSearch`]: https://docs.rs/duat-utils/latest/duat_utils/modes/struct.IncSearch.html
689    pub fn search_inc_rev(
690        &mut self,
691        start: Option<Point>,
692    ) -> impl Iterator<Item = [Point; 2]> + '_ {
693        let range = if let Some(start) = start {
694            (start..self.selection.caret()).to_range(self.text().len().byte())
695        } else {
696            (..self.selection.caret()).to_range(self.text().len().byte())
697        };
698        self.inc_searcher.search_rev(self.widget.text(), range)
699    }
700
701    /// Whether the [`Selection`]'s selection matches the
702    /// [`IncSearch`] request
703    ///
704    /// [`IncSearch`]: https://docs.rs/duat-utils/latest/duat_utils/modes/struct.IncSearch.html
705    pub fn matches_inc(&mut self) -> bool {
706        let range = self.selection.range(self.widget.text());
707        self.inc_searcher
708            .matches(self.widget.text().strs(range).unwrap().to_string().as_str())
709    }
710}
711
712// SAFETY: In theory, it should be impossible to maintain a reference
713// to W after it has dropped, since the Handle would be mutably
714// borrowing from said W, and you can only get a Cursor from Handles.
715// Thus, the only thing which may have been dropped is the Selections
716// within, which are accounted for.
717unsafe impl<#[may_dangle] 'a, W: Widget<A::Ui> + ?Sized + 'a, A: Area + 'a, S: 'a> Drop
718    for Cursor<'a, W, A, S>
719{
720    fn drop(&mut self) {
721        let selection = std::mem::take(&mut self.selection);
722        let ([inserted_i, selections_taken], last_selection_overhangs) = self
723            .widget
724            .text_mut()
725            .selections_mut()
726            .insert(self.n, selection, self.was_main);
727
728        if let Some(next_i) = self.next_i.as_ref()
729            && inserted_i <= next_i.get()
730        {
731            let go_to_next = !last_selection_overhangs as usize;
732            next_i.set(
733                next_i
734                    .get()
735                    .saturating_sub(selections_taken)
736                    .max(inserted_i)
737                    + go_to_next,
738            )
739        }
740    }
741}
742
743impl<'a, W: Widget<A::Ui> + ?Sized, A: Area, S> std::fmt::Debug for Cursor<'a, W, A, S> {
744    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
745        f.debug_struct("Cursor")
746            .field("selection", &self.selection)
747            .finish_non_exhaustive()
748    }
749}
750
751/// An [`Iterator`] overf all [`Cursor`]s
752pub struct Cursors<'a, W: Widget<A::Ui> + ?Sized, A: Area, S> {
753    next_i: Rc<Cell<usize>>,
754    widget: &'a mut W,
755    area: &'a A,
756    inc_searcher: RefMut<'a, S>,
757}
758
759impl<'a, W: Widget<A::Ui> + ?Sized, A: Area, S> Cursors<'a, W, A, S> {
760    /// Creates a new [`Cursors`]
761    pub(crate) fn new(
762        next_i: usize,
763        widget: &'a mut W,
764        area: &'a A,
765        inc_searcher: RefMut<'a, S>,
766    ) -> Self {
767        Self {
768            next_i: Rc::new(Cell::new(next_i)),
769            widget,
770            area,
771            inc_searcher,
772        }
773    }
774}
775
776impl<'a, 'lend, W: Widget<A::Ui> + ?Sized, A: Area, S> Lending<'lend> for Cursors<'a, W, A, S> {
777    type Lend = Cursor<'lend, W, A, S>;
778}
779
780impl<'a, W: Widget<A::Ui> + ?Sized, A: Area, S> Lender for Cursors<'a, W, A, S> {
781    fn next<'lend>(&'lend mut self) -> Option<<Self as Lending<'lend>>::Lend> {
782        let current_i = self.next_i.get();
783        let (selection, was_main) = self.widget.text_mut().selections_mut().remove(current_i)?;
784
785        Some(Cursor::new(
786            selection,
787            current_i,
788            was_main,
789            self.widget,
790            self.area,
791            Some(self.next_i.clone()),
792            &mut self.inc_searcher,
793        ))
794    }
795}
796
797/// One or two [`Point`]s
798pub trait PointOrPoints {
799    /// Internal movement function for monomorphization
800    #[doc(hidden)]
801    fn move_to<W: Widget<U> + ?Sized, U: Ui, S>(self, cursor: &mut Cursor<'_, W, U::Area, S>);
802}
803
804impl PointOrPoints for Point {
805    fn move_to<W: Widget<U> + ?Sized, U: Ui, S>(self, cursor: &mut Cursor<'_, W, U::Area, S>) {
806        cursor.selection.move_to(self, cursor.widget.text());
807    }
808}
809
810impl PointOrPoints for Range<Point> {
811    fn move_to<W: Widget<U> + ?Sized, U: Ui, S>(self, cursor: &mut Cursor<'_, W, U::Area, S>) {
812        assert!(
813            self.start <= self.end,
814            "slice index start is larger than end"
815        );
816
817        cursor.selection.move_to(self.start, cursor.widget.text());
818        if self.start < self.end {
819            cursor.set_anchor();
820            cursor.selection.move_to(self.end, cursor.widget.text());
821            if self.end < cursor.widget.text().len() {
822                cursor.move_hor(-1);
823            }
824        }
825    }
826}
827
828impl PointOrPoints for RangeInclusive<Point> {
829    fn move_to<W: Widget<U> + ?Sized, U: Ui, S>(self, cursor: &mut Cursor<'_, W, U::Area, S>) {
830        assert!(
831            self.start() <= self.end(),
832            "slice index start is larger than end"
833        );
834
835        cursor
836            .selection
837            .move_to(*self.start(), cursor.widget.text());
838        cursor.set_anchor();
839        cursor.selection.move_to(*self.end(), cursor.widget.text());
840    }
841}
842
843impl PointOrPoints for RangeFrom<Point> {
844    fn move_to<W: Widget<U> + ?Sized, U: Ui, S>(self, cursor: &mut Cursor<'_, W, U::Area, S>) {
845        cursor.selection.move_to(self.start, cursor.widget.text());
846        if self.start < cursor.text().len() {
847            cursor.set_anchor();
848            cursor
849                .selection
850                .move_to(cursor.widget.text().len(), cursor.widget.text());
851            cursor.move_hor(-1);
852        }
853    }
854}
855
856impl PointOrPoints for RangeTo<Point> {
857    fn move_to<W: Widget<U> + ?Sized, U: Ui, S>(self, cursor: &mut Cursor<'_, W, U::Area, S>) {
858        cursor.move_to_start();
859        if Point::default() < self.end {
860            cursor.set_anchor();
861            cursor.selection.move_to(self.end, cursor.widget.text());
862            cursor.move_hor(-1);
863        }
864    }
865}
866
867impl PointOrPoints for RangeToInclusive<Point> {
868    fn move_to<W: Widget<U> + ?Sized, U: Ui, S>(self, cursor: &mut Cursor<'_, W, U::Area, S>) {
869        cursor.move_to_start();
870        cursor.set_anchor();
871        cursor.selection.move_to(self.end, cursor.widget.text());
872    }
873}
874
875impl PointOrPoints for RangeFull {
876    fn move_to<W: Widget<U> + ?Sized, U: Ui, S>(self, cursor: &mut Cursor<'_, W, U::Area, S>) {
877        cursor.move_to_start();
878        cursor.set_anchor();
879        cursor
880            .selection
881            .move_to(cursor.widget.text().len(), cursor.widget.text());
882    }
883}