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