duat_core/
form.rs

1//! Utilities for stylizing the text of Duat
2use std::sync::{LazyLock, OnceLock};
3
4use FormType::*;
5use crossterm::style::{Attribute, Attributes, ContentStyle};
6pub use crossterm::{cursor::SetCursorStyle as CursorShape, style::Color};
7use parking_lot::{RwLock, RwLockReadGuard};
8
9pub use self::global::*;
10pub(crate) use self::global::{colorscheme_exists, exists};
11use crate::{
12    hooks::{self, FormSet},
13    ui::Sender,
14};
15
16pub trait ColorScheme: Send + Sync + 'static {
17    fn apply(&self);
18
19    fn name(&self) -> &'static str;
20}
21
22static SENDER: OnceLock<Sender> = OnceLock::new();
23static BASE_FORMS: &[(&str, Form, FormType)] = &[
24    ("Default", Form::new().0, Normal),
25    ("Accent", Form::bold().0, Normal),
26    ("DefaultOk", Form::blue().0, Normal),
27    ("AccentOk", Form::cyan().0, Normal),
28    ("DefaultErr", Form::red().0, Normal),
29    ("AccentErr", Form::red().bold().0, Normal),
30    ("DefaultHint", Form::grey().0, Normal),
31    ("AccentHint", Form::grey().bold().0, Normal),
32    ("MainCursor", Form::reverse().0, Normal),
33    ("ExtraCursor", Form::reverse().0, Ref(M_CUR_ID.0 as usize)),
34    ("MainSelection", Form::white().on_dark_grey().0, Normal),
35    (
36        "ExtraSelection",
37        Form::white().on_dark_grey().0,
38        Ref(M_SEL_ID.0 as usize),
39    ),
40    ("Inactive", Form::grey().0, Normal),
41];
42
43/// The functions that will be exposed for public use.
44mod global {
45    use std::{
46        any::TypeId,
47        collections::HashMap,
48        sync::{LazyLock, mpsc},
49        time::Duration,
50    };
51
52    use parking_lot::Mutex;
53
54    use super::{BASE_FORMS, BuiltForm, ColorScheme, CursorShape, Form, FormId, Painter, Palette};
55    use crate::{
56        context,
57        hooks::{self, ColorSchemeSet},
58        text::err,
59    };
60
61    static PALETTE: Palette = Palette::new();
62    static FORMS: LazyLock<Mutex<Vec<&str>>> =
63        LazyLock::new(|| Mutex::new(BASE_FORMS.iter().map(|(name, ..)| *name).collect()));
64    static COLORSCHEMES: LazyLock<Mutex<Vec<Box<dyn ColorScheme>>>> = LazyLock::new(Mutex::default);
65
66    /// Either a [`Form`] or a name of a form
67    ///
68    /// Note that the referenced form does not need to exist for
69    /// [`form::set`] or [`form::set_weak`] to work properly.
70    ///
71    /// [`form::set`]: set
72    /// [`form::set_weak`]: set_weak
73    pub trait FormFmt: InnerFormFmt {}
74    impl FormFmt for Form {}
75    impl FormFmt for BuiltForm {}
76    impl FormFmt for &str {}
77    impl FormFmt for &mut str {}
78    impl FormFmt for String {}
79
80    /// Sets the [`Form`] by the name of `name`
81    ///
82    /// This will create a new form or replace one that already
83    /// exists, and you can either set it to a [`Form`] directly, or
84    /// reference another form by its name:
85    ///
86    /// ```rust
87    /// # use duat_core::form::{self, Form};
88    /// // Creates a regular form
89    /// form::set("MyRegularForm", Form::red());
90    /// // Creates a form that references the first
91    /// form::set("MyRefForm", "MyRegularForm");
92    /// // Sets both "MyRegularForm" and "MyRefForm" to blue
93    /// form::set("MyRegularForm", Form::blue());
94    /// ```
95    ///
96    /// If you are creating a plugin, or another kind of tool for
97    /// others using Duat, use [`form::set_weak`] instead of this
98    /// function.
99    ///
100    /// [`form::set_weak`]: set_weak
101    pub fn set(name: impl ToString, form: impl FormFmt) -> FormId {
102        let kind = form.kind();
103        let name: &'static str = name.to_string().leak();
104
105        match kind {
106            Kind::Form(form) => queue(move || PALETTE.set_form(name, form)),
107            Kind::Ref(refed) => queue(move || PALETTE.set_ref(name, refed)),
108        };
109
110        let mut forms = FORMS.lock();
111        if let Kind::Ref(refed) = kind {
112            position_of_name(&mut forms, refed);
113        }
114        FormId(position_of_name(&mut forms, name) as u16)
115    }
116
117    /// Sets a form, "weakly"
118    ///
119    /// The difference between this function and [`form::set`] is
120    /// that this function will only trigger if the form didn't
121    /// already exist.
122    ///
123    /// This is useful for plugins, since it prioritizes the user's
124    /// preferences, no matter in what order this function and
125    /// [`form::set`] are called:
126    ///
127    /// ```rust
128    /// use duat_core::form::{self, Form};
129    /// // Creates a form
130    /// form::set_weak("WeakForm", Form::blue().on_white());
131    /// // Creates a form "strongly"
132    /// form::set("StrongForm", Form::new().bold());
133    /// // Does nothing
134    /// form::set_weak("StrongForm", "Default");
135    /// ```
136    ///
137    /// [`form::set`]: set
138    pub fn set_weak(name: impl ToString, form: impl FormFmt) -> FormId {
139        let kind = form.kind();
140        let name: &'static str = name.to_string().leak();
141
142        match kind {
143            Kind::Form(form) => queue(move || PALETTE.set_weak_form(name, form)),
144            Kind::Ref(refed) => queue(move || PALETTE.set_weak_ref(name, refed)),
145        };
146
147        let mut forms = FORMS.lock();
148        if let Kind::Ref(refed) = kind {
149            position_of_name(&mut forms, refed);
150        }
151        FormId(position_of_name(&mut forms, name) as u16)
152    }
153
154    /// Returns a [`Form`], given a [`FormId`].
155    ///
156    /// If you are thinking of using this for printing purposes,
157    /// consider using [`form::painter`] instead.
158    ///
159    /// [`form::painter`]: painter
160    pub fn from_id(id: FormId) -> Form {
161        PALETTE.form_from_id(id).unwrap_or(Form::new().0)
162    }
163
164    /// The current main cursor, with the `"MainCursor"` [`Form`]
165    pub fn main_cursor() -> (Form, Option<CursorShape>) {
166        PALETTE.main_cursor()
167    }
168
169    /// The current extra cursor, with the `"ExtraCursor"` [`Form`]
170    pub fn extra_cursor() -> (Form, Option<CursorShape>) {
171        PALETTE.extra_cursor()
172    }
173
174    /// Sets the main cursor's [shape]
175    ///
176    /// Cursors in Duat can either be a distinct [shape], or can be
177    /// defined as a [`Form`], just like the rest of the styling.
178    ///
179    /// This is done because some UIs (like a terminal) lack the
180    /// ability to show multiple cursors, so extra cursors are usually
181    /// printed as solid blocks with a background color.
182    ///
183    /// If you want to set the cursor's color, do something like this:
184    ///
185    /// ```rust
186    /// # use duat_core::form::{self, Form, Color};
187    /// form::set("MainCursor", Form::black().on("rgb 240 210 200"));
188    /// ```
189    ///
190    /// However, if possible, Duat will still try to use the main
191    /// cursor's [shape]. If you don't want that to happen, see
192    /// [`form::unset_main_cursor`].
193    ///
194    /// [shape]: CursorShape
195    /// [`form::unset_main_cursor`]: unset_main_cursor
196    pub fn set_main_cursor(shape: CursorShape) {
197        queue(move || PALETTE.set_main_cursor(shape));
198    }
199
200    /// Sets extra cursors's [shape]s
201    ///
202    /// Cursors in Duat can either be a distinct [shape], or can be
203    /// defined as a [`Form`], just like the rest of the styling.
204    ///
205    /// This is done because some UIs (like a terminal) lack the
206    /// ability to show multiple cursors, so extra cursors are usually
207    /// printed as solid blocks with a background color.
208    ///
209    /// If you want to set the cursor's color, do something like this:
210    ///
211    /// ```rust
212    /// # use duat_core::form::{self, Form, Color};
213    /// form::set("ExtraCursor", Form::black().on_cyan());
214    /// ```
215    ///
216    /// However, if possible, Duat will still try to use the main
217    /// cursor's [shape]. If you don't want that to happen, see
218    /// [`form::unset_extra_cursor`].
219    ///
220    /// [shape]: CursorShape
221    /// [`form::unset_extra_cursor`]: unset_extra_cursor
222    pub fn set_extra_cursor(shape: CursorShape) {
223        queue(move || PALETTE.set_extra_cursor(shape));
224    }
225
226    /// Removes the main cursor's [shape]
227    ///
228    /// By doing this, you will force Duat to draw the main cursor by
229    /// use of the `"MainCursor"` form.
230    ///
231    /// If you want to set the [shape] instead, see
232    /// [`form::set_main_cursor`].
233    ///
234    /// [shape]: CursorShape
235    /// [`form::set_main_cursor`]: set_main_cursor
236    pub fn unset_main_cursor() {
237        queue(move || PALETTE.unset_main_cursor());
238    }
239
240    /// Removes extra cursors's [shape]s
241    ///
242    /// By doing this, you will force Duat to draw the extra cursor by
243    /// use of the `"MainCursor"` form. Do note however that, in
244    /// something like a terminal, extra cursors would never be
245    /// printed as a [shape] anyways, since terminals can only
246    /// print one cursor at a time.
247    ///
248    /// If you want to set the [shape] instead, see
249    /// [`form::set_extra_cursor`].
250    ///
251    /// [shape]: CursorShape
252    /// [`form::set_extra_cursor`]: set_extra_cursor
253    pub fn unset_extra_cursor() {
254        queue(move || PALETTE.unset_extra_cursor());
255    }
256
257    /// A [`Painter`] for coloring text efficiently
258    ///
259    /// The type argument is used to distinguish which `"Default"`
260    /// [`Form`] is supposed to be used (e.g. `"Default.File"`,
261    /// `"Default.StatusLine"`, etc).
262    ///
263    /// This function will be used primarily when printing widgets to
264    /// the screen, which is something that only [`Ui`]s should be
265    /// doing.
266    ///
267    /// One thing to note is that a [`Painter`] will lock the form
268    /// palette while it is being used. This means that, if a form is
269    /// changed while a widget is in the middle of printing, the
270    /// printed form will be the old version, not the new one. Only
271    /// after said widget is done printing will the new form come into
272    /// effect.
273    ///
274    /// [`Ui`]: crate::ui::Ui
275    pub fn painter<W: ?Sized + 'static>() -> Painter {
276        fn default_id(type_id: TypeId, type_name: &'static str) -> FormId {
277            static IDS: LazyLock<Mutex<HashMap<TypeId, FormId>>> = LazyLock::new(Mutex::default);
278            let mut ids = IDS.lock();
279
280            if let Some(id) = ids.get(&type_id) {
281                *id
282            } else {
283                let name: &'static str = format!("Default.{type_name}").leak();
284                let id = id_from_name(name);
285                add_forms(vec![name]);
286                ids.insert(type_id, id);
287                id
288            }
289        }
290        PALETTE.painter(default_id(TypeId::of::<W>(), crate::duat_name::<W>()))
291    }
292
293    /// Returns the [`FormId`] from the name of a [`Form`]
294    ///
295    /// You can also pass multiple names, in order to get a list of
296    /// ids.
297    ///
298    /// If there is no [`Form`] with the given name, a new one is
299    /// created, which will behave according to the following
300    /// priority:
301    ///
302    /// - If the name contains a `'.'` character, it will reference
303    ///   the [`Form`] whose name is a suffix up to the last `'.'`.
304    ///   For example, `"Prefix.Middle.Suffix"` will reference
305    ///   `"Prefix.Middle"`;
306    /// - If the name does not contain a `'.'`, it will not reference
307    ///   anything, having the [default `Form`];
308    ///
309    /// If a referenced [`Form`] does not exist, it will be added,
310    /// following the same rules.
311    ///
312    /// # Note
313    ///
314    /// This is a macro because, in order to be as efficient as
315    /// possible, it is better to store this value inside of a
316    /// static variable, since it is guaranteed to not change. This
317    /// way, you only have to figure it out once, and it is much
318    /// faster than with a [`HashMap`] (how this is usually done).
319    ///
320    /// [`HashMap`]: std::collections::HashMap
321    /// [default `Form`]: Form::new
322    pub macro id_of {
323        ($form:expr) => {{
324            static ID: std::sync::OnceLock<FormId> = std::sync::OnceLock::new();
325            *ID.get_or_init(|| {
326                let name: &'static str = $form;
327                let id = id_from_name(name);
328                add_forms(vec![name]);
329                id
330            })
331        }},
332        ($($form:expr),+) => {{
333            static IDS: std::sync::OnceLock<&[FormId]> = std::sync::OnceLock::new();
334            let ids = *IDS.get_or_init(|| {
335    			let mut ids = Vec::new();
336    			let names = vec![$( $form ),+];
337    			for name in names.iter() {
338        			ids.push(id_from_name(name));
339    			}
340    			add_forms(names);
341    			ids.leak()
342    		});
343    		ids
344        }}
345    }
346
347    /// Non static version of [`id_of!`]
348    ///
349    /// You should only use this if the names of the [`Form`]s in
350    /// question are not known at compile time. And if that is the
351    /// case, you should try to find a way to memoize around this
352    /// issue (usually with something like a [`HashMap`]).
353    pub fn ids_of_non_static(names: impl IntoIterator<Item = impl ToString>) -> Vec<FormId> {
354        let names: Vec<&str> = names
355            .into_iter()
356            .map(|n| {
357                let str: &'static str = n.to_string().leak();
358                str
359            })
360            .collect();
361
362        let mut ids = Vec::new();
363        let mut forms = FORMS.lock();
364        for name in names.iter() {
365            ids.push(FormId(position_of_name(&mut forms, name) as u16));
366        }
367        add_forms(names);
368        ids
369    }
370
371    /// Returns the [`FormId`] of the form's name
372    #[doc(hidden)]
373    pub fn id_from_name(name: &'static str) -> FormId {
374        let mut forms = FORMS.lock();
375        FormId(position_of_name(&mut forms, name) as u16)
376    }
377
378    #[doc(hidden)]
379    pub fn add_forms(names: Vec<&'static str>) {
380        queue(move || PALETTE.set_many(names.as_ref()));
381    }
382
383    /// Adds a [`ColorScheme`] to the list of colorschemes
384    ///
385    /// This [`ColorScheme`] can then be added via
386    /// [`form::set_colorscheme`] or through the command
387    /// `colorscheme`.
388    ///
389    /// If a [`ColorScheme`] of the same name was already added, it
390    /// will be overritten.
391    ///
392    /// [`form::set_colorscheme`]: set_colorscheme
393    pub fn add_colorscheme(cs: impl ColorScheme) {
394        let mut colorschemes = COLORSCHEMES.lock();
395        let name = cs.name();
396        if let Some(i) = colorschemes.iter().position(|cs| cs.name() == name) {
397            colorschemes[i] = Box::new(cs);
398        } else {
399            colorschemes.push(Box::new(cs));
400        }
401    }
402
403    /// Applies a [`ColorScheme`]
404    ///
405    /// This [`ColorScheme`] must've first been added via
406    /// [`form::add_colorscheme`].
407    ///
408    /// [`form::add_colorscheme`]: add_colorscheme
409    pub fn set_colorscheme(name: &str) {
410        let colorschemes = COLORSCHEMES.lock();
411        if let Some(cs) = colorschemes.iter().find(|cs| cs.name() == name) {
412            cs.apply();
413            hooks::trigger::<ColorSchemeSet>(cs.name());
414        } else {
415            context::notify(err!("The colorscheme " [*a] name [] " was not found"));
416        }
417    }
418
419    /// Calls [`form::set`] on each tuple in the list
420    ///
421    /// [`form::set`]: set
422    pub macro set_many($(($name:literal, $form:expr)),+ $(,)?) {{
423        $(
424            set($name, $form);
425        )+
426    }}
427
428    /// Wether or not a specific [`Form`] has been set
429    pub(crate) fn exists(name: &str) -> bool {
430        FORMS.lock().contains(&name)
431    }
432
433    /// Wether or not a specific [`ColorScheme`] was added
434    pub(crate) fn colorscheme_exists(name: &str) -> bool {
435        COLORSCHEMES.lock().iter().any(|cs| cs.name() == name)
436    }
437
438    /// The name of a form, given a [`FormId`]
439    pub(super) fn name_of(id: FormId) -> &'static str {
440        FORMS.lock()[id.0 as usize]
441    }
442
443    fn position_of_name(names: &mut Vec<&'static str>, name: &'static str) -> usize {
444        if let Some((i, _)) = names.iter().enumerate().find(|(_, rhs)| **rhs == name) {
445            i
446        } else if let Some((refed, _)) = name.rsplit_once('.') {
447            position_of_name(names, refed);
448            names.push(name);
449            names.len() - 1
450        } else {
451            names.push(name);
452            names.len() - 1
453        }
454    }
455
456    fn queue<R>(f: impl FnOnce() -> R + Send + Sync + 'static) {
457        static SENDER: Mutex<Option<mpsc::Sender<Box<dyn FnOnce() + Send + Sync>>>> =
458            Mutex::new(None);
459
460        if context::will_reload_or_quit() {
461            return;
462        }
463
464        let f = Box::new(move || {
465            f();
466        });
467
468        let mut sender = SENDER.lock();
469        let f = if let Some(tx) = sender.as_ref() {
470            let Err(err) = tx.send(f) else {
471                return;
472            };
473            err.0
474        } else {
475            f
476        };
477        let (tx, rx) = mpsc::channel();
478        tx.send(f).unwrap();
479        *sender = Some(tx);
480
481        crate::thread::spawn(move || {
482            while let Ok(f) = rx.recv_timeout(Duration::from_micros(500)) {
483                f();
484            }
485        });
486    }
487
488    /// A kind of [`Form`]
489    #[derive(Clone, Copy)]
490    enum Kind {
491        Form(Form),
492        Ref(&'static str),
493    }
494
495    /// So [`Form`]s and [`impl ToString`]s are arguments for [`set`]
496    ///
497    /// [`impl ToString`]: ToString
498    trait InnerFormFmt {
499        /// The kind of [`Form`] that this type represents
500        fn kind(self) -> Kind;
501    }
502
503    impl InnerFormFmt for Form {
504        fn kind(self) -> Kind {
505            Kind::Form(self)
506        }
507    }
508
509    impl InnerFormFmt for BuiltForm {
510        fn kind(self) -> Kind {
511            Kind::Form(self.0)
512        }
513    }
514
515    impl InnerFormFmt for &str {
516        fn kind(self) -> Kind {
517            Kind::Ref(self.to_string().leak())
518        }
519    }
520
521    impl InnerFormFmt for &mut str {
522        fn kind(self) -> Kind {
523            Kind::Ref(self.to_string().leak())
524        }
525    }
526
527    impl InnerFormFmt for String {
528        fn kind(self) -> Kind {
529            Kind::Ref(self.leak())
530        }
531    }
532}
533
534/// An identifier of a [`Form`]
535///
536/// This struct is always going to point to the same form, since those
537/// cannot be destroyed.
538///
539/// The main use for keeping these things directly is in order to
540/// modify a file's text in an efficient manner, by adding tags
541/// directly, instead of using a macro like [`text!`]
542///
543/// [`text!`]: crate::text::text
544#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
545pub struct FormId(u16);
546
547impl FormId {
548    /// The internal id of the [`FormId`]
549    ///
550    /// This may be useful in certain situations.
551    pub const fn to_u16(self) -> u16 {
552        self.0
553    }
554
555    /// The name of this [`FormId`]
556    pub fn name(self) -> &'static str {
557        name_of(self)
558    }
559}
560
561impl std::fmt::Debug for FormId {
562    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
563        write!(f, "FormId({})", name_of(*self))
564    }
565}
566
567/// A style for text.
568#[derive(Clone, Copy, PartialEq, Eq)]
569pub struct Form {
570    pub style: ContentStyle,
571}
572
573#[rustfmt::skip]
574impl Form {
575    mimic_method_new!(/**bold*/ bold Attribute::Bold);
576    mimic_method_new!(/**dim*/ dim Attribute::Dim);
577    mimic_method_new!(/**italic*/ italic Attribute::Italic);
578    mimic_method_new!(/**underlined*/ underlined Attribute::Underlined);
579    mimic_method_new!(/**double_underlined*/ double_underlined Attribute::DoubleUnderlined);
580    mimic_method_new!(/**undercurled*/ undercurled Attribute::Undercurled);
581    mimic_method_new!(/**underdashed*/ underdashed Attribute::Underdashed);
582    mimic_method_new!(/**reverse*/ reverse Attribute::Reverse);
583    mimic_method_new!(/**crossed_out*/ crossed_out Attribute::CrossedOut);
584    mimic_method_new!(/**black*/ black on_black underline_black Color::Black);
585    mimic_method_new!(/**dark_grey*/ dark_grey on_dark_grey underline_dark_grey Color::DarkGrey);
586    mimic_method_new!(/**red*/ red on_red underline_red Color::Red);
587    mimic_method_new!(/**dark_red*/ dark_red on_dark_red underline_dark_red Color::DarkRed);
588    mimic_method_new!(/**green*/ green on_green underline_green Color::Green);
589    mimic_method_new!(
590        /**dark_green*/ dark_green on_dark_green underline_dark_green Color::DarkGreen
591    );
592    mimic_method_new!(/**yellow*/ yellow on_yellow underline_yellow Color::Yellow);
593    mimic_method_new!(
594        /**dark_yellow*/ dark_yellow on_dark_yellow underline_dark_yellow Color::DarkYellow
595    );
596    mimic_method_new!(/**blue*/ blue on_blue underline_blue Color::Blue);
597    mimic_method_new!(/**dark_blue*/ dark_blue on_dark_blue underline_dark_blue Color::DarkBlue);
598    mimic_method_new!(/**magenta*/ magenta on_magenta underline_magenta Color::Magenta);
599    mimic_method_new!(
600        /**dark_magenta*/ dark_magenta on_dark_magenta underline_dark_magenta Color::DarkMagenta
601    );
602    mimic_method_new!(/**cyan*/ cyan on_cyan underline_cyan Color::Cyan);
603    mimic_method_new!(/**dark_cyan*/ dark_cyan on_dark_cyan underline_dark_cyan Color::DarkCyan);
604    mimic_method_new!(/**white*/ white on_white underline_white Color::White);
605    mimic_method_new!(/**grey*/ grey on_grey underline_grey Color::Grey);
606}
607
608impl Form {
609    /// Returns a new [`Form`] with a default style
610    ///
611    /// This method actually returns [`BuiltForm`]
612    #[allow(clippy::new_ret_no_self)]
613    pub const fn new() -> BuiltForm {
614        let style = ContentStyle {
615            foreground_color: None,
616            background_color: None,
617            underline_color: None,
618            attributes: Attributes::none(),
619        };
620        BuiltForm(Self { style })
621    }
622
623    /// Returns a new [`Form`] with the [`Reset`] attribute
624    ///
625    /// In Duat, the [`Reset`] attribute should remove only other
626    /// [`Attribute`]s, not any of the colors in use.
627    ///
628    /// [`Reset`]: Attribute::Reset
629    pub const fn reset() -> BuiltForm {
630        let mut built = Form::new();
631        built.0.style.attributes = built.0.style.attributes.with(Attribute::Reset);
632        built
633    }
634
635    /// New [`Form`] with a colored foreground
636    ///
637    /// This function accepts three color formats:
638    ///
639    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
640    /// - Three rgb values, like `"rgb 123 456 789"`;
641    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
642    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
643    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
644    pub const fn with(str: &str) -> BuiltForm {
645        let mut built = Form::new();
646        built.0.style.foreground_color = match str_to_color(str) {
647            Ok(color) => Some(color),
648            Err(err) => panic!("{}", err),
649        };
650        built
651    }
652
653    /// New [`Form`] with a colored background
654    ///
655    /// This function accepts three color formats:
656    ///
657    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
658    /// - Three rgb values, like `"rgb 123 456 789"`;
659    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
660    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
661    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
662    pub const fn on(str: &str) -> BuiltForm {
663        let mut built = Form::new();
664        built.0.style.background_color = match str_to_color(str) {
665            Ok(color) => Some(color),
666            Err(err) => panic!("{}", err),
667        };
668        built
669    }
670
671    /// New [`Form`] with a colored underlining
672    ///
673    /// This function accepts three color formats:
674    ///
675    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
676    /// - Three rgb values, like `"rgb 123 456 789"`;
677    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
678    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
679    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
680    pub const fn underline(str: &str) -> BuiltForm {
681        let mut built = Form::new();
682        built.0.style.underline_color = match str_to_color(str) {
683            Ok(color) => Some(color),
684            Err(err) => panic!("{}", err),
685        };
686        built
687    }
688
689    /// The foreground color
690    pub const fn fg(&self) -> Option<Color> {
691        self.style.foreground_color
692    }
693
694    /// The background color
695    pub const fn bg(&self) -> Option<Color> {
696        self.style.background_color
697    }
698
699    /// The foreground color
700    pub const fn ul(&self) -> Option<Color> {
701        self.style.underline_color
702    }
703
704    /// The attributes
705    pub const fn attr(&self) -> Attributes {
706        self.style.attributes
707    }
708}
709
710/// A convenience struct for [`Form`]s
711///
712/// This struct exists in order to have [`Form`] methods be
713/// initializers, while [`BuiltForm`] methods consume and return a
714/// [`BuiltForm`]s
715///
716/// This is their only difference, everywhere else, they are
717/// functionally identical.
718pub struct BuiltForm(Form);
719
720#[rustfmt::skip]
721impl BuiltForm {
722    mimic_method_mod!(/**bold*/ bold Attribute::Bold);
723    mimic_method_mod!(/**dim*/ dim Attribute::Dim);
724    mimic_method_mod!(/**italic*/ italic Attribute::Italic);
725    mimic_method_mod!(/**underlined*/ underlined Attribute::Underlined);
726    mimic_method_mod!(/**double_underlined*/ double_underlined Attribute::DoubleUnderlined);
727    mimic_method_mod!(/**undercurled*/ undercurled Attribute::Undercurled);
728    mimic_method_mod!(/**underdashed*/ underdashed Attribute::Underdashed);
729    mimic_method_mod!(/**reverse*/ reverse Attribute::Reverse);
730    mimic_method_mod!(/**crossed_out*/ crossed_out Attribute::CrossedOut);
731    mimic_method_mod!(/**overlined*/ overlined Attribute::OverLined);
732    mimic_method_mod!(/**black*/ black on_black underline_black Color::Black);
733    mimic_method_mod!(/**dark_grey*/ dark_grey on_dark_grey underline_dark_grey Color::DarkGrey);
734    mimic_method_mod!(/**red*/ red on_red underline_red Color::Red);
735    mimic_method_mod!(/**dark_red*/ dark_red on_dark_red underline_dark_red Color::DarkRed);
736    mimic_method_mod!(/**green*/ green on_green underline_green Color::Green);
737    mimic_method_mod!(
738        /**dark_green*/ dark_green on_dark_green underline_dark_green Color::DarkGreen
739    );
740    mimic_method_mod!(/**yellow*/ yellow on_yellow underline_yellow Color::Yellow);
741    mimic_method_mod!(
742        /**dark_yellow*/ dark_yellow on_dark_yellow underline_dark_yellow Color::DarkYellow
743    );
744    mimic_method_mod!(/**blue*/ blue on_blue underline_blue Color::Blue);
745    mimic_method_mod!(/**dark_blue*/ dark_blue on_dark_blue underline_dark_blue Color::DarkBlue);
746    mimic_method_mod!(/**magenta*/ magenta on_magenta underline_magenta Color::Magenta);
747    mimic_method_mod!(
748        /**dark_magenta*/ dark_magenta on_dark_magenta underline_dark_magenta Color::DarkMagenta
749    );
750    mimic_method_mod!(/**cyan*/ cyan on_cyan underline_cyan Color::Cyan);
751    mimic_method_mod!(/**dark_cyan*/ dark_cyan on_dark_cyan underline_dark_cyan Color::DarkCyan);
752    mimic_method_mod!(/**white*/ white on_white underline_white Color::White);
753    mimic_method_mod!(/**grey*/ grey on_grey underline_grey Color::Grey);
754}
755
756impl BuiltForm {
757    /// Adds the [`Reset`] attribute to this [`Form`]
758    ///
759    /// In Duat, the [`Reset`] attribute should remove only other
760    /// [`Attribute`]s, not any of the colors in use.
761    ///
762    /// [`Reset`]: Attribute::Reset
763    pub const fn reset(mut self) -> BuiltForm {
764        self.0.style.attributes = self.0.style.attributes.with(Attribute::Reset);
765        self
766    }
767
768    /// Colors the foreground of this [`Form`]
769    ///
770    /// This function accepts three color formats:
771    ///
772    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
773    /// - Three rgb values, like `"rgb 123 456 789"`;
774    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
775    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
776    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
777    pub const fn with(mut self, str: &str) -> Self {
778        self.0.style.foreground_color = match str_to_color(str) {
779            Ok(color) => Some(color),
780            Err(err) => panic!("{}", err),
781        };
782        self
783    }
784
785    /// Colors the background of this [`Form`]
786    ///
787    /// This function accepts three color formats:
788    ///
789    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
790    /// - Three rgb values, like `"rgb 123 456 789"`;
791    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
792    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
793    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
794    pub const fn on(mut self, str: &str) -> Self {
795        self.0.style.background_color = match str_to_color(str) {
796            Ok(color) => Some(color),
797            Err(err) => panic!("{}", err),
798        };
799        self
800    }
801
802    /// Colors the underlining of this [`Form`]
803    ///
804    /// This function accepts three color formats:
805    ///
806    /// - A hexcode, like `"#abcdef"`, capitalization is ignored;
807    /// - Three rgb values, like `"rgb 123 456 789"`;
808    /// - Three hsl values, like `"hsl {hue} {sat} {lit}"`, where
809    ///   {hue}, {sat} and {lit} can either be a number from `0..255`,
810    ///   or a percentage, followed by `'%'`, e.g. `"hsl 234 50% 42"`.
811    pub const fn underline(mut self, str: &str) -> Self {
812        self.0.style.underline_color = match str_to_color(str) {
813            Ok(color) => Some(color),
814            Err(err) => panic!("{}", err),
815        };
816        self
817    }
818}
819
820impl std::ops::Deref for BuiltForm {
821    type Target = Form;
822
823    fn deref(&self) -> &Self::Target {
824        &self.0
825    }
826}
827
828impl std::ops::DerefMut for BuiltForm {
829    fn deref_mut(&mut self) -> &mut Self::Target {
830        &mut self.0
831    }
832}
833
834/// The [`FormId`] of the `"Default"` form
835pub const DEFAULT_ID: FormId = FormId(0);
836/// The [`FormId`] of the `"MainCursor"` form
837pub const M_CUR_ID: FormId = FormId(8);
838/// The [`FormId`] of the `"ExtraCursor"` form
839pub const E_CUR_ID: FormId = FormId(9);
840/// The [`FormId`] of the `"MainSelection"` form
841pub const M_SEL_ID: FormId = FormId(10);
842/// The [`FormId`] of the `"ExtraSelection"` form
843pub const E_SEL_ID: FormId = FormId(11);
844/// The [`FormId`] of the `"Inactive"` form
845pub const INACTIVE_ID: FormId = FormId(12);
846
847struct InnerPalette {
848    main_cursor: Option<CursorShape>,
849    extra_cursor: Option<CursorShape>,
850    forms: Vec<(&'static str, Form, FormType)>,
851}
852
853/// The list of forms to be used when rendering.
854struct Palette(LazyLock<RwLock<InnerPalette>>);
855
856impl Palette {
857    /// Returns a new instance of [`FormPalette`]
858    const fn new() -> Self {
859        Self(LazyLock::new(|| {
860            let main_cursor = Some(CursorShape::DefaultUserShape);
861
862            RwLock::new(InnerPalette {
863                main_cursor,
864                extra_cursor: main_cursor,
865                forms: BASE_FORMS.to_vec(),
866            })
867        }))
868    }
869
870    /// Sets a [`Form`]
871    fn set_form(&self, name: &'static str, form: Form) {
872        let mut inner = self.0.write();
873        let (i, _) = position_and_form(&mut inner.forms, name);
874
875        inner.forms[i] = (name, form, FormType::Normal);
876
877        for refed in refs_of(&inner, i) {
878            inner.forms[refed].1 = form;
879        }
880
881        if let Some(sender) = SENDER.get() {
882            sender.send_form_changed().unwrap()
883        }
884
885        hooks::trigger::<FormSet>((name, FormId(i as u16), form));
886    }
887
888    /// Sets a [`Form`] "weakly"
889    fn set_weak_form(&self, name: &'static str, form: Form) {
890        let mut inner = self.0.write();
891        let (i, _) = position_and_form(&mut inner.forms, name);
892
893        let (_, f, f_ty) = &mut inner.forms[i];
894        if let FormType::Weakest | FormType::WeakestRef(_) = f_ty {
895            *f = form;
896            *f_ty = FormType::Normal;
897
898            if let Some(sender) = SENDER.get() {
899                sender.send_form_changed().unwrap()
900            }
901            for refed in refs_of(&inner, i) {
902                inner.forms[refed].1 = form;
903            }
904        }
905    }
906
907    /// Makes a [`Form`] reference another
908    fn set_ref(&self, name: &'static str, refed: &'static str) {
909        let mut inner = self.0.write();
910        let (refed, form) = position_and_form(&mut inner.forms, refed);
911        let (i, _) = position_and_form(&mut inner.forms, name);
912
913        for refed in refs_of(&inner, i) {
914            inner.forms[refed].1 = form;
915        }
916
917        // If it would be circular, we just don't reference anything.
918        if would_be_circular(&inner, i, refed) {
919            inner.forms[i] = (name, form, FormType::Normal);
920        } else {
921            inner.forms[i] = (name, form, FormType::Ref(refed));
922        }
923
924        if let Some(sender) = SENDER.get() {
925            sender.send_form_changed().unwrap()
926        }
927        hooks::trigger::<FormSet>((name, FormId(i as u16), form));
928    }
929
930    /// Makes a [`Form`] reference another "weakly"
931    fn set_weak_ref(&self, name: &'static str, refed: &'static str) {
932        let mut inner = self.0.write();
933        let (refed, form) = position_and_form(&mut inner.forms, refed);
934        let (i, _) = position_and_form(&mut inner.forms, name);
935
936        // For weak refs, no checks are done, since a form is only set if it
937        // doesn't exist, and for there to be refs to it, it must exist.
938        let (_, f, f_ty) = &mut inner.forms[i];
939        if let FormType::Weakest | FormType::WeakestRef(_) = f_ty {
940            *f = form;
941            *f_ty = FormType::WeakestRef(refed);
942
943            if let Some(sender) = SENDER.get() {
944                sender.send_form_changed().unwrap()
945            }
946            for refed in refs_of(&inner, i) {
947                inner.forms[refed].1 = form;
948            }
949        }
950    }
951
952    /// Sets many [`Form`]s
953    fn set_many(&self, names: &[&'static str]) {
954        let mut inner = self.0.write();
955        for name in names {
956            position_and_form(&mut inner.forms, name);
957        }
958    }
959
960    /// Returns a form, given a [`FormId`].
961    fn form_from_id(&self, id: FormId) -> Option<Form> {
962        let inner = self.0.read();
963        inner.forms.get(id.0 as usize).map(|(_, form, _)| *form)
964    }
965
966    /// The [`Form`] and [`CursorShape`] of the main cursor
967    fn main_cursor(&self) -> (Form, Option<CursorShape>) {
968        let form = self.form_from_id(M_CUR_ID).unwrap();
969        (form, self.0.read().main_cursor)
970    }
971
972    /// The [`Form`] and [`CursorShape`] of extra cursors
973    fn extra_cursor(&self) -> (Form, Option<CursorShape>) {
974        let form = self.form_from_id(E_CUR_ID).unwrap();
975        (form, self.0.read().extra_cursor)
976    }
977
978    /// Sets the [`CursorShape`] of the main cursor
979    fn set_main_cursor(&self, shape: CursorShape) {
980        self.0.write().main_cursor = Some(shape);
981        if let Some(sender) = SENDER.get() {
982            sender.send_form_changed().unwrap()
983        }
984    }
985
986    /// Sets the [`CursorShape`] of extra cursors
987    fn set_extra_cursor(&self, shape: CursorShape) {
988        self.0.write().extra_cursor = Some(shape);
989        if let Some(sender) = SENDER.get() {
990            sender.send_form_changed().unwrap()
991        }
992    }
993
994    /// Unsets the [`CursorShape`] of the main cursor
995    fn unset_main_cursor(&self) {
996        self.0.write().main_cursor = None;
997        if let Some(sender) = SENDER.get() {
998            sender.send_form_changed().unwrap()
999        }
1000    }
1001
1002    /// Unsets the [`CursorShape`] of the extra cursors
1003    fn unset_extra_cursor(&self) {
1004        self.0.write().extra_cursor = None;
1005        if let Some(sender) = SENDER.get() {
1006            sender.send_form_changed().unwrap()
1007        }
1008    }
1009
1010    /// Returns a [`Painter`]
1011    fn painter(&'static self, id: FormId) -> Painter {
1012        let inner = self.0.read();
1013        let default = inner
1014            .forms
1015            .get(id.0 as usize)
1016            .map(|(_, f, _)| *f)
1017            .unwrap_or(Form::new().0);
1018        Painter {
1019            inner,
1020            forms: vec![(default, id)],
1021            reset_count: 0,
1022            final_form_start: 1,
1023            still_on_same_byte: false,
1024            reset_is_needed: false,
1025        }
1026    }
1027}
1028
1029pub struct Painter {
1030    inner: RwLockReadGuard<'static, InnerPalette>,
1031    forms: Vec<(Form, FormId)>,
1032    reset_count: usize,
1033    final_form_start: usize,
1034    still_on_same_byte: bool,
1035    reset_is_needed: bool,
1036}
1037
1038impl Painter {
1039    /// Applies the `Form` with the given `id` and returns the result,
1040    /// given previous triggers.
1041    ///
1042    /// Will return a [`Form`] _relative_ to what the previous
1043    /// [`Form`] was, that is, if the new [`Form`] doesn't include a
1044    /// background, its combination with the other [`Form`]s also
1045    /// won't, since it wasn't changed.
1046    #[inline(always)]
1047    pub fn apply(&mut self, id: FormId) -> ContentStyle {
1048        let i = id.0 as usize;
1049        let forms = &self.inner.forms;
1050        let form = forms.get(i).map(|(_, f, _)| *f).unwrap_or(Form::new().0);
1051
1052        self.reset_count += form.style.attributes.has(Attribute::Reset) as usize;
1053
1054        self.forms.insert(self.final_form_start, (form, id));
1055        if !(id == M_SEL_ID || id == E_SEL_ID) {
1056            self.final_form_start += 1;
1057        }
1058
1059        let mut style = self.make_style();
1060        if self.reset_is_needed || self.reset_count > 0 {
1061            self.still_on_same_byte = true;
1062            self.reset_is_needed = true;
1063            style.attributes.set(Attribute::Reset);
1064        // Only when we are certain that all forms have been
1065        // printed, can we cull unnecessary colors for efficiency
1066        // (this happens most of the time).
1067        } else if !self.still_on_same_byte {
1068            self.still_on_same_byte = true;
1069            style.foreground_color = form.fg().and(style.foreground_color.or(Some(Color::Reset)));
1070            style.background_color = form.bg().and(style.background_color.or(Some(Color::Reset)));
1071            style.underline_color = form.ul().and(style.underline_color.or(Some(Color::Reset)));
1072        }
1073        style
1074    }
1075
1076    /// Removes the [`Form`] with the given `id` and returns the
1077    /// result, given previous triggers
1078    #[inline(always)]
1079    pub fn remove(&mut self, id: FormId) -> ContentStyle {
1080        let mut applied_forms = self.forms.iter().enumerate();
1081        let Some((i, &(form, _))) = applied_forms.rfind(|(_, (_, i))| *i == id) else {
1082            return absolute_style(&self.forms);
1083        };
1084
1085        self.reset_count -= form.style.attributes.has(Attribute::Reset) as usize;
1086        self.forms.remove(i);
1087        if id != M_SEL_ID && id != E_SEL_ID {
1088            self.final_form_start -= 1;
1089        }
1090
1091        let mut style = self.make_style();
1092        if !form.style.attributes.is_empty() || self.reset_is_needed || self.reset_count > 0 {
1093            self.still_on_same_byte = true;
1094            self.reset_is_needed = true;
1095            style.attributes.set(Attribute::Reset);
1096        // Only when we are certain that all forms have been
1097        // printed, can we cull unnecessary colors for efficiency
1098        // (this happens most of the time).
1099        } else if !self.still_on_same_byte {
1100            self.still_on_same_byte = true;
1101            style.foreground_color = form.fg().and(style.foreground_color.or(Some(Color::Reset)));
1102            style.background_color = form.bg().and(style.background_color.or(Some(Color::Reset)));
1103            style.underline_color = form.ul().and(style.underline_color.or(Some(Color::Reset)));
1104        }
1105        style
1106    }
1107
1108    /// Removes all [`Form`]s except the default one
1109    ///
1110    /// Should be used when a [`ResetState`] part is printed
1111    ///
1112    /// [`ResetState`]: crate::text::Part::ResetState
1113    #[inline(always)]
1114    pub fn reset(&mut self) -> ContentStyle {
1115        self.forms.splice(1.., []);
1116        self.make_style()
1117    }
1118
1119    /// Generates the form to be printed, given all the previously
1120    /// pushed forms in the `Form` stack.
1121    #[inline(always)]
1122    pub fn make_style(&self) -> ContentStyle {
1123        let mut style = ContentStyle::new();
1124
1125        for &(form, _) in &self.forms {
1126            style.foreground_color = form.fg().or(style.foreground_color);
1127            style.background_color = form.bg().or(style.background_color);
1128            style.underline_color = form.ul().or(style.underline_color);
1129            style.attributes = if form.attr().has(Attribute::Reset) {
1130                form.attr()
1131            } else {
1132                form.attr() | style.attributes
1133            }
1134        }
1135
1136        style
1137    }
1138
1139    #[inline(always)]
1140    pub fn apply_main_cursor(&mut self) -> ContentStyle {
1141        let style = self.apply(M_CUR_ID);
1142        self.final_form_start -= 1;
1143        style
1144    }
1145
1146    #[inline(always)]
1147    pub fn remove_main_cursor(&mut self) -> ContentStyle {
1148        let style = self.remove(M_CUR_ID);
1149        self.final_form_start += 1;
1150        style
1151    }
1152
1153    #[inline(always)]
1154    pub fn apply_extra_cursor(&mut self) -> ContentStyle {
1155        let style = self.apply(E_CUR_ID);
1156        self.final_form_start -= 1;
1157        style
1158    }
1159
1160    #[inline(always)]
1161    pub fn remove_extra_cursor(&mut self) -> ContentStyle {
1162        let style = self.remove(E_CUR_ID);
1163        self.final_form_start += 1;
1164        style
1165    }
1166
1167    /// Tells the [`Painter`] that it has printed a character
1168    pub fn confirm_printing(&mut self) {
1169        self.still_on_same_byte = false;
1170        self.reset_is_needed = false;
1171    }
1172
1173    /// The [`Form`] "ExtraCursor", and its shape.
1174    pub fn main_cursor(&self) -> Option<CursorShape> {
1175        self.inner.main_cursor
1176    }
1177
1178    /// The [`Form`] "ExtraCursor", and its shape.
1179    pub fn extra_cursor(&self) -> Option<CursorShape> {
1180        self.inner.extra_cursor
1181    }
1182
1183    /// The `"Default"` form's [`Form`]
1184    pub fn get_default(&self) -> Form {
1185        self.forms[0].0
1186    }
1187}
1188
1189pub(crate) fn set_sender(sender: Sender) {
1190    SENDER
1191        .set(sender)
1192        .unwrap_or_else(|_| panic!("Sender set more than once"));
1193}
1194
1195/// An enum that helps in the modification of forms
1196#[derive(Clone)]
1197enum FormType {
1198    Normal,
1199    Ref(usize),
1200    Weakest,
1201    WeakestRef(usize),
1202}
1203
1204/// The position of each form that eventually references the `n`th
1205fn refs_of(inner: &InnerPalette, refed: usize) -> Vec<usize> {
1206    let mut refs = Vec::new();
1207    for (i, (.., f_ty)) in inner.forms.iter().enumerate() {
1208        if let FormType::Ref(ref_id) | FormType::WeakestRef(ref_id) = f_ty
1209            && *ref_id == refed
1210        {
1211            refs.push(i);
1212            refs.extend(refs_of(inner, i));
1213        }
1214    }
1215    refs
1216}
1217
1218/// If form references would eventually lead to a loop
1219fn would_be_circular(inner: &InnerPalette, referee: usize, refed: usize) -> bool {
1220    if let (.., FormType::Ref(refed_ref) | FormType::WeakestRef(refed_ref)) = inner.forms[refed] {
1221        match refed_ref == referee {
1222            true => true,
1223            false => would_be_circular(inner, referee, refed_ref),
1224        }
1225    } else {
1226        false
1227    }
1228}
1229
1230/// Returns an absolute [`Form`]
1231fn absolute_style(list: &[(Form, FormId)]) -> ContentStyle {
1232    let mut style = ContentStyle::new();
1233
1234    for &(form, _) in list {
1235        style.foreground_color = form.fg().or(style.foreground_color);
1236        style.background_color = form.bg().or(style.background_color);
1237        style.underline_color = form.ul().or(style.underline_color);
1238        style.attributes = if form.attr().has(Attribute::Reset) {
1239            form.attr()
1240        } else {
1241            form.attr() | style.attributes
1242        }
1243    }
1244
1245    style
1246}
1247
1248fn position_and_form(forms: &mut Vec<(&str, Form, FormType)>, name: &'static str) -> (usize, Form) {
1249    if let Some((i, (_, form, _))) = forms.iter().enumerate().find(|(_, (lhs, ..))| *lhs == name) {
1250        (i, *form)
1251    } else if let Some((refed, _)) = name.rsplit_once('.') {
1252        let (i, form) = position_and_form(forms, refed);
1253        forms.push((name, form, FormType::WeakestRef(i)));
1254        (forms.len() - 1, form)
1255    } else {
1256        forms.push((name, Form::new().0, FormType::Weakest));
1257        (forms.len() - 1, Form::new().0)
1258    }
1259}
1260
1261/// Converts a string to a color, supporst hex, RGB and HSL
1262const fn str_to_color(str: &str) -> std::result::Result<Color, &'static str> {
1263    use core::str::from_utf8_unchecked as utf8_str;
1264    const fn strip_prefix<'a>(prefix: &str, str: &'a str) -> Option<&'a str> {
1265        let prefix = prefix.as_bytes();
1266        let str = str.as_bytes();
1267
1268        let mut i = 0;
1269        while i < prefix.len() {
1270            if str[i] != prefix[i] {
1271                return None;
1272            }
1273            i += 1;
1274        }
1275
1276        let (_, str) = str.split_at(prefix.len());
1277        Some(unsafe { utf8_str(str) })
1278    }
1279    const fn strip_suffix<'a>(suffix: &str, str: &'a str) -> Option<&'a str> {
1280        let prefix = suffix.as_bytes();
1281        let str = str.as_bytes();
1282
1283        let mut i = str.len() - 1;
1284        while i >= str.len() - prefix.len() {
1285            if str[i] != prefix[i - (str.len() - prefix.len())] {
1286                return None;
1287            }
1288            i += 1;
1289        }
1290
1291        let (str, _) = str.split_at(str.len() - suffix.len());
1292        Some(unsafe { utf8_str(str) })
1293    }
1294    const fn split_space(str: &str) -> Option<(&str, &str)> {
1295        if str.is_empty() {
1296            return None;
1297        }
1298        let str = str.as_bytes();
1299
1300        let mut i = 0;
1301        while i < str.len() {
1302            if str[i] == b' ' {
1303                break;
1304            }
1305            i += 1;
1306        }
1307
1308        let (cut, rest) = str.split_at(i);
1309        let (_, rest) = rest.split_at(if rest.is_empty() { 0 } else { 1 });
1310        Some(unsafe { (utf8_str(cut), utf8_str(rest)) })
1311    }
1312    const fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
1313        t = if t < 0.0 { t + 1.0 } else { t };
1314        t = if t > 1.0 { t - 1.0 } else { t };
1315        if t < 1.0 / 6.0 {
1316            p + (q - p) * 6.0 * t
1317        } else if t < 1.0 / 2.0 {
1318            q
1319        } else if t < 2.0 / 3.0 {
1320            p + (q - p) * (2.0 / 3.0 - t) * 6.0
1321        } else {
1322            p
1323        }
1324    }
1325
1326    // Expects "#{red:x}{green:x}{blue:x}"
1327    if let Some(hex) = strip_prefix("#", str) {
1328        let total = match u32::from_str_radix(hex, 16) {
1329            Ok(total) if hex.len() == 6 => total,
1330            _ => return Err("Hexcode does not contain 6 hex values"),
1331        };
1332        let r = (total >> 16) as u8;
1333        let g = (total >> 8) as u8;
1334        let b = total as u8;
1335
1336        Ok(Color::Rgb { r, g, b })
1337        // Expects "rgb {red} {green} {blue}"
1338    } else if let Some(mut rgb) = strip_prefix("rgb ", str) {
1339        let mut values = [0, 0, 0];
1340        let mut i = 0;
1341        while i < values.len() {
1342            if let Some((cut, rest)) = split_space(rgb) {
1343                rgb = rest;
1344                values[i] = match u8::from_str_radix(cut, 10) {
1345                    Ok(value) => value,
1346                    Err(_) => return Err("Rgb format value could not be parsed"),
1347                }
1348            } else {
1349                return Err("Missing value in rgb format");
1350            }
1351            i += 1;
1352        }
1353
1354        let [r, g, b] = values;
1355        Ok(Color::Rgb { r, g, b })
1356        // Expects "hsl {hue%?} {saturation%?} {lightness%?}"
1357    } else if let Some(mut hsl) = strip_prefix("hsl ", str) {
1358        let mut values = [0.0, 0.0, 0.0];
1359        let mut i = 0;
1360        while i < values.len() {
1361            if let Some((cut, rest)) = split_space(hsl) {
1362                hsl = rest;
1363                let (num, div) = match strip_suffix("%", cut) {
1364                    Some(perc) => (perc, 100),
1365                    None => (cut, 255),
1366                };
1367                values[i] = match u8::from_str_radix(num, 10) {
1368                    Ok(value) if value <= div => value as f32 / div as f32,
1369                    _ => return Err("Hsl format property could not be parsed"),
1370                }
1371            } else {
1372                return Err("Missing value in hsl format");
1373            }
1374            i += 1;
1375        }
1376        let [hue, sat, lit] = values;
1377
1378        let (r, g, b) = if sat == 0.0 {
1379            (lit, lit, lit)
1380        } else {
1381            let q = if lit < 0.5 {
1382                lit * (1.0 + sat)
1383            } else {
1384                lit + sat - lit * sat
1385            };
1386            let p = 2.0 * lit - q;
1387            let r = hue_to_rgb(p, q, hue + 1.0 / 3.0);
1388            let g = hue_to_rgb(p, q, hue);
1389            let b = hue_to_rgb(p, q, hue - 1.0 / 3.0);
1390            (r, g, b)
1391        };
1392
1393        // + 0.5 because `as` rounds floats down.
1394        let r = (0.5 + r * 255.0) as u8;
1395        let g = (0.5 + g * 255.0) as u8;
1396        let b = (0.5 + b * 255.0) as u8;
1397        Ok(Color::Rgb { r, g, b })
1398    } else {
1399        return Err("Color format was not recognized");
1400    }
1401}
1402
1403impl std::fmt::Debug for Form {
1404    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1405        struct DebugColor(Option<Color>);
1406        impl std::fmt::Debug for DebugColor {
1407            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1408                match self.0 {
1409                    Some(Color::Rgb { r, g, b }) => write!(f, "Some(Rgb({r}, {g}, {b}))"),
1410                    Some(Color::AnsiValue(ansi)) => write!(f, "Some(Ansi({ansi}))"),
1411                    Some(color) => write!(f, "Some({color:?})"),
1412                    None => f.write_str("None"),
1413                }
1414            }
1415        }
1416
1417        struct DebugAttributes(Attributes);
1418        impl std::fmt::Debug for DebugAttributes {
1419            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1420                if self.0.is_empty() {
1421                    f.write_str("None")
1422                } else {
1423                    let mut is_first = true;
1424                    for attr in Attribute::iterator() {
1425                        if self.0.has(attr) {
1426                            if !is_first {
1427                                f.write_str(" | ")?;
1428                            }
1429                            is_first = false;
1430                            write!(f, "{attr:?}")?;
1431                        }
1432                    }
1433                    Ok(())
1434                }
1435            }
1436        }
1437
1438        f.debug_struct("Form")
1439            .field("fg", &DebugColor(self.style.foreground_color))
1440            .field("bg", &DebugColor(self.style.background_color))
1441            .field("ul", &DebugColor(self.style.underline_color))
1442            .field("attr", &DebugAttributes(self.style.attributes))
1443            .finish()
1444    }
1445}
1446
1447impl std::fmt::Debug for InnerPalette {
1448    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1449        struct DebugForms<'a>(&'a [(&'static str, Form, FormType)]);
1450        impl std::fmt::Debug for DebugForms<'_> {
1451            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1452                if f.alternate() {
1453                    f.write_str("[\n")?;
1454					let max = self.0.len().ilog10() as usize + 3;
1455                    for (n, entry) in self.0.iter().enumerate() {
1456                        let num = format!("{n}:");
1457                        writeln!(f, "{num:<max$}{entry:#?}")?;
1458                    }
1459                    f.write_str("]")
1460                } else {
1461                    write!(f, "{:?}", self.0)
1462                }
1463            }
1464        }
1465
1466        struct DebugCursorShape(CursorShape);
1467        impl std::fmt::Debug for DebugCursorShape {
1468            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1469                match self.0 {
1470                    CursorShape::DefaultUserShape => f.write_str("DefaultUserShape"),
1471                    CursorShape::BlinkingBlock => f.write_str("BlinkingBlock"),
1472                    CursorShape::SteadyBlock => f.write_str("SteadyBlock"),
1473                    CursorShape::BlinkingUnderScore => f.write_str("BlinkingUnderScore"),
1474                    CursorShape::SteadyUnderScore => f.write_str("SteadyUnderScore"),
1475                    CursorShape::BlinkingBar => f.write_str("BlinkingBar"),
1476                    CursorShape::SteadyBar => f.write_str("SteadyBar"),
1477                }
1478            }
1479        }
1480
1481        f.debug_struct("InnerPalette")
1482            .field("main_cursor", &self.main_cursor.map(DebugCursorShape))
1483            .field("extra_cursor", &self.extra_cursor.map(DebugCursorShape))
1484            .field("forms", &DebugForms(&self.forms))
1485            .finish()
1486    }
1487}
1488
1489impl std::fmt::Debug for FormType {
1490    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1491        match self {
1492            Self::Normal => write!(f, "Normal"),
1493            Self::Ref(refed) => write!(f, "Ref({refed})"),
1494            Self::Weakest => write!(f, "Weakest"),
1495            Self::WeakestRef(refed) => write!(f, "WeakestRef({refed})"),
1496        }
1497    }
1498}
1499
1500/// Mimics [`ContentStyle`] methods for the [`Form`] type
1501macro mimic_method_new {
1502    (#[$attr:meta] $method:ident $attrib:expr) => {
1503        /// New [`Form`] with the
1504        #[$attr]
1505        /// attribute
1506        pub const fn $method() -> BuiltForm {
1507            let mut built = Form::new();
1508            built.0.style.attributes = built.0.style.attributes.with($attrib);
1509            built
1510        }
1511    },
1512
1513    (#[$attr:meta] $fg:ident $bg:ident $ul:ident $color:expr) => {
1514        /// New [`Form`] with a
1515        #[$attr]
1516        /// foreground
1517        pub const fn $fg() -> BuiltForm {
1518            let mut built = Form::new();
1519            built.0.style.foreground_color = Some($color);
1520            built
1521        }
1522
1523        /// New [`Form`] with a
1524        #[$attr]
1525        /// background
1526        pub const fn $bg() -> BuiltForm {
1527            let mut built = Form::new();
1528            built.0.style.background_color = Some($color);
1529            built
1530        }
1531
1532        /// New [`Form`] with a
1533        #[$attr]
1534        /// underlining
1535        ///
1536        /// Do note that this feature may not be supported in all [`Ui`]s.
1537        ///
1538        /// [`Ui`]: crate::ui::Ui
1539        pub const fn $ul() -> BuiltForm {
1540            let mut built = Form::new();
1541            built.0.style.underline_color = Some($color);
1542            built
1543        }
1544    }
1545}
1546
1547macro mimic_method_mod {
1548    (#[$attr:meta] $method:ident $attrib:expr) => {
1549        /// Applies the
1550        #[$attr]
1551        /// attribute to this [`Form`]
1552        pub const fn $method(mut self) -> Self {
1553            self.0.style.attributes = self.0.style.attributes.with($attrib);
1554            self
1555        }
1556    },
1557
1558    (#[$attr:meta] $fg:ident $bg:ident $ul:ident $color:expr) => {
1559        /// Turns the foreground of this [`Form`]
1560        #[$attr]
1561        pub const fn $fg(mut self) -> Self {
1562            self.0.style.foreground_color = Some($color);
1563            self
1564        }
1565
1566		/// Turns the background of this [`Form`]
1567        #[$attr]
1568        pub const fn $bg(mut self) -> Self {
1569            self.0.style.background_color = Some($color);
1570            self
1571        }
1572
1573		/// Turns the underlining of this [`Form`]
1574        #[$attr]
1575        ///
1576        /// Do note that this feature may not be supported in all [`Ui`]s.
1577        ///
1578        /// [`Ui`]: crate::ui::Ui
1579        pub const fn $ul(mut self) -> Self {
1580            self.0.style.underline_color = Some($color);
1581            self
1582        }
1583    }
1584}