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,
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},
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: ?Sized = crate::buffer::Buffer> {
154 widget: RwData<W>,
155 pub(crate) area: RwArea,
156 related: RwData<Vec<(Handle<dyn Widget>, WidgetRelation)>>,
157 is_closed: Arc<AtomicBool>,
158 pub(crate) update_requested: Arc<AtomicBool>,
159}
160
161impl<W: Widget + ?Sized> Handle<W> {
162 /// Returns a new instance of a [`Handle<W, U>`].
163 pub(crate) fn new(
164 widget: RwData<W>,
165 area: RwArea,
166 main: Option<Handle<dyn Widget>>,
167 is_closed: Arc<AtomicBool>,
168 ) -> Self {
169 Self {
170 widget,
171 area,
172 related: RwData::new(
173 main.map(|handle| (handle, WidgetRelation::Main))
174 .into_iter()
175 .collect(),
176 ),
177 is_closed,
178 update_requested: Arc::new(AtomicBool::new(false)),
179 }
180 }
181}
182
183impl<W: 'static + ?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 related: self.related.clone(),
278 is_closed: self.is_closed.clone(),
279 update_requested: self.update_requested.clone(),
280 })
281 }
282
283 ////////// Querying functions
284
285 /// This [`Handle`]'s [`Widget`].
286 pub fn widget(&self) -> &RwData<W> {
287 &self.widget
288 }
289
290 /// This [`Handle`]'s [`RwArea`]
291 pub fn area(&self) -> &RwArea {
292 &self.area
293 }
294
295 /// Wether someone else called [`write`] or [`write_as`] since the
296 /// last [`read`] or `write`.
297 ///
298 /// Do note that this *DOES NOT* mean that the value inside has
299 /// actually been changed, it just means a mutable reference was
300 /// acquired after the last call to [`has_changed`].
301 ///
302 /// [`write`]: RwData::write
303 /// [`write_as`]: RwData::write_as
304 /// [`read`]: RwData::read
305 /// [`has_changed`]: RwData::has_changed
306 pub fn has_changed(&self, pa: &Pass) -> bool {
307 self.widget.has_changed() || self.area.has_changed(pa)
308 }
309
310 /// Wether the [`RwData`] within and another point to the same
311 /// value.
312 pub fn ptr_eq<T: ?Sized>(&self, other: &RwData<T>) -> bool {
313 self.widget.ptr_eq(other)
314 }
315
316 /// Request that this [`Handle`] be updated.
317 ///
318 /// You can use this to request updates from other threads.
319 pub fn request_update(&self) {
320 self.update_requested.store(true, Ordering::Relaxed);
321 }
322
323 ////////// Related Handles
324
325 /// Returns the [`Handle`] this one was pushed to, if it was
326 /// pushed to another.
327 ///
328 /// Will return [`Some`] if this `self` was created by calling
329 /// [`Handle::push_outer_widget`], [`Handle::push_inner_widget`],
330 /// [`Handle::spawn_widget`], or if the [`Widget`] was [spawned]
331 /// on the master's [`Text`].
332 ///
333 /// [spawned]: crate::text::Spawn
334 pub fn master(&self, pa: &Pass) -> Option<Handle<dyn Widget>> {
335 self.related.read(pa).iter().find_map(|(handle, relation)| {
336 (*relation == WidgetRelation::Main).then_some(handle.clone())
337 })
338 }
339
340 /// Returns the [`Handle<Buffer>`] this one was pushed to, if it
341 /// was pushed to one.
342 ///
343 /// Will return [`Some`] if this `self` was created by calling
344 /// [`Handle::push_outer_widget`], [`Handle::push_inner_widget`],
345 /// [`Handle::spawn_widget`], or if the [`Widget`] was [spawned]
346 /// on the master's [`Text`].
347 ///
348 /// [spawned]: crate::text::Spawn
349 pub fn buffer(&self, pa: &Pass) -> Option<Handle> {
350 self.related.read(pa).iter().find_map(|(handle, relation)| {
351 handle
352 .try_downcast()
353 .filter(|_| *relation == WidgetRelation::Main)
354 })
355 }
356
357 /// Reads related [`Widget`]s of type `W2`, as well as its
358 /// [`Area`].
359 ///
360 /// This can also be done by calling [`Handle::get_related`], and
361 /// [`Handle::read`], but this function should generally be
362 /// faster, since there is no cloning of [`Arc`]s going on.
363 pub fn read_related<'a, W2: Widget>(
364 &'a self,
365 pa: &'a Pass,
366 ) -> impl Iterator<Item = (&'a W2, &'a Area, WidgetRelation)> {
367 self.read_as(pa)
368 .map(|w| (w, self.area().read(pa), WidgetRelation::Main))
369 .into_iter()
370 .chain(self.related.read(pa).iter().filter_map(|(handle, rel)| {
371 handle
372 .read_as(pa)
373 .map(|w| (w, handle.area().read(pa), *rel))
374 }))
375 }
376
377 /// Gets related [`Handle`]s of type [`Widget`].
378 ///
379 /// If you are doing this just to read the [`Widget`] and
380 /// [`Area`], consider using [`Handle::read_related`].
381 pub fn get_related<'a, W2: Widget>(
382 &'a self,
383 pa: &'a Pass,
384 ) -> Vec<(Handle<W2>, WidgetRelation)> {
385 self.related
386 .read(pa)
387 .iter()
388 .filter_map(|(handle, rel)| handle.try_downcast().zip(Some(*rel)))
389 .collect()
390 }
391
392 /// Raw access to the related widgets.
393 pub(crate) fn related(&self) -> &RwData<Vec<(Handle<dyn Widget>, WidgetRelation)>> {
394 &self.related
395 }
396
397 ////////// Other methods
398
399 /// Wether this `Handle` was already closed.
400 pub fn is_closed(&self) -> bool {
401 self.is_closed.load(Ordering::Relaxed)
402 }
403
404 /// Declares that this `Handle` has been closed.
405 pub(crate) fn declare_closed(&self) {
406 self.is_closed.store(true, Ordering::Relaxed);
407 }
408}
409
410impl<W: Widget + ?Sized> Handle<W> {
411 ////////// Refined access functions
412
413 /// A shared reference to the [`Text`] of the [`Widget`].
414 ///
415 /// This is the same as calling `handle.read(pa).text()`.
416 pub fn text<'p>(&'p self, pa: &'p Pass) -> &'p Text {
417 self.read(pa).text()
418 }
419
420 /// A mutable reference to the [`Text`] of the [`Widget`].
421 ///
422 /// This is the same as calling `handle.write(pa).text_mut()`.
423 pub fn text_mut<'p>(&'p self, pa: &'p mut Pass) -> TextMut<'p> {
424 self.write(pa).text_mut()
425 }
426
427 /// The [`TextParts`] of the [`Widget`].
428 ///
429 /// You can use this in order to get a shared reference to the
430 /// [`Strs`] and [`Selections`], while maintaining a mutable
431 /// reference to the [`Tags`] of the [`Text`], letting you place
432 /// [`Tag`]s while still reading other information from the
433 /// [`Widget`].
434 ///
435 /// This is the same as calling `handle.text_mut().parts()`.
436 ///
437 /// [`Strs`]: crate::text::Strs
438 /// [`Tags`]: crate::text::Tags
439 /// [`Tag`]: crate::text::Tag
440 pub fn text_parts<'p>(&'p self, pa: &'p mut Pass) -> TextParts<'p> {
441 self.write(pa).text_mut().parts()
442 }
443
444 /// A shared reference to the [`Selections`] of the [`Widget`]'s
445 /// [`Text`].
446 ///
447 /// This is the same as calling `handle.read(pa).selections()`.
448 pub fn selections<'p>(&'p self, pa: &'p Pass) -> &'p Selections {
449 self.read(pa).text().selections()
450 }
451
452 /// A mutable reference to the [`Selections`] of the [`Widget`]'s
453 /// [`Text`].
454 ///
455 /// This is the same as calling
456 /// `handle.write(pa).selections_mut()`.
457 pub fn selections_mut<'p>(&'p self, pa: &'p mut Pass) -> &'p mut Selections {
458 self.write(pa).text_mut().selections_mut()
459 }
460
461 ////////// Selection Editing functions
462
463 /// Edits the nth [`Selection`] in the [`Text`].
464 ///
465 /// Once dropped, the [`Selection`] in this [`Cursor`] will be
466 /// added back to the list of [`Selection`]s, unless it is
467 /// [destroyed].
468 ///
469 /// If you want to edit on the main selection, see [`edit_main`],
470 /// if you want to edit on all [`Selection`]s, see [`edit_all`].
471 ///
472 /// Just like all other `edit` methods, this one will populate the
473 /// [`Selections`], so if there are no [`Selection`]s, it will
474 /// create one at [`Point::default`].
475 ///
476 /// [destroyed]: Cursor::destroy
477 /// [`edit_main`]: Self::edit_main
478 /// [`edit_all`]: Self::edit_all
479 /// [`Point::default`]: crate::text::Point::default
480 pub fn edit_nth<Ret>(
481 &self,
482 pa: &mut Pass,
483 n: usize,
484 edit: impl FnOnce(Cursor<W>) -> Ret,
485 ) -> Ret {
486 fn get_parts<'a, W: Widget + ?Sized>(
487 pa: &'a mut Pass,
488 handle: &'a Handle<W>,
489 n: usize,
490 ) -> (Selection, bool, &'a mut W, &'a Area) {
491 let (widget, area) = handle.write_with_area(pa);
492 let selections = widget.text_mut().selections_mut();
493 selections.populate();
494 let Some((selection, was_main)) = selections.remove(n) else {
495 panic!("Selection index {n} out of bounds");
496 };
497
498 (selection, was_main, widget, area)
499 }
500
501 let (selection, was_main, widget, area) = get_parts(pa, self, n);
502
503 let mut selections = vec![Some(ModSelection::new(selection, n, was_main))];
504
505 let ret = edit(Cursor::new(&mut selections, 0, (widget, area), None));
506
507 crate::mode::reinsert_selections(selections.into_iter().flatten(), widget, None);
508
509 ret
510 }
511
512 /// Edits the main [`Selection`] in the [`Text`].
513 ///
514 /// Once dropped, the `Selection` in this [`Cursor`] will be
515 /// added back to the list of `Selection`s, unless it is
516 /// [destroyed].
517 ///
518 /// If you want to edit on the `nth` selection, see [`edit_nth`],
519 /// same for [`edit_last`], if you want to edit on many
520 /// `Selection`s, see [`edit_all`].
521 ///
522 /// Just like all other `edit` methods, this one will populate the
523 /// `Selections`, so if there are no `Selection`s, it will
524 /// create one at [`Point::default`].
525 ///
526 /// [destroyed]: Cursor::destroy
527 /// [`edit_nth`]: Self::edit_nth
528 /// [`edit_last`]: Self::edit_last
529 /// [`edit_all`]: Self::edit_all
530 /// [`Point::default`]: crate::text::Point::default
531 pub fn edit_main<Ret>(&self, pa: &mut Pass, edit: impl FnOnce(Cursor<W>) -> Ret) -> Ret {
532 self.edit_nth(
533 pa,
534 self.widget.read(pa).text().selections().main_index(),
535 edit,
536 )
537 }
538
539 /// Edits the last [`Selection`] in the [`Text`].
540 ///
541 /// Once dropped, the `Selection` in this [`Cursor`] will be
542 /// added back to the list of `Selection`s, unless it is
543 /// [destroyed].
544 ///
545 /// If you want to edit on the `nth` selection, see [`edit_nth`],
546 /// same for [`edit_main`], if you want to edit on all
547 /// `Selection`s, see [`edit_all`].
548 ///
549 /// Just like all other `edit` methods, this one will populate the
550 /// `Selections`, so if there are no `Selection`s, it will
551 /// create one at [`Point::default`].
552 ///
553 /// [destroyed]: Cursor::destroy
554 /// [`edit_nth`]: Self::edit_nth
555 /// [`edit_main`]: Self::edit_main
556 /// [`edit_all`]: Self::edit_all
557 /// [`Point::default`]: crate::text::Point::default
558 pub fn edit_last<Ret>(&self, pa: &mut Pass, edit: impl FnOnce(Cursor<W>) -> Ret) -> Ret {
559 let len = self.widget.read(pa).text().selections().len();
560 self.edit_nth(pa, len.saturating_sub(1), edit)
561 }
562
563 /// A shortcut for iterating over all selections.
564 ///
565 /// But it can't return a value, and is meant to reduce the
566 /// indentation that will inevitably come from using the
567 /// equivalent long form call.
568 pub fn edit_all(&self, pa: &mut Pass, edit: impl FnMut(Cursor<W>)) {
569 let (widget, area) = self.write_with_area(pa);
570 widget.text_mut().selections_mut().populate();
571 crate::mode::on_each_cursor(widget, area, edit);
572 }
573
574 ////////// Area functions
575
576 /// Scrolls the [`Text`] veritcally by an amount.
577 ///
578 /// If [`PrintOpts.allow_overscroll`] is set, then the [`Text`]
579 /// will be allowed to scroll beyond the last line, up until
580 /// reaching the `scrolloff.y` value.
581 ///
582 /// [`PrintOpts.allow_overscroll`]: crate::opts::PrintOpts::allow_overscroll
583 pub fn scroll_ver(&self, pa: &mut Pass, dist: i32) {
584 let (widget, area) = self.write_with_area(pa);
585 area.scroll_ver(widget.text(), dist, widget.print_opts());
586 self.widget.declare_written();
587 }
588
589 /// Scrolls the [`Text`] to the visual line of a [`TwoPoints`].
590 ///
591 /// If `scroll_beyond` is set, then the [`Text`] will be allowed
592 /// to scroll beyond the last line, up until reaching the
593 /// `scrolloff.y` value.
594 pub fn scroll_to_points(&self, pa: &mut Pass, points: TwoPoints) {
595 let (widget, area) = self.write_with_area(pa);
596 area.scroll_to_points(widget.text(), points, widget.print_opts());
597 self.widget.declare_written();
598 }
599
600 /// The start points that should be printed.
601 pub fn start_points(&self, pa: &Pass) -> TwoPoints {
602 let widget = self.widget.read(pa);
603 self.area
604 .start_points(pa, widget.text(), widget.print_opts())
605 }
606
607 /// The end points that should be printed.
608 pub fn end_points(&self, pa: &Pass) -> TwoPoints {
609 let widget = self.widget.read(pa);
610 self.area.end_points(pa, widget.text(), widget.print_opts())
611 }
612
613 /// The [`Widget`]'s [`PrintOpts`].
614 pub fn opts(&self, pa: &Pass) -> PrintOpts {
615 self.widget.read(pa).print_opts()
616 }
617
618 /// Closes this `Handle`, removing the [`Widget`] from the.
619 /// [`Window`]
620 ///
621 /// [`Window`]: crate::ui::Window
622 pub fn close(&self, pa: &mut Pass) -> Result<(), Text> {
623 context::windows().close(pa, self)
624 }
625}
626
627impl<W: Widget> Handle<W> {
628 /// Pushes a [`Widget`] around this one.
629 ///
630 /// This `Widget` will be placed internally, i.e., around the
631 /// [`Area`] of `self`. This is in contrast to
632 /// [`Handle::push_outer_widget`], which will push around the
633 /// "cluster master" of `self`.
634 ///
635 /// A cluster master is the collection of every `Widget` that was
636 /// pushed around a central one with [`PushSpecs::cluster`] set to
637 /// `true`.
638 ///
639 /// Both of these functions behave identically in the situation
640 /// where no other [`Widget`]s were pushed around `self`.
641 ///
642 /// However, if, for example, a [`Widget`] was previously pushed
643 /// below `self`, when pushing to the left, the following would
644 /// happen:
645 ///
646 /// ```text
647 /// ╭────────────────╮ ╭─────┬──────────╮
648 /// │ │ │ │ │
649 /// │ self │ │ new │ self │
650 /// │ │ -> │ │ │
651 /// ├────────────────┤ ├─────┴──────────┤
652 /// │ old │ │ old │
653 /// ╰────────────────╯ ╰────────────────╯
654 /// ```
655 ///
656 /// While in [`Handle::push_outer_widget`], this happens instead:
657 ///
658 /// ```text
659 /// ╭────────────────╮ ╭─────┬──────────╮
660 /// │ │ │ │ │
661 /// │ self │ │ │ self │
662 /// │ │ -> │ new │ │
663 /// ├────────────────┤ │ ├──────────┤
664 /// │ old │ │ │ old │
665 /// ╰────────────────╯ ╰─────┴──────────╯
666 /// ```
667 ///
668 /// Note that `new` was pushed _around_ other clustered widgets in
669 /// the second case, not just around `self`.
670 pub fn push_inner_widget<PW: Widget>(
671 &self,
672 pa: &mut Pass,
673 widget: PW,
674 specs: PushSpecs,
675 ) -> Handle<PW> {
676 let main = if let Some((main, _)) = self
677 .related
678 .read(pa)
679 .iter()
680 .find(|(_, relation)| *relation == WidgetRelation::Main)
681 {
682 main.clone()
683 } else {
684 self.to_dyn()
685 };
686
687 let handle = context::windows()
688 .push_widget(pa, (&self.area, None, specs), widget, Some(&self.area))
689 .unwrap();
690
691 main.related
692 .write(pa)
693 .push((handle.to_dyn(), WidgetRelation::Pushed));
694
695 handle
696 }
697
698 /// Pushes a [`Widget`] around the "cluster master" of this one.
699 ///
700 /// A cluster master is the collection of every `Widget` that was
701 /// pushed around a central one with [`PushSpecs::cluster`] set to
702 /// `true`.
703 ///
704 /// This [`Widget`] will be placed externally, i.e., around every
705 /// other [`Widget`] that was pushed around `self`. This is in
706 /// contrast to [`Handle::push_inner_widget`], which will push
707 /// only around `self`.
708 ///
709 /// Both of these functions behave identically in the situation
710 /// where no other [`Widget`]s were pushed around `self`.
711 ///
712 /// However, if, for example, a [`Widget`] was previously pushed
713 /// to the left of `self`, when pushing to the left again, the
714 /// following would happen:
715 ///
716 /// ```text
717 /// ╭──────┬──────────╮ ╭─────┬─────┬──────╮
718 /// │ │ │ │ │ │ │
719 /// │ │ │ │ │ │ │
720 /// │ old │ self │ -> │ new │ old │ self │
721 /// │ │ │ │ │ │ │
722 /// │ │ │ │ │ │ │
723 /// ╰──────┴──────────╯ ╰─────┴─────┴──────╯
724 /// ```
725 ///
726 /// While in [`Handle::push_inner_widget`], this happens instead:
727 ///
728 /// ```text
729 /// ╭──────┬──────────╮ ╭─────┬─────┬──────╮
730 /// │ │ │ │ │ │ │
731 /// │ │ │ │ │ │ │
732 /// │ old │ self │ -> │ old │ new │ self │
733 /// │ │ │ │ │ │ │
734 /// │ │ │ │ │ │ │
735 /// ╰──────┴──────────╯ ╰─────┴─────┴──────╯
736 /// ```
737 ///
738 /// Note that `new` was pushed _around_ other clustered widgets in
739 /// the first case, not just around `self`.
740 pub fn push_outer_widget<PW: Widget>(
741 &self,
742 pa: &mut Pass,
743 widget: PW,
744 specs: PushSpecs,
745 ) -> Handle<PW> {
746 let main = if let Some((main, _)) = self
747 .related
748 .read(pa)
749 .iter()
750 .find(|(_, relation)| *relation == WidgetRelation::Main)
751 {
752 main.clone()
753 } else {
754 self.to_dyn()
755 };
756
757 let handle = if let Some(master) = self.area.get_cluster_master(pa) {
758 context::windows()
759 .push_widget(pa, (&master, None, specs), widget, Some(main.area()))
760 .unwrap()
761 } else {
762 context::windows()
763 .push_widget(pa, (&self.area, None, specs), widget, Some(main.area()))
764 .unwrap()
765 };
766
767 main.related
768 .write(pa)
769 .push((handle.to_dyn(), WidgetRelation::Pushed));
770
771 handle
772 }
773
774 /// Spawns a floating [`Widget`].
775 pub fn spawn_widget<SW: Widget>(
776 &self,
777 pa: &mut Pass,
778 widget: SW,
779 specs: DynSpawnSpecs,
780 ) -> Option<Handle<SW>> {
781 let self_handle = self.to_dyn();
782 context::windows().spawn_on_widget(pa, (&self.area, specs), widget, move |pa, handle| {
783 let related = self_handle.related.write(pa);
784
785 related.push((handle.clone(), WidgetRelation::Spawned));
786
787 if let Some((main, _)) = related
788 .iter_mut()
789 .find(|(_, relation)| *relation == WidgetRelation::Main)
790 .cloned()
791 {
792 main.related
793 .write(pa)
794 .push((handle.clone(), WidgetRelation::Spawned));
795 handle.related.write(pa).push((main, WidgetRelation::Main));
796 } else {
797 handle
798 .related
799 .write(pa)
800 .push((self_handle, WidgetRelation::Main));
801 }
802 })
803 }
804
805 /// Transforms this [`Handle`] into a [`Handle<dyn Widget>`].
806 pub fn to_dyn(&self) -> Handle<dyn Widget> {
807 Handle {
808 widget: self.widget.to_dyn_widget(),
809 area: self.area.clone(),
810 related: self.related.clone(),
811 is_closed: self.is_closed.clone(),
812 update_requested: self.update_requested.clone(),
813 }
814 }
815}
816
817// SAFETY: The only parts that are accessible from other threads are
818// the atomic counters from the Arcs. Everything else can only be
819// acquired when there is a Pass, i.e., on the main thread.
820unsafe impl<W: ?Sized> Send for Handle<W> {}
821unsafe impl<W: ?Sized> Sync for Handle<W> {}
822
823impl<W1: ?Sized, W2: ?Sized> PartialEq<Handle<W2>> for Handle<W1> {
824 fn eq(&self, other: &Handle<W2>) -> bool {
825 self.widget.ptr_eq(&other.widget)
826 }
827}
828
829impl<W: ?Sized> Clone for Handle<W> {
830 fn clone(&self) -> Self {
831 Self {
832 widget: self.widget.clone(),
833 area: self.area.clone(),
834 related: self.related.clone(),
835 is_closed: self.is_closed.clone(),
836 update_requested: self.update_requested.clone(),
837 }
838 }
839}
840
841impl<W: ?Sized> std::fmt::Debug for Handle<W> {
842 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
843 f.debug_struct("Handle").finish_non_exhaustive()
844 }
845}
846
847/// What relation this [`Widget`] has to its parent.
848#[derive(Clone, Copy, Debug, PartialEq, Eq)]
849pub enum WidgetRelation {
850 /// The main widget of the cluster, most commonly a [`Buffer`].
851 ///
852 /// [`Buffer`]: crate::buffer::Buffer
853 Main,
854 /// A [`Widget`] that was pushed around the main `Widget`, e.g.
855 /// [`LineNumbers`].
856 ///
857 /// [`LineNumbers`]: https://docs.rs/duat/latest/duat/widgets/struct.LineNumbers.html
858 Pushed,
859 /// A [`Widget`] that was spawned on the `Widget`, e.g.
860 /// completion. lists
861 Spawned,
862}