rat_theme4/
palette.rs

1//!
2//! [Palette] is the color palette for salsa-themes.
3//!
4//! It has graduations for white, black, gray, red, orange,
5//! yellow, limegreen, green, bluegreen, cyan, blue, deepblue,
6//! purple, magenta and a redpink.
7//! And it has a primary and a secondary highlight color.
8//! And it has graduations for light/dark text.
9//!
10//! There is an algorithm that chooses the text-color for a
11//! given background.
12//!
13//! And there is a semantic layer, that can give names to
14//! specific colors. It's these names/aliases that are primarily
15//! used when composing everything into a theme.
16//!
17//! This way salsa-theme can have one dark theme that works
18//! with multiple palettes.
19//!
20
21use ratatui::style::{Color, Style};
22#[cfg(feature = "serde")]
23use serde::de::{Error, MapAccess, SeqAccess, Unexpected, Visitor};
24#[cfg(feature = "serde")]
25use serde::ser::SerializeStruct;
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Deserializer, Serialize, Serializer};
28use std::borrow::Cow;
29use std::fmt::{Display, Formatter};
30use std::mem;
31use std::str::FromStr;
32
33/// Refers to a color in the Palette.
34/// This is used for color-aliases.
35#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
36pub struct ColorIdx(pub Colors, pub usize);
37
38/// Names/Indexes into the color-table of the palette.
39#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub enum Colors {
41    /// Colors for light text.
42    TextLight = 0,
43    /// Colors for dark text.
44    TextDark,
45    /// Primary highlight color.
46    Primary,
47    /// Secondary highlight color.
48    Secondary,
49    White,
50    Black,
51    Gray,
52    Red,
53    Orange,
54    Yellow,
55    LimeGreen,
56    Green,
57    BlueGreen,
58    Cyan,
59    Blue,
60    DeepBlue,
61    Purple,
62    Magenta,
63    RedPink,
64    /// Undefined color.
65    ///
66    /// Maps to Color::Reset when queried as a color.
67    /// When used to define a style fg or bg it sets them to [Option::None].
68    #[default]
69    None,
70}
71
72impl Display for ColorIdx {
73    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
74        write!(f, "{}:{}", self.0, self.1)
75    }
76}
77
78#[derive(Debug)]
79pub struct ColorIdxError;
80
81impl Display for ColorIdxError {
82    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
83        write!(f, "{:?}", self)
84    }
85}
86
87impl std::error::Error for ColorIdxError {}
88
89impl FromStr for ColorIdx {
90    type Err = ColorIdxError;
91
92    fn from_str(s: &str) -> Result<Self, Self::Err> {
93        let mut ss = s.split(':');
94        let Some(name) = ss.next() else {
95            return Err(ColorIdxError);
96        };
97        let Ok(c) = Colors::from_str(name) else {
98            return Err(ColorIdxError);
99        };
100        let Some(idx) = ss.next() else {
101            return Err(ColorIdxError);
102        };
103        let Ok(idx) = idx.parse::<usize>() else {
104            return Err(ColorIdxError);
105        };
106        Ok(ColorIdx(c, idx))
107    }
108}
109
110#[cfg(feature = "serde")]
111impl Serialize for ColorIdx {
112    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
113    where
114        S: Serializer,
115    {
116        ser.serialize_str(&self.to_string())
117    }
118}
119
120#[cfg(feature = "serde")]
121struct ColorIdxVisitor;
122
123#[cfg(feature = "serde")]
124impl<'de> Visitor<'de> for ColorIdxVisitor {
125    type Value = ColorIdx;
126
127    fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
128        write!(f, "ColorIdx")
129    }
130
131    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
132    where
133        E: serde::de::Error,
134    {
135        v.parse::<ColorIdx>()
136            .map_err(|_| serde::de::Error::invalid_value(Unexpected::Str(v), &self))
137    }
138}
139
140#[cfg(feature = "serde")]
141impl<'de> Deserialize<'de> for ColorIdx {
142    fn deserialize<D>(des: D) -> Result<Self, D::Error>
143    where
144        D: Deserializer<'de>,
145    {
146        des.deserialize_str(ColorIdxVisitor)
147    }
148}
149
150impl Display for Colors {
151    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152        write!(f, "{}", self.str())
153    }
154}
155
156impl FromStr for Colors {
157    type Err = ();
158
159    fn from_str(s: &str) -> Result<Self, Self::Err> {
160        match s {
161            "text-light" => Ok(Colors::TextLight),
162            "text-dark" => Ok(Colors::TextDark),
163            "primary" => Ok(Colors::Primary),
164            "secondary" => Ok(Colors::Secondary),
165            "white" => Ok(Colors::White),
166            "black" => Ok(Colors::Black),
167            "gray" => Ok(Colors::Gray),
168            "red" => Ok(Colors::Red),
169            "orange" => Ok(Colors::Orange),
170            "yellow" => Ok(Colors::Yellow),
171            "lime-green" => Ok(Colors::LimeGreen),
172            "green" => Ok(Colors::Green),
173            "blue-green" => Ok(Colors::BlueGreen),
174            "cyan" => Ok(Colors::Cyan),
175            "blue" => Ok(Colors::Blue),
176            "deep-blue" => Ok(Colors::DeepBlue),
177            "purple" => Ok(Colors::Purple),
178            "magenta" => Ok(Colors::Magenta),
179            "red-pink" => Ok(Colors::RedPink),
180            "none" => Ok(Colors::None),
181            _ => Err(()),
182        }
183    }
184}
185
186impl Colors {
187    pub const LEN: usize = 19;
188
189    pub fn array() -> &'static [Colors] {
190        use Colors::*;
191        // don't include None!
192        &[
193            TextLight, TextDark, Primary, Secondary, White, Black, Gray, Red, Orange, Yellow,
194            LimeGreen, Green, BlueGreen, Cyan, Blue, DeepBlue, Purple, Magenta, RedPink,
195        ]
196    }
197
198    pub const fn str(self) -> &'static str {
199        match self {
200            Colors::TextLight => "text-light",
201            Colors::TextDark => "text-dark",
202            Colors::Primary => "primary",
203            Colors::Secondary => "secondary",
204            Colors::White => "white",
205            Colors::Black => "black",
206            Colors::Gray => "gray",
207            Colors::Red => "red",
208            Colors::Orange => "orange",
209            Colors::Yellow => "yellow",
210            Colors::LimeGreen => "lime-green",
211            Colors::Green => "green",
212            Colors::BlueGreen => "blue-green",
213            Colors::Cyan => "cyan",
214            Colors::Blue => "blue",
215            Colors::DeepBlue => "deep-blue",
216            Colors::Purple => "purple",
217            Colors::Magenta => "magenta",
218            Colors::RedPink => "red-pink",
219            Colors::None => "none",
220        }
221    }
222}
223
224/// Color palette.
225///
226/// This provides the palette used for a theme.
227#[derive(Debug, Clone, PartialEq, Eq)]
228pub struct Palette {
229    /// Name of the theme.
230    pub theme_name: Cow<'static, str>,
231    /// Which theme should be created.
232    /// Known themes:
233    /// * Dark
234    /// * Light
235    /// * Shell
236    /// There are 3 more special cased themes for fallback/testing
237    /// purposes.
238    /// * Core - Fallback theme if something fails.
239    /// * Blackout - Testing theme that blacks everything.
240    /// * Fallback - Testing theme that relies on each widget's own defaults.
241    pub theme: Cow<'static, str>,
242    /// Name of the color palette.
243    pub name: Cow<'static, str>,
244    /// Doc string.
245    pub doc: Cow<'static, str>,
246    /// Generator function.
247    /// Determines how the palette is stored.
248    /// Currently:
249    /// * light-dark:N
250    ///   stores color[0] and color[3] and interpolates between them.
251    ///   color[4]..=color[7] are generated by scaling the rgb values
252    ///   down to N.
253    // maybe:
254    // color-1 : aaaaaaaa
255    // color-2 : aaaabbbb
256    // color-4 : abcdabcd
257    // color-4-dark:N: abcdABCD
258    // color-8 : abcdefgh
259    pub generator: Cow<'static, str>,
260    /// Color palette. Use [Colors] for indexing.
261    pub color: [[Color; 8]; Colors::LEN],
262    /// **Sorted** list of aliases.
263    /// Must be pre-sorted for binary-search.
264    pub aliased: Cow<'static, [(Cow<'static, str>, ColorIdx)]>,
265}
266
267#[cfg(feature = "serde")]
268impl Serialize for Palette {
269    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
270    where
271        S: Serializer,
272    {
273        let mut pal = ser.serialize_struct("Palette", 25)?;
274        pal.serialize_field("theme_name", &self.theme_name)?;
275        pal.serialize_field("theme", &self.theme)?;
276        pal.serialize_field("name", &self.name)?;
277        pal.serialize_field("doc", &self.doc)?;
278        pal.serialize_field("generator", &self.generator)?;
279        if self.generator.starts_with("light-dark") {
280            for cc in Colors::array() {
281                pal.serialize_field(
282                    cc.str(),
283                    &(self.color[*cc as usize][0], self.color[*cc as usize][3]),
284                )?;
285            }
286        }
287        pal.serialize_field("aliased", &self.aliased)?;
288        pal.end()
289    }
290}
291
292#[cfg(feature = "serde")]
293struct PaletteVisitor;
294
295#[cfg(feature = "serde")]
296impl<'de> Visitor<'de> for PaletteVisitor {
297    type Value = Palette;
298
299    fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
300        write!(f, "struct Palette")
301    }
302
303    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
304    where
305        A: SeqAccess<'de>,
306    {
307        let mut pal = Palette::default();
308        pal.theme_name = seq
309            .next_element::<Cow<'static, str>>()?
310            .ok_or(A::Error::invalid_length(0, &"Palette.theme_name"))?;
311        pal.theme = seq
312            .next_element::<Cow<'static, str>>()?
313            .ok_or(A::Error::invalid_length(0, &"Palette.theme"))?;
314        pal.name = seq
315            .next_element::<Cow<'static, str>>()?
316            .ok_or(A::Error::invalid_length(0, &"Palette.name"))?;
317        pal.doc = seq
318            .next_element::<Cow<'static, str>>()?
319            .ok_or(A::Error::invalid_length(0, &"Palette.doc"))?;
320        pal.generator = seq
321            .next_element::<Cow<'static, str>>()?
322            .ok_or(A::Error::invalid_length(0, &"Palette.generator"))?;
323        if pal.generator.starts_with("light-dark") {
324            let mut dark = 63;
325            if let Some(s) = pal.generator.split(':').nth(1) {
326                dark = s.trim().parse::<u8>().unwrap_or(63);
327            }
328
329            for cn in Colors::array() {
330                let (c0, c3) = seq
331                    .next_element::<(Color, Color)>()?
332                    .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
333
334                if *cn == Colors::TextLight || *cn == Colors::TextDark {
335                    pal.color[*cn as usize] =
336                        Palette::interpolatec2(c0, c3, Color::default(), Color::default())
337                } else {
338                    pal.color[*cn as usize] = Palette::interpolatec(c0, c3, dark);
339                }
340            }
341        } else {
342            return Err(A::Error::invalid_type(
343                Unexpected::Str(&pal.generator),
344                &"expected 'light-dark:N'",
345            ));
346        }
347        pal.aliased = seq
348            .next_element::<Cow<'static, [(Cow<'static, str>, ColorIdx)]>>()?
349            .ok_or(A::Error::invalid_length(0, &"Palette.aliased"))?;
350
351        Ok(pal)
352    }
353
354    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
355    where
356        A: MapAccess<'de>,
357    {
358        let mut pal = Palette::default();
359        while let Some(key) = map.next_key::<&str>()? {
360            match key {
361                "theme_name" => pal.theme_name = map.next_value::<Cow<'static, str>>()?,
362                "theme" => pal.theme = map.next_value::<Cow<'static, str>>()?,
363                "name" => pal.name = map.next_value::<Cow<'static, str>>()?,
364                "doc" => pal.doc = map.next_value::<Cow<'static, str>>()?,
365                "generator" => {
366                    pal.generator = map.next_value::<Cow<'static, str>>()?;
367                }
368                "aliased" => {
369                    pal.aliased =
370                        map.next_value::<Cow<'static, [(Cow<'static, str>, ColorIdx)]>>()?
371                }
372                c_str => {
373                    let cn =
374                        Colors::from_str(c_str).map_err(|_| A::Error::unknown_field(c_str, &[]))?;
375                    if pal.generator.starts_with("light-dark") {
376                        let mut dark = 63;
377                        if let Some(s) = pal.generator.split(':').nth(1) {
378                            dark = s.trim().parse::<u8>().unwrap_or(63);
379                        }
380                        let (c0, c3) = map.next_value::<(Color, Color)>()?;
381                        if cn == Colors::TextLight || cn == Colors::TextDark {
382                            pal.color[cn as usize] =
383                                Palette::interpolatec2(c0, c3, Color::default(), Color::default())
384                        } else {
385                            pal.color[cn as usize] = Palette::interpolatec(c0, c3, dark);
386                        }
387                    } else {
388                        return Err(A::Error::invalid_type(
389                            Unexpected::Str(&pal.generator),
390                            &"expected 'light-dark:N'",
391                        ));
392                    }
393                }
394            }
395        }
396
397        Ok(pal)
398    }
399}
400
401#[cfg(feature = "serde")]
402impl<'de> Deserialize<'de> for Palette {
403    fn deserialize<D>(des: D) -> Result<Self, D::Error>
404    where
405        D: Deserializer<'de>,
406    {
407        use Colors::*;
408        const FIELDS: &'static [&'static str] = &[
409            "theme_name",
410            "theme",
411            "name",
412            "doc",
413            "generator",
414            TextLight.str(),
415            TextDark.str(),
416            Primary.str(),
417            Secondary.str(),
418            White.str(),
419            Black.str(),
420            Gray.str(),
421            Red.str(),
422            Orange.str(),
423            Yellow.str(),
424            LimeGreen.str(),
425            Green.str(),
426            BlueGreen.str(),
427            Cyan.str(),
428            Blue.str(),
429            DeepBlue.str(),
430            Purple.str(),
431            Magenta.str(),
432            RedPink.str(),
433            "aliased",
434        ];
435        des.deserialize_struct("Palette", FIELDS, PaletteVisitor)
436    }
437}
438
439impl Default for Palette {
440    fn default() -> Self {
441        Self {
442            theme_name: Default::default(),
443            theme: Default::default(),
444            name: Default::default(),
445            doc: Default::default(),
446            generator: Default::default(),
447            color: Default::default(),
448            aliased: Default::default(),
449        }
450    }
451}
452
453/// Contrast rating for the text-color that should be used.
454#[derive(Debug)]
455pub(crate) enum Rating {
456    /// Use light/white text for the given background.
457    Light,
458    /// Use dark/black text for the given background.
459    Dark,
460}
461
462/// Create a color alias. Useful when creating a static Palette.
463pub const fn define_alias(
464    alias: &'static str,
465    color: Colors,
466    n: usize,
467) -> (Cow<'static, str>, ColorIdx) {
468    (Cow::Borrowed(alias), ColorIdx(color, n))
469}
470
471/// Create a color alias. This function is useful when
472/// modifying a Palette at runtime.
473pub fn define_rt_alias(
474    alias: impl Into<String>,
475    color: Colors,
476    n: usize,
477) -> (Cow<'static, str>, ColorIdx) {
478    let alias = alias.into();
479    (Cow::Owned(alias), ColorIdx(color, n))
480}
481
482impl Palette {
483    /// Create a style from the given white shade.
484    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
485    pub fn white(&self, n: usize) -> Style {
486        self.style(Colors::White, n)
487    }
488
489    /// Create a style from the given black shade.
490    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
491    pub fn black(&self, n: usize) -> Style {
492        self.style(Colors::Black, n)
493    }
494
495    /// Create a style from the given gray shade.
496    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
497    pub fn gray(&self, n: usize) -> Style {
498        self.style(Colors::Gray, n)
499    }
500
501    /// Create a style from the given red shade.
502    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
503    pub fn red(&self, n: usize) -> Style {
504        self.style(Colors::Red, n)
505    }
506
507    /// Create a style from the given orange shade.
508    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
509    pub fn orange(&self, n: usize) -> Style {
510        self.style(Colors::Orange, n)
511    }
512
513    /// Create a style from the given yellow shade.
514    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
515    pub fn yellow(&self, n: usize) -> Style {
516        self.style(Colors::Yellow, n)
517    }
518
519    /// Create a style from the given limegreen shade.
520    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
521    pub fn limegreen(&self, n: usize) -> Style {
522        self.style(Colors::LimeGreen, n)
523    }
524
525    /// Create a style from the given green shade.
526    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
527    pub fn green(&self, n: usize) -> Style {
528        self.style(Colors::Green, n)
529    }
530
531    /// Create a style from the given bluegreen shade.
532    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
533    pub fn bluegreen(&self, n: usize) -> Style {
534        self.style(Colors::BlueGreen, n)
535    }
536
537    /// Create a style from the given cyan shade.
538    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
539    pub fn cyan(&self, n: usize) -> Style {
540        self.style(Colors::Cyan, n)
541    }
542
543    /// Create a style from the given blue shade.
544    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
545    pub fn blue(&self, n: usize) -> Style {
546        self.style(Colors::Blue, n)
547    }
548
549    /// Create a style from the given deepblue shade.
550    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
551    pub fn deepblue(&self, n: usize) -> Style {
552        self.style(Colors::DeepBlue, n)
553    }
554
555    /// Create a style from the given purple shade.
556    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
557    pub fn purple(&self, n: usize) -> Style {
558        self.style(Colors::Purple, n)
559    }
560
561    /// Create a style from the given magenta shade.
562    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
563    pub fn magenta(&self, n: usize) -> Style {
564        self.style(Colors::Magenta, n)
565    }
566
567    /// Create a style from the given redpink shade.
568    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
569    pub fn redpink(&self, n: usize) -> Style {
570        self.style(Colors::RedPink, n)
571    }
572
573    /// Create a style from the given primary shade.
574    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
575    pub fn primary(&self, n: usize) -> Style {
576        self.style(Colors::Primary, n)
577    }
578
579    /// Create a style from the given secondary shade.
580    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
581    pub fn secondary(&self, n: usize) -> Style {
582        self.style(Colors::Secondary, n)
583    }
584}
585
586impl Palette {
587    /// The Color for the id + index n.
588    pub fn color(&self, id: Colors, n: usize) -> Color {
589        if id == Colors::None {
590            Color::Reset
591        } else {
592            self.color[id as usize][n]
593        }
594    }
595
596    /// Create a style with the given background color.
597    /// The foreground is chosen from the text-colors for a
598    /// normal contrast.
599    pub fn style(&self, id: Colors, n: usize) -> Style {
600        let color = self.color(id, n);
601        self.normal_contrast(color)
602    }
603
604    /// Create a style with the given background color.
605    /// The foreground is chosen from the text-colors for
606    /// high contrast.
607    pub fn high_style(&self, id: Colors, n: usize) -> Style {
608        let color = self.color(id, n);
609        self.high_contrast(color)
610    }
611
612    /// Create a style with the given fg/bg.
613    pub fn fg_bg_style(&self, fg: Colors, n: usize, bg: Colors, m: usize) -> Style {
614        let color = self.color(fg, n);
615        let color_bg = self.color(bg, m);
616        let mut style = Style::new();
617        if color != Color::Reset {
618            style = style.fg(color);
619        }
620        if color_bg != Color::Reset {
621            style = style.bg(color_bg);
622        }
623        style
624    }
625
626    /// Create a style with only fg set.
627    pub fn fg_style(&self, id: Colors, n: usize) -> Style {
628        let color = self.color(id, n);
629        let mut style = Style::new();
630        if color != Color::Reset {
631            style = style.fg(color);
632        }
633        style
634    }
635
636    /// Create a style with only bg set.
637    pub fn bg_style(&self, id: Colors, n: usize) -> Style {
638        let color = self.color(id, n);
639        let mut style = Style::new();
640        if color != Color::Reset {
641            style = style.bg(color);
642        }
643        style
644    }
645
646    /// Add an alias.
647    pub fn add_aliased(&mut self, id: &str, color_idx: ColorIdx) {
648        if matches!(self.aliased, Cow::Borrowed(_)) {
649            self.aliased = Cow::Owned(mem::take(&mut self.aliased).into_owned());
650        }
651        match &mut self.aliased {
652            Cow::Borrowed(_) => {
653                unreachable!()
654            }
655            Cow::Owned(aliased) => {
656                aliased.push((Cow::Owned(id.to_string()), color_idx));
657                aliased.sort();
658            }
659        }
660    }
661
662    /// Try to find an alias.
663    pub fn try_aliased(&self, id: &str) -> Option<ColorIdx> {
664        match self.aliased.binary_search_by_key(&id, |v| v.0.as_ref()) {
665            Ok(n) => Some(self.aliased[n].1),
666            Err(_) => None,
667        }
668    }
669
670    /// Get the ColorIdx of an aliased color.
671    ///
672    /// __Panic__
673    ///
674    /// With debug_assertions this panics if the alias is not found.
675    /// Otherwise, it returns a default.
676    pub fn aliased(&self, id: &str) -> ColorIdx {
677        match self.try_aliased(id) {
678            Some(c) => c,
679            None => {
680                if cfg!(debug_assertions) {
681                    panic!("unknown aliased color {:?} in palette {:?}", id, self.name);
682                } else {
683                    ColorIdx::default()
684                }
685            }
686        }
687    }
688
689    /// Get an aliased color.
690    pub fn color_alias(&self, id: &str) -> Color {
691        match self.try_aliased(id) {
692            Some(ColorIdx { 0: c, 1: idx }) => {
693                if c != Colors::None {
694                    self.color[c as usize][idx]
695                } else {
696                    Color::default()
697                }
698            }
699            None => {
700                if cfg!(debug_assertions) {
701                    panic!("unknown aliased color {:?} in palette {:?}", id, self.name);
702                } else {
703                    Color::default()
704                }
705            }
706        }
707    }
708
709    /// Get a Style for a color-alias.
710    /// Uses the color as bg() and finds the matching text-color
711    /// for normal contrast.
712    pub fn style_alias(&self, bg: &str) -> Style {
713        let color = self.color_alias(bg);
714        self.normal_contrast(color)
715    }
716
717    /// Get a Style for a color-alias.
718    /// Uses the color as bg() and finds the matching text-color
719    /// for high contrast.
720    pub fn high_style_alias(&self, bg: &str) -> Style {
721        let color = self.color_alias(bg);
722        self.high_contrast(color)
723    }
724
725    /// Get a Style for a color-alias.
726    /// Uses explicit aliases for fg() and bg()
727    pub fn fg_bg_style_alias(&self, fg: &str, bg: &str) -> Style {
728        let color = self.color_alias(fg);
729        let color_bg = self.color_alias(bg);
730        let mut style = Style::new();
731        if color != Color::Reset {
732            style = style.fg(color);
733        }
734        if color_bg != Color::Reset {
735            style = style.bg(color_bg);
736        }
737        style
738    }
739
740    /// Get a Style for a color-alias.
741    /// This creates a style with only the fg() color set.
742    pub fn fg_style_alias(&self, fg: &str) -> Style {
743        let color = self.color_alias(fg);
744        let mut style = Style::new();
745        if color != Color::Reset {
746            style = style.fg(color);
747        }
748        style
749    }
750
751    /// Get a Style for a color-alias.
752    /// This creates a style with only the bg() color set.
753    pub fn bg_style_alias(&self, bg: &str) -> Style {
754        let color = self.color_alias(bg);
755        let mut style = Style::new();
756        if color != Color::Reset {
757            style = style.bg(color);
758        }
759        style
760    }
761}
762
763impl Palette {
764    /// Create a style with the given background color.
765    /// Uses `white[3]` or `black[0]` for the foreground,
766    /// based on `rate_text_color`.
767    pub fn high_contrast(&self, color: Color) -> Style {
768        match Self::rate_text_color(color) {
769            None => Style::new(),
770            Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 3)),
771            Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 3)),
772        }
773    }
774
775    /// Create a style with the given background color.
776    /// Uses text_light or text_dark for the foreground,
777    /// based on `rate_text_color`.
778    pub fn normal_contrast(&self, color: Color) -> Style {
779        match Self::rate_text_color(color) {
780            None => Style::new(),
781            Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 0)),
782            Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 0)),
783        }
784    }
785
786    /// Pick a color from the choice with a good contrast to the
787    /// given background.
788    pub fn normal_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
789        if bg == Color::Reset {
790            return Style::new();
791        }
792        let mut color0 = text[0];
793        let mut color1 = text[0];
794        let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
795
796        for text_color in text {
797            let test = Self::contrast_bt_srgb(*text_color, bg);
798            if test > contrast1 {
799                color0 = color1;
800                color1 = *text_color;
801                contrast1 = test;
802            }
803        }
804
805        Style::new().bg(bg).fg(color0)
806    }
807
808    /// Pick a color from the choice with the best contrast to the
809    /// given background.
810    pub fn high_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
811        if bg == Color::Reset {
812            return Style::new();
813        }
814        let mut color0 = text[0];
815        let mut color1 = text[0];
816        let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
817
818        for text_color in text {
819            let test = Self::contrast_bt_srgb(*text_color, bg);
820            if test > contrast1 {
821                color0 = color1;
822                color1 = *text_color;
823                contrast1 = test;
824            }
825        }
826        // don't use the second brightest.
827        _ = color0;
828
829        Style::new().bg(bg).fg(color1)
830    }
831
832    // /// Gives the luminance according to Rec.ITU-R BT.601-7.
833    // const fn luminance_itu(color: Color) -> f32 {
834    //     let (r, g, b) = Self::color2rgb(color);
835    //     0.2989f32 * (r as f32) / 255f32
836    //         + 0.5870f32 * (g as f32) / 255f32
837    //         + 0.1140f32 * (b as f32) / 255f32
838    // }
839    //
840    // /// Gives the luminance according to Rec.ITU-R BT.601-7.
841    // fn luminance_itu_srgb(color: Color) -> f32 {
842    //     let (r, g, b) = Self::color2rgb(color);
843    //     0.2989f32 * (r as f32) / 255f32
844    //         + 0.5870f32 * (g as f32) / 255f32
845    //         + 0.1140f32 * (b as f32) / 255f32
846    // }
847    //
848    // /// Contrast between two colors.
849    // fn contrast_itu_srgb(color: Color, color2: Color) -> f32 {
850    //     let lum1 = Self::luminance_itu_srgb(color);
851    //     let lum2 = Self::luminance_itu_srgb(color2);
852    //     (lum1 + 0.05f32) / (lum2 + 0.05f32)
853    // }
854
855    /// Gives the luminance according to BT.709.
856    pub(crate) const fn luminance_bt(color: Color) -> f32 {
857        let (r, g, b) = Self::color_to_rgb(color);
858        0.2126f32 * ((r as f32) / 255f32)
859            + 0.7152f32 * ((g as f32) / 255f32)
860            + 0.0722f32 * ((b as f32) / 255f32)
861    }
862
863    /// Gives the luminance according to BT.709.
864    pub(crate) fn luminance_bt_srgb(color: Color) -> f32 {
865        let (r, g, b) = Self::color_to_rgb(color);
866        0.2126f32 * ((r as f32) / 255f32).powf(2.2f32)
867            + 0.7152f32 * ((g as f32) / 255f32).powf(2.2f32)
868            + 0.0722f32 * ((b as f32) / 255f32).powf(2.2f32)
869    }
870
871    /// Contrast between two colors.
872    pub(crate) fn contrast_bt_srgb(color: Color, color2: Color) -> f32 {
873        let lum1 = Self::luminance_bt_srgb(color);
874        let lum2 = Self::luminance_bt_srgb(color2);
875        (lum1 - lum2).abs()
876        // Don't use this prescribed method.
877        // The abs diff comes out better.
878        // (lum1 + 0.05f32) / (lum2 + 0.05f32)
879    }
880
881    /// This gives back a [Rating] for the given background.
882    ///
883    /// This converts RGB to grayscale and takes the grayscale value
884    /// of VGA cyan as threshold, which is about 105 out of 255.
885    /// This point is a bit arbitrary, just based on what I
886    /// perceive as acceptable. But it produces a good reading
887    /// contrast in my experience.
888    ///
889    /// For the named colors it takes the VGA equivalent as a base.
890    /// For indexed colors it splits the range in half as an estimate.
891    pub(crate) fn rate_text_color(color: Color) -> Option<Rating> {
892        match color {
893            Color::Reset => None,
894            Color::Black => Some(Rating::Light),       //0
895            Color::Red => Some(Rating::Light),         //1
896            Color::Green => Some(Rating::Light),       //2
897            Color::Yellow => Some(Rating::Light),      //3
898            Color::Blue => Some(Rating::Light),        //4
899            Color::Magenta => Some(Rating::Light),     //5
900            Color::Cyan => Some(Rating::Light),        //6
901            Color::Gray => Some(Rating::Dark),         //7
902            Color::DarkGray => Some(Rating::Light),    //8
903            Color::LightRed => Some(Rating::Dark),     //9
904            Color::LightGreen => Some(Rating::Dark),   //10
905            Color::LightYellow => Some(Rating::Dark),  //11
906            Color::LightBlue => Some(Rating::Light),   //12
907            Color::LightMagenta => Some(Rating::Dark), //13
908            Color::LightCyan => Some(Rating::Dark),    //14
909            Color::White => Some(Rating::Dark),        //15
910            c => {
911                let lum = Self::luminance_bt(c);
912                if lum >= 0.4117f32 {
913                    Some(Rating::Dark)
914                } else {
915                    Some(Rating::Light)
916                }
917            }
918        }
919    }
920
921    /// Converts the given color to an equivalent grayscale.
922    pub const fn grayscale(color: Color) -> Color {
923        let lum = Self::luminance_bt(color);
924        let gray = lum * 255f32;
925        Color::Rgb(gray as u8, gray as u8, gray as u8)
926    }
927
928    /// Color from u32
929    pub const fn color_from_u32(c: u32) -> Color {
930        let r0 = (c >> 16) as u8;
931        let g0 = (c >> 8) as u8;
932        let b0 = c as u8;
933        Color::Rgb(r0, g0, b0)
934    }
935
936    /// Color to u32
937    pub const fn color_to_u32(color: Color) -> u32 {
938        let (r, g, b) = Self::color_to_rgb(color);
939        ((r as u32) << 16) + ((g as u32) << 8) + (b as u32)
940    }
941
942    /// Calculates a linear interpolation for the two colors
943    /// and fills the first 4 colors with it.
944    /// The next 4 colors are scaled down versions using dark_scale_to.
945    pub const fn interpolatec(c0: Color, c3: Color, dark_scale_to: u8) -> [Color; 8] {
946        Self::interpolate(
947            Self::color_to_u32(c0),
948            Self::color_to_u32(c3),
949            dark_scale_to,
950        )
951    }
952
953    /// Calculates a linear interpolation for the two colors
954    /// and fills the first 4 colors with it.
955    /// The next 4 colors are scaled down versions using dark_scale_to.
956    pub const fn interpolate(c0: u32, c3: u32, dark_scale_to: u8) -> [Color; 8] {
957        // dark
958        let mut c4 = Self::color_to_rgb(Self::color_from_u32(c0));
959        c4.0 = Self::scale_to(c4.0, dark_scale_to);
960        c4.1 = Self::scale_to(c4.1, dark_scale_to);
961        c4.2 = Self::scale_to(c4.2, dark_scale_to);
962        let c4 = ((c4.0 as u32) << 16) + ((c4.1 as u32) << 8) + (c4.2 as u32);
963
964        let mut c7 = Self::color_to_rgb(Self::color_from_u32(c3));
965        c7.0 = Self::scale_to(c7.0, dark_scale_to);
966        c7.1 = Self::scale_to(c7.1, dark_scale_to);
967        c7.2 = Self::scale_to(c7.2, dark_scale_to);
968        let c7 = ((c7.0 as u32) << 16) + ((c7.1 as u32) << 8) + (c7.2 as u32);
969
970        Self::interpolate2(c0, c3, c4, c7)
971    }
972
973    /// Calculates a linear interpolation for the two colors
974    /// and fills the first 4 colors with it.
975    /// The next 4 colors are scaled down versions using dark_scale_to.
976    pub const fn interpolatec2(c0: Color, c3: Color, c4: Color, c7: Color) -> [Color; 8] {
977        Self::interpolate2(
978            Self::color_to_u32(c0),
979            Self::color_to_u32(c3),
980            Self::color_to_u32(c4),
981            Self::color_to_u32(c7),
982        )
983    }
984
985    /// Calculates a linear interpolation for the two colors
986    /// and fills the first 4 colors with it.
987    /// The next 4 colors are scaled down versions using dark_scale_to.
988    pub const fn interpolate2(c0: u32, c3: u32, c4: u32, c7: u32) -> [Color; 8] {
989        // 1/3
990        const fn i1(a: u8, b: u8) -> u8 {
991            if a < b {
992                a + (b - a) / 3
993            } else {
994                a - (a - b) / 3
995            }
996        }
997        // 2/3
998        const fn i2(a: u8, b: u8) -> u8 {
999            if a < b {
1000                b - (b - a) / 3
1001            } else {
1002                b + (a - b) / 3
1003            }
1004        }
1005
1006        let r0 = (c0 >> 16) as u8;
1007        let g0 = (c0 >> 8) as u8;
1008        let b0 = c0 as u8;
1009
1010        let r3 = (c3 >> 16) as u8;
1011        let g3 = (c3 >> 8) as u8;
1012        let b3 = c3 as u8;
1013
1014        let r1 = i1(r0, r3);
1015        let g1 = i1(g0, g3);
1016        let b1 = i1(b0, b3);
1017
1018        let r2 = i2(r0, r3);
1019        let g2 = i2(g0, g3);
1020        let b2 = i2(b0, b3);
1021
1022        // dark
1023        let r4 = (c4 >> 16) as u8;
1024        let g4 = (c4 >> 8) as u8;
1025        let b4 = c4 as u8;
1026
1027        let r7 = (c7 >> 16) as u8;
1028        let g7 = (c7 >> 8) as u8;
1029        let b7 = c7 as u8;
1030
1031        let r5 = i1(r4, r7);
1032        let g5 = i1(g4, g7);
1033        let b5 = i1(b4, b7);
1034
1035        let r6 = i2(r4, r7);
1036        let g6 = i2(g4, g7);
1037        let b6 = i2(b4, b7);
1038
1039        [
1040            Color::Rgb(r0, g0, b0),
1041            Color::Rgb(r1, g1, b1),
1042            Color::Rgb(r2, g2, b2),
1043            Color::Rgb(r3, g3, b3),
1044            Color::Rgb(r4, g4, b4),
1045            Color::Rgb(r5, g5, b5),
1046            Color::Rgb(r6, g6, b6),
1047            Color::Rgb(r7, g7, b7),
1048        ]
1049    }
1050
1051    /// Scale the u8 down to scale_to.
1052    pub const fn scale_to(v: u8, scale_to: u8) -> u8 {
1053        (((v as u16) * scale_to as u16) / 255u16) as u8
1054    }
1055
1056    /// Gives back the rgb for any ratatui Color.
1057    /// Has the indexed and the named colors too.
1058    pub const fn color_to_rgb(color: Color) -> (u8, u8, u8) {
1059        match color {
1060            Color::Black => (0x00, 0x00, 0x00),
1061            Color::Red => (0xaa, 0x00, 0x00),
1062            Color::Green => (0x00, 0xaa, 0x00),
1063            Color::Yellow => (0xaa, 0x55, 0x00),
1064            Color::Blue => (0x00, 0x00, 0xaa),
1065            Color::Magenta => (0xaa, 0x00, 0xaa),
1066            Color::Cyan => (0x00, 0xaa, 0xaa),
1067            Color::Gray => (0xaa, 0xaa, 0xaa),
1068            Color::DarkGray => (0x55, 0x55, 0x55),
1069            Color::LightRed => (0xff, 0x55, 0x55),
1070            Color::LightGreen => (0x55, 0xff, 0x55),
1071            Color::LightYellow => (0xff, 0xff, 0x55),
1072            Color::LightBlue => (0x55, 0x55, 0xff),
1073            Color::LightMagenta => (0xff, 0x55, 0xff),
1074            Color::LightCyan => (0x55, 0xff, 0xff),
1075            Color::White => (0xff, 0xff, 0xff),
1076            Color::Rgb(r, g, b) => (r, g, b),
1077            Color::Indexed(i) => {
1078                const VGA256: [(u8, u8, u8); 256] = [
1079                    (0x00, 0x00, 0x00),
1080                    (0x80, 0x00, 0x00),
1081                    (0x00, 0x80, 0x00),
1082                    (0x80, 0x80, 0x00),
1083                    (0x00, 0x00, 0x80),
1084                    (0x80, 0x00, 0x80),
1085                    (0x00, 0x80, 0x80),
1086                    (0xc0, 0xc0, 0xc0),
1087                    (0x80, 0x80, 0x80),
1088                    (0xff, 0x00, 0x00),
1089                    (0x00, 0xff, 0x00),
1090                    (0xff, 0xff, 0x00),
1091                    (0x00, 0x00, 0xff),
1092                    (0xff, 0x00, 0xff),
1093                    (0x00, 0xff, 0xff),
1094                    (0xff, 0xff, 0xff),
1095                    (0x00, 0x00, 0x00),
1096                    (0x00, 0x00, 0x5f),
1097                    (0x00, 0x00, 0x87),
1098                    (0x00, 0x00, 0xaf),
1099                    (0x00, 0x00, 0xd7),
1100                    (0x00, 0x00, 0xff),
1101                    (0x00, 0x5f, 0x00),
1102                    (0x00, 0x5f, 0x5f),
1103                    (0x00, 0x5f, 0x87),
1104                    (0x00, 0x5f, 0xaf),
1105                    (0x00, 0x5f, 0xd7),
1106                    (0x00, 0x5f, 0xff),
1107                    (0x00, 0x87, 0x00),
1108                    (0x00, 0x87, 0x5f),
1109                    (0x00, 0x87, 0x87),
1110                    (0x00, 0x87, 0xaf),
1111                    (0x00, 0x87, 0xd7),
1112                    (0x00, 0x87, 0xff),
1113                    (0x00, 0xaf, 0x00),
1114                    (0x00, 0xaf, 0x5f),
1115                    (0x00, 0xaf, 0x87),
1116                    (0x00, 0xaf, 0xaf),
1117                    (0x00, 0xaf, 0xd7),
1118                    (0x00, 0xaf, 0xff),
1119                    (0x00, 0xd7, 0x00),
1120                    (0x00, 0xd7, 0x5f),
1121                    (0x00, 0xd7, 0x87),
1122                    (0x00, 0xd7, 0xaf),
1123                    (0x00, 0xd7, 0xd7),
1124                    (0x00, 0xd7, 0xff),
1125                    (0x00, 0xff, 0x00),
1126                    (0x00, 0xff, 0x5f),
1127                    (0x00, 0xff, 0x87),
1128                    (0x00, 0xff, 0xaf),
1129                    (0x00, 0xff, 0xd7),
1130                    (0x00, 0xff, 0xff),
1131                    (0x5f, 0x00, 0x00),
1132                    (0x5f, 0x00, 0x5f),
1133                    (0x5f, 0x00, 0x87),
1134                    (0x5f, 0x00, 0xaf),
1135                    (0x5f, 0x00, 0xd7),
1136                    (0x5f, 0x00, 0xff),
1137                    (0x5f, 0x5f, 0x00),
1138                    (0x5f, 0x5f, 0x5f),
1139                    (0x5f, 0x5f, 0x87),
1140                    (0x5f, 0x5f, 0xaf),
1141                    (0x5f, 0x5f, 0xd7),
1142                    (0x5f, 0x5f, 0xff),
1143                    (0x5f, 0x87, 0x00),
1144                    (0x5f, 0x87, 0x5f),
1145                    (0x5f, 0x87, 0x87),
1146                    (0x5f, 0x87, 0xaf),
1147                    (0x5f, 0x87, 0xd7),
1148                    (0x5f, 0x87, 0xff),
1149                    (0x5f, 0xaf, 0x00),
1150                    (0x5f, 0xaf, 0x5f),
1151                    (0x5f, 0xaf, 0x87),
1152                    (0x5f, 0xaf, 0xaf),
1153                    (0x5f, 0xaf, 0xd7),
1154                    (0x5f, 0xaf, 0xff),
1155                    (0x5f, 0xd7, 0x00),
1156                    (0x5f, 0xd7, 0x5f),
1157                    (0x5f, 0xd7, 0x87),
1158                    (0x5f, 0xd7, 0xaf),
1159                    (0x5f, 0xd7, 0xd7),
1160                    (0x5f, 0xd7, 0xff),
1161                    (0x5f, 0xff, 0x00),
1162                    (0x5f, 0xff, 0x5f),
1163                    (0x5f, 0xff, 0x87),
1164                    (0x5f, 0xff, 0xaf),
1165                    (0x5f, 0xff, 0xd7),
1166                    (0x5f, 0xff, 0xff),
1167                    (0x87, 0x00, 0x00),
1168                    (0x87, 0x00, 0x5f),
1169                    (0x87, 0x00, 0x87),
1170                    (0x87, 0x00, 0xaf),
1171                    (0x87, 0x00, 0xd7),
1172                    (0x87, 0x00, 0xff),
1173                    (0x87, 0x5f, 0x00),
1174                    (0x87, 0x5f, 0x5f),
1175                    (0x87, 0x5f, 0x87),
1176                    (0x87, 0x5f, 0xaf),
1177                    (0x87, 0x5f, 0xd7),
1178                    (0x87, 0x5f, 0xff),
1179                    (0x87, 0x87, 0x00),
1180                    (0x87, 0x87, 0x5f),
1181                    (0x87, 0x87, 0x87),
1182                    (0x87, 0x87, 0xaf),
1183                    (0x87, 0x87, 0xd7),
1184                    (0x87, 0x87, 0xff),
1185                    (0x87, 0xaf, 0x00),
1186                    (0x87, 0xaf, 0x5f),
1187                    (0x87, 0xaf, 0x87),
1188                    (0x87, 0xaf, 0xaf),
1189                    (0x87, 0xaf, 0xd7),
1190                    (0x87, 0xaf, 0xff),
1191                    (0x87, 0xd7, 0x00),
1192                    (0x87, 0xd7, 0x5f),
1193                    (0x87, 0xd7, 0x87),
1194                    (0x87, 0xd7, 0xaf),
1195                    (0x87, 0xd7, 0xd7),
1196                    (0x87, 0xd7, 0xff),
1197                    (0x87, 0xff, 0x00),
1198                    (0x87, 0xff, 0x5f),
1199                    (0x87, 0xff, 0x87),
1200                    (0x87, 0xff, 0xaf),
1201                    (0x87, 0xff, 0xd7),
1202                    (0x87, 0xff, 0xff),
1203                    (0xaf, 0x00, 0x00),
1204                    (0xaf, 0x00, 0x5f),
1205                    (0xaf, 0x00, 0x87),
1206                    (0xaf, 0x00, 0xaf),
1207                    (0xaf, 0x00, 0xd7),
1208                    (0xaf, 0x00, 0xff),
1209                    (0xaf, 0x5f, 0x00),
1210                    (0xaf, 0x5f, 0x5f),
1211                    (0xaf, 0x5f, 0x87),
1212                    (0xaf, 0x5f, 0xaf),
1213                    (0xaf, 0x5f, 0xd7),
1214                    (0xaf, 0x5f, 0xff),
1215                    (0xaf, 0x87, 0x00),
1216                    (0xaf, 0x87, 0x5f),
1217                    (0xaf, 0x87, 0x87),
1218                    (0xaf, 0x87, 0xaf),
1219                    (0xaf, 0x87, 0xd7),
1220                    (0xaf, 0x87, 0xff),
1221                    (0xaf, 0xaf, 0x00),
1222                    (0xaf, 0xaf, 0x5f),
1223                    (0xaf, 0xaf, 0x87),
1224                    (0xaf, 0xaf, 0xaf),
1225                    (0xaf, 0xaf, 0xd7),
1226                    (0xaf, 0xaf, 0xff),
1227                    (0xaf, 0xd7, 0x00),
1228                    (0xaf, 0xd7, 0x5f),
1229                    (0xaf, 0xd7, 0x87),
1230                    (0xaf, 0xd7, 0xaf),
1231                    (0xaf, 0xd7, 0xd7),
1232                    (0xaf, 0xd7, 0xff),
1233                    (0xaf, 0xff, 0x00),
1234                    (0xaf, 0xff, 0x5f),
1235                    (0xaf, 0xff, 0x87),
1236                    (0xaf, 0xff, 0xaf),
1237                    (0xaf, 0xff, 0xd7),
1238                    (0xaf, 0xff, 0xff),
1239                    (0xd7, 0x00, 0x00),
1240                    (0xd7, 0x00, 0x5f),
1241                    (0xd7, 0x00, 0x87),
1242                    (0xd7, 0x00, 0xaf),
1243                    (0xd7, 0x00, 0xd7),
1244                    (0xd7, 0x00, 0xff),
1245                    (0xd7, 0x5f, 0x00),
1246                    (0xd7, 0x5f, 0x5f),
1247                    (0xd7, 0x5f, 0x87),
1248                    (0xd7, 0x5f, 0xaf),
1249                    (0xd7, 0x5f, 0xd7),
1250                    (0xd7, 0x5f, 0xff),
1251                    (0xd7, 0x87, 0x00),
1252                    (0xd7, 0x87, 0x5f),
1253                    (0xd7, 0x87, 0x87),
1254                    (0xd7, 0x87, 0xaf),
1255                    (0xd7, 0x87, 0xd7),
1256                    (0xd7, 0x87, 0xff),
1257                    (0xd7, 0xaf, 0x00),
1258                    (0xd7, 0xaf, 0x5f),
1259                    (0xd7, 0xaf, 0x87),
1260                    (0xd7, 0xaf, 0xaf),
1261                    (0xd7, 0xaf, 0xd7),
1262                    (0xd7, 0xaf, 0xff),
1263                    (0xd7, 0xd7, 0x00),
1264                    (0xd7, 0xd7, 0x5f),
1265                    (0xd7, 0xd7, 0x87),
1266                    (0xd7, 0xd7, 0xaf),
1267                    (0xd7, 0xd7, 0xd7),
1268                    (0xd7, 0xd7, 0xff),
1269                    (0xd7, 0xff, 0x00),
1270                    (0xd7, 0xff, 0x5f),
1271                    (0xd7, 0xff, 0x87),
1272                    (0xd7, 0xff, 0xaf),
1273                    (0xd7, 0xff, 0xd7),
1274                    (0xd7, 0xff, 0xff),
1275                    (0xff, 0x00, 0x00),
1276                    (0xff, 0x00, 0x5f),
1277                    (0xff, 0x00, 0x87),
1278                    (0xff, 0x00, 0xaf),
1279                    (0xff, 0x00, 0xd7),
1280                    (0xff, 0x00, 0xff),
1281                    (0xff, 0x5f, 0x00),
1282                    (0xff, 0x5f, 0x5f),
1283                    (0xff, 0x5f, 0x87),
1284                    (0xff, 0x5f, 0xaf),
1285                    (0xff, 0x5f, 0xd7),
1286                    (0xff, 0x5f, 0xff),
1287                    (0xff, 0x87, 0x00),
1288                    (0xff, 0x87, 0x5f),
1289                    (0xff, 0x87, 0x87),
1290                    (0xff, 0x87, 0xaf),
1291                    (0xff, 0x87, 0xd7),
1292                    (0xff, 0x87, 0xff),
1293                    (0xff, 0xaf, 0x00),
1294                    (0xff, 0xaf, 0x5f),
1295                    (0xff, 0xaf, 0x87),
1296                    (0xff, 0xaf, 0xaf),
1297                    (0xff, 0xaf, 0xd7),
1298                    (0xff, 0xaf, 0xff),
1299                    (0xff, 0xd7, 0x00),
1300                    (0xff, 0xd7, 0x5f),
1301                    (0xff, 0xd7, 0x87),
1302                    (0xff, 0xd7, 0xaf),
1303                    (0xff, 0xd7, 0xd7),
1304                    (0xff, 0xd7, 0xff),
1305                    (0xff, 0xff, 0x00),
1306                    (0xff, 0xff, 0x5f),
1307                    (0xff, 0xff, 0x87),
1308                    (0xff, 0xff, 0xaf),
1309                    (0xff, 0xff, 0xd7),
1310                    (0xff, 0xff, 0xff),
1311                    (0x08, 0x08, 0x08),
1312                    (0x12, 0x12, 0x12),
1313                    (0x1c, 0x1c, 0x1c),
1314                    (0x26, 0x26, 0x26),
1315                    (0x30, 0x30, 0x30),
1316                    (0x3a, 0x3a, 0x3a),
1317                    (0x44, 0x44, 0x44),
1318                    (0x4e, 0x4e, 0x4e),
1319                    (0x58, 0x58, 0x58),
1320                    (0x62, 0x62, 0x62),
1321                    (0x6c, 0x6c, 0x6c),
1322                    (0x76, 0x76, 0x76),
1323                    (0x80, 0x80, 0x80),
1324                    (0x8a, 0x8a, 0x8a),
1325                    (0x94, 0x94, 0x94),
1326                    (0x9e, 0x9e, 0x9e),
1327                    (0xa8, 0xa8, 0xa8),
1328                    (0xb2, 0xb2, 0xb2),
1329                    (0xbc, 0xbc, 0xbc),
1330                    (0xc6, 0xc6, 0xc6),
1331                    (0xd0, 0xd0, 0xd0),
1332                    (0xda, 0xda, 0xda),
1333                    (0xe4, 0xe4, 0xe4),
1334                    (0xee, 0xee, 0xee),
1335                ];
1336                VGA256[i as usize]
1337            }
1338            Color::Reset => (0, 0, 0),
1339        }
1340    }
1341}