duat_core/
form.rs

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