Skip to main content

duat_core/
form.rs

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