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