colors.rs

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