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}