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