duat_core/
form.rs

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