duat-core 0.10.0

The core of Duat, a highly customizable text editor.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
//! [Ui] structs and functions.
//!
//! Although there is only a terminal [Ui] implemented at the
//! moment, Duat is supposed to be Ui agnostic, and I plan to create a
//! GUI app (probably in `gpui` or something), and a web app as well,
//! which is honestly more of an excuse for me to become more well
//! versed on javascript.
//!
//! Each [Ui] is essentially a screen separated by a bunch of
//! [`Ui::Area`]s. This happens by splitting a main `Ui::Area`
//! continuously, by pushing [`Widget`]s on other `Widget`s. When a
//! `Widget` is pushed to another, the area of the prior `Widget`
//! is split in half, with [`PushSpecs`] defining information about
//! the new area.
//!
//! Additionally, [`Widget`]s may be spawned via various methods, such
//! as [on `Handle`]s, [on `Text`], or even [around the `Window`]
//!
//! Duat also supports multiple [`Window`]s in a [`Windows`] struct,
//! each of which is defined by a main [`Ui::Area`] that was split
//! many times over. This `Windows` struct is accessible in
//! [`context::windows`], and you are free to inspect and mutate
//! whatever state is in there.
//!
//! The [Ui] also supports the concept of "clustering", that is,
//! when you push a [`Widget`] to a [`Buffer`], it gets "clustered" to
//! that `Buffer`. This means a few things. For one, if you close that
//! `Buffer`, all of its clustered `Widget`s will also close. If
//! you swap two `Buffer`s, what you will actually swap is the
//! [`Ui::Area`] that contains the `Buffer` and all of its clustered
//! `Widget`.
//!
//! Additionally, on the terminal [Ui], clustering is used to
//! determine where to draw borders between [`Ui::Area`]s, and it
//! should be used like that in other [Ui] implementations as well.
//!
//! [`hook`]: crate::hook
//! [`Buffer`]: crate::buffer::Buffer
//! [`WidgetOpened`]: crate::hook::WidgetOpened
//! [Ui]: traits::RawUi
//! [`Ui::Area`]: traits::RawUi::Area
//! [on `Handle`]: Handle::spawn_widget
//! [on `Text`]: crate::text::Spawn
//! [`context::windows`]: crate::context::windows
use std::{
    fmt::Debug,
    sync::atomic::{AtomicU16, Ordering},
};

pub(crate) use self::widget::Node;
pub use self::{
    type_erased::{Area, PrintInfo, RwArea, Ui, ui_is},
    widget::Widget,
    window::{Window, Windows},
};
use crate::{context::Handle, data::Pass};

pub mod layout;
pub mod traits;
mod type_erased;
mod widget;
mod window;

/// A coordinate on screen.
///
/// An integer value should represent the size of a monospaced font
/// cell. So, for example, in a terminal, x should represent the top
/// left corner of a column, and y represents the top left corner of a
/// row.
///
/// For non terminal GUIs, an integer should have the same
/// representation, but fractional values should be permitted as well.
#[derive(Default, Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Coord {
    /// The x value of this coordinate. In a terminal cell, it would
    /// be the top left corner.
    pub x: f32,
    /// The y value of this coordinate. In a terminal cell, it would
    /// be the top left corner.
    pub y: f32,
}

impl Coord {
    /// Returns a new `Coord` from an `x` and a `y` values,
    /// respectively.
    pub const fn new(x: f32, y: f32) -> Self {
        Self { x, y }
    }
}

impl std::ops::Add for Coord {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Self { x: self.x + rhs.x, y: self.y + rhs.y }
    }
}

impl std::ops::Sub for Coord {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        Self { x: self.x - rhs.x, y: self.y - rhs.y }
    }
}

impl std::ops::Mul<f32> for Coord {
    type Output = Self;

    fn mul(self, rhs: f32) -> Self::Output {
        Self { x: rhs * self.x, y: rhs * self.y }
    }
}

impl std::ops::Mul<Coord> for f32 {
    type Output = Coord;

    fn mul(self, rhs: Coord) -> Self::Output {
        Coord { x: self * rhs.x, y: self * rhs.y }
    }
}

impl std::ops::Div<f32> for Coord {
    type Output = Self;

    fn div(self, rhs: f32) -> Self::Output {
        Self { x: self.x / rhs, y: self.y / rhs }
    }
}

/// A dimension on screen, can either be horizontal or vertical.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Axis {
    /// The horizontal axis.
    Horizontal,
    /// The vertical axis.
    Vertical,
}

impl Axis {
    /// The [`Axis`] perpendicular to this one.
    pub fn perp(&self) -> Self {
        match self {
            Axis::Horizontal => Axis::Vertical,
            Axis::Vertical => Axis::Horizontal,
        }
    }

    /// Returns `true` if the axis is [`Horizontal`].
    ///
    /// [`Horizontal`]: Axis::Horizontal
    #[must_use]
    pub fn is_hor(&self) -> bool {
        matches!(self, Self::Horizontal)
    }

    /// Returns `true` if the axis is [`Vertical`].
    ///
    /// [`Vertical`]: Axis::Vertical
    #[must_use]
    pub fn is_ver(&self) -> bool {
        matches!(self, Self::Vertical)
    }
}

impl From<PushSpecs> for Axis {
    fn from(value: PushSpecs) -> Self {
        match value.side {
            Side::Above | Side::Below => Axis::Vertical,
            _ => Axis::Horizontal,
        }
    }
}

/// Information on how a [`Widget`] should be pushed onto another.
///
/// This information is composed of four parts:
///
/// * A side to push;
/// * An optional width;
/// * An optional height;
/// * Wether to hide it by default;
/// * wether to cluster the [`Widget`]
///
/// Constraints are demands that must be met by the widget's
/// [`Area`], on a best effort basis.
///
/// So, for example, if the [`PushSpecs`] are:
///
/// ```rust
/// # duat_core::doc_duat!(duat);
/// use duat::prelude::*;
/// let specs = ui::PushSpecs {
///     side: ui::Side::Left,
///     width: Some(3.0),
///     height: None,
///     hidden: false,
///     cluster: true,
/// };
/// ```
///
/// Then the widget should be pushed to the left, with a width of 3,
/// an unspecified height, _not_ hidden by default and clustered if
/// possible. Note that you can shorten the definition above:
///
/// ```rust
/// # duat_core::doc_duat!(duat);
/// use duat::prelude::*;
/// let specs = ui::PushSpecs {
///     side: ui::Side::Left,
///     width: Some(3.0),
///     ..Default::default()
/// };
/// ```
///
/// Since the remaining values are the default.
#[derive(Clone, Copy, Debug)]
pub struct PushSpecs {
    /// Which [`Side`] to push the [`Widget`] to.
    pub side: Side,
    /// A width (in character cells) for this `Widget`.
    ///
    /// Note that this may be ignored if it is not possible to
    /// create an area big (or small) enough.
    pub width: Option<f32>,
    /// A height (in lines) for this `Widget`.
    ///
    /// Note that this may be ignored if it is not possible to
    /// create an area big (or small) enough.
    pub height: Option<f32>,
    /// Hide this `Widget` by default.
    ///
    /// You can call [`Area::hide`] or [`Area::reveal`] to toggle
    /// this property.
    pub hidden: bool,
    /// Cluster this `Widget` when pushing.
    ///
    /// This makes it so, if the main `Widget` is moved or deleted,
    /// then this one will follow. Useful for things like
    /// [`LineNumbers`], since they should follow their [`Buffer`]
    /// around.
    ///
    /// [`LineNumbers`]: https://docs.rs/duat/latest/duat/widgets/struct.LineNumbers.html
    /// [`Buffer`]: crate::buffer::Buffer
    pub cluster: bool,
}

impl Default for PushSpecs {
    fn default() -> Self {
        Self {
            side: Side::Right,
            width: None,
            height: None,
            hidden: false,
            cluster: true,
        }
    }
}

impl PushSpecs {
    /// The [`Axis`] where it will be pushed.
    ///
    /// - left/right: [`Axis::Horizontal`].
    /// - above/below: [`Axis::Vertical`].
    pub const fn axis(&self) -> Axis {
        match self.side {
            Side::Above | Side::Below => Axis::Vertical,
            Side::Right | Side::Left => Axis::Horizontal,
        }
    }

    /// Wether this "comes earlier" on the screen.
    ///
    /// This returns true if `self.side() == Side::Left || self.side()
    /// == Side::Above`, since that is considered "earlier" on
    /// screens.
    pub const fn comes_earlier(&self) -> bool {
        matches!(self.side, Side::Left | Side::Above)
    }

    /// The constraints on a given [`Axis`].
    pub fn len_on(&self, axis: Axis) -> Option<f32> {
        match axis {
            Axis::Horizontal => self.width,
            Axis::Vertical => self.height,
        }
    }
}

/// Information about how a [`Widget`] should be spawned dynamically.
///
/// Dynamically spawned `Widget`s are those that are spawned on
/// [`Handle`]s or [`Text`]. They are called dynamic because their
/// spawning location can change automatically, either by the widget
/// they are spawned on resizing, or the `Text` changing, etc.
///
/// This is in contrast with [`StaticSpawnSpecs`], which are not
/// spawned on a `Handle` or `Text`, and are instead placed in a
/// [`Coord`] on screen.
///
/// [`Handle`]: Handle::push_outer_widget
/// [`Text`]: crate::text::Spawn
#[derive(Default, Debug, Clone, Copy)]
pub struct DynSpawnSpecs {
    /// The orientation to place this [`Widget`] in.
    ///
    /// May receive some reworks in the future.
    pub orientation: Orientation,
    /// A width (in character cells) for this `Widget`.
    ///
    /// Note that this may be ignored if it is not possible to
    /// create an area big (or small) enough.
    pub width: Option<f32>,
    /// A height (in lines) for this `Widget`.
    ///
    /// Note that this may be ignored if it is not possible to
    /// create an area big (or small) enough.
    pub height: Option<f32>,
    /// Hide this `Widget` by default.
    ///
    /// You can call [`Area::hide`] or [`Area::reveal`] to toggle
    /// this property.
    pub hidden: bool,
    /// Put this `Widget` _inside_, rather than outside.
    ///
    /// A consequence of this is that no repositioning will ever be
    /// done, since there is no spatial difference between placing the
    /// [`Widget`] above the bottom or below the top.
    ///
    /// This is `false` by default.
    pub inside: bool,
}

impl DynSpawnSpecs {
    /// The constraints on a given [`Axis`].
    pub const fn len_on(&self, axis: Axis) -> Option<f32> {
        match axis {
            Axis::Horizontal => self.width,
            Axis::Vertical => self.height,
        }
    }
}

/// Information about how a [`Widget`] should be spawned statically.
///
/// Statically spawned `Widget`s are those that are placed in a
/// [`Coord`] on screen via [`Window::spawn`] and don't change
/// location.
///
/// This is in contrast with [`DynSpawnSpecs`], which are allowed to
/// be moved automatically, due to being spawned on [`Handle`]s or
/// [`Text`], which are allowed to change.
///
/// [`Text`]: crate::text::Text
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StaticSpawnSpecs {
    /// The top left corner where the [`Widget`] will be spawned.
    pub top_left: Coord,
    /// The size of the [`Widget`], represented by a [`Coord`].
    pub size: Coord,
    /// Hide this [`Widget`] by default.
    ///
    /// You can call [`Area::hide`] or [`Area::reveal`] to toggle
    /// this property.
    pub hidden: bool,
    /// Reposition the [`Widget`] in case the [`Window`] resizes.
    ///
    /// Normally, this is [`None`], which means no repositioning is
    /// done unless the `Widget` would be clipped by the `Window`, in
    /// which case it will be "dragged up and to the left" until it no
    /// longer clips the window (or not, depending on the Ui you're
    /// using :P)
    ///
    /// However, if this is [`Some`], then the `Widget` will be
    /// repositioned. If it is `Some(false)`, then it will keep an
    /// absolute distance from the bottom right corner. This is useful
    /// for, for example, notifications which you'd want to be located
    /// "near the bottom right".
    ///
    /// If it is `Some(true)`, then the repositioning will be
    /// _fractional_. What this means is that, if it was placed
    /// centrally, it will remain centered.
    pub fractional_repositioning: Option<bool>,
}

impl StaticSpawnSpecs {
    /// The constraints on a given [`Axis`].
    pub const fn len_on(&self, axis: Axis) -> f32 {
        match axis {
            Axis::Horizontal => self.size.x,
            Axis::Vertical => self.size.y,
        }
    }
}

impl Default for StaticSpawnSpecs {
    fn default() -> Self {
        Self {
            top_left: Coord { x: 0.0, y: 0.0 },
            size: Coord { x: 50.0, y: 5.0 },
            hidden: false,
            fractional_repositioning: None,
        }
    }
}

/// A direction, where a [`Widget`] will be placed in relation to
/// another.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum Side {
    /// Put the [`Widget`] above another.
    Above,
    /// Put the [`Widget`] on the right.
    #[default]
    Right,
    /// Put the [`Widget`] on the left.
    Below,
    /// Put the [`Widget`] below another.
    Left,
}

impl Side {
    /// Which [`Axis`] this [`Side`] belongs to.
    pub fn axis(&self) -> Axis {
        match self {
            Side::Above | Side::Below => Axis::Vertical,
            Side::Right | Side::Left => Axis::Horizontal,
        }
    }
}

/// Where to place a spawned [`Widget`].
///
/// The `Orientation` has 3 components of positioning, which follow
/// priorities in order to relocate the `Widget` in case there isn't
/// enough space. Respectively, they are the following:
///
/// - An axis to align the `Widget`.
/// - How to align said `Widget` on said axis.
/// - Which side of the parent should be prioritized.
///
/// For example, [`Orientation::HorTopLeft`] means: Spawn this
/// `Widget` horizontally, trying to align its top edge with the top
/// edge of the parent, prioritizing the left side. Visually speaking,
/// it will try to spawn a `Widget` like this:
///
/// ```text
/// ╭─────────┬────────╮
/// │         │ Parent │
/// │ Spawned ├────────╯
/// │         │
/// ╰─────────╯
/// ```
///
/// Notice that their tops are aligned, the edges connect on the
/// horizontal axis, and it is on the left side. However, if there is
/// not enough space, (e.g. the parent is very close to the bottom
/// left edge of the screen) it might try to spawn it like this:
///
/// ```text
/// ╭─────────╮                                 ╭─────────╮
/// │         ├────────╮                        │         │
/// │ Spawned │ Parent │, or even like ╭────────┤ Spawned │
/// │         ├────────╯               │ Parent │         │
/// ╰─────────╯                        ╰────────┴─────────╯
/// ```
///
/// This prioritization gives more flexibility to the spawning of
/// `Widget`s, which usually follows patterns of where to spawn and
/// how to place things, mostly to prevent obscuring information. The
/// most notable example of this are completion lists. For obvious
/// reasons, those should only be placed above or below (`Ver`),
/// alignment should try to be on the left edge (`VerLeft`), and
/// ideally below the cursor ([`Orientation::VerLeftBelow`]).
/// Likewise, these completion lists are sometimes accompanied by
/// description panels, which should ideally follow a
/// [`HorCenterRight`] or [`HorBottomRight`] orientation.
///
/// [`HorCenterRight`]: Orientation::HorCenterRight
/// [`HorBottomRight`]: Orientation::HorBottomRight
#[derive(Default, Debug, Clone, Copy)]
pub enum Orientation {
    /// Place the [`Widget`] vertically, prioritizing the left edge
    /// above.
    VerLeftAbove,
    /// Place the [`Widget`] vertically, prioritizing centering above.
    VerCenterAbove,
    /// Place the [`Widget`] vertically, prioritizing the right edge
    /// above.
    VerRightAbove,
    /// Place the [`Widget`] vertically, prioritizing the left edge
    /// below.
    #[default]
    VerLeftBelow,
    /// Place the [`Widget`] vertically, prioritizing centering below.
    VerCenterBelow,
    /// Place the [`Widget`] vertically, prioritizing the right edge
    /// below.
    VerRightBelow,
    /// Place the [`Widget`] horizontally, prioritizing the top edge
    /// on the left.
    HorTopLeft,
    /// Place the [`Widget`] horizontally, prioritizing centering
    /// on the left.
    HorCenterLeft,
    /// Place the [`Widget`] horizontally, prioritizing the right edge
    /// on the left.
    HorBottomLeft,
    /// Place the [`Widget`] horizontally, prioritizing the top edge
    /// on the right.
    HorTopRight,
    /// Place the [`Widget`] horizontally, prioritizing centering
    /// on the right.
    HorCenterRight,
    /// Place the [`Widget`] horizontally, prioritizing the bottom
    /// edge on the right.
    HorBottomRight,
}

impl Orientation {
    /// The [`Axis`] to which this `Orientation` pushes.
    pub fn axis(&self) -> Axis {
        match self {
            Orientation::VerLeftAbove
            | Orientation::VerCenterAbove
            | Orientation::VerRightAbove
            | Orientation::VerLeftBelow
            | Orientation::VerCenterBelow
            | Orientation::VerRightBelow => Axis::Vertical,
            Orientation::HorTopLeft
            | Orientation::HorCenterLeft
            | Orientation::HorBottomLeft
            | Orientation::HorTopRight
            | Orientation::HorCenterRight
            | Orientation::HorBottomRight => Axis::Horizontal,
        }
    }

    /// Wether this should prefer being pushed before (left or above).
    pub fn prefers_before(&self) -> bool {
        match self {
            Orientation::VerLeftAbove
            | Orientation::VerCenterAbove
            | Orientation::VerRightAbove
            | Orientation::HorTopLeft
            | Orientation::HorCenterLeft
            | Orientation::HorBottomLeft => true,
            Orientation::VerLeftBelow
            | Orientation::VerCenterBelow
            | Orientation::VerRightBelow
            | Orientation::HorTopRight
            | Orientation::HorCenterRight
            | Orientation::HorBottomRight => false,
        }
    }
}

/// A target for pushing [`Widget`]s to.
///
/// This can either be a [`Handle`], which will push around a `Widget`
/// or a [`Window`], which will push around the window.
///
/// This trait is useful if you wish to let your [`Widget`] both be
/// pushed around other `Widget`s and also around the window with the
/// [`Window`]. One example of this is the [`StatusLine`] widget,
/// which behaves differently depending on if it was pushed to a
/// [`Handle<Buffer>`].
///
/// [`StatusLine`]: https://docs.rs/duat/duat/latest/widgets/struct.StatusLine.html
pub trait PushTarget {
    /// Pushes a [`Widget`] around `self`
    ///
    /// If `self` is a [`Handle`], this will push around the
    /// `Handle`'s own [`Area`]. If this is a [`Window`],
    /// this will push around the master `Area` of the central
    /// region of buffers.
    ///
    /// This `Widget` will be placed internally, i.e., around the
    /// [`Area`] of `self`. This is in contrast to
    /// [`Handle::push_outer_widget`], which will push around the
    /// "cluster master" of `self`.
    ///
    /// A cluster master is the collection of every `Widget` that was
    /// pushed around a central one with [`PushSpecs::cluster`] set to
    /// `true`.
    ///
    /// Both of these functions behave identically in the situation
    /// where no other [`Widget`]s were pushed around `self`.
    ///
    /// However, if, for example, a `Widget` was previously pushed
    /// below `self`, when pushing to the left, the following would
    /// happen:
    ///
    /// ```text
    /// ╭────────────────╮    ╭─────┬──────────╮
    /// │                │    │     │          │
    /// │      self      │    │ new │   self   │
    /// │                │ -> │     │          │
    /// ├────────────────┤    ├─────┴──────────┤
    /// │      old       │    │      old       │
    /// ╰────────────────╯    ╰────────────────╯
    /// ```
    ///
    /// While in [`Handle::push_outer_widget`], this happens instead:
    ///
    /// ```text
    /// ╭────────────────╮    ╭─────┬──────────╮
    /// │                │    │     │          │
    /// │      self      │    │     │   self   │
    /// │                │ -> │ new │          │
    /// ├────────────────┤    │     ├──────────┤
    /// │      old       │    │     │   old    │
    /// ╰────────────────╯    ╰─────┴──────────╯
    /// ```
    ///
    /// Note that `new` was pushed _around_ other clustered widgets in
    /// the second case, not just around `self`.
    fn push_inner<PW: Widget>(&self, pa: &mut Pass, widget: PW, specs: PushSpecs) -> Handle<PW>;

    /// Pushes a [`Widget`] around the "master region" of `self`
    ///
    /// If `self` is a [`Handle`], this will push its "cluster
    /// master". If this is a [`Window`], this will push the
    /// `Widget` to the edges of the window.
    ///
    /// A cluster master is the collection of every `Widget` that was
    /// pushed around a central one with [`PushSpecs::cluster`] set to
    /// `true`.
    ///
    /// This [`Widget`] will be placed externally, i.e., around every
    /// other `Widget` that was pushed around `self`. This is in
    /// contrast to [`Handle::push_inner_widget`], which will push
    /// only around `self`.
    ///
    /// Both of these functions behave identically in the situation
    /// where no other [`Widget`]s were pushed around `self`.
    ///
    /// However, if, for example, a `Widget` was previously pushed
    /// to the left of `self`, when pushing to the left again, the
    /// following would happen:
    ///
    /// ```text
    /// ╭──────┬──────────╮    ╭─────┬─────┬──────╮
    /// │      │          │    │     │     │      │
    /// │      │          │    │     │     │      │
    /// │  old │   self   │ -> │ new │ old │ self │
    /// │      │          │    │     │     │      │
    /// │      │          │    │     │     │      │
    /// ╰──────┴──────────╯    ╰─────┴─────┴──────╯
    /// ```
    ///
    /// While in [`Handle::push_inner_widget`], this happens instead:
    ///
    /// ```text
    /// ╭──────┬──────────╮    ╭─────┬─────┬──────╮
    /// │      │          │    │     │     │      │
    /// │      │          │    │     │     │      │
    /// │  old │   self   │ -> │ old │ new │ self │
    /// │      │          │    │     │     │      │
    /// │      │          │    │     │     │      │
    /// ╰──────┴──────────╯    ╰─────┴─────┴──────╯
    /// ```
    ///
    /// Note that `new` was pushed _around_ other clustered widgets in
    /// the first case, not just around `self`.
    fn push_outer<PW: Widget>(&self, pa: &mut Pass, widget: PW, specs: PushSpecs) -> Handle<PW>;

    /// Tries to downcast to a [`Handle`] of some `W`
    fn try_downcast<W: Widget>(&self) -> Option<Handle<W>>;
}

impl<W: Widget> PushTarget for Handle<W> {
    #[doc(hidden)]
    fn push_inner<PW: Widget>(&self, pa: &mut Pass, widget: PW, specs: PushSpecs) -> Handle<PW> {
        self.push_inner_widget(pa, widget, specs)
    }

    #[doc(hidden)]
    fn push_outer<PW: Widget>(&self, pa: &mut Pass, widget: PW, specs: PushSpecs) -> Handle<PW> {
        self.push_outer_widget(pa, widget, specs)
    }

    fn try_downcast<DW: Widget>(&self) -> Option<Handle<DW>> {
        self.try_downcast()
    }
}

impl PushTarget for Window {
    #[doc(hidden)]
    fn push_inner<PW: Widget>(&self, pa: &mut Pass, widget: PW, specs: PushSpecs) -> Handle<PW> {
        Window::push_inner(self, pa, widget, specs)
    }

    #[doc(hidden)]
    fn push_outer<PW: Widget>(&self, pa: &mut Pass, widget: PW, specs: PushSpecs) -> Handle<PW> {
        Window::push_outer(self, pa, widget, specs)
    }

    fn try_downcast<W: Widget>(&self) -> Option<Handle<W>> {
        None
    }
}

/// The id of a spawned [`Widget`].
///
/// [`Widget`]: crate::ui::Widget
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpawnId(u16);

impl SpawnId {
    /// Creates a new [`SpawnId`]
    #[allow(clippy::new_without_default)]
    pub(crate) fn new() -> Self {
        static SPAWN_COUNT: AtomicU16 = AtomicU16::new(0);
        Self(SPAWN_COUNT.fetch_add(1, Ordering::Relaxed))
    }
}

impl std::fmt::Debug for SpawnId {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "SpawnId({})", self.0)
    }
}

/// Information about a line that was printed.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PrintedLine {
    /// The line's number.
    pub number: usize,
    /// Wether the line is wrapped.
    pub is_wrapped: bool,
    /// Wether the wrapped line was entirely a ghost line.
    pub is_ghost: bool
}

/// Information about the horizontal place of a [`TwoPoints`]
///
/// [`TwoPoints`]: crate::text::TwoPoints
pub struct Columns {
    /// The distance from the last `\n` character (or start).
    pub line: usize,
    /// The distance from the leftmost edge of the area.
    pub wrapped: usize,
    /// How much horizontal space the character in this position is
    /// occupying.
    pub len: usize,
}