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