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