Skip to main content

duat_core/
form.rs

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