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