duat_core/
form.rs

1//! Utilities for stylizing the text of Duat
2use std::sync::{OnceLock, RwLock, RwLockReadGuard};
3
4use FormType::*;
5use crossterm::style::{Attribute, Attributes, ContentStyle};
6pub use crossterm::{cursor::SetCursorStyle as CursorShape, style::Color};
7
8pub use self::global::*;
9pub(crate) use self::global::{colorscheme_exists, exists};
10use crate::{
11    hook::{self, FormSet},
12    session::DuatSender,
13    text::FormTag,
14};
15
16/// Lists of [`Form`]s to be applied by a name
17pub trait ColorScheme: Send + Sync + 'static {
18    /// Applies the [`Form`]s
19    ///
20    /// # Note
21    ///
22    /// This can technically do anything, mostly because one might
23    /// want to do a bunch of `if`s and `else`s in order to get to a
24    /// finalized [`ColorScheme`].
25    fn apply(&self);
26
27    /// The name of this [`ColorScheme`], shouldn't be altered
28    fn name(&self) -> &'static str;
29}
30
31static SENDER: OnceLock<DuatSender> = OnceLock::new();
32static BASE_FORMS: &[(&str, Form, FormType)] = &[
33    ("default", Form::new().0, Normal),
34    ("accent", Form::bold().0, Normal),
35    ("caret.main", Form::reverse().0, Normal),
36    ("caret.extra", Form::reverse().0, Ref(2)),
37    ("selection.main", Form::white().on_dark_grey().0, Normal),
38    ("selection.extra", Form::white().on_grey().0, Ref(5)),
39    ("cloak", Form::grey().on_black().0, Normal),
40    ("character.control", Form::grey().0, Normal),
41    ("param.buffer", Form::yellow().0, Normal),
42    ("param.buffer.open", Form::yellow().0, Ref(8)),
43    ("param.buffer.exists", Form::yellow().underlined().0, Normal),
44];
45
46/// The functions that will be exposed for public use.
47mod global {
48    use std::{
49        any::TypeId,
50        collections::HashMap,
51        sync::{LazyLock, Mutex, OnceLock, mpsc},
52        time::Duration,
53    };
54
55    use super::{BASE_FORMS, BuiltForm, ColorScheme, CursorShape, Form, FormId, Painter, Palette};
56    #[doc(inline)]
57    pub use crate::{
58        __id_of__ as id_of, __set_many__ as set_many, __set_many_weak__ as set_many_weak,
59    };
60    use crate::{
61        context,
62        hook::{self, ColorSchemeSet},
63    };
64
65    static PALETTE: OnceLock<&'static Palette> = OnceLock::new();
66    static FORMS: OnceLock<&'static Mutex<Vec<&str>>> = OnceLock::new();
67    static COLORSCHEMES: LazyLock<Mutex<Vec<Box<dyn ColorScheme>>>> = LazyLock::new(Mutex::default);
68
69    /// Either a [`Form`] or the name of a form
70    ///
71    /// Note that the referenced form does not need to exist for
72    /// [`form::set`] or [`form::set_weak`] to work properly. In that
73    /// case, a new form with that name will be created, as well as
74    /// any of its inherited parents (separated by `"."`).
75    ///
76    /// [`form::set`]: set
77    /// [`form::set_weak`]: set_weak
78    #[doc(hidden)]
79    pub trait FormFmt {
80        /// The kind of [`Form`] that this type represents
81        fn kind(&self) -> Kind;
82    }
83    impl FormFmt for Form {
84        fn kind(&self) -> Kind {
85            Kind::Form(*self)
86        }
87    }
88
89    impl FormFmt for BuiltForm {
90        fn kind(&self) -> Kind {
91            Kind::Form(self.0)
92        }
93    }
94
95    impl FormFmt for &str {
96        fn kind(&self) -> Kind {
97            Kind::Ref(self.to_string())
98        }
99    }
100
101    impl FormFmt for &mut str {
102        fn kind(&self) -> Kind {
103            Kind::Ref(self.to_string())
104        }
105    }
106
107    impl FormFmt for String {
108        fn kind(&self) -> Kind {
109            Kind::Ref(self.clone())
110        }
111    }
112
113    /// Sets the [`Form`] by the name of `name`
114    ///
115    /// This will create a new form or replace one that already
116    /// exists, and you can either set it to a [`Form`] directly, or
117    /// reference another form by its name:
118    ///
119    /// ```rust
120    /// # duat_core::form::set_initial(duat_core::form::get_initial());
121    /// # use duat_core::form::{self, Form};
122    /// // Creates a regular form
123    /// let reg_id = form::set("my_regular_form", Form::red());
124    /// // Creates a form that references the first
125    /// let ref_id = form::set("my_ref_form", "my_regular_form");
126    /// // Sets both "MyRegularForm" and "MyRefForm" to blue
127    /// form::set("my_regular_form", Form::blue());
128    /// ```
129    ///
130    /// If you are creating a plugin, or another kind of tool for
131    /// others using Duat, use [`form::set_weak`] instead of this
132    /// function.
133    ///
134    /// [`form::set_weak`]: set_weak
135    pub fn set(name: impl ToString, form: impl FormFmt) -> FormId {
136        let name = name.to_string();
137        let cloned_name = name.clone();
138
139        match form.kind() {
140            Kind::Form(form) => queue(move || PALETTE.get().unwrap().set_form(cloned_name, form)),
141            Kind::Ref(refed) => queue(move || PALETTE.get().unwrap().set_ref(cloned_name, refed)),
142        };
143
144        let mut forms = FORMS.get().unwrap().lock().unwrap();
145        if let Kind::Ref(refed) = form.kind() {
146            position_of_name(&mut forms, refed);
147        }
148        FormId(position_of_name(&mut forms, name) as u16)
149    }
150
151    /// Sets a form, "weakly"
152    ///
153    /// The difference between this function and [`form::set`] is
154    /// that this function will only trigger if the form didn't
155    /// already exist/was previously onle set with [`set_weak`].
156    ///
157    /// This is useful for plugins, since it prioritizes the user's
158    /// preferences, no matter in what order this function and
159    /// [`form::set`] are called:
160    ///
161    /// ```rust
162    /// # duat_core::form::set_initial(duat_core::form::get_initial());
163    /// use duat_core::form::{self, Form};
164    ///
165    /// // Creates a form "weakly"
166    /// form::set_weak("weak_form", Form::blue().on_white());
167    ///
168    /// // Sets that form "strongly"
169    /// form::set("weak_form", Form::red().on_grey());
170    ///
171    /// // Even if setting the form weakly afterwards, it won't change again.
172    /// form::set_weak("weak_form", Form::blue().underlined());
173    /// ```
174    ///
175    /// [`form::set`]: set
176    pub fn set_weak(name: impl ToString, form: impl FormFmt) -> FormId {
177        let name = name.to_string();
178        let cloned_name = name.clone();
179
180        match form.kind() {
181            Kind::Form(form) => {
182                queue(move || PALETTE.get().unwrap().set_weak_form(cloned_name, form))
183            }
184            Kind::Ref(refed) => {
185                queue(move || PALETTE.get().unwrap().set_weak_ref(cloned_name, refed))
186            }
187        };
188
189        let mut forms = FORMS.get().unwrap().lock().unwrap();
190        if let Kind::Ref(refed) = form.kind() {
191            position_of_name(&mut forms, refed);
192        }
193        FormId(position_of_name(&mut forms, name) as u16)
194    }
195
196    /// Returns a [`Form`], given a [`FormId`].
197    pub fn from_id(id: FormId) -> Form {
198        PALETTE
199            .get()
200            .unwrap()
201            .form_from_id(id)
202            .unwrap_or(Form::new().0)
203    }
204
205    /// The current main cursor, with the `"caret.main"` [`Form`]
206    pub fn main_cursor() -> (Form, Option<CursorShape>) {
207        PALETTE.get().unwrap().main_cursor()
208    }
209
210    /// The current extra cursor, with the `"caret.extra"` [`Form`]
211    pub fn extra_cursor() -> (Form, Option<CursorShape>) {
212        PALETTE.get().unwrap().extra_cursor()
213    }
214
215    /// Sets the main cursor's [shape]
216    ///
217    /// Cursors in Duat can either be a distinct [shape], or can be
218    /// defined as a [`Form`], just like the rest of the styling.
219    ///
220    /// This is done because some UIs (like a terminal) lack the
221    /// ability to show multiple cursors, so extra cursors are usually
222    /// printed as solid blocks with a background color.
223    ///
224    /// If you want to set the cursor's color, do something like this:
225    ///
226    /// ```rust
227    /// # use duat_core::form::{self, Form, Color};
228    /// # duat_core::form::set_initial(duat_core::form::get_initial());
229    /// form::set("caret.main", Form::black().on("rgb 240 210 200"));
230    /// ```
231    ///
232    /// However, if possible, Duat will still try to use the main
233    /// cursor's [shape]. If you don't want that to happen, see
234    /// [`form::unset_main_cursor`].
235    ///
236    /// [shape]: CursorShape
237    /// [`form::unset_main_cursor`]: unset_main_cursor
238    pub fn set_main_cursor(shape: CursorShape) {
239        queue(move || PALETTE.get().unwrap().set_main_cursor(shape));
240    }
241
242    /// Sets extra cursors's [shape]s
243    ///
244    /// Cursors in Duat can either be a distinct [shape], or can be
245    /// defined as a [`Form`], just like the rest of the styling.
246    ///
247    /// This is done because some UIs (like a terminal) lack the
248    /// ability to show multiple cursors, so extra cursors are usually
249    /// printed as solid blocks with a background color.
250    ///
251    /// If you want to set the cursor's color, do something like this:
252    ///
253    /// ```rust
254    /// # use duat_core::form::{self, Form, Color};
255    /// # duat_core::form::set_initial(duat_core::form::get_initial());
256    /// form::set("caret.extra", Form::black().on_cyan());
257    /// ```
258    ///
259    /// However, if possible, Duat will still try to use the main
260    /// cursor's [shape]. If you don't want that to happen, see
261    /// [`form::unset_extra_cursor`].
262    ///
263    /// [shape]: CursorShape
264    /// [`form::unset_extra_cursor`]: unset_extra_cursor
265    pub fn set_extra_cursor(shape: CursorShape) {
266        queue(move || PALETTE.get().unwrap().set_extra_cursor(shape));
267    }
268
269    /// Removes the main cursor's [shape]
270    ///
271    /// By doing this, you will force Duat to draw the main cursor by
272    /// use of the `"caret.main"` form.
273    ///
274    /// If you want to set the [shape] instead, see
275    /// [`form::set_main_cursor`].
276    ///
277    /// [shape]: CursorShape
278    /// [`form::set_main_cursor`]: set_main_cursor
279    pub fn unset_main_cursor() {
280        queue(move || PALETTE.get().unwrap().unset_main_cursor());
281    }
282
283    /// Removes extra cursors's [shape]s
284    ///
285    /// By doing this, you will force Duat to draw the extra cursor by
286    /// use of the `"caret.main"` form. Do note however that, in
287    /// something like a terminal, extra cursors would never be
288    /// printed as a [shape] anyways, since terminals can only
289    /// print one cursor at a time.
290    ///
291    /// If you want to set the [shape] instead, see
292    /// [`form::set_extra_cursor`].
293    ///
294    /// [shape]: CursorShape
295    /// [`form::set_extra_cursor`]: set_extra_cursor
296    pub fn unset_extra_cursor() {
297        queue(move || PALETTE.get().unwrap().unset_extra_cursor());
298    }
299
300    /// Removes all cursors's [shape]s
301    ///
302    /// Is the equivalent of calling [`unset_main_cursor`] and
303    /// [`unset_extra_cursor`].
304    ///
305    /// [shape]: CursorShape
306    pub fn unset_cursors() {
307        queue(move || {
308            PALETTE.get().unwrap().unset_main_cursor();
309            PALETTE.get().unwrap().unset_extra_cursor();
310        })
311    }
312
313    /// Creates a [`Painter`] with a mask
314    pub(crate) fn painter_with_mask<W: ?Sized + 'static>(mask: &'static str) -> Painter {
315        PALETTE.get().unwrap().painter(
316            default_id(TypeId::of::<W>(), crate::utils::duat_name::<W>()),
317            mask,
318        )
319    }
320
321    /// Enables the use of this mask
322    ///
323    /// A mask is essentially a remapping of [`Form`]s based on
324    /// suffix, this remapping doesn't take place outside of a
325    /// [`Painter`] (i.e. [`form::from_id`] won't be altered), here's
326    /// how it works:
327    ///
328    /// ```rust
329    /// # duat_core::doc_duat!(duat);
330    /// use duat::prelude::*;
331    ///
332    /// fn test<W: Widget>(pa: &mut Pass, handle: Handle<W>) {
333    ///     // Assume that a Form with the given name exists
334    ///     form::set("my_form", Form::red().on_blue());
335    ///
336    ///     // If I create a second Form like this one, they are separate
337    ///     form::set("my_form.suffix", Form::undercurled());
338    ///
339    ///     *handle.text_mut(pa) = txt!("[my_form]This is red on blue[], [my_form.suffix]undercurled");
340    ///
341    ///     // But if I enable the "suffix" mask that's at the end of the second Form
342    ///     form::enable_mask("suffix");
343    ///
344    ///     // After doing this, the Text should be printed with the "suffix" mask
345    ///     handle.set_mask("suffix");
346    ///
347    ///     // So when the widget is printed, it'd be equivalent to this:
348    ///     *handle.text_mut(pa) =
349    ///         txt!("[my_form.suffix]This is red on blue[], [my_form.suffix]undercurled");
350    /// }
351    /// ```
352    ///
353    /// Masks can serve a myriad of different purposes, but here's a
354    /// few:
355    ///
356    /// - When you want to temporarily change the [`Form`]s on a
357    ///   single [`Widget`]. This is, for example, used in the
358    ///   [`Notifications`] [`Widget`], which maps [`Form`]s in order
359    ///   to correspond to the [`Level`] of their severity.
360    /// - When you want to have [`Widget`]s change [`Form`] based on
361    ///   [hooks], so you could have, for example, an `"inactive"`
362    ///   mask for your [`Buffer`]s
363    /// - If you want to quickly cycle through [`Form`]s in a
364    ///   [`Text`], this is the most efficient way of doing that,
365    ///   since it relies on static remaps, not on changing the
366    ///   [`Form`]s themselves.
367    ///
368    /// When Duat first starts, the only available masks are
369    /// `"error"`, `"warn"` and `"info"`, but you can use this
370    /// function to add more of them.
371    ///
372    /// [`form::from_id`]: from_id
373    /// [`Widget`]: crate::ui::Widget
374    /// [`Notifications`]: https://docs.rs/duat/latest/duat
375    /// [`Level`]: crate::context::Level
376    /// [hooks]: crate::hook
377    /// [`Buffer`]: crate::buffer::Buffer
378    /// [`Text`]: crate::text::Text
379    pub fn enable_mask(mask: impl AsRef<str> + Send + Sync + 'static) {
380        queue(move || {
381            let mask = mask.as_ref();
382            let mut inner = PALETTE.get().unwrap().0.write().unwrap();
383            if !inner.masks.iter().any(|(m, _)| *m == mask) {
384                let mut remaps: Vec<u16> = (0..inner.forms.len() as u16).collect();
385
386                for (i, (name, ..)) in inner.forms.iter().enumerate() {
387                    if let Some((pref, suf)) = name.rsplit_once('.')
388                        && suf == mask
389                        && let Some(j) = inner.forms.iter().position(|(name, ..)| *name == pref)
390                    {
391                        remaps[j] = i as u16;
392                    }
393                }
394
395                inner.masks.push((mask.to_string().leak(), remaps));
396            }
397        })
398    }
399
400    /// Returns the [`FormId`] from the name of a [`Form`]
401    ///
402    /// If there is no [`Form`] with the given name, a new one is
403    /// created, which will behave according to the following
404    /// priority:
405    ///
406    /// - If the name contains a `'.'` character, it will reference
407    ///   the [`Form`] whose name is a suffix up to the last `'.'`.
408    ///   For example, `"Prefix.Middle.Suffix"` will reference
409    ///   `"Prefix.Middle"`;
410    /// - If the name does not contain a `'.'`, it will not reference
411    ///   anything, having the [default `Form`];
412    ///
413    /// If a referenced [`Form`] does not exist, it will be added,
414    /// following the same rules.
415    ///
416    /// # Note
417    ///
418    /// This is a macro because, in order to be as efficient as
419    /// possible, it is better to store this value inside of a
420    /// static variable, since it is guaranteed to not change. This
421    /// way, you only have to figure it out once, and it is much
422    /// faster than with a [`HashMap`] (how this is usually done).
423    ///
424    /// [`HashMap`]: std::collections::HashMap
425    /// [default `Form`]: Form::new
426    // SAFETY: Since _set_many always resolves to the same value, then the
427    // static muts should eventually be set to their correct values, after
428    // which no problems can occurr.
429    // Before that point, the absolute worst thing that could happen is
430    // DEFAULT_ID will be returned instead of the correct id (if the two
431    // unsafe setting statements are in the wrong order for some reason),
432    // but this should pretty much never happen.
433    #[macro_export]
434    #[doc(hidden)]
435    macro_rules! __id_of__ {
436        ($form:expr) => {{
437            use $crate::form::{_set_many, DEFAULT_ID, FormId};
438
439            static mut WAS_SET: bool = false;
440            static mut ID: FormId = DEFAULT_ID;
441            if unsafe { WAS_SET } {
442                unsafe { ID }
443            } else {
444                let name = $form.to_string();
445                let id = _set_many(true, vec![(name, None)])[0];
446                unsafe {
447                    ID = id;
448                    WAS_SET = true;
449                }
450                id
451            }
452        }};
453    }
454
455    /// Non static version of [`id_of!`]
456    ///
457    /// You should only use this if the names of the [`Form`]s in
458    /// question are not known at compile time. And if that is the
459    /// case, you should try to find a way to memoize around this
460    /// issue (usually with something like a [`HashMap`]).
461    pub fn id_of_non_static(name: impl ToString) -> FormId {
462        let name = name.to_string();
463        _set_many(true, vec![(name, None)])[0]
464    }
465
466    /// Non static version of [`id_of!`], for many [`Form`]s
467    ///
468    /// You should only use this if the names of the [`Form`]s in
469    /// question are not known at compile time. And if that is the
470    /// case, you should try to find a way to memoize around this
471    /// issue (usually with something like a [`HashMap`]).
472    pub fn ids_of_non_static(names: impl IntoIterator<Item = impl ToString>) -> Vec<FormId> {
473        let names: Vec<(String, Option<Kind>)> =
474            names.into_iter().map(|n| (n.to_string(), None)).collect();
475        _set_many(true, names)
476    }
477
478    /// Sets a bunch of [`Form`]s
479    #[doc(hidden)]
480    pub fn _set_many<S: AsRef<str> + Send + Sync + 'static>(
481        weak: bool,
482        sets: Vec<(S, Option<Kind>)>,
483    ) -> Vec<FormId> {
484        let mut ids = Vec::new();
485        let mut forms = FORMS.get().unwrap().lock().unwrap();
486        for (name, _) in sets.iter() {
487            ids.push(FormId(position_of_name(&mut forms, name) as u16));
488        }
489
490        queue(move || PALETTE.get().unwrap().set_many(weak, &sets));
491
492        ids
493    }
494
495    /// Adds a [`ColorScheme`] to the list of colorschemes
496    ///
497    /// This [`ColorScheme`] can then be added via
498    /// [`form::set_colorscheme`] or through the command
499    /// `colorscheme`.
500    ///
501    /// If a [`ColorScheme`] of the same name was already added, it
502    /// will be overritten.
503    ///
504    /// [`form::set_colorscheme`]: set_colorscheme
505    pub fn add_colorscheme(cs: impl ColorScheme) {
506        let mut colorschemes = COLORSCHEMES.lock().unwrap();
507        let name = cs.name();
508        if let Some(i) = colorschemes.iter().position(|cs| cs.name() == name) {
509            colorschemes[i] = Box::new(cs);
510        } else {
511            colorschemes.push(Box::new(cs));
512        }
513    }
514
515    /// Applies a [`ColorScheme`]
516    ///
517    /// This [`ColorScheme`] must've first been added via
518    /// [`form::add_colorscheme`].
519    ///
520    /// [`form::add_colorscheme`]: add_colorscheme
521    pub fn set_colorscheme(name: &str) {
522        let name = name.to_string();
523        let colorschemes = COLORSCHEMES.lock().unwrap();
524        if let Some(cs) = colorschemes.iter().find(|cs| cs.name() == name) {
525            cs.apply();
526            hook::queue(ColorSchemeSet(cs.name()));
527        } else {
528            context::error!("The colorscheme [a]{name}[] was not found");
529        }
530    }
531
532    /// Calls [`form::set`] on each tuple in the list
533    ///
534    /// This macro should primarily be used by colorschemes. If you
535    /// want to call a weak version of this macro (most useful for
536    /// other types of [`Plugin`]), then see [`set_many_weak!`].
537    ///
538    /// [`Plugin`]: crate::Plugin
539    /// [`form::set`]: set
540    #[macro_export]
541    #[doc(hidden)]
542    macro_rules! __set_many__ {
543        ($(($name:literal, $form:expr)),+ $(,)?) => {{
544            use $crate::form::FormFmt;
545            $crate::form::_set_many(false, vec![$( ($name, Some($form.kind())) ),+]);
546        }}
547    }
548
549    /// Calls [`form::set_weak`] on each tuple in the list
550    ///
551    /// This macro should be used when defining default colors in
552    /// [`Plugin`]s that are _not_ colorscheme [`Plugin`]s. This makes
553    /// it so the set [`Form`]s don't overrule the choices of the end
554    /// user, who might have called [`form::set`] or
555    /// [`form::set_colorscheme`] by the point that the [`Plugin`] is
556    /// added.
557    ///
558    /// [`Plugin`]: crate::Plugin
559    /// [`form::set_weak`]: set_weak
560    /// [`form::set`]: set
561    /// [`form::set_colorscheme`]: set_colorscheme
562    #[macro_export]
563    #[doc(hidden)]
564    macro_rules! __set_many_weak__ {
565        ($(($name:literal, $form:expr)),+ $(,)?) => {{
566            use $crate::form::FormFmt;
567            $crate::form::_set_many(true, vec![$( ($name, Some($form.kind())) ),+]);
568        }}
569    }
570
571    /// Wether or not a specific [`Form`] has been set
572    pub(crate) fn exists(name: &str) -> bool {
573        FORMS.get().unwrap().lock().unwrap().contains(&name)
574    }
575
576    /// Wether or not a specific [`ColorScheme`] was added
577    pub(crate) fn colorscheme_exists(name: &str) -> bool {
578        COLORSCHEMES
579            .lock()
580            .unwrap()
581            .iter()
582            .any(|cs| cs.name() == name)
583    }
584
585    /// The name of a form, given a [`FormId`]
586    pub(super) fn name_of(id: FormId) -> &'static str {
587        FORMS.get().unwrap().lock().unwrap()[id.0 as usize]
588    }
589
590    fn default_id(type_id: TypeId, type_name: &'static str) -> FormId {
591        static IDS: LazyLock<Mutex<HashMap<TypeId, FormId>>> = LazyLock::new(Mutex::default);
592        let mut ids = IDS.lock().unwrap();
593
594        if let Some(id) = ids.get(&type_id) {
595            *id
596        } else {
597            let name = format!("default.{type_name}");
598            let id = _set_many(true, vec![(name, None)])[0];
599            ids.insert(type_id, id);
600            id
601        }
602    }
603
604    fn position_of_name(names: &mut Vec<&'static str>, name: impl AsRef<str>) -> usize {
605        let name = name.as_ref();
606        if let Some((i, _)) = names.iter().enumerate().find(|(_, rhs)| **rhs == name) {
607            i
608        } else if let Some((refed, _)) = name.rsplit_once('.') {
609            position_of_name(names, refed);
610            names.push(name.to_string().leak());
611            names.len() - 1
612        } else {
613            names.push(name.to_string().leak());
614            names.len() - 1
615        }
616    }
617
618    fn queue<R>(f: impl FnOnce() -> R + Send + Sync + 'static) {
619        static SENDER: Mutex<Option<mpsc::Sender<Box<dyn FnOnce() + Send + Sync>>>> =
620            Mutex::new(None);
621
622        if context::will_reload_or_quit() {
623            return;
624        }
625
626        let f = Box::new(move || {
627            f();
628        });
629
630        let mut sender = SENDER.lock().unwrap();
631        let f = if let Some(tx) = sender.as_ref() {
632            let Err(err) = tx.send(f) else {
633                return;
634            };
635            err.0
636        } else {
637            f
638        };
639        let (tx, rx) = mpsc::channel();
640        tx.send(f).unwrap();
641        *sender = Some(tx);
642
643        std::thread::spawn(move || {
644            while let Ok(f) = rx.recv_timeout(Duration::from_micros(500)) {
645                f();
646            }
647        });
648    }
649
650    /// Gets a [`Mutex`] for the initial [`Form`]'s list of Duat
651    ///
652    /// ONLY MEANT TO BE USED BY THE DUAT EXECUTABLE
653    #[doc(hidden)]
654    pub fn get_initial() -> (&'static Mutex<Vec<&'static str>>, &'static Palette) {
655        let forms = Box::leak(Box::new(Mutex::new(
656            BASE_FORMS.iter().map(|(n, ..)| *n).collect(),
657        )));
658        let palette = Box::leak(Box::new(Palette::new()));
659        (forms, palette)
660    }
661
662    /// Sets the [`Mutex`] for the initial [`Form`]'s list of Duat
663    ///
664    /// ONLY MEANT TO BE USED BY THE DUAT EXECUTABLE
665    #[doc(hidden)]
666    pub fn set_initial((forms, palette): (&'static Mutex<Vec<&'static str>>, &'static Palette)) {
667        FORMS.set(forms).expect("Forms setup ran twice");
668        PALETTE.set(palette).expect("Forms setup ran twice");
669    }
670
671    /// A kind of [`Form`]
672    #[doc(hidden)]
673    pub enum Kind {
674        Form(Form),
675        Ref(String),
676    }
677}
678
679/// An identifier of a [`Form`]
680///
681/// [`Builder`] part: Applies the [`Form`] destructively
682///
683/// This struct is always going to point to the same form, since those
684/// cannot be destroyed.
685///
686/// The main use for keeping these things directly is in order to
687/// modify a buffer's text in an efficient manner, by adding tags
688/// directly, instead of using a macro like [`txt!`]
689///
690/// [`txt!`]: crate::text::txt
691/// [`Builder`]: crate::text::Builder
692#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
693pub struct FormId(u16);
694
695impl FormId {
696    /// Creates a [`Tag`] out of this [`FormId`]
697    ///
698    /// In order to push a [`Form`] to the [`Text`], it needs a
699    /// priority value, in order to properly sort the [`Form`]s within
700    /// the same byte.
701    ///
702    /// [`Tag`]: crate::text::Tag
703    /// [`Text`]: crate::text::Text
704    pub const fn to_tag(self, prio: u8) -> FormTag {
705        FormTag(self, prio)
706    }
707
708    /// The internal id of the [`FormId`]
709    ///
710    /// This may be useful in certain situations.
711    pub const fn to_u16(self) -> u16 {
712        self.0
713    }
714
715    /// The name of this [`FormId`]
716    pub fn name(self) -> &'static str {
717        name_of(self)
718    }
719}
720
721impl std::fmt::Debug for FormId {
722    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
723        write!(f, "FormId({})", name_of(*self))
724    }
725}
726
727/// Mimics [`ContentStyle`] methods for the [`Form`] type
728macro_rules! mimic_method_new {
729    (#[$attr:meta] $method:ident $attrib:expr) => {
730        /// New [`Form`] with the
731        #[$attr]
732        /// attribute
733        pub const fn $method() -> BuiltForm {
734            let mut built = Form::new();
735            built.0.style.attributes = built.0.style.attributes.with($attrib);
736            built
737        }
738    };
739    (#[$attr:meta] $fg:ident $bg:ident $ul:ident $color:expr) => {
740        /// New [`Form`] with a
741        #[$attr]
742        /// foreground
743        pub const fn $fg() -> BuiltForm {
744            let mut built = Form::new();
745            built.0.style.foreground_color = Some($color);
746            built
747        }
748
749        /// New [`Form`] with a
750        #[$attr]
751        /// background
752        pub const fn $bg() -> BuiltForm {
753            let mut built = Form::new();
754            built.0.style.background_color = Some($color);
755            built
756        }
757
758        /// New [`Form`] with a
759        #[$attr]
760        /// underlining
761        ///
762        /// Do note that this feature may not be supported in all `Ui`s,
763        /// for example, various terminals don't support this feature,
764        /// since it is a part of the kitty protocol, and hasn't been
765        /// universally accepted yet.
766        ///
767        /// `Ui`: crate::ui::traits::RawUi
768        pub const fn $ul() -> BuiltForm {
769            let mut built = Form::new();
770            built.0.style.underline_color = Some($color);
771            built
772        }
773    };
774}
775
776macro_rules! mimic_method_mod {
777    (#[$attr:meta] $method:ident $attrib:expr) => {
778        /// Applies the
779        #[$attr]
780        /// attribute to this [`Form`]
781        pub const fn $method(mut self) -> Self {
782            self.0.style.attributes = self.0.style.attributes.with($attrib);
783            self
784        }
785    };
786    (#[$attr:meta] $fg:ident $bg:ident $ul:ident $color:expr) => {
787        /// Turns the foreground of this [`Form`]
788        #[$attr]
789        pub const fn $fg(mut self) -> Self {
790            self.0.style.foreground_color = Some($color);
791            self
792        }
793
794        /// Turns the background of this [`Form`]
795        #[$attr]
796        pub const fn $bg(mut self) -> Self {
797            self.0.style.background_color = Some($color);
798            self
799        }
800
801        /// Turns the underlining of this [`Form`]
802        #[$attr]
803        /// Do note that this feature may not be supported in all `Ui`s,
804        /// for example, various terminals don't support this feature,
805        /// since it is a part of the kitty protocol, and hasn't been
806        /// universally accepted yet.
807        ///
808        /// `Ui`: crate::ui::traits::RawUi
809        pub const fn $ul(mut self) -> Self {
810            self.0.style.underline_color = Some($color);
811            self
812        }
813    };
814}
815/// A style for text.
816#[derive(Clone, Copy, PartialEq, Eq)]
817pub struct Form {
818    /// The actual [style](ContentStyle) that is applied
819    pub style: ContentStyle,
820}
821
822#[rustfmt::skip]
823impl Form {
824    mimic_method_new!(/**bold*/ bold Attribute::Bold);
825    mimic_method_new!(/**dim*/ dim Attribute::Dim);
826    mimic_method_new!(/**italic*/ italic Attribute::Italic);
827    mimic_method_new!(/**underlined*/ underlined Attribute::Underlined);
828    mimic_method_new!(/**double_underlined*/ double_underlined Attribute::DoubleUnderlined);
829    mimic_method_new!(/**undercurled*/ undercurled Attribute::Undercurled);
830    mimic_method_new!(/**underdashed*/ underdashed Attribute::Underdashed);
831    mimic_method_new!(/**reverse*/ reverse Attribute::Reverse);
832    mimic_method_new!(/**crossed_out*/ crossed_out Attribute::CrossedOut);
833    mimic_method_new!(/**black*/ black on_black underline_black Color::Black);
834    mimic_method_new!(/**dark_grey*/ dark_grey on_dark_grey underline_dark_grey Color::DarkGrey);
835    mimic_method_new!(/**red*/ red on_red underline_red Color::Red);
836    mimic_method_new!(/**dark_red*/ dark_red on_dark_red underline_dark_red Color::DarkRed);
837    mimic_method_new!(/**green*/ green on_green underline_green Color::Green);
838    mimic_method_new!(
839        /**dark_green*/ dark_green on_dark_green underline_dark_green Color::DarkGreen
840    );
841    mimic_method_new!(/**yellow*/ yellow on_yellow underline_yellow Color::Yellow);
842    mimic_method_new!(
843        /**dark_yellow*/ dark_yellow on_dark_yellow underline_dark_yellow Color::DarkYellow
844    );
845    mimic_method_new!(/**blue*/ blue on_blue underline_blue Color::Blue);
846    mimic_method_new!(/**dark_blue*/ dark_blue on_dark_blue underline_dark_blue Color::DarkBlue);
847    mimic_method_new!(/**magenta*/ magenta on_magenta underline_magenta Color::Magenta);
848    mimic_method_new!(
849        /**dark_magenta*/ dark_magenta on_dark_magenta underline_dark_magenta Color::DarkMagenta
850    );
851    mimic_method_new!(/**cyan*/ cyan on_cyan underline_cyan Color::Cyan);
852    mimic_method_new!(/**dark_cyan*/ dark_cyan on_dark_cyan underline_dark_cyan Color::DarkCyan);
853    mimic_method_new!(/**white*/ white on_white underline_white Color::White);
854    mimic_method_new!(/**grey*/ grey on_grey underline_grey Color::Grey);
855}
856
857impl Form {
858    /// Returns a new [`Form`] with a default style
859    ///
860    /// This method actually returns [`BuiltForm`]
861    #[allow(clippy::new_ret_no_self)]
862    pub const fn new() -> BuiltForm {
863        let style = ContentStyle {
864            foreground_color: None,
865            background_color: None,
866            underline_color: None,
867            attributes: Attributes::none(),
868        };
869        BuiltForm(Self { style })
870    }
871
872    /// Returns a new [`Form`] with the [`Reset`] attribute
873    ///
874    /// In Duat, the [`Reset`] attribute should remove only other
875    /// [`Attribute`]s, not any of the colors in use.
876    ///
877    /// [`Reset`]: Attribute::Reset
878    pub const fn reset() -> BuiltForm {
879        let mut built = Form::new();
880        built.0.style.attributes = built.0.style.attributes.with(Attribute::Reset);
881        built
882    }
883
884    /// New [`Form`] with a colored foreground
885    ///
886    /// This function accepts three color formats:
887    ///
888    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
889    /// - Three rgb values, like `"rgb 123 456 789"`;
890    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
891    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
892    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
893    pub const fn with(str: &str) -> BuiltForm {
894        let mut built = Form::new();
895        built.0.style.foreground_color = match str_to_color(str) {
896            Ok(color) => Some(color),
897            Err(err) => panic!("{}", err),
898        };
899        built
900    }
901
902    /// New [`Form`] with a colored background
903    ///
904    /// This function accepts three color formats:
905    ///
906    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
907    /// - Three rgb values, like `"rgb 123 456 789"`;
908    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
909    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
910    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
911    pub const fn on(str: &str) -> BuiltForm {
912        let mut built = Form::new();
913        built.0.style.background_color = match str_to_color(str) {
914            Ok(color) => Some(color),
915            Err(err) => panic!("{}", err),
916        };
917        built
918    }
919
920    /// New [`Form`] with a colored underlining
921    ///
922    /// This function accepts three color formats:
923    ///
924    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
925    /// - Three rgb values, like `"rgb 123 456 789"`;
926    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
927    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
928    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
929    pub const fn underline(str: &str) -> BuiltForm {
930        let mut built = Form::new();
931        built.0.style.underline_color = match str_to_color(str) {
932            Ok(color) => Some(color),
933            Err(err) => panic!("{}", err),
934        };
935        built
936    }
937
938    /// The foreground color
939    pub const fn fg(&self) -> Option<Color> {
940        self.style.foreground_color
941    }
942
943    /// The background color
944    pub const fn bg(&self) -> Option<Color> {
945        self.style.background_color
946    }
947
948    /// The foreground color
949    pub const fn ul(&self) -> Option<Color> {
950        self.style.underline_color
951    }
952
953    /// The attributes
954    pub const fn attrs(&self) -> Attributes {
955        self.style.attributes
956    }
957}
958
959/// A convenience struct for [`Form`]s
960///
961/// This struct exists in order to have [`Form`] methods be
962/// initializers, while [`BuiltForm`] methods consume and return a
963/// [`BuiltForm`]s
964///
965/// This is their only difference, everywhere else, they are
966/// functionally identical.
967#[derive(Clone, Copy, Debug)]
968pub struct BuiltForm(Form);
969
970#[rustfmt::skip]
971impl BuiltForm {
972    mimic_method_mod!(/**bold*/ bold Attribute::Bold);
973    mimic_method_mod!(/**dim*/ dim Attribute::Dim);
974    mimic_method_mod!(/**italic*/ italic Attribute::Italic);
975    mimic_method_mod!(/**underlined*/ underlined Attribute::Underlined);
976    mimic_method_mod!(/**double_underlined*/ double_underlined Attribute::DoubleUnderlined);
977    mimic_method_mod!(/**undercurled*/ undercurled Attribute::Undercurled);
978    mimic_method_mod!(/**underdashed*/ underdashed Attribute::Underdashed);
979    mimic_method_mod!(/**reverse*/ reverse Attribute::Reverse);
980    mimic_method_mod!(/**crossed_out*/ crossed_out Attribute::CrossedOut);
981    mimic_method_mod!(/**overlined*/ overlined Attribute::OverLined);
982    mimic_method_mod!(/**black*/ black on_black underline_black Color::Black);
983    mimic_method_mod!(/**dark_grey*/ dark_grey on_dark_grey underline_dark_grey Color::DarkGrey);
984    mimic_method_mod!(/**red*/ red on_red underline_red Color::Red);
985    mimic_method_mod!(/**dark_red*/ dark_red on_dark_red underline_dark_red Color::DarkRed);
986    mimic_method_mod!(/**green*/ green on_green underline_green Color::Green);
987    mimic_method_mod!(
988        /**dark_green*/ dark_green on_dark_green underline_dark_green Color::DarkGreen
989    );
990    mimic_method_mod!(/**yellow*/ yellow on_yellow underline_yellow Color::Yellow);
991    mimic_method_mod!(
992        /**dark_yellow*/ dark_yellow on_dark_yellow underline_dark_yellow Color::DarkYellow
993    );
994    mimic_method_mod!(/**blue*/ blue on_blue underline_blue Color::Blue);
995    mimic_method_mod!(/**dark_blue*/ dark_blue on_dark_blue underline_dark_blue Color::DarkBlue);
996    mimic_method_mod!(/**magenta*/ magenta on_magenta underline_magenta Color::Magenta);
997    mimic_method_mod!(
998        /**dark_magenta*/ dark_magenta on_dark_magenta underline_dark_magenta Color::DarkMagenta
999    );
1000    mimic_method_mod!(/**cyan*/ cyan on_cyan underline_cyan Color::Cyan);
1001    mimic_method_mod!(/**dark_cyan*/ dark_cyan on_dark_cyan underline_dark_cyan Color::DarkCyan);
1002    mimic_method_mod!(/**white*/ white on_white underline_white Color::White);
1003    mimic_method_mod!(/**grey*/ grey on_grey underline_grey Color::Grey);
1004}
1005
1006impl BuiltForm {
1007    /// Adds the [`Reset`] attribute to this [`Form`]
1008    ///
1009    /// In Duat, the [`Reset`] attribute should remove only other
1010    /// [`Attribute`]s, not any of the colors in use.
1011    ///
1012    /// [`Reset`]: Attribute::Reset
1013    pub const fn reset(mut self) -> BuiltForm {
1014        self.0.style.attributes = self.0.style.attributes.with(Attribute::Reset);
1015        self
1016    }
1017
1018    /// Colors the foreground of this [`Form`]
1019    ///
1020    /// This function accepts three color formats:
1021    ///
1022    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
1023    /// - Three rgb values, like `"rgb 123 456 789"`;
1024    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
1025    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
1026    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
1027    pub const fn with(mut self, str: &str) -> Self {
1028        self.0.style.foreground_color = match str_to_color(str) {
1029            Ok(color) => Some(color),
1030            Err(err) => panic!("{}", err),
1031        };
1032        self
1033    }
1034
1035    /// Colors the background of this [`Form`]
1036    ///
1037    /// This function accepts three color formats:
1038    ///
1039    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
1040    /// - Three rgb values, like `"rgb 123 456 789"`;
1041    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
1042    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
1043    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
1044    pub const fn on(mut self, str: &str) -> Self {
1045        self.0.style.background_color = match str_to_color(str) {
1046            Ok(color) => Some(color),
1047            Err(err) => panic!("{}", err),
1048        };
1049        self
1050    }
1051
1052    /// Colors the underlining of this [`Form`]
1053    ///
1054    /// This function accepts three color formats:
1055    ///
1056    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
1057    /// - Three rgb values, like `"rgb 123 456 789"`;
1058    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
1059    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
1060    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
1061    pub const fn underline(mut self, str: &str) -> Self {
1062        self.0.style.underline_color = match str_to_color(str) {
1063            Ok(color) => Some(color),
1064            Err(err) => panic!("{}", err),
1065        };
1066        self
1067    }
1068}
1069
1070impl std::ops::Deref for BuiltForm {
1071    type Target = Form;
1072
1073    fn deref(&self) -> &Self::Target {
1074        &self.0
1075    }
1076}
1077
1078impl std::ops::DerefMut for BuiltForm {
1079    fn deref_mut(&mut self) -> &mut Self::Target {
1080        &mut self.0
1081    }
1082}
1083
1084impl From<BuiltForm> for Form {
1085    fn from(value: BuiltForm) -> Self {
1086        value.0
1087    }
1088}
1089
1090/// The [`FormId`] of `"default"`
1091pub const DEFAULT_ID: FormId = FormId(0);
1092/// The [`FormId`] of `"accent"`
1093pub const ACCENT_ID: FormId = FormId(1);
1094/// The [`FormId`] of `"caret.main"`
1095pub const M_CAR_ID: FormId = FormId(2);
1096/// The [`FormId`] of `"caret.extra"`
1097pub const E_CAR_ID: FormId = FormId(3);
1098/// The [`FormId`] of `"slection.main"`
1099pub const M_SEL_ID: FormId = FormId(4);
1100/// The [`FormId`] of `"selection.extra"`
1101pub const E_SEL_ID: FormId = FormId(5);
1102/// The [`FormId`] of `"character.control"`
1103pub const CONTROL_CHAR_ID: FormId = FormId(7);
1104
1105/// The list of forms to be used when rendering.
1106///
1107/// ONLY MEANT TO BE ACCESSED BY DUAT AND DUAT-CORE.
1108#[derive(Debug)]
1109#[doc(hidden)]
1110pub struct Palette(RwLock<InnerPalette>);
1111
1112impl Palette {
1113    /// Returns a new instance of [`FormPalette`]
1114    fn new() -> Self {
1115        let main_cursor = Some(CursorShape::DefaultUserShape);
1116        Self(RwLock::new(InnerPalette {
1117            main_cursor,
1118            extra_cursor: main_cursor,
1119            forms: BASE_FORMS.to_vec(),
1120            masks: vec![(
1121                "".to_string().leak(),
1122                (0..BASE_FORMS.len() as u16).collect(),
1123            )],
1124        }))
1125    }
1126
1127    /// Sets a [`Form`]
1128    fn set_form(&self, name: impl AsRef<str>, form: Form) {
1129        let name = name.as_ref();
1130        self.0.write().unwrap().set_form(name, form);
1131    }
1132
1133    /// Sets a [`Form`] "weakly"
1134    fn set_weak_form(&self, name: impl AsRef<str>, form: Form) {
1135        let name = name.as_ref();
1136        self.0.write().unwrap().set_weak_form(name, form);
1137    }
1138
1139    /// Makes a [`Form`] reference another
1140    fn set_ref(&self, name: impl AsRef<str>, refed: impl AsRef<str>) {
1141        let (name, refed) = (name.as_ref(), refed.as_ref());
1142        self.0.write().unwrap().set_ref(name, refed);
1143    }
1144
1145    /// Makes a [`Form`] reference another "weakly"
1146    fn set_weak_ref(&self, name: impl AsRef<str>, refed: impl AsRef<str>) {
1147        let (name, refed) = (name.as_ref(), refed.as_ref());
1148        self.0.write().unwrap().set_weak_ref(name, refed);
1149    }
1150
1151    /// Sets many [`Form`]s
1152    fn set_many<S: AsRef<str>>(&self, weak: bool, sets: &[(S, Option<self::global::Kind>)]) {
1153        let mut inner = self.0.write().unwrap();
1154        for (name, kind) in sets {
1155            match (weak, kind) {
1156                (false, Some(Kind::Form(form))) => inner.set_form(name.as_ref(), *form),
1157                (false, Some(Kind::Ref(refed))) => inner.set_ref(name.as_ref(), refed),
1158                (true, Some(Kind::Form(form))) => inner.set_weak_form(name.as_ref(), *form),
1159                (true, Some(Kind::Ref(refed))) => inner.set_weak_ref(name.as_ref(), refed),
1160                (_, None) => {
1161                    position_and_form(&mut inner.forms, name);
1162                }
1163            }
1164        }
1165    }
1166
1167    /// Returns a form, given a [`FormId`].
1168    fn form_from_id(&self, id: FormId) -> Option<Form> {
1169        let inner = self.0.read().unwrap();
1170        inner.forms.get(id.0 as usize).map(|(_, form, _)| *form)
1171    }
1172
1173    /// The [`Form`] and [`CursorShape`] of the main cursor
1174    fn main_cursor(&self) -> (Form, Option<CursorShape>) {
1175        let form = self.form_from_id(M_CAR_ID).unwrap();
1176        (form, self.0.read().unwrap().main_cursor)
1177    }
1178
1179    /// The [`Form`] and [`CursorShape`] of extra cursors
1180    fn extra_cursor(&self) -> (Form, Option<CursorShape>) {
1181        let form = self.form_from_id(E_CAR_ID).unwrap();
1182        (form, self.0.read().unwrap().extra_cursor)
1183    }
1184
1185    /// Sets the [`CursorShape`] of the main cursor
1186    fn set_main_cursor(&self, shape: CursorShape) {
1187        self.0.write().unwrap().main_cursor = Some(shape);
1188        if let Some(sender) = SENDER.get() {
1189            sender.send_form_changed().unwrap()
1190        }
1191    }
1192
1193    /// Sets the [`CursorShape`] of extra cursors
1194    fn set_extra_cursor(&self, shape: CursorShape) {
1195        self.0.write().unwrap().extra_cursor = Some(shape);
1196        if let Some(sender) = SENDER.get() {
1197            sender.send_form_changed().unwrap()
1198        }
1199    }
1200
1201    /// Unsets the [`CursorShape`] of the main cursor
1202    fn unset_main_cursor(&self) {
1203        self.0.write().unwrap().main_cursor = None;
1204        if let Some(sender) = SENDER.get() {
1205            sender.send_form_changed().unwrap()
1206        }
1207    }
1208
1209    /// Unsets the [`CursorShape`] of the extra cursors
1210    fn unset_extra_cursor(&self) {
1211        self.0.write().unwrap().extra_cursor = None;
1212        if let Some(sender) = SENDER.get() {
1213            sender.send_form_changed().unwrap()
1214        }
1215    }
1216
1217    /// Returns a [`Painter`]
1218    fn painter(&'static self, default_id: FormId, mask: &str) -> Painter {
1219        let inner = self.0.read().unwrap();
1220        let mask_i = inner
1221            .masks
1222            .iter()
1223            .position(|(m, _)| *m == mask)
1224            .unwrap_or_default();
1225
1226        let default = inner
1227            .forms
1228            .get(match inner.masks[mask_i].1.get(default_id.0 as usize) {
1229                Some(i) => *i as usize,
1230                None => default_id.0 as usize,
1231            })
1232            .map(|(_, f, _)| *f)
1233            .unwrap_or(Form::new().0);
1234
1235        Painter {
1236            inner,
1237            mask_i,
1238            default,
1239            forms: Vec::new(),
1240            set_fg: true,
1241            set_bg: true,
1242            set_ul: true,
1243            reset_attrs: false,
1244            prev_style: None,
1245        }
1246    }
1247}
1248
1249struct InnerPalette {
1250    main_cursor: Option<CursorShape>,
1251    extra_cursor: Option<CursorShape>,
1252    forms: Vec<(&'static str, Form, FormType)>,
1253    masks: Vec<(&'static str, Vec<u16>)>,
1254}
1255
1256impl InnerPalette {
1257    /// Sets a [`Form`]
1258    fn set_form(&mut self, name: &str, form: Form) {
1259        let (i, _) = position_and_form(&mut self.forms, name);
1260
1261        self.forms[i].1 = form;
1262        self.forms[i].2 = FormType::Normal;
1263
1264        for refed in refs_of(self, i) {
1265            self.forms[refed].1 = form;
1266        }
1267
1268        if let Some(sender) = SENDER.get() {
1269            sender.send_form_changed().unwrap()
1270        }
1271
1272        mask_form(name, i, self);
1273        hook::queue(FormSet((self.forms[i].0, FormId(i as u16), form)));
1274    }
1275
1276    /// Sets a [`Form`] "weakly"
1277    fn set_weak_form(&mut self, name: &str, form: Form) {
1278        let (i, _) = position_and_form(&mut self.forms, name);
1279
1280        let (_, f, f_ty) = &mut self.forms[i];
1281        if let FormType::Weakest | FormType::WeakestRef(_) = f_ty {
1282            *f = form;
1283            *f_ty = FormType::Normal;
1284
1285            if let Some(sender) = SENDER.get() {
1286                sender.send_form_changed().unwrap()
1287            }
1288            for refed in refs_of(self, i) {
1289                self.forms[refed].1 = form;
1290            }
1291
1292            mask_form(name, i, self);
1293        }
1294    }
1295
1296    /// Makes a [`Form`] reference another
1297    fn set_ref(&mut self, name: &str, refed: &str) {
1298        let (refed, form) = position_and_form(&mut self.forms, refed);
1299        let (i, _) = position_and_form(&mut self.forms, name);
1300
1301        self.forms[i].1 = form;
1302        for refed in refs_of(self, i) {
1303            self.forms[refed].1 = form;
1304        }
1305
1306        // If it would be circular, we just don't reference anything.
1307        if would_be_circular(self, i, refed) {
1308            self.forms[i].2 = FormType::Normal;
1309        } else {
1310            self.forms[i].2 = FormType::Ref(refed);
1311        }
1312
1313        if let Some(sender) = SENDER.get() {
1314            sender.send_form_changed().unwrap()
1315        }
1316
1317        mask_form(name, i, self);
1318        hook::queue(FormSet((self.forms[i].0, FormId(i as u16), form)));
1319    }
1320
1321    /// Makes a [`Form`] reference another "weakly"
1322    fn set_weak_ref(&mut self, name: &str, refed: &str) {
1323        let (refed, form) = position_and_form(&mut self.forms, refed);
1324        let (i, _) = position_and_form(&mut self.forms, name);
1325
1326        // For weak refs, no checks are done, since a form is only set if it
1327        // doesn't exist, and for there to be refs to it, it must exist.
1328        let (_, f, f_ty) = &mut self.forms[i];
1329        if let FormType::Weakest | FormType::WeakestRef(_) = f_ty {
1330            *f = form;
1331            *f_ty = FormType::WeakestRef(refed);
1332
1333            if let Some(sender) = SENDER.get() {
1334                sender.send_form_changed().unwrap()
1335            }
1336            for refed in refs_of(self, i) {
1337                self.forms[refed].1 = form;
1338            }
1339
1340            mask_form(name, i, self);
1341        }
1342    }
1343}
1344
1345/// If setting a form with an existing mask suffix, mask its prefix
1346fn mask_form(name: &str, form_i: usize, inner: &mut InnerPalette) {
1347    if inner.masks[0].1.len() < inner.forms.len() {
1348        for (_, remaps) in inner.masks.iter_mut() {
1349            remaps.extend(remaps.len() as u16..inner.forms.len() as u16);
1350        }
1351    }
1352
1353    if let Some((pref, mask)) = name.rsplit_once(".")
1354        && let Some((_, remaps)) = inner.masks.iter_mut().find(|(m, _)| *m == mask)
1355        && let Some(j) = inner.forms.iter().position(|(name, ..)| *name == pref)
1356    {
1357        remaps[j] = form_i as u16;
1358    }
1359}
1360
1361/// A struct to create [`Form`]s from [`RawTag`] in a [`Text`]
1362///
1363/// This [`Painter`] not only prints the [`Form`]s in the [`Text`],
1364/// but within it there is also a "mask". This mask will remap
1365/// [`Form`]s based on suffix, like in the following example:
1366///
1367/// ```rust
1368/// # duat_core::doc_duat!(duat);
1369/// use duat::prelude::*;
1370///
1371/// fn test<W: Widget>(pa: &mut Pass, handle: Handle<W>) {
1372///     // Assume that a Form with the given name exists
1373///     form::set("my_form", Form::red().on_blue());
1374///
1375///     // If I create a second Form like this one, they are separate
1376///     form::set("my_form.suffix", Form::undercurled());
1377///
1378///     *handle.text_mut(pa) =
1379///         txt!("[my_form]This text is red on blue[], [my_form.suffix]undercurled");
1380///
1381///     // But if I enable the "suffix" mask that's at the end of the second Form
1382///     form::enable_mask("suffix");
1383///
1384///     // After doing this, the Text should be printed with the "suffix" mask
1385///     handle.set_mask("suffix");
1386///
1387///     // So when the widget is printed, it'd be equivalent to this:
1388///     *handle.text_mut(pa) =
1389///         txt!("[my_form.suffix]This text is red on blue[], [my_form.suffix]undercurled");
1390/// }
1391/// ```
1392///
1393/// Masks can serve a myriad of different purposes, but here's a
1394/// few:
1395///
1396/// - When you want to temporarily change the [`Form`]s on a single
1397///   [`Widget`]. This is, for example, used in the [`Notifications`]
1398///   [`Widget`], which maps [`Form`]s in order to correspond to the
1399///   [`Level`] of their severity.
1400/// - When you want to have [`Widget`]s change [`Form`] based on
1401///   [hooks], so you could have, for example, an `"inactive"` mask
1402///   for your [`Buffer`]s
1403/// - If you want to quickly cycle through [`Form`]s in a [`Text`],
1404///   this is the most efficient way of doing that, since it relies on
1405///   static remaps, not on changing the [`Form`]s themselves.
1406///
1407/// Do note that no suffix, except `"error"`, `"warn"` and
1408/// `"info"` is a mask when Duat starts. In order to enable more
1409/// masks, see [`enable_mask`].
1410///
1411/// [`Widget`]: crate::ui::Widget
1412/// [`Notifications`]: https://docs.rs/duat/latest/duat
1413/// [`Level`]: crate::context::Level
1414/// [hooks]: crate::hook
1415/// [`Buffer`]: crate::buffer::Buffer
1416/// [`Text`]: crate::text::Text
1417///
1418/// [`RawTag`]: crate::text::RawTag
1419/// [`Text`]: crate::text::Text
1420pub struct Painter {
1421    inner: RwLockReadGuard<'static, InnerPalette>,
1422    mask_i: usize,
1423    default: Form,
1424    forms: Vec<(Form, FormId, u8)>,
1425    set_fg: bool,
1426    set_bg: bool,
1427    set_ul: bool,
1428    reset_attrs: bool,
1429    prev_style: Option<ContentStyle>,
1430}
1431
1432impl Painter {
1433    /// Applies the `Form` with the given `id` and returns the result,
1434    /// given previous triggers.
1435    ///
1436    /// Will return a [`Form`] _relative_ to what the previous
1437    /// [`Form`] was, that is, if the new [`Form`] doesn't include a
1438    /// background, its combination with the other [`Form`]s also
1439    /// won't, since it wasn't changed.
1440    #[inline(always)]
1441    pub fn apply(&mut self, id: FormId, prio: u8) {
1442        let (_, mask) = &self.inner.masks[self.mask_i];
1443        let id = FormId(mask.get(id.0 as usize).copied().unwrap_or(id.0));
1444
1445        let forms = &self.inner.forms;
1446        let form = forms
1447            .get(id.0 as usize)
1448            .map(|(_, f, _)| *f)
1449            .unwrap_or(Form::new().0);
1450
1451        let gt = |(.., p): &&(_, _, u8)| *p > prio;
1452        let i = self.forms.len() - self.forms.iter().rev().take_while(gt).count();
1453        self.forms.insert(i, (form, id, prio));
1454
1455        self.set_fg |= form.fg().is_some();
1456        self.set_bg |= form.bg().is_some();
1457        self.set_ul |= form.ul().is_some();
1458        self.reset_attrs |= form.attrs().has(Attribute::Reset);
1459    }
1460
1461    /// Removes the [`Form`] with the given `id` and returns the
1462    /// result, given previous triggers
1463    #[inline(always)]
1464    pub fn remove(&mut self, id: FormId) {
1465        let mask = &self.inner.masks[self.mask_i].1;
1466        let id = FormId(mask.get(id.0 as usize).copied().unwrap_or(id.0));
1467
1468        let mut applied_forms = self.forms.iter().enumerate();
1469        if let Some((i, &(form, ..))) = applied_forms.rfind(|(_, (_, lhs, _))| *lhs == id) {
1470            self.forms.remove(i);
1471
1472            self.set_fg |= form.fg().is_some();
1473            self.set_bg |= form.bg().is_some();
1474            self.set_ul |= form.ul().is_some();
1475            self.reset_attrs |= !form.attrs().is_empty();
1476        };
1477    }
1478
1479    /// Removes all [`Form`]s except the default one
1480    ///
1481    /// Should be used when a [`ResetState`] part is printed
1482    ///
1483    /// [`ResetState`]: crate::text::Part::ResetState
1484    #[inline(always)]
1485    pub fn reset(&mut self) -> ContentStyle {
1486        self.forms.clear();
1487        self.absolute_style()
1488    }
1489
1490    /// Generates the absolute [`ContentStyle`] to be set
1491    ///
1492    /// This function assumes that all previous styling is not being
1493    /// carried over, i.e., we're styling from scratch.
1494    #[inline(always)]
1495    pub fn absolute_style(&self) -> ContentStyle {
1496        let mut style = self.default.style;
1497
1498        for &(form, ..) in &self.forms {
1499            style.foreground_color = form.fg().or(style.foreground_color);
1500            style.background_color = form.bg().or(style.background_color);
1501            style.underline_color = form.ul().or(style.underline_color);
1502            style.attributes = if form.attrs().has(Attribute::Reset) {
1503                form.attrs()
1504            } else {
1505                form.attrs() | style.attributes
1506            }
1507        }
1508
1509        style
1510    }
1511
1512    /// Generates the relative [`ContentStyle`] to be set
1513    ///
1514    /// This function assumes that previously printed styles are being
1515    /// carried over, influencing this one.
1516    ///
1517    /// You should strive to use this function more than
1518    /// [`absolute_style`], since it "theoretically" should be less
1519    /// work to change just one aspect of the style, rather than
1520    /// replacing the whole thing.
1521    ///
1522    /// [`absolute_style`]: Painter::absolute_style
1523    #[inline(always)]
1524    pub fn relative_style(&mut self) -> Option<ContentStyle> {
1525        let abs_style = self.absolute_style();
1526        let mut style = abs_style;
1527
1528        if style.attributes.has(Attribute::Reset) || self.reset_attrs {
1529            style.attributes.set(Attribute::Reset);
1530        // Only when we are certain that all forms have been
1531        // printed, can we cull unnecessary colors for efficiency
1532        // (this happens most of the time).
1533        } else {
1534            style.foreground_color = self
1535                .set_fg
1536                .then_some(style.foreground_color.unwrap_or(Color::Reset))
1537                .filter(|fg| Some(*fg) != self.prev_style.and_then(|s| s.foreground_color));
1538            style.background_color = self
1539                .set_bg
1540                .then_some(style.background_color.unwrap_or(Color::Reset))
1541                .filter(|bg| Some(*bg) != self.prev_style.and_then(|s| s.background_color));
1542            style.underline_color = self
1543                .set_ul
1544                .then_some(style.underline_color.unwrap_or(Color::Reset))
1545                .filter(|ul| Some(*ul) != self.prev_style.and_then(|s| s.underline_color));
1546        }
1547
1548        self.set_fg = false;
1549        self.set_bg = false;
1550        self.set_ul = false;
1551        self.reset_attrs = false;
1552
1553        if let Some(prev_style) = self.prev_style.replace(abs_style) {
1554            (style != prev_style && style != Default::default()).then_some(style)
1555        } else {
1556            Some(style)
1557        }
1558    }
1559
1560    /// Makes it so the next call to [`relative_style`] returns the
1561    /// same thing as a call to [`absolute_style`]
1562    ///
1563    /// [`relative_style`]: Self::relative_style
1564    /// [`absolute_style`]: Self::absolute_style
1565    pub fn reset_prev_style(&mut self) {
1566        self.prev_style = None;
1567        self.set_fg = true;
1568        self.set_bg = true;
1569        self.set_ul = true;
1570        self.reset_attrs = true;
1571    }
1572
1573    /// Applies the `"caret.main"` [`Form`]
1574    #[inline(always)]
1575    pub fn apply_main_cursor(&mut self) {
1576        self.apply(M_CAR_ID, 100);
1577    }
1578
1579    /// Removes the `"caret.main"` [`Form`]
1580    #[inline(always)]
1581    pub fn remove_main_caret(&mut self) {
1582        self.remove(M_CAR_ID);
1583    }
1584
1585    /// Applies the `"caret.extra"` [`Form`]
1586    #[inline(always)]
1587    pub fn apply_extra_cursor(&mut self) {
1588        self.apply(E_CAR_ID, 100);
1589    }
1590
1591    /// Removes the `"caret.extra"` [`Form`]
1592    #[inline(always)]
1593    pub fn remove_extra_caret(&mut self) {
1594        self.remove(E_CAR_ID);
1595    }
1596
1597    /// The [`Form`] "caret.extra", and its shape.
1598    pub fn main_cursor(&self) -> Option<CursorShape> {
1599        self.inner.main_cursor
1600    }
1601
1602    /// The [`Form`] "caret.extra", and its shape.
1603    pub fn extra_cursor(&self) -> Option<CursorShape> {
1604        self.inner.extra_cursor
1605    }
1606
1607    /// The `"default"` form's [`Form`]
1608    pub fn get_default(&self) -> Form {
1609        self.default
1610    }
1611}
1612
1613pub(crate) fn set_sender(sender: DuatSender) {
1614    SENDER
1615        .set(sender)
1616        .unwrap_or_else(|_| panic!("Sender set more than once"));
1617}
1618
1619/// An enum that helps in the modification of forms
1620#[derive(Clone)]
1621enum FormType {
1622    Normal,
1623    Ref(usize),
1624    Weakest,
1625    WeakestRef(usize),
1626}
1627
1628/// The position of each form that eventually references the `n`th
1629fn refs_of(inner: &InnerPalette, refed: usize) -> Vec<usize> {
1630    let mut refs = Vec::new();
1631    for (i, (.., f_ty)) in inner.forms.iter().enumerate() {
1632        if let FormType::Ref(ref_id) | FormType::WeakestRef(ref_id) = f_ty
1633            && *ref_id == refed
1634        {
1635            refs.push(i);
1636            refs.extend(refs_of(inner, i));
1637        }
1638    }
1639    refs
1640}
1641
1642/// If form references would eventually lead to a loop
1643fn would_be_circular(inner: &InnerPalette, referee: usize, refed: usize) -> bool {
1644    if let (.., FormType::Ref(refed_ref) | FormType::WeakestRef(refed_ref)) = inner.forms[refed] {
1645        match refed_ref == referee {
1646            true => true,
1647            false => would_be_circular(inner, referee, refed_ref),
1648        }
1649    } else {
1650        false
1651    }
1652}
1653
1654fn position_and_form(
1655    forms: &mut Vec<(&str, Form, FormType)>,
1656    name: impl AsRef<str>,
1657) -> (usize, Form) {
1658    let name = name.as_ref();
1659    if let Some((i, (_, form, _))) = forms.iter().enumerate().find(|(_, (lhs, ..))| *lhs == name) {
1660        (i, *form)
1661    } else if let Some((refed, _)) = name.rsplit_once('.') {
1662        let (i, form) = position_and_form(forms, refed);
1663        forms.push((name.to_string().leak(), form, FormType::WeakestRef(i)));
1664        (forms.len() - 1, form)
1665    } else {
1666        forms.push((name.to_string().leak(), Form::new().0, FormType::Weakest));
1667        (forms.len() - 1, Form::new().0)
1668    }
1669}
1670
1671/// Converts a string to a color, supporst hex, RGB and HSL
1672const fn str_to_color(str: &str) -> std::result::Result<Color, &'static str> {
1673    const fn strip_prefix<'a>(prefix: &str, str: &'a str) -> Option<&'a str> {
1674        let prefix = prefix.as_bytes();
1675
1676        let mut i = 0;
1677        while i < prefix.len() {
1678            if str.as_bytes()[i] != prefix[i] {
1679                return None;
1680            }
1681            i += 1;
1682        }
1683
1684        Some(str.split_at(prefix.len()).1)
1685    }
1686    const fn strip_suffix<'a>(suffix: &str, str: &'a str) -> Option<&'a str> {
1687        let prefix = suffix.as_bytes();
1688
1689        let mut i = str.len() - 1;
1690        while i >= str.len() - prefix.len() {
1691            if str.as_bytes()[i] != prefix[i - (str.len() - prefix.len())] {
1692                return None;
1693            }
1694            i += 1;
1695        }
1696
1697        Some(str.split_at(str.len() - suffix.len()).0)
1698    }
1699    const fn split_space(str: &str) -> Option<(&str, &str)> {
1700        if str.is_empty() {
1701            return None;
1702        }
1703
1704        let mut i = 0;
1705        while i < str.len() {
1706            if str.as_bytes()[i] == b' ' {
1707                break;
1708            }
1709            i += 1;
1710        }
1711
1712        let (cut, rest) = str.split_at(i);
1713        let (_, rest) = rest.split_at(if rest.is_empty() { 0 } else { 1 });
1714        Some((cut, rest))
1715    }
1716    const fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
1717        t = if t < 0.0 { t + 1.0 } else { t };
1718        t = if t > 1.0 { t - 1.0 } else { t };
1719        if t < 1.0 / 6.0 {
1720            p + (q - p) * 6.0 * t
1721        } else if t < 1.0 / 2.0 {
1722            q
1723        } else if t < 2.0 / 3.0 {
1724            p + (q - p) * (2.0 / 3.0 - t) * 6.0
1725        } else {
1726            p
1727        }
1728    }
1729
1730    // Expects "#{red:x}{green:x}{blue:x}"
1731    if let Some(hex) = strip_prefix("#", str) {
1732        let total = match u32::from_str_radix(hex, 16) {
1733            Ok(total) if hex.len() == 6 => total,
1734            _ => return Err("Hexcode does not contain 6 hex values"),
1735        };
1736        let r = (total >> 16) as u8;
1737        let g = (total >> 8) as u8;
1738        let b = total as u8;
1739
1740        Ok(Color::Rgb { r, g, b })
1741        // Expects "rgb {red} {green} {blue}"
1742    } else if let Some(mut rgb) = strip_prefix("rgb ", str) {
1743        let mut values = [0, 0, 0];
1744        let mut i = 0;
1745
1746        while i < values.len() {
1747            if let Some((cut, rest)) = split_space(rgb) {
1748                rgb = rest;
1749                values[i] = match u8::from_str_radix(cut, 10) {
1750                    Ok(value) => value,
1751                    Err(_) => return Err("Rgb format value could not be parsed"),
1752                }
1753            } else {
1754                return Err("Missing value in rgb format");
1755            }
1756            i += 1;
1757        }
1758
1759        let [r, g, b] = values;
1760        Ok(Color::Rgb { r, g, b })
1761        // Expects "hsl {hue%?} {saturation%?} {lightness%?}"
1762    } else if let Some(mut hsl) = strip_prefix("hsl ", str) {
1763        let mut values = [0.0, 0.0, 0.0];
1764        let mut i = 0;
1765        while i < values.len() {
1766            if let Some((cut, rest)) = split_space(hsl) {
1767                hsl = rest;
1768                let (num, div) = match strip_suffix("%", cut) {
1769                    Some(perc) => (perc, 100),
1770                    None => (cut, 255),
1771                };
1772                values[i] = match u8::from_str_radix(num, 10) {
1773                    Ok(value) if value <= div => value as f32 / div as f32,
1774                    _ => return Err("Hsl format property could not be parsed"),
1775                }
1776            } else {
1777                return Err("Missing value in hsl format");
1778            }
1779            i += 1;
1780        }
1781        let [hue, sat, lit] = values;
1782
1783        let (r, g, b) = if sat == 0.0 {
1784            (lit, lit, lit)
1785        } else {
1786            let q = if lit < 0.5 {
1787                lit * (1.0 + sat)
1788            } else {
1789                lit + sat - lit * sat
1790            };
1791            let p = 2.0 * lit - q;
1792            let r = hue_to_rgb(p, q, hue + 1.0 / 3.0);
1793            let g = hue_to_rgb(p, q, hue);
1794            let b = hue_to_rgb(p, q, hue - 1.0 / 3.0);
1795            (r, g, b)
1796        };
1797
1798        // + 0.5 because `as` rounds floats down.
1799        let r = (0.5 + r * 255.0) as u8;
1800        let g = (0.5 + g * 255.0) as u8;
1801        let b = (0.5 + b * 255.0) as u8;
1802        Ok(Color::Rgb { r, g, b })
1803    } else {
1804        Err("Color format was not recognized")
1805    }
1806}
1807
1808impl std::fmt::Debug for Form {
1809    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1810        struct DebugColor(Option<Color>);
1811        impl std::fmt::Debug for DebugColor {
1812            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1813                match self.0 {
1814                    Some(Color::Rgb { r, g, b }) => write!(f, "Some(Rgb({r}, {g}, {b}))"),
1815                    Some(Color::AnsiValue(ansi)) => write!(f, "Some(Ansi({ansi}))"),
1816                    Some(color) => write!(f, "Some({color:?})"),
1817                    None => f.write_str("None"),
1818                }
1819            }
1820        }
1821
1822        struct DebugAttributes(Attributes);
1823        impl std::fmt::Debug for DebugAttributes {
1824            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1825                if self.0.is_empty() {
1826                    f.write_str("None")
1827                } else {
1828                    let mut is_first = true;
1829                    for attr in Attribute::iterator() {
1830                        if self.0.has(attr) {
1831                            if !is_first {
1832                                f.write_str(" | ")?;
1833                            }
1834                            is_first = false;
1835                            write!(f, "{attr:?}")?;
1836                        }
1837                    }
1838                    Ok(())
1839                }
1840            }
1841        }
1842
1843        f.debug_struct("Form")
1844            .field("fg", &DebugColor(self.style.foreground_color))
1845            .field("bg", &DebugColor(self.style.background_color))
1846            .field("ul", &DebugColor(self.style.underline_color))
1847            .field("attr", &DebugAttributes(self.style.attributes))
1848            .finish()
1849    }
1850}
1851
1852impl std::fmt::Debug for InnerPalette {
1853    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1854        struct DebugForms<'a>(&'a [(&'static str, Form, FormType)]);
1855        impl std::fmt::Debug for DebugForms<'_> {
1856            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1857                if f.alternate() {
1858                    f.write_str("[\n")?;
1859                    let max = self.0.len().ilog10() as usize + 3;
1860                    for (n, (name, form, ty)) in self.0.iter().enumerate() {
1861                        let num = format!("{n}:");
1862                        writeln!(f, "{num:<max$}({name}, {ty:?}, {form:#?})")?;
1863                    }
1864                    f.write_str("]")
1865                } else {
1866                    write!(f, "{:?}", self.0)
1867                }
1868            }
1869        }
1870
1871        struct DebugCursorShape(CursorShape);
1872        impl std::fmt::Debug for DebugCursorShape {
1873            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1874                match self.0 {
1875                    CursorShape::DefaultUserShape => f.write_str("DefaultUserShape"),
1876                    CursorShape::BlinkingBlock => f.write_str("BlinkingBlock"),
1877                    CursorShape::SteadyBlock => f.write_str("SteadyBlock"),
1878                    CursorShape::BlinkingUnderScore => f.write_str("BlinkingUnderScore"),
1879                    CursorShape::SteadyUnderScore => f.write_str("SteadyUnderScore"),
1880                    CursorShape::BlinkingBar => f.write_str("BlinkingBar"),
1881                    CursorShape::SteadyBar => f.write_str("SteadyBar"),
1882                }
1883            }
1884        }
1885
1886        f.debug_struct("InnerPalette")
1887            .field("main_cursor", &self.main_cursor.map(DebugCursorShape))
1888            .field("extra_cursor", &self.extra_cursor.map(DebugCursorShape))
1889            .field("forms", &DebugForms(&self.forms))
1890            .field("masks", &self.masks)
1891            .finish()
1892    }
1893}
1894
1895impl std::fmt::Debug for FormType {
1896    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1897        match self {
1898            Self::Normal => write!(f, "Normal"),
1899            Self::Ref(refed) => write!(f, "Ref({refed})"),
1900            Self::Weakest => write!(f, "Weakest"),
1901            Self::WeakestRef(refed) => write!(f, "WeakestRef({refed})"),
1902        }
1903    }
1904}