Skip to main content

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 with an [`Area`].
5use std::sync::{
6    Arc, Mutex,
7    atomic::{AtomicBool, Ordering},
8};
9
10use crate::{
11    context,
12    data::{Pass, RwData, WriteableTuple},
13    mode::{Cursor, ModSelection, Selection, Selections},
14    opts::PrintOpts,
15    text::{Text, TextMut, TextParts, TwoPoints, txt},
16    ui::{Area, DynSpawnSpecs, PushSpecs, RwArea, Widget},
17};
18
19/// A handle to a [`Widget`] in Duat.
20///
21/// The [`Handle`] lets you do all sorts of edits on a [`Widget`]. You
22/// can, for example, make use of the [`Selection`]s in its [`Text`]
23/// in order to edit the [`Text`] in a very declarative way.
24///
25/// One of the places where this is commonly done is within [`Mode`]s,
26/// where you get access to the [`Handle`] of the currently active
27/// [`Widget`]. Below is a very straightforward [`Mode`]:
28///
29/// ```rust
30/// # duat_core::doc_duat!(duat);
31/// use duat::prelude::*;
32///
33/// /// A very basic example Mode.
34/// #[derive(Clone)]
35/// struct PlacesCharactersAndMoves;
36///
37/// impl Mode for PlacesCharactersAndMoves {
38///     type Widget = Buffer;
39///
40///     // ..
41///     fn send_key(&mut self, _: &mut Pass, _: KeyEvent, _: Handle) {
42///         todo!();
43///     }
44/// }
45/// ```
46///
47/// In order to modify the widget, you must implement the
48/// [`Mode::send_key`] method. In it, you receive the following:
49///
50/// - A [`&mut Pass`], which will give you access to all of duat's
51///   shared state;
52/// - The [key] that was sent, may be a [mapped] key.
53/// - The [`Handle`] for a [`Mode::Widget`].
54///
55/// ```rust
56/// # duat_core::doc_duat!(duat);
57/// use duat::prelude::*;
58///
59/// #[derive(Clone)]
60/// struct PlacesCharactersAndMoves;
61/// impl Mode for PlacesCharactersAndMoves {
62///     type Widget = Buffer;
63///
64///     fn send_key(&mut self, pa: &mut Pass, key_event: KeyEvent, handle: Handle) {
65///         match key_event {
66///             // actions based on the key pressed
67///             event!(KeyCode::Char(char)) => {
68///                 // Do something when the character 'c' is typed.
69///             }
70///             _ => todo!("The remaining keys"),
71///         }
72///     }
73/// }
74/// ```
75///
76/// Note the [`event!`] macro. It (alongside [`alt!`], [`ctrl!`] and
77/// [`shift!`]) can be used to easily create [`KeyEvent`]s for
78/// matching purposes. They are very useful for succinctly describing
79/// an exact match in just a short pattern:
80///
81/// ```rust
82/// # duat_core::doc_duat!(duat);
83/// use KeyCode::*;
84/// use duat::prelude::*;
85///
86/// let key_event = KeyEvent::from(Char('a'));
87/// match key_event {
88///     event!('a' | 'b') => { /* .. */ }
89///     shift!(Right | Left) => { /* .. */ }
90///     ctrl!(alt!('d')) => { /* .. */ }
91///     _ => { /* .. */ }
92/// }
93/// ```
94///
95/// With the [`Handle`], you can modify [`Text`] in a simplified
96/// way. This is done by two actions, [editing] and [moving]. You
97/// can only do one of these on any number of selections at the same
98/// time.
99///
100/// ```rust
101/// # duat_core::doc_duat!(duat);
102/// # use duat::prelude::*;
103/// # #[derive(Clone)]
104/// # struct PlacesCharactersAndMoves;
105/// impl Mode for PlacesCharactersAndMoves {
106///     type Widget = Buffer;
107///
108///     // ..
109///     fn send_key(&mut self, pa: &mut Pass, key_event: KeyEvent, handle: Handle) {
110///         use KeyCode::*;
111///         match key_event {
112///             event!(Char(char)) => handle.edit_all(pa, |mut c| {
113///                 c.insert('c');
114///                 c.move_hor(1);
115///             }),
116///             shift!(Right) => handle.edit_all(pa, |mut c| {
117///                 if c.anchor().is_none() {
118///                     c.set_anchor();
119///                 }
120///                 c.move_hor(1);
121///             }),
122///             event!(KeyCode::Right) => handle.edit_all(pa, |mut c| {
123///                 c.unset_anchor();
124///                 c.move_hor(1);
125///             }),
126///             _ => todo!("Predictable remaining implementations"),
127///         }
128///     }
129/// # }
130/// ```
131///
132/// [`Mode`]: crate::mode::Mode
133/// [`Mode::Widget`]: crate::mode::Mode::Widget
134/// [`&mut Pass`]: Pass
135/// [`PromptLine`]: https://docs.rs/duat/latest/duat/widgets/struct.PromptLine.html
136/// [`Mode::send_key`]: crate::mode::Mode::send_key
137/// [key]: crate::mode::KeyEvent
138/// [mapped]: crate::mode::map
139/// [`read`]: RwData::read
140/// [`write`]: RwData::write
141/// [`Self::Widget`]: crate::mode::Mode::Widget
142/// [`Some(selections)`]: Some
143/// [`Area`]: crate::ui::Area
144/// [commands]: crate::cmd
145/// [`KeyEvent`]: crate::mode::KeyEvent
146/// [editing]: Cursor
147/// [moving]: Cursor
148/// [`Mode`]: crate::mode::Mode
149/// [`event!`]: crate::mode::event
150/// [`alt!`]: crate::mode::alt
151/// [`ctrl!`]: crate::mode::ctrl
152/// [`shift!`]: crate::mode::shift
153pub struct Handle<W: Widget + ?Sized = crate::buffer::Buffer> {
154    widget: RwData<W>,
155    pub(crate) area: RwArea,
156    mask: Arc<Mutex<&'static str>>,
157    related: RelatedWidgets,
158    is_closed: RwData<bool>,
159    master: Option<Box<Handle<dyn Widget>>>,
160    pub(crate) update_requested: Arc<AtomicBool>,
161}
162
163impl<W: Widget + ?Sized> Handle<W> {
164    /// Returns a new instance of a [`Handle<W, U>`].
165    pub(crate) fn new(
166        widget: RwData<W>,
167        area: RwArea,
168        mask: Arc<Mutex<&'static str>>,
169        master: Option<Handle<dyn Widget>>,
170    ) -> Self {
171        Self {
172            widget,
173            area,
174            mask,
175            related: RelatedWidgets(RwData::default()),
176            is_closed: RwData::new(false),
177            master: master.map(Box::new),
178            update_requested: Arc::new(AtomicBool::new(false)),
179        }
180    }
181}
182
183impl<W: Widget + ?Sized> Handle<W> {
184    ////////// Read and write access functions
185
186    /// Reads from the [`Widget`], making use of a [`Pass`].
187    ///
188    /// The consistent use of a [`Pass`] for the purposes of
189    /// reading/writing to the values of [`RwData`]s ensures that no
190    /// panic or invalid borrow happens at runtime, even while working
191    /// with untrusted code. More importantly, Duat uses these
192    /// guarantees in order to give the end user a ridiculous amount
193    /// of freedom in where they can do things, whilst keeping Rust's
194    /// number one rule and ensuring thread safety, even with a
195    /// relatively large amount of shareable state.
196    ///
197    /// [`Area`]: crate::ui::Area
198    pub fn read<'a>(&'a self, pa: &'a Pass) -> &'a W {
199        self.widget.read(pa)
200    }
201
202    /// Tries to read as a concrete [`Widget`] implementor.
203    pub fn read_as<'a, W2: Widget>(&'a self, pa: &'a Pass) -> Option<&'a W2> {
204        self.widget.read_as(pa)
205    }
206
207    /// Declares the [`Widget`] within as read.
208    ///
209    /// Same as calling `handle.widget().declare_as_read()`. You
210    /// should use this function if you want to signal to others that
211    /// the widget was read, even if you don't have access to a
212    /// [`Pass`].
213    pub fn declare_as_read(&self) {
214        self.widget.declare_as_read();
215    }
216
217    /// Writes to the [`Widget`], making use of a [`Pass`].
218    ///
219    /// The consistent use of a [`Pass`] for the purposes of
220    /// reading/writing to the values of [`RwData`]s ensures that no
221    /// panic or invalid borrow happens at runtime, even while working
222    /// with untrusted code. More importantly, Duat uses these
223    /// guarantees in order to give the end user a ridiculous amount
224    /// of freedom in where they can do things, whilst keeping Rust's
225    /// number one rule and ensuring thread safety, even with a
226    /// relatively large amount of shareable state.
227    ///
228    /// [`Area`]: crate::ui::Area
229    pub fn write<'a>(&'a self, pa: &'a mut Pass) -> &'a mut W {
230        self.widget.write(pa)
231    }
232
233    /// Writes to the [`Widget`] and [`Area`], making use of a
234    /// [`Pass`].
235    ///
236    /// The consistent use of a [`Pass`] for the purposes of
237    /// reading/writing to the values of [`RwData`]s ensures that no
238    /// panic or invalid borrow happens at runtime, even while working
239    /// with untrusted code. More importantly, Duat uses these
240    /// guarantees in order to give the end user a ridiculous amount
241    /// of freedom in where they can do things, whilst keeping Rust's
242    /// number one rule and ensuring thread safety, even with a
243    /// relatively large amount of shareable state.
244    ///
245    /// [`Area`]: crate::ui::Area
246    pub fn write_with_area<'p>(&'p self, pa: &'p mut Pass) -> (&'p mut W, &'p mut Area) {
247        pa.write_many((&self.widget, &self.area.0))
248    }
249
250    /// The same as [`RwData::write_then`].
251    ///
252    /// This lets you write to a [`Widget`] and other [`RwData`]-like
253    /// structs within said `Widget` at the same time.
254    pub fn write_then<'p, Tup: WriteableTuple<'p, impl std::any::Any>>(
255        &'p self,
256        pa: &'p mut Pass,
257        tup_fn: impl FnOnce(&'p W) -> Tup,
258    ) -> (&'p mut W, Tup::Return) {
259        self.widget.write_then(pa, tup_fn)
260    }
261
262    /// Declares the [`Widget`] within as written.
263    ///
264    /// Same as calling `handle.widget().declare_written()`. You
265    /// should use this function if you want to signal to others that
266    /// the widget was written to, even if you don't have access to a
267    /// [`Pass`].
268    pub fn declare_written(&self) {
269        self.widget.declare_written();
270    }
271
272    /// Tries to downcast from `dyn Widget` to a concrete [`Widget`].
273    pub fn try_downcast<W2: Widget>(&self) -> Option<Handle<W2>> {
274        Some(Handle {
275            widget: self.widget.try_downcast()?,
276            area: self.area.clone(),
277            mask: self.mask.clone(),
278            related: self.related.clone(),
279            is_closed: self.is_closed.clone(),
280            master: self.master.clone(),
281            update_requested: self.update_requested.clone(),
282        })
283    }
284
285    ////////// Refined access functions
286
287    /// A shared reference to the [`Text`] of the [`Widget`].
288    ///
289    /// This is the same as calling `handle.read(pa).text()`.
290    pub fn text<'p>(&'p self, pa: &'p Pass) -> &'p Text {
291        self.read(pa).text()
292    }
293
294    /// A mutable reference to the [`Text`] of the [`Widget`].
295    ///
296    /// This is the same as calling `handle.write(pa).text_mut()`.
297    pub fn text_mut<'p>(&'p self, pa: &'p mut Pass) -> TextMut<'p> {
298        self.write(pa).text_mut()
299    }
300
301    /// The [`TextParts`] of the [`Widget`].
302    ///
303    /// You can use this in order to get a shared reference to the
304    /// [`Strs`] and [`Selections`], while maintaining a mutable
305    /// reference to the [`Tags`] of the [`Text`], letting you place
306    /// [`Tag`]s while still reading other information from the
307    /// [`Widget`].
308    ///
309    /// This is the same as calling `handle.text_mut().parts()`.
310    ///
311    /// [`Strs`]: crate::text::Strs
312    /// [`Tags`]: crate::text::Tags
313    /// [`Tag`]: crate::text::Tag
314    pub fn text_parts<'p>(&'p self, pa: &'p mut Pass) -> TextParts<'p> {
315        self.write(pa).text_mut().parts()
316    }
317
318    /// A shared reference to the [`Selections`] of the [`Widget`]'s
319    /// [`Text`].
320    ///
321    /// This is the same as calling `handle.read(pa).selections()`.
322    pub fn selections<'p>(&'p self, pa: &'p Pass) -> &'p Selections {
323        self.read(pa).text().selections()
324    }
325
326    /// A mutable reference to the [`Selections`] of the [`Widget`]'s
327    /// [`Text`].
328    ///
329    /// This is the same as calling
330    /// `handle.write(pa).selections_mut()`.
331    pub fn selections_mut<'p>(&'p self, pa: &'p mut Pass) -> &'p mut Selections {
332        self.write(pa).text_mut().selections_mut()
333    }
334
335    ////////// Selection Editing functions
336
337    /// Edits the nth [`Selection`] in the [`Text`].
338    ///
339    /// Once dropped, the [`Selection`] in this [`Cursor`] will be
340    /// added back to the list of [`Selection`]s, unless it is
341    /// [destroyed].
342    ///
343    /// If you want to edit on the main selection, see [`edit_main`],
344    /// if you want to edit on all [`Selection`]s, see [`edit_all`].
345    ///
346    /// Just like all other `edit` methods, this one will populate the
347    /// [`Selections`], so if there are no [`Selection`]s, it will
348    /// create one at [`Point::default`].
349    ///
350    /// [destroyed]: Cursor::destroy
351    /// [`edit_main`]: Self::edit_main
352    /// [`edit_all`]: Self::edit_all
353    /// [`Point::default`]: crate::text::Point::default
354    pub fn edit_nth<Ret>(
355        &self,
356        pa: &mut Pass,
357        n: usize,
358        edit: impl FnOnce(Cursor<W>) -> Ret,
359    ) -> Ret {
360        fn get_parts<'a, W: Widget + ?Sized>(
361            pa: &'a mut Pass,
362            handle: &'a Handle<W>,
363            n: usize,
364        ) -> (Selection, bool, &'a mut W, &'a Area) {
365            let (widget, area) = handle.write_with_area(pa);
366            let selections = widget.text_mut().selections_mut();
367            selections.populate();
368            let Some((selection, was_main)) = selections.remove(n) else {
369                panic!("Selection index {n} out of bounds");
370            };
371
372            (selection, was_main, widget, area)
373        }
374
375        let (selection, was_main, widget, area) = get_parts(pa, self, n);
376
377        let mut selections = vec![Some(ModSelection::new(selection, n, was_main))];
378
379        let ret = edit(Cursor::new(&mut selections, 0, (widget, area), None));
380
381        crate::mode::reinsert_selections(selections.into_iter().flatten(), widget, None);
382
383        ret
384    }
385
386    /// Edits the main [`Selection`] in the [`Text`].
387    ///
388    /// Once dropped, the `Selection` in this [`Cursor`] will be
389    /// added back to the list of `Selection`s, unless it is
390    /// [destroyed].
391    ///
392    /// If you want to edit on the `nth` selection, see [`edit_nth`],
393    /// same for [`edit_last`], if you want to edit on many
394    /// `Selection`s, see [`edit_all`].
395    ///
396    /// Just like all other `edit` methods, this one will populate the
397    /// `Selections`, so if there are no `Selection`s, it will
398    /// create one at [`Point::default`].
399    ///
400    /// [destroyed]: Cursor::destroy
401    /// [`edit_nth`]: Self::edit_nth
402    /// [`edit_last`]: Self::edit_last
403    /// [`edit_all`]: Self::edit_all
404    /// [`Point::default`]: crate::text::Point::default
405    pub fn edit_main<Ret>(&self, pa: &mut Pass, edit: impl FnOnce(Cursor<W>) -> Ret) -> Ret {
406        self.edit_nth(
407            pa,
408            self.widget.read(pa).text().selections().main_index(),
409            edit,
410        )
411    }
412
413    /// Edits the last [`Selection`] in the [`Text`].
414    ///
415    /// Once dropped, the `Selection` in this [`Cursor`] will be
416    /// added back to the list of `Selection`s, unless it is
417    /// [destroyed].
418    ///
419    /// If you want to edit on the `nth` selection, see [`edit_nth`],
420    /// same for [`edit_main`], if you want to edit on all
421    /// `Selection`s, see [`edit_all`].
422    ///
423    /// Just like all other `edit` methods, this one will populate the
424    /// `Selections`, so if there are no `Selection`s, it will
425    /// create one at [`Point::default`].
426    ///
427    /// [destroyed]: Cursor::destroy
428    /// [`edit_nth`]: Self::edit_nth
429    /// [`edit_main`]: Self::edit_main
430    /// [`edit_all`]: Self::edit_all
431    /// [`Point::default`]: crate::text::Point::default
432    pub fn edit_last<Ret>(&self, pa: &mut Pass, edit: impl FnOnce(Cursor<W>) -> Ret) -> Ret {
433        let len = self.widget.read(pa).text().selections().len();
434        self.edit_nth(pa, len.saturating_sub(1), edit)
435    }
436
437    /// A shortcut for iterating over all selections.
438    ///
439    /// But it can't return a value, and is meant to reduce the
440    /// indentation that will inevitably come from using the
441    /// equivalent long form call.
442    pub fn edit_all(&self, pa: &mut Pass, edit: impl FnMut(Cursor<W>)) {
443        let (widget, area) = self.write_with_area(pa);
444        widget.text_mut().selections_mut().populate();
445        crate::mode::on_each_cursor(widget, area, edit);
446    }
447
448    ////////// Area functions
449
450    /// Scrolls the [`Text`] veritcally by an amount.
451    ///
452    /// If [`PrintOpts.allow_overscroll`] is set, then the [`Text`]
453    /// will be allowed to scroll beyond the last line, up until
454    /// reaching the `scrolloff.y` value.
455    ///
456    /// [`PrintOpts.allow_overscroll`]: crate::opts::PrintOpts::allow_overscroll
457    pub fn scroll_ver(&self, pa: &mut Pass, dist: i32) {
458        let (widget, area) = self.write_with_area(pa);
459        area.scroll_ver(widget.text(), dist, widget.print_opts());
460        self.widget.declare_written();
461    }
462
463    /// Scrolls the [`Text`] to the visual line of a [`TwoPoints`].
464    ///
465    /// If `scroll_beyond` is set, then the [`Text`] will be allowed
466    /// to scroll beyond the last line, up until reaching the
467    /// `scrolloff.y` value.
468    pub fn scroll_to_points(&self, pa: &mut Pass, points: TwoPoints) {
469        let (widget, area) = self.write_with_area(pa);
470        area.scroll_to_points(widget.text(), points, widget.print_opts());
471        self.widget.declare_written();
472    }
473
474    /// The start points that should be printed.
475    pub fn start_points(&self, pa: &Pass) -> TwoPoints {
476        let widget = self.widget.read(pa);
477        self.area
478            .start_points(pa, widget.text(), widget.print_opts())
479    }
480
481    /// The end points that should be printed.
482    pub fn end_points(&self, pa: &Pass) -> TwoPoints {
483        let widget = self.widget.read(pa);
484        self.area.end_points(pa, widget.text(), widget.print_opts())
485    }
486
487    ////////// Querying functions
488
489    /// This [`Handle`]'s [`Widget`].
490    pub fn widget(&self) -> &RwData<W> {
491        &self.widget
492    }
493
494    /// This [`Handle`]'s [`RwArea`]
495    pub fn area(&self) -> &RwArea {
496        &self.area
497    }
498
499    /// Gets this [`Handle`]'s mask.
500    ///
501    /// This mask is going to be used to map [`Form`]s to other
502    /// `Form`s when printing. To see more about how masks work, see
503    /// [`form::enable_mask`].
504    ///
505    /// [`Form`]: crate::form::Form
506    /// [`form::enable_mask`]: crate::form::enable_mask
507    pub fn mask(&self) -> &Arc<Mutex<&'static str>> {
508        &self.mask
509    }
510
511    /// Sets this [`Handle`]'s mask, returning the previous one.
512    ///
513    /// This mask is going to be used to map [`Form`]s to other
514    /// `Form`s when printing. To see more about how masks work, see
515    /// [`form::enable_mask`].
516    ///
517    /// [`Form`]: crate::form::Form
518    /// [`form::enable_mask`]: crate::form::enable_mask
519    pub fn set_mask(&self, mask: &'static str) -> &'static str {
520        self.widget.declare_written();
521        std::mem::replace(&mut self.mask.lock().unwrap(), mask)
522    }
523
524    /// Wether someone else called [`write`] or [`write_as`] since the
525    /// last [`read`] or `write`.
526    ///
527    /// Do note that this *DOES NOT* mean that the value inside has
528    /// actually been changed, it just means a mutable reference was
529    /// acquired after the last call to [`has_changed`].
530    ///
531    /// Some types like [`Text`], and traits like [`Widget`] offer
532    /// [`needs_update`] methods, you should try to determine what
533    /// parts to look for changes.
534    ///
535    /// Generally though, you can use this method to gauge that.
536    ///
537    /// [`write`]: RwData::write
538    /// [`write_as`]: RwData::write_as
539    /// [`read`]: RwData::read
540    /// [`has_changed`]: RwData::has_changed
541    /// [`Text`]: crate::text::Text
542    /// [`Widget`]: crate::ui::Widget
543    /// [`needs_update`]: crate::ui::Widget::needs_update
544    pub fn has_changed(&self, pa: &Pass) -> bool {
545        self.widget.has_changed() || self.area.has_changed(pa)
546    }
547
548    /// Wether the [`RwData`] within and another point to the same
549    /// value.
550    pub fn ptr_eq<T: ?Sized>(&self, other: &RwData<T>) -> bool {
551        self.widget.ptr_eq(other)
552    }
553
554    /// The [`Widget`]'s [`PrintOpts`].
555    pub fn opts(&self, pa: &Pass) -> PrintOpts {
556        self.widget.read(pa).print_opts()
557    }
558
559    /// Request that this [`Handle`] be updated.
560    ///
561    /// You can use this to request updates from other threads.
562    pub fn request_update(&self) {
563        self.update_requested.store(true, Ordering::Relaxed);
564    }
565
566    ////////// Related Handles
567
568    /// Returns the [`Handle`] this one was pushed to, if it was
569    /// pushed to another.
570    ///
571    /// Will return [`Some`] if this `self` was created by calling
572    /// [`Handle::push_outer_widget`], [`Handle::push_inner_widget`],
573    /// [`Handle::spawn_widget`], or if the [`Widget`] was [spawned]
574    /// on the master's [`Text`].
575    ///
576    /// [spawned]: crate::text::SpawnTag
577    pub fn master(&self) -> Result<&Handle<dyn Widget>, Text> {
578        self.master
579            .as_ref()
580            .map(|handle| handle.as_ref())
581            .ok_or_else(|| txt!("Widget was not pushed to another"))
582    }
583
584    /// Returns the [`Handle<Buffer>`] this one was pushed to, if it
585    /// was pushed to one.
586    ///
587    /// Will return [`Some`] if this `self` was created by calling
588    /// [`Handle::push_outer_widget`], [`Handle::push_inner_widget`],
589    /// [`Handle::spawn_widget`], or if the [`Widget`] was [spawned]
590    /// on the master's [`Text`].
591    ///
592    /// [spawned]: crate::text::SpawnTag
593    pub fn buffer(&self) -> Result<Handle, Text> {
594        self.master
595            .as_ref()
596            .and_then(|handle| handle.try_downcast())
597            .ok_or_else(|| txt!("Widget was not pushed to a [a]Buffer"))
598    }
599
600    /// Reads related [`Widget`]s of type `W2`, as well as its
601    /// [`Area`].
602    ///
603    /// This can also be done by calling [`Handle::get_related`], and
604    /// [`Handle::read`], but this function should generally be
605    /// faster, since there is no cloning of [`Arc`]s going on.
606    pub fn read_related<'a, W2: Widget>(
607        &'a self,
608        pa: &'a Pass,
609    ) -> impl Iterator<Item = (&'a W2, &'a Area, WidgetRelation)> {
610        self.read_as(pa)
611            .map(|w| (w, self.area().read(pa), WidgetRelation::Main))
612            .into_iter()
613            .chain(self.related.0.read(pa).iter().filter_map(|(handle, rel)| {
614                handle
615                    .read_as(pa)
616                    .map(|w| (w, handle.area().read(pa), *rel))
617            }))
618    }
619
620    /// Gets related [`Handle`]s of type [`Widget`].
621    ///
622    /// If you are doing this just to read the [`Widget`] and
623    /// [`Area`], consider using [`Handle::read_related`].
624    pub fn get_related<'a, W2: Widget>(
625        &'a self,
626        pa: &'a Pass,
627    ) -> impl Iterator<Item = (Handle<W2>, WidgetRelation)> + 'a {
628        self.try_downcast()
629            .zip(Some(WidgetRelation::Main))
630            .into_iter()
631            .chain(
632                self.related
633                    .0
634                    .read(pa)
635                    .iter()
636                    .filter_map(|(handle, rel)| handle.try_downcast().zip(Some(*rel))),
637            )
638    }
639
640    /// Raw access to the related widgets.
641    pub(crate) fn related(&self) -> &RwData<Vec<(Handle<dyn Widget>, WidgetRelation)>> {
642        &self.related.0
643    }
644
645    ////////// Other methods
646
647    /// Pushes a [`Widget`] around this one.
648    ///
649    /// This `Widget` will be placed internally, i.e., around the
650    /// [`Area`] of `self`. This is in contrast to
651    /// [`Handle::push_outer_widget`], which will push around the
652    /// "cluster master" of `self`.
653    ///
654    /// A cluster master is the collection of every `Widget` that was
655    /// pushed around a central one with [`PushSpecs::cluster`] set to
656    /// `true`.
657    ///
658    /// Both of these functions behave identically in the situation
659    /// where no other [`Widget`]s were pushed around `self`.
660    ///
661    /// However, if, for example, a [`Widget`] was previously pushed
662    /// below `self`, when pushing to the left, the following would
663    /// happen:
664    ///
665    /// ```text
666    /// ╭────────────────╮    ╭─────┬──────────╮
667    /// │                │    │     │          │
668    /// │      self      │    │ new │   self   │
669    /// │                │ -> │     │          │
670    /// ├────────────────┤    ├─────┴──────────┤
671    /// │      old       │    │      old       │
672    /// ╰────────────────╯    ╰────────────────╯
673    /// ```
674    ///
675    /// While in [`Handle::push_outer_widget`], this happens instead:
676    ///
677    /// ```text
678    /// ╭────────────────╮    ╭─────┬──────────╮
679    /// │                │    │     │          │
680    /// │      self      │    │     │   self   │
681    /// │                │ -> │ new │          │
682    /// ├────────────────┤    │     ├──────────┤
683    /// │      old       │    │     │   old    │
684    /// ╰────────────────╯    ╰─────┴──────────╯
685    /// ```
686    ///
687    /// Note that `new` was pushed _around_ other clustered widgets in
688    /// the second case, not just around `self`.
689    pub fn push_inner_widget<PW: Widget>(
690        &self,
691        pa: &mut Pass,
692        widget: PW,
693        specs: PushSpecs,
694    ) -> Handle<PW> {
695        context::windows()
696            .push_widget(pa, (&self.area, None, specs), widget, Some(&self.area))
697            .unwrap()
698    }
699
700    /// Pushes a [`Widget`] around the "cluster master" of this one.
701    ///
702    /// A cluster master is the collection of every `Widget` that was
703    /// pushed around a central one with [`PushSpecs::cluster`] set to
704    /// `true`.
705    ///
706    /// This [`Widget`] will be placed externally, i.e., around every
707    /// other [`Widget`] that was pushed around `self`. This is in
708    /// contrast to [`Handle::push_inner_widget`], which will push
709    /// only around `self`.
710    ///
711    /// Both of these functions behave identically in the situation
712    /// where no other [`Widget`]s were pushed around `self`.
713    ///
714    /// However, if, for example, a [`Widget`] was previously pushed
715    /// to the left of `self`, when pushing to the left again, the
716    /// following would happen:
717    ///
718    /// ```text
719    /// ╭──────┬──────────╮    ╭─────┬─────┬──────╮
720    /// │      │          │    │     │     │      │
721    /// │      │          │    │     │     │      │
722    /// │  old │   self   │ -> │ new │ old │ self │
723    /// │      │          │    │     │     │      │
724    /// │      │          │    │     │     │      │
725    /// ╰──────┴──────────╯    ╰─────┴─────┴──────╯
726    /// ```
727    ///
728    /// While in [`Handle::push_inner_widget`], this happens instead:
729    ///
730    /// ```text
731    /// ╭──────┬──────────╮    ╭─────┬─────┬──────╮
732    /// │      │          │    │     │     │      │
733    /// │      │          │    │     │     │      │
734    /// │  old │   self   │ -> │ old │ new │ self │
735    /// │      │          │    │     │     │      │
736    /// │      │          │    │     │     │      │
737    /// ╰──────┴──────────╯    ╰─────┴─────┴──────╯
738    /// ```
739    ///
740    /// Note that `new` was pushed _around_ other clustered widgets in
741    /// the first case, not just around `self`.
742    pub fn push_outer_widget<PW: Widget>(
743        &self,
744        pa: &mut Pass,
745        widget: PW,
746        specs: PushSpecs,
747    ) -> Handle<PW> {
748        if let Some(master) = self.area().get_cluster_master(pa) {
749            context::windows()
750                .push_widget(pa, (&master, None, specs), widget, Some(self.area()))
751                .unwrap()
752        } else {
753            context::windows()
754                .push_widget(pa, (&self.area, None, specs), widget, Some(self.area()))
755                .unwrap()
756        }
757    }
758
759    /// Spawns a floating [`Widget`].
760    pub fn spawn_widget<SW: Widget>(
761        &self,
762        pa: &mut Pass,
763        widget: SW,
764        specs: DynSpawnSpecs,
765    ) -> Option<Handle<SW>> {
766        context::windows().spawn_on_widget(pa, (&self.area, specs), widget)
767    }
768
769    /// Closes this `Handle`, removing the [`Widget`] from the.
770    /// [`Window`]
771    ///
772    /// [`Window`]: crate::ui::Window
773    pub fn close(&self, pa: &mut Pass) -> Result<(), Text> {
774        context::windows().close(pa, self)
775    }
776
777    /// Wether this `Handle` was already closed.
778    pub fn is_closed(&self, pa: &Pass) -> bool {
779        *self.is_closed.read(pa)
780    }
781
782    /// Declares that this `Handle` has been closed.
783    pub(crate) fn declare_closed(&self, pa: &mut Pass) {
784        *self.is_closed.write(pa) = true;
785    }
786}
787
788impl<W: Widget> Handle<W> {
789    /// Transforms this [`Handle`] into a [`Handle<dyn Widget>`].
790    pub fn to_dyn(&self) -> Handle<dyn Widget> {
791        Handle {
792            widget: self.widget.to_dyn_widget(),
793            // TODO: Arc wrapper, and Area: !Clone
794            area: self.area.clone(),
795            mask: self.mask.clone(),
796            related: self.related.clone(),
797            is_closed: self.is_closed.clone(),
798            master: self.master.clone(),
799            update_requested: self.update_requested.clone(),
800        }
801    }
802}
803
804// SAFETY: The only parts that are accessible from other threads are
805// the atomic counters from the Arcs. Everything else can only be
806// acquired when there is a Pass, i.e., on the main thread.
807unsafe impl<W: Widget + ?Sized> Send for Handle<W> {}
808unsafe impl<W: Widget + ?Sized> Sync for Handle<W> {}
809
810impl<W1, W2> PartialEq<Handle<W2>> for Handle<W1>
811where
812    W1: Widget + ?Sized,
813    W2: Widget + ?Sized,
814{
815    fn eq(&self, other: &Handle<W2>) -> bool {
816        self.widget().ptr_eq(other.widget())
817    }
818}
819
820impl<W: Widget + ?Sized> Clone for Handle<W> {
821    fn clone(&self) -> Self {
822        Self {
823            widget: self.widget.clone(),
824            area: self.area.clone(),
825            mask: self.mask.clone(),
826            related: self.related.clone(),
827            is_closed: self.is_closed.clone(),
828            master: self.master.clone(),
829            update_requested: self.update_requested.clone(),
830        }
831    }
832}
833
834impl<W: Widget + ?Sized> std::fmt::Debug for Handle<W> {
835    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
836        f.debug_struct("Handle")
837            .field("mask", &self.mask)
838            .finish_non_exhaustive()
839    }
840}
841
842#[derive(Clone)]
843struct RelatedWidgets(RwData<Vec<(Handle<dyn Widget>, WidgetRelation)>>);
844
845/// What relation this [`Widget`] has to its parent.
846#[derive(Clone, Copy, Debug)]
847pub enum WidgetRelation {
848    /// The main widget of the cluster, most commonly a [`Buffer`].
849    ///
850    /// [`Buffer`]: crate::buffer::Buffer
851    Main,
852    /// A [`Widget`] that was pushed around the main `Widget`, e.g.
853    /// [`LineNumbers`].
854    ///
855    /// [`LineNumbers`]: docs.rs/duat/latest/duat/widgets/struct.LineNumbers.html
856    Pushed,
857    /// A [`Widget`] that was spawned on the `Widget`, e.g. completion.
858    /// lists
859    Spawned,
860}