diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index d6ecfce3c3..6e62ce2a9f 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -4,7 +4,7 @@ use alacritty_terminal::{ event_loop::{EventLoop, Msg, Notifier}, grid::Scroll, sync::FairMutex, - term::{color::Rgb, SizeInfo}, + term::{color::Rgb as AlacRgb, SizeInfo}, tty, Term, }; @@ -13,8 +13,8 @@ use futures::{ StreamExt, }; use gpui::{ - actions, elements::*, impl_internal_actions, platform::CursorStyle, ClipboardItem, Entity, - MutableAppContext, View, ViewContext, + actions, color::Color, elements::*, impl_internal_actions, platform::CursorStyle, + ClipboardItem, Entity, MutableAppContext, View, ViewContext, }; use project::{Project, ProjectPath}; use settings::Settings; @@ -22,7 +22,7 @@ use smallvec::SmallVec; use std::{path::PathBuf, sync::Arc}; use workspace::{Item, Workspace}; -use crate::terminal_element::TerminalEl; +use crate::terminal_element::{get_color_at_index, TerminalEl}; //ASCII Control characters on a keyboard //Consts -> Structs -> Impls -> Functions, Vaguely in order of importance @@ -203,9 +203,26 @@ impl Terminal { cx, ), AlacTermEvent::ColorRequest(index, format) => { - //TODO test this as well - //TODO: change to getting the display colors, like alacrityy, instead of a default - let color = self.term.lock().colors()[index].unwrap_or(Rgb::default()); + let color = self.term.lock().colors()[index].unwrap_or_else(|| { + let term_style = &cx.global::().theme.terminal; + match index { + 0..=255 => to_alac_rgb(get_color_at_index(&(index as u8), term_style)), + 256 => to_alac_rgb(term_style.foreground), + 257 => to_alac_rgb(term_style.background), + 258 => to_alac_rgb(term_style.cursor), + 259 => to_alac_rgb(term_style.dim_black), + 260 => to_alac_rgb(term_style.dim_red), + 261 => to_alac_rgb(term_style.dim_green), + 262 => to_alac_rgb(term_style.dim_yellow), + 263 => to_alac_rgb(term_style.dim_blue), + 264 => to_alac_rgb(term_style.dim_magenta), + 265 => to_alac_rgb(term_style.dim_cyan), + 266 => to_alac_rgb(term_style.dim_white), + 267 => to_alac_rgb(term_style.bright_foreground), + 268 => to_alac_rgb(term_style.black), //Dim Background, non-standard + _ => AlacRgb { r: 0, g: 0, b: 0 }, + } + }); self.write_to_pty(&Input(format(color)), cx) } AlacTermEvent::CursorBlinkingChange => { @@ -420,6 +437,14 @@ impl Item for Terminal { } } +fn to_alac_rgb(color: Color) -> AlacRgb { + AlacRgb { + r: color.r, + g: color.g, + b: color.g, + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 2002b5c144..b0c01391ca 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -329,10 +329,59 @@ fn alac_color_to_gpui_color(allac_color: &AnsiColor, style: &TerminalStyle) -> C alacritty_terminal::ansi::NamedColor::DimForeground => style.dim_foreground, }, //Theme defined alacritty_terminal::ansi::Color::Spec(rgb) => Color::new(rgb.r, rgb.g, rgb.b, 1), - alacritty_terminal::ansi::Color::Indexed(_) => Color::white(), //Color cube weirdness + alacritty_terminal::ansi::Color::Indexed(i) => get_color_at_index(i, style), //Color cube weirdness } } +pub fn get_color_at_index(index: &u8, style: &TerminalStyle) -> Color { + match index { + 0 => style.black, + 1 => style.red, + 2 => style.green, + 3 => style.yellow, + 4 => style.blue, + 5 => style.magenta, + 6 => style.cyan, + 7 => style.white, + 8 => style.bright_black, + 9 => style.bright_red, + 10 => style.bright_green, + 11 => style.bright_yellow, + 12 => style.bright_blue, + 13 => style.bright_magenta, + 14 => style.bright_cyan, + 15 => style.bright_white, + 16..=231 => { + let (r, g, b) = rgb_for_index(index); //Split the index into it's rgb components + let step = (u8::MAX as f32 / 5.).round() as u8; //Split the GPUI range into 5 chunks + Color::new(r * step, g * step, b * step, 1) //Map the rgb components to GPUI's range + } + //Grayscale from black to white, 0 to 24 + 232..=255 => { + let i = 24 - (index - 232); //Align index to 24..0 + let step = (u8::MAX as f32 / 24.).round() as u8; //Split the 256 range grayscale into 24 chunks + Color::new(i * step, i * step, i * step, 1) //Map the rgb components to GPUI's range + } + } +} + +///Generates the rgb channels in [0, 5] for a given index into the 6x6x6 ANSI color cube +///See: [8 bit ansi color](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit). +/// +///Wikipedia gives a formula for calculating the index for a given color: +/// +///index = 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) +/// +///This function does the reverse, calculating the r, g, and b components from a given index. +fn rgb_for_index(i: &u8) -> (u8, u8, u8) { + debug_assert!(i >= &16 && i <= &231); + let i = i - 16; + let r = (i - (i % 36)) / 36; + let g = ((i % 36) - (i % 6)) / 6; + let b = (i % 36) % 6; + (r, g, b) +} + #[cfg(debug_assertions)] fn draw_debug_grid(bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) { let width = layout.cur_size.width(); @@ -361,3 +410,16 @@ fn draw_debug_grid(bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContex }); } } + +mod tests { + use crate::terminal_element::rgb_for_index; + + #[test] + fn test_rgb_for_index() { + //Test every possible value in the color cube + for i in 16..=231 { + let (r, g, b) = rgb_for_index(&(i as u8)); + assert_eq!(i, 16 + 36 * r + 6 * g + b); + } + } +}