duat_core/context/
handles.rs

1//! Widget handles for Duat
2//!
3//! These are used pretty much everywhere, and are essentially just an
4//! [`RwData<W>`] conjoined to an [`Ui::Area`].
5
6use std::{
7    any::TypeId,
8    cell::{Cell, RefCell, RefMut},
9    rc::Rc,
10};
11
12use lender::Lender;
13
14use super::FileParts;
15use crate::{
16    cfg::PrintCfg,
17    data::{Pass, RwData},
18    file::File,
19    mode::{Cursor, Cursors, Selection, Selections},
20    text::{Searcher, Text},
21    ui::{Node, RawArea, Ui, Widget},
22};
23
24/// A handle to a [`File`] widget
25///
26/// This handle acts much like an [`RwData<File>`], but it also
27/// includes an [`Area`] that can be acted upon alongside the
28/// [`File`].
29///
30/// This is the only way you are supposed to read information about
31/// the [`File`], in order to display it on [`Widget`]s, create
32/// [`Text`]s, and do all sorts of things. You can, of course, also
33/// modify a [`File`] from within this struct, but you should be
34/// careful to prevent infinite loops, where you modify a [`File`], it
35/// gets updated, and then you modify it again after noticing that it
36/// has changed.
37///
38/// The main difference between a [`FileHandle<U>`] and a
39/// [`Handle<File<U>, U>`] is that the
40///
41/// [`Area`]: crate::ui::RawArea
42/// [`Text`]: crate::text::Text
43#[derive(Clone)]
44pub struct FileHandle<U: Ui> {
45    fixed: Option<FileParts<U>>,
46    current: RwData<Option<FileParts<U>>>,
47}
48
49impl<U: Ui> FileHandle<U> {
50    /// Returns a new [`FileHandle`] from its parts
51    pub(crate) fn from_parts(
52        fixed: Option<FileParts<U>>,
53        current: RwData<Option<FileParts<U>>>,
54    ) -> Self {
55        Self { fixed, current }
56    }
57
58    /// Reads from the [`File`] and the [`Area`] using a [`Pass`]
59    ///
60    /// The consistent use of a [`Pass`] for the purposes of
61    /// reading/writing to the values of [`RwData`]s ensures that no
62    /// panic or invalid borrow happens at runtime, even while working
63    /// with untrusted code. More importantly, Duat uses these
64    /// guarantees in order to give the end user a ridiculous amount
65    /// of freedom in where they can do things, whilst keeping Rust's
66    /// number one rule and ensuring thread safety, even with a
67    /// relatively large amount of shareable state.
68    ///
69    /// # Panics
70    ///
71    /// Panics if there is a mutable borrow of this struct somewhere,
72    /// which could happen if you use [`RwData::write_unsafe`] or
73    /// [`RwData::write_unsafe_as`] from some other place
74    ///
75    /// [`Area`]: crate::ui::RawArea
76    pub fn read<Ret>(&self, pa: &Pass, f: impl FnOnce(&File<U>, &U::Area) -> Ret) -> Ret {
77        if let Some((handle, _)) = self.fixed.as_ref() {
78            let file = handle.widget().acquire(pa);
79            f(&file, handle.area())
80        } else {
81            self.current.read(pa, |parts| {
82                let (handle, _) = parts.as_ref().unwrap();
83                let file = handle.widget().acquire(pa);
84                f(&file, handle.area())
85            })
86        }
87    }
88
89    /// Writes to the [`File`] and [`Area`] within using a [`Pass`]
90    ///
91    /// The consistent use of a [`Pass`] for the purposes of
92    /// reading/writing to the values of [`RwData`]s ensures that no
93    /// panic or invalid borrow happens at runtime, even while working
94    /// with untrusted code. More importantly, Duat uses these
95    /// guarantees in order to give the end user a ridiculous amount
96    /// of freedom in where they can do things, whilst keeping Rust's
97    /// number one rule and ensuring thread safety, even with a
98    /// relatively large amount of shareable state.
99    ///
100    /// # Panics
101    ///
102    /// Panics if there is any type of borrow of this struct
103    /// somewhere, which could happen if you use
104    /// [`RwData::read_unsafe`] or [`RwData::write_unsafe`], for
105    /// example.
106    ///
107    /// [`Area`]: crate::ui::RawArea
108    pub fn write<Ret>(&self, pa: &mut Pass, f: impl FnOnce(&mut File<U>, &U::Area) -> Ret) -> Ret {
109        if let Some((handle, _)) = self.fixed.as_ref() {
110            f(&mut handle.widget.acquire_mut(pa), &handle.area)
111        } else {
112            // SAFETY: Since the update closure only uses a write method, the
113            // Pass becomes unusable for other purposes, making it impossible
114            // to make further borrows, asserting that there is no other borrow
115            // for self.current.
116            unsafe {
117                self.current.read_unsafe(|parts| {
118                    let (handle, _) = parts.as_ref().unwrap();
119                    f(&mut handle.widget.acquire_mut(pa), &handle.area)
120                })
121            }
122        }
123    }
124
125    /// Reads a [`Widget`] related to this [`File`], alongside its
126    /// [`Area`], with a [`Pass`]
127    ///
128    /// A related [`Widget`] is one that was pushed to this [`File`]
129    /// during the [`OnFileOpen`] [hook].
130    ///
131    /// [`Area`]: crate::ui::Area
132    /// [`OnFileOpen`]: crate::hook::OnFileOpen
133    /// [hook]: crate::hook
134    pub fn read_related<W: 'static, R>(
135        &self,
136        pa: &Pass,
137        f: impl FnOnce(&W, &U::Area) -> R,
138    ) -> Option<R> {
139        let read = |(handle, related): &FileParts<U>| {
140            if TypeId::of::<W>() == TypeId::of::<File<U>>() {
141                let area = handle.area();
142                handle.widget().read_as(pa, |w| f(w, area))
143            } else {
144                related.read(pa, |related| {
145                    related
146                        .iter()
147                        .find(|node| node.data_is::<W>())
148                        .and_then(|node| node.widget().read_as(pa, |w| f(w, node.area())))
149                })
150            }
151        };
152
153        if let Some(parts) = self.fixed.as_ref() {
154            read(parts)
155        } else {
156            self.current.read(pa, |parts| read(parts.as_ref().unwrap()))
157        }
158    }
159
160    /// Gets the [`RwData`] and [`Area`] of a related widget, with a
161    /// [`Pass`]
162    ///
163    /// A related [`Widget`] is one that was pushed to this [`File`]
164    /// during the [`OnFileOpen`] [hook].
165    ///
166    /// [`Area`]: crate::ui::Area
167    /// [`OnFileOpen`]: crate::hook::OnFileOpen
168    /// [hook]: crate::hook
169    pub fn get_related_widget<W: Widget<U> + 'static>(&self, pa: &Pass) -> Option<Handle<W, U>> {
170        let get_related = |(handle, related): &FileParts<U>| {
171            if TypeId::of::<W>() == TypeId::of::<File<U>>() {
172                let widget = handle.widget().try_downcast()?;
173                Some(Handle::from_parts(
174                    widget,
175                    handle.area().clone(),
176                    handle.mask().clone(),
177                ))
178            } else {
179                related.read(pa, |related| {
180                    related.iter().find_map(|node| {
181                        let (widget, area, mask, _) = node.parts();
182                        widget
183                            .try_downcast()
184                            .map(|data| Handle::from_parts(data, area.clone(), mask.clone()))
185                    })
186                })
187            }
188        };
189
190        if let Some(parts) = self.fixed.as_ref() {
191            get_related(parts)
192        } else {
193            self.current
194                .read(pa, |parts| get_related(parts.as_ref().unwrap()))
195        }
196    }
197
198    /// Writes to the related widgets
199    pub(crate) fn write_related_widgets(&self, pa: &mut Pass, f: impl FnOnce(&mut Vec<Node<U>>)) {
200        if let Some((.., related)) = self.fixed.as_ref() {
201            related.write(pa, f)
202        } else {
203            // SAFETY: Same situation as the write method
204            unsafe {
205                self.current
206                    .read_unsafe(|parts| parts.as_ref().unwrap().1.write(pa, f))
207            }
208        }
209    }
210
211    ////////// Querying functions
212
213    /// Gets a [`Handle`] from this [`FileHandle`]
214    pub fn handle(&self, pa: &Pass) -> Handle<File<U>, U> {
215        if let Some((handle, _)) = self.fixed.as_ref() {
216            handle.clone()
217        } else {
218            self.current.acquire(pa).as_ref().unwrap().0.clone()
219        }
220    }
221
222    /// Wether someone else called [`write`] or [`write_as`] since the
223    /// last [`read`] or [`write`]
224    ///
225    /// Do note that this *DOES NOT* mean that the value inside has
226    /// actually been changed, it just means a mutable reference was
227    /// acquired after the last call to [`has_changed`].
228    ///
229    /// Some types like [`Text`], and traits like [`Widget`] offer
230    /// [`needs_update`] methods, you should try to determine what
231    /// parts to look for changes.
232    ///
233    /// Generally though, you can use this method to gauge that.
234    ///
235    /// [`write`]: RwData::write
236    /// [`write_as`]: RwData::write_as
237    /// [`read`]: RwData::read
238    /// [`has_changed`]: RwData::has_changed
239    /// [`Text`]: crate::text::Text
240    /// [`Widget`]: crate::ui::Widget
241    /// [`needs_update`]: crate::ui::Widget::needs_update
242    pub fn has_changed(&self) -> bool {
243        if let Some((handle, _)) = self.fixed.as_ref() {
244            handle.has_changed()
245        } else {
246            self.current.has_changed()
247                || self.current.read_raw(|parts| {
248                    let (handle, _) = parts.as_ref().unwrap();
249                    handle.has_changed()
250                })
251        }
252    }
253
254    /// Wether the [`File`] within has swapped to another
255    ///
256    /// This can only happen when this is a
257    pub fn has_swapped(&self) -> bool {
258        let has_changed = self.current.has_changed();
259        self.current.declare_as_read();
260        has_changed
261    }
262
263    /// Wether the [`RwData`] within and another point to the same
264    /// value
265    pub fn ptr_eq<T: ?Sized>(&self, pa: &Pass, other: &RwData<T>) -> bool {
266        if let Some((handle, ..)) = self.fixed.as_ref() {
267            handle.ptr_eq(other)
268        } else {
269            self.current
270                .read(pa, |parts| parts.as_ref().unwrap().0.ptr_eq(other))
271        }
272    }
273
274    /// The name of the [`File`] in question
275    pub fn name(&self, pa: &Pass) -> String {
276        if let Some((handle, ..)) = self.fixed.as_ref() {
277            handle.read(pa, |f, _| f.name())
278        } else {
279            self.current.read(pa, |parts| {
280                parts.as_ref().unwrap().0.read(pa, |f, _| f.name())
281            })
282        }
283    }
284
285    /// The path of the [`File`] in question
286    pub fn path(&self, pa: &Pass) -> String {
287        if let Some((handle, ..)) = self.fixed.as_ref() {
288            handle.read(pa, |f, _| f.path())
289        } else {
290            self.current.read(pa, |parts| {
291                parts.as_ref().unwrap().0.read(pa, |f, _| f.path())
292            })
293        }
294    }
295
296    /// The path of the [`File`] in question, if it was set
297    pub fn set_path(&self, pa: &Pass) -> Option<String> {
298        if let Some((handle, ..)) = self.fixed.as_ref() {
299            handle.read(pa, |f, _| f.path_set())
300        } else {
301            self.current.read(pa, |parts| {
302                parts.as_ref().unwrap().0.read(pa, |f, _| f.path_set())
303            })
304        }
305    }
306}
307
308/// A handle to a [`Widget`] in Duat
309///
310/// The [`Handle`] lets you do all sorts of edits on a [`Widget`]. You
311/// can, for example, make use of the [`Selection`]s in its [`Text`]
312/// in order to edit the [`Text`] in a very declarative way.
313///
314/// One of the places where this is commonly done is within [`Mode`]s,
315/// where you get access to the [`Handle`] of the currently active
316/// [`Widget`]. Below is a very straightforward [`Mode`]:
317///
318/// ```rust
319/// use duat_core::prelude::*;
320/// /// A very basic example Mode.
321/// #[derive(Clone)]
322/// struct PlacesCharactersAndMoves;
323///
324/// impl<U: Ui> Mode<U> for PlacesCharactersAndMoves {
325///     type Widget = File<U>;
326///
327///     // ...
328///     fn send_key(&mut self, _: &mut Pass, _: KeyEvent, _: Handle<Self::Widget, U>) {
329///         todo!();
330///     }
331/// }
332/// ```
333///
334/// In order to modify the widget, you must implement the
335/// [`Mode::send_key`] method. In it, you receive the following:
336///
337/// - A [`&mut Pass`], which will give you access to all of duat's
338///   shared state;
339/// - The [key] that was sent, may be a [mapped] key.
340/// - The [`Handle`] for a [`Mode::Widget`].
341///
342/// ```rust
343/// use duat_core::prelude::*;
344/// #[derive(Clone)]
345/// struct PlacesCharactersAndMoves;
346/// impl<U: Ui> Mode<U> for PlacesCharactersAndMoves {
347///     type Widget = File<U>;
348///
349///     fn send_key(&mut self, pa: &mut Pass, key: KeyEvent, handle: Handle<File<U>, U>) {
350///         match key {
351///             // actions based on the key pressed
352///             key!(KeyCode::Char('c')) => {
353///                 // Do something when the character 'c' is typed.
354///             }
355///             _ => todo!("The remaining keys"),
356///         }
357///     }
358/// }
359/// ```
360///
361/// (You can use the [`key!`] macro in order to match [`KeyEvent`]s).
362///
363/// With the [`Handle`], you can modify [`Text`] in a simplified
364/// way. This is done by two actions, [editing] and [moving]. You
365/// can only do one of these on any number of selections at the same
366/// time.
367///
368/// ```rust
369/// # use duat_core::prelude::*;
370/// # #[derive(Clone)]
371/// # struct PlacesCharactersAndMoves;
372/// impl<U: Ui> Mode<U> for PlacesCharactersAndMoves {
373/// #   type Widget = File<U>;
374///     /* ... */
375///     fn send_key(&mut self, pa: &mut Pass, key: KeyEvent, handle: Handle<Self::Widget, U>) {
376///         match key {
377///             key!(KeyCode::Char(c)) => {
378///                 handle.edit_all(pa, |mut e| {
379///                     e.insert('c');
380///                     e.move_hor(1);
381///                 });
382///             },
383///             key!(KeyCode::Right, KeyMod::SHIFT) => {
384///                 handle.edit_all(pa, |mut e| {
385///                     if e.anchor().is_none() {
386///                         e.set_anchor();
387///                     }
388///                     e.move_hor(1);
389///                 });
390///             }
391///             key!(KeyCode::Right) => {
392///                 handle.edit_all(pa, |mut e| {
393///                     e.unset_anchor();
394///                     e.move_hor(1);
395///                 });
396///             }
397///             _ => todo!("Predictable remaining implementations")
398///         }
399///     }
400/// # }
401/// ```
402///
403/// [`Mode`]: crate::mode::Mode
404/// [`Mode::Widget`]: crate::mode::Mode::Widget
405/// [`&mut Pass`]: Pass
406/// [`PromptLine`]: https://docs.rs/duat-utils/latest/duat_utils/widgets/struct.PromptLine.html
407/// [`Mode::send_key`]: crate::mode::Mode::send_key
408/// [key]: crate::mode::KeyEvent
409/// [mapped]: crate::mode::map
410/// [`read`]: RwData::read
411/// [`write`]: RwData::write
412/// [`U::Area`]: Ui::Area
413/// [`Self::Widget`]: crate::mode::Mode::Widget
414/// [`Some(selections)`]: Some
415/// [`Ui::Area`]: crate::ui::Ui::Area
416/// [commands]: crate::cmd
417/// [`key!`]: crate::mode::key
418/// [`KeyEvent`]: crate::mode::KeyEvent
419/// [editing]: Cursor
420/// [moving]: Cursor
421/// [`Mode`]: crate::mode::Mode
422/// [`U::Area`]: Ui::Area
423#[derive(Debug)]
424pub struct Handle<W: Widget<U>, U: Ui, S = ()> {
425    widget: RwData<W>,
426    area: U::Area,
427    mask: Rc<Cell<&'static str>>,
428    searcher: RefCell<S>,
429}
430
431impl<W: Widget<U>, U: Ui> Handle<W, U> {
432    /// Returns a new instance of a [`Handle<W, U>`]
433    pub(crate) fn from_parts(
434        widget: RwData<W>,
435        area: U::Area,
436        mask: Rc<Cell<&'static str>>,
437    ) -> Self {
438        Self {
439            widget,
440            area,
441            mask,
442            searcher: RefCell::new(()),
443        }
444    }
445}
446
447impl<W: Widget<U>, U: Ui, S> Handle<W, U, S> {
448    /// Reads from the [`Widget`] and the [`Area`] using a [`Pass`]
449    ///
450    /// The consistent use of a [`Pass`] for the purposes of
451    /// reading/writing to the values of [`RwData`]s ensures that no
452    /// panic or invalid borrow happens at runtime, even while working
453    /// with untrusted code. More importantly, Duat uses these
454    /// guarantees in order to give the end user a ridiculous amount
455    /// of freedom in where they can do things, whilst keeping Rust's
456    /// number one rule and ensuring thread safety, even with a
457    /// relatively large amount of shareable state.
458    ///
459    /// # Panics
460    ///
461    /// Panics if there is a mutable borrow of this struct somewhere,
462    /// which could happen if you use [`RwData::write_unsafe`] or
463    /// [`RwData::write_unsafe_as`] from some other place
464    ///
465    /// [`Area`]: crate::ui::RawArea
466    pub fn read<Ret>(&self, pa: &Pass, f: impl FnOnce(&W, &U::Area) -> Ret) -> Ret {
467        f(&self.widget.acquire(pa), &self.area)
468    }
469
470    /// Writes to the [`Widget`] and [`Area`] within using a [`Pass`]
471    ///
472    /// The consistent use of a [`Pass`] for the purposes of
473    /// reading/writing to the values of [`RwData`]s ensures that no
474    /// panic or invalid borrow happens at runtime, even while working
475    /// with untrusted code. More importantly, Duat uses these
476    /// guarantees in order to give the end user a ridiculous amount
477    /// of freedom in where they can do things, whilst keeping Rust's
478    /// number one rule and ensuring thread safety, even with a
479    /// relatively large amount of shareable state.
480    ///
481    /// # Panics
482    ///
483    /// Panics if there is any type of borrow of this struct
484    /// somewhere, which could happen if you use
485    /// [`RwData::read_unsafe`] or [`RwData::write_unsafe`], for
486    /// example.
487    ///
488    /// [`Area`]: crate::ui::RawArea
489    pub fn write<Ret>(&self, pa: &mut Pass, f: impl FnOnce(&mut W, &U::Area) -> Ret) -> Ret {
490        f(&mut self.widget.acquire_mut(pa), &self.area)
491    }
492
493    ////////// Selection Editing functions
494
495    /// Edits the nth [`Selection`] in the [`Text`]
496    ///
497    /// Once dropped, the [`Selection`] in this [`Cursor`] will be
498    /// added back to the list of [`Selection`]s, unless it is
499    /// [destroyed]
500    ///
501    /// If you want to edit on the main selection, see [`edit_main`],
502    /// if you want to edit on many [`Selection`]s, see
503    /// [`edit_iter`].
504    ///
505    /// Just like all other `edit` methods, this one will populate the
506    /// [`Selections`], so if there are no [`Selection`]s, it will
507    /// create one at [`Point::default`].
508    ///
509    /// [destroyed]: Cursor::destroy
510    /// [`edit_main`]: Self::edit_main
511    /// [`edit_iter`]: Self::edit_iter
512    /// [`Point::default`]: crate::text::Point::default
513    pub fn edit_nth<Ret>(
514        &self,
515        pa: &mut Pass,
516        n: usize,
517        edit: impl FnOnce(Cursor<W, U::Area, S>) -> Ret,
518    ) -> Ret {
519        fn get_parts<'a, W: Widget<U>, U: Ui>(
520            pa: &mut Pass,
521            widget: &'a RwData<W>,
522            n: usize,
523        ) -> (Selection, bool, RefMut<'a, W>) {
524            let mut widget = widget.acquire_mut(pa);
525            let selections = widget.text_mut().selections_mut().unwrap();
526            selections.populate();
527            let Some((selection, was_main)) = selections.remove(n) else {
528                panic!("Selection index {n} out of bounds");
529            };
530
531            (selection, was_main, widget)
532        }
533
534        let (selection, was_main, mut widget) = get_parts(pa, &self.widget, n);
535
536        // This is safe because of the &mut Pass argument
537        let mut searcher = self.searcher.borrow_mut();
538
539        edit(Cursor::new(
540            selection,
541            n,
542            was_main,
543            &mut *widget,
544            &self.area,
545            None,
546            &mut searcher,
547        ))
548    }
549
550    /// Edits the main [`Selection`] in the [`Text`]
551    ///
552    /// Once dropped, the [`Selection`] in this [`Cursor`] will be
553    /// added back to the list of [`Selection`]s, unless it is
554    /// [destroyed]
555    ///
556    /// If you want to edit on the `nth` selection, see [`edit_nth`],
557    /// same for [`edit_last`], if you want to edit on many
558    /// [`Selection`]s, see [`edit_iter`].
559    ///
560    /// Just like all other `edit` methods, this one will populate the
561    /// [`Selections`], so if there are no [`Selection`]s, it will
562    /// create one at [`Point::default`].
563    ///
564    /// [destroyed]: Cursor::destroy
565    /// [`edit_nth`]: Self::edit_nth
566    /// [`edit_last`]: Self::edit_last
567    /// [`edit_iter`]: Self::edit_iter
568    /// [`Point::default`]: crate::text::Point::default
569    pub fn edit_main<Ret>(
570        &self,
571        pa: &mut Pass,
572        edit: impl FnOnce(Cursor<W, U::Area, S>) -> Ret,
573    ) -> Ret {
574        self.edit_nth(
575            pa,
576            self.widget
577                .read(pa, |wid| wid.text().selections().unwrap().main_index()),
578            edit,
579        )
580    }
581
582    /// Edits the last [`Selection`] in the [`Text`]
583    ///
584    /// Once dropped, the [`Selection`] in this [`Cursor`] will be
585    /// added back to the list of [`Selection`]s, unless it is
586    /// [destroyed]
587    ///
588    /// If you want to edit on the `nth` selection, see [`edit_nth`],
589    /// same for [`edit_main`], if you want to edit on many
590    /// [`Selection`]s, see [`edit_iter`].
591    ///
592    /// Just like all other `edit` methods, this one will populate the
593    /// [`Selections`], so if there are no [`Selection`]s, it will
594    /// create one at [`Point::default`].
595    ///
596    /// [destroyed]: Cursor::destroy
597    /// [`edit_nth`]: Self::edit_nth
598    /// [`edit_main`]: Self::edit_main
599    /// [`edit_iter`]: Self::edit_iter
600    /// [`Point::default`]: crate::text::Point::default
601    pub fn edit_last<Ret>(
602        &self,
603        pa: &mut Pass,
604        edit: impl FnOnce(Cursor<W, U::Area, S>) -> Ret,
605    ) -> Ret {
606        self.edit_nth(
607            pa,
608            self.widget
609                .read(pa, |wid| wid.text().selections().unwrap().len())
610                .saturating_sub(1),
611            edit,
612        )
613    }
614
615    /// A [`Lender`] over all [`Cursor`]s of the [`Text`]
616    ///
617    /// This lets you easily iterate over all [`Selection`]s, without
618    /// having to worry about insertion affecting the order at which
619    /// they are edited (like what repeated calls to [`edit_nth`]
620    /// would do)
621    ///
622    /// Note however that you can't use a [`Lender`] (also known as a
623    /// lending iterator) in a `for` loop, but you should be able
624    /// to just `while let Some(e) = editors.next() {}` or
625    /// `handle.edit_iter().for_each(|_| {})` instead.
626    ///
627    /// Just like all other `edit` methods, this one will populate the
628    /// [`Selections`], so if there are no [`Selection`]s, it will
629    /// create one at [`Point::default`].
630    ///
631    /// [`edit_nth`]: Self::edit_nth
632    /// [`Point::default`]: crate::text::Point::default
633    pub fn edit_iter<Ret>(
634        &self,
635        pa: &mut Pass,
636        edit: impl FnOnce(Cursors<'_, W, U::Area, S>) -> Ret,
637    ) -> Ret {
638        edit(self.get_iter(pa))
639    }
640
641    /// A shortcut for iterating over all selections
642    ///
643    /// This is the equivalent of calling:
644    ///
645    /// ```rust
646    /// # use duat_core::prelude::*;
647    /// # fn test<U: Ui>(pa: &mut Pass, handle: Handle<File<U>, U, ()>) {
648    /// handle.edit_iter(pa, |iter| iter.for_each(|e| { /* .. */ }));
649    /// # }
650    /// ```
651    ///
652    /// But it can't return a value, and is meant to reduce the
653    /// indentation that will inevitably come from using the
654    /// equivalent long form call.
655    pub fn edit_all(&self, pa: &mut Pass, edit: impl FnMut(Cursor<W, U::Area, S>)) {
656        self.get_iter(pa).for_each(edit);
657    }
658
659    fn get_iter(&self, pa: &mut Pass) -> Cursors<'_, W, U::Area, S> {
660        let mut widget = self.widget.acquire_mut(pa);
661        let selections = widget.text_mut().selections_mut().unwrap();
662        selections.populate();
663
664        let searcher = self.searcher.borrow_mut();
665
666        Cursors::new(0, widget, &self.area, searcher)
667    }
668
669    ////////// Functions derived from RwData
670
671    /// Reads the [`Text`] of the [`Widget`]
672    pub fn read_text<Ret>(&self, pa: &Pass, read: impl FnOnce(&Text) -> Ret) -> Ret {
673        let widget = self.widget.acquire(pa);
674        read(widget.text())
675    }
676
677    /// Writes to the [`Text`] of the [`Widget`]
678    pub fn write_text<Ret>(&self, pa: &mut Pass, write: impl FnOnce(&mut Text) -> Ret) -> Ret {
679        let mut widget = self.widget.acquire_mut(pa);
680        write(widget.text_mut())
681    }
682
683    /// Reads the [`Selections`] of the [`Widget`]
684    pub fn read_selections<Ret>(&self, pa: &Pass, read: impl FnOnce(&Selections) -> Ret) -> Ret {
685        let widget = self.widget.acquire(pa);
686        read(widget.text().selections().unwrap())
687    }
688
689    /// Writes to the [`Selections`] of the [`Widget`]
690    pub fn write_selections<Ret>(
691        &self,
692        pa: &mut Pass,
693        write: impl FnOnce(&mut Selections) -> Ret,
694    ) -> Ret {
695        let mut widget = self.widget.acquire_mut(pa);
696        write(widget.text_mut().selections_mut().unwrap())
697    }
698
699    ////////// Direct Text manipulation
700
701    /// Clones the [`Text`] within
702    pub fn clone_text(&self, pa: &Pass) -> Text {
703        self.widget.clone_text(pa)
704    }
705
706    /// Replaces the [`Text`] within with a [`Default`] version
707    pub fn take_text(&self, pa: &mut Pass) -> Text {
708        self.widget.take_text(pa)
709    }
710
711    /// Replaces the [`Text`] of the [`Widget`], returning the
712    /// previous value
713    pub fn replace_text(&self, pa: &mut Pass, text: impl Into<Text>) -> Text {
714        self.widget.replace_text(pa, text.into())
715    }
716
717    /// Undoes the last moment in the history, if there is one
718    pub fn undo(&self, pa: &mut Pass) {
719        self.widget.write(pa, |wid| wid.text_mut().undo());
720    }
721
722    /// Redoes the last moment in the history, if there is one
723    pub fn redo(&self, pa: &mut Pass) {
724        self.widget.write(pa, |wid| wid.text_mut().redo());
725    }
726
727    /// Finishes the current moment and adds a new one to the history
728    pub fn new_moment(&self, pa: &mut Pass) {
729        self.widget.write(pa, |wid| wid.text_mut().new_moment());
730    }
731
732    ////////// Querying functions
733
734    /// This [`Handle`]'s [`Widget`]
735    pub fn widget(&self) -> &RwData<W> {
736        &self.widget
737    }
738
739    /// This [`Handle`]'s [`U::Area`]
740    ///
741    /// [`U::Area`]: crate::ui::Ui::Area
742    pub fn area(&self) -> &U::Area {
743        &self.area
744    }
745
746    /// Gets this [`Handle`]'s mask
747    ///
748    /// This mask is going to be used to map [`Form`]s to other
749    /// [`Form`]s when printing via [`Widget::print`]. To see more
750    /// about how masks work, see [`form::enable_mask`].
751    ///
752    /// [`Form`]: crate::form::Form
753    /// [`form::enable_mask`]: crate::form::enable_mask
754    pub fn mask(&self) -> &Rc<Cell<&'static str>> {
755        &self.mask
756    }
757
758    /// Sets this [`Handle`]'s mask, returning the previous one
759    ///
760    /// This mask is going to be used to map [`Form`]s to other
761    /// [`Form`]s when printing via [`Widget::print`]. To see more
762    /// about how masks work, see [`form::enable_mask`].
763    ///
764    /// [`Form`]: crate::form::Form
765    /// [`form::enable_mask`]: crate::form::enable_mask
766    pub fn set_mask(&self, mask: &'static str) -> &'static str {
767        self.widget.declare_written();
768        self.mask.replace(mask)
769    }
770
771    /// Wether someone else called [`write`] or [`write_as`] since the
772    /// last [`read`] or [`write`]
773    ///
774    /// Do note that this *DOES NOT* mean that the value inside has
775    /// actually been changed, it just means a mutable reference was
776    /// acquired after the last call to [`has_changed`].
777    ///
778    /// Some types like [`Text`], and traits like [`Widget`] offer
779    /// [`needs_update`] methods, you should try to determine what
780    /// parts to look for changes.
781    ///
782    /// Generally though, you can use this method to gauge that.
783    ///
784    /// [`write`]: RwData::write
785    /// [`write_as`]: RwData::write_as
786    /// [`read`]: RwData::read
787    /// [`has_changed`]: RwData::has_changed
788    /// [`Text`]: crate::text::Text
789    /// [`Widget`]: crate::ui::Widget
790    /// [`needs_update`]: crate::ui::Widget::needs_update
791    pub fn has_changed(&self) -> bool {
792        self.widget.has_changed() || self.area.has_changed()
793    }
794
795    /// Wether the [`RwData`] within and another point to the same
796    /// value
797    pub fn ptr_eq<T: ?Sized>(&self, other: &RwData<T>) -> bool {
798        self.widget.ptr_eq(other)
799    }
800
801    /// The [`Widget`]'s [`PrintCfg`]
802    pub fn cfg(&self, pa: &Pass) -> PrintCfg {
803        self.widget.read(pa, Widget::print_cfg)
804    }
805}
806
807impl<U: Ui> Handle<File<U>, U> {
808    /// Attaches a [`Searcher`] to this [`Handle`], so you can do
809    /// incremental search
810    ///
811    /// An [`Handle`] with a [`Searcher`] not only has its usual
812    /// editing capabilities, but is also able to act on requested
813    /// regex searches, like those from [`IncSearch`], in
814    /// [`duat-utils`]. This means that a user can type up a
815    /// [prompt] to search for something, and the [`Handle`]
816    /// can use the [`Searcher`] to interpret how that search will
817    /// be utilized. Examples of this can be found in the
818    /// [`duat-utils`] crate, as well as the [`duat-kak`] crate,
819    /// which has some more advanced usage.
820    ///
821    /// [`Searcher`]: crate::text::Searcher
822    /// [`Selection`]: crate::mode::Selection
823    /// [`Cursor`]: crate::mode::Cursor
824    /// [`IncSearch`]: https://docs.rs/duat-utils/latest/duat_utils/modes/struct.IncSearch.html
825    /// [`duat-utils`]: https://docs.rs/duat-utils/lastest/
826    /// [prompt]: https://docs.rs/duat-utils/latest/duat_utils/modes/trait.PromptMode.html
827    /// [`duat-kak`]: https://docs.rs/duat-kak/lastest/
828    pub fn attach_searcher(&self, searcher: Searcher) -> Handle<File<U>, U, Searcher> {
829        Handle {
830            widget: self.widget.clone(),
831            area: self.area.clone(),
832            mask: self.mask.clone(),
833            searcher: RefCell::new(searcher),
834        }
835    }
836}
837
838impl<W: Widget<U>, U: Ui, S: Clone> Clone for Handle<W, U, S> {
839    fn clone(&self) -> Self {
840        Self {
841            widget: self.widget.clone(),
842            area: self.area.clone(),
843            mask: self.mask.clone(),
844            searcher: self.searcher.clone(),
845        }
846    }
847}