colors.rs

  1use alacritty_terminal::{ansi::Color as AnsiColor, term::color::Rgb as AlacRgb};
  2use gpui::color::Color;
  3use theme::TerminalStyle;
  4
  5///Converts a 2, 8, or 24 bit color ANSI color to the GPUI equivalent
  6pub fn convert_color(alac_color: &AnsiColor, style: &TerminalStyle) -> Color {
  7    match alac_color {
  8        //Named and theme defined colors
  9        alacritty_terminal::ansi::Color::Named(n) => match n {
 10            alacritty_terminal::ansi::NamedColor::Black => style.black,
 11            alacritty_terminal::ansi::NamedColor::Red => style.red,
 12            alacritty_terminal::ansi::NamedColor::Green => style.green,
 13            alacritty_terminal::ansi::NamedColor::Yellow => style.yellow,
 14            alacritty_terminal::ansi::NamedColor::Blue => style.blue,
 15            alacritty_terminal::ansi::NamedColor::Magenta => style.magenta,
 16            alacritty_terminal::ansi::NamedColor::Cyan => style.cyan,
 17            alacritty_terminal::ansi::NamedColor::White => style.white,
 18            alacritty_terminal::ansi::NamedColor::BrightBlack => style.bright_black,
 19            alacritty_terminal::ansi::NamedColor::BrightRed => style.bright_red,
 20            alacritty_terminal::ansi::NamedColor::BrightGreen => style.bright_green,
 21            alacritty_terminal::ansi::NamedColor::BrightYellow => style.bright_yellow,
 22            alacritty_terminal::ansi::NamedColor::BrightBlue => style.bright_blue,
 23            alacritty_terminal::ansi::NamedColor::BrightMagenta => style.bright_magenta,
 24            alacritty_terminal::ansi::NamedColor::BrightCyan => style.bright_cyan,
 25            alacritty_terminal::ansi::NamedColor::BrightWhite => style.bright_white,
 26            alacritty_terminal::ansi::NamedColor::Foreground => style.foreground,
 27            alacritty_terminal::ansi::NamedColor::Background => style.background,
 28            alacritty_terminal::ansi::NamedColor::Cursor => style.cursor,
 29            alacritty_terminal::ansi::NamedColor::DimBlack => style.dim_black,
 30            alacritty_terminal::ansi::NamedColor::DimRed => style.dim_red,
 31            alacritty_terminal::ansi::NamedColor::DimGreen => style.dim_green,
 32            alacritty_terminal::ansi::NamedColor::DimYellow => style.dim_yellow,
 33            alacritty_terminal::ansi::NamedColor::DimBlue => style.dim_blue,
 34            alacritty_terminal::ansi::NamedColor::DimMagenta => style.dim_magenta,
 35            alacritty_terminal::ansi::NamedColor::DimCyan => style.dim_cyan,
 36            alacritty_terminal::ansi::NamedColor::DimWhite => style.dim_white,
 37            alacritty_terminal::ansi::NamedColor::BrightForeground => style.bright_foreground,
 38            alacritty_terminal::ansi::NamedColor::DimForeground => style.dim_foreground,
 39        },
 40        //'True' colors
 41        alacritty_terminal::ansi::Color::Spec(rgb) => Color::new(rgb.r, rgb.g, rgb.b, u8::MAX),
 42        //8 bit, indexed colors
 43        alacritty_terminal::ansi::Color::Indexed(i) => get_color_at_index(&(*i as usize), style),
 44    }
 45}
 46
 47///Converts an 8 bit ANSI color to it's GPUI equivalent.
 48///Accepts usize for compatibility with the alacritty::Colors interface,
 49///Other than that use case, should only be called with values in the [0,255] range
 50pub fn get_color_at_index(index: &usize, style: &TerminalStyle) -> Color {
 51    match index {
 52        //0-15 are the same as the named colors above
 53        0 => style.black,
 54        1 => style.red,
 55        2 => style.green,
 56        3 => style.yellow,
 57        4 => style.blue,
 58        5 => style.magenta,
 59        6 => style.cyan,
 60        7 => style.white,
 61        8 => style.bright_black,
 62        9 => style.bright_red,
 63        10 => style.bright_green,
 64        11 => style.bright_yellow,
 65        12 => style.bright_blue,
 66        13 => style.bright_magenta,
 67        14 => style.bright_cyan,
 68        15 => style.bright_white,
 69        //16-231 are mapped to their RGB colors on a 0-5 range per channel
 70        16..=231 => {
 71            let (r, g, b) = rgb_for_index(&(*index as u8)); //Split the index into it's ANSI-RGB components
 72            let step = (u8::MAX as f32 / 5.).floor() as u8; //Split the RGB range into 5 chunks, with floor so no overflow
 73            Color::new(r * step, g * step, b * step, u8::MAX) //Map the ANSI-RGB components to an RGB color
 74        }
 75        //232-255 are a 24 step grayscale from black to white
 76        232..=255 => {
 77            let i = *index as u8 - 232; //Align index to 0..24
 78            let step = (u8::MAX as f32 / 24.).floor() as u8; //Split the RGB grayscale values into 24 chunks
 79            Color::new(i * step, i * step, i * step, u8::MAX) //Map the ANSI-grayscale components to the RGB-grayscale
 80        }
 81        //For compatibility with the alacritty::Colors interface
 82        256 => style.foreground,
 83        257 => style.background,
 84        258 => style.cursor,
 85        259 => style.dim_black,
 86        260 => style.dim_red,
 87        261 => style.dim_green,
 88        262 => style.dim_yellow,
 89        263 => style.dim_blue,
 90        264 => style.dim_magenta,
 91        265 => style.dim_cyan,
 92        266 => style.dim_white,
 93        267 => style.bright_foreground,
 94        268 => style.black, //'Dim Background', non-standard color
 95        _ => Color::new(0, 0, 0, 255),
 96    }
 97}
 98///Generates the rgb channels in [0, 5] for a given index into the 6x6x6 ANSI color cube
 99///See: [8 bit ansi color](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit).
100///
101///Wikipedia gives a formula for calculating the index for a given color:
102///
103///index = 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
104///
105///This function does the reverse, calculating the r, g, and b components from a given index.
106fn rgb_for_index(i: &u8) -> (u8, u8, u8) {
107    debug_assert!((&16..=&231).contains(&i));
108    let i = i - 16;
109    let r = (i - (i % 36)) / 36;
110    let g = ((i % 36) - (i % 6)) / 6;
111    let b = (i % 36) % 6;
112    (r, g, b)
113}
114
115//Convenience method to convert from a GPUI color to an alacritty Rgb
116pub fn to_alac_rgb(color: Color) -> AlacRgb {
117    AlacRgb {
118        r: color.r,
119        g: color.g,
120        b: color.g,
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    #[test]
127    fn test_rgb_for_index() {
128        //Test every possible value in the color cube
129        for i in 16..=231 {
130            let (r, g, b) = crate::mappings::colors::rgb_for_index(&(i as u8));
131            assert_eq!(i, 16 + 36 * r + 6 * g + b);
132        }
133    }
134}