diff --git a/src/terminal_pane/terminal_character.rs b/src/terminal_pane/terminal_character.rs index a591652f..acf32f1f 100644 --- a/src/terminal_pane/terminal_character.rs +++ b/src/terminal_pane/terminal_character.rs @@ -20,9 +20,11 @@ pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum AnsiCode { + On, Reset, NamedColor(NamedColor), - Code((Option, Option)), + RGBCode((u8, u8, u8)), + ColorIndex(u8), } #[derive(Clone, Copy, Eq, PartialEq, Debug)] @@ -300,77 +302,131 @@ impl CharacterStyles { } pub fn add_style_from_ansi_params(&mut self, ansi_params: &[i64]) { let mut params_used = 1; // if there's a parameter, it is always used - match ansi_params { - [] | [0, ..] => self.reset_all(), - [39, ..] => *self = self.foreground(Some(AnsiCode::Reset)), - [49, ..] => *self = self.background(Some(AnsiCode::Reset)), - [21, ..] => *self = self.bold(Some(AnsiCode::Reset)), - [22, ..] => { - *self = self.bold(Some(AnsiCode::Reset)); - *self = self.dim(Some(AnsiCode::Reset)); - } - [23, ..] => *self = self.italic(Some(AnsiCode::Reset)), - [24, ..] => *self = self.underline(Some(AnsiCode::Reset)), - [25, ..] => { - *self = self.blink_slow(Some(AnsiCode::Reset)); - *self = self.blink_fast(Some(AnsiCode::Reset)); - } - [27, ..] => *self = self.reverse(Some(AnsiCode::Reset)), - [28, ..] => *self = self.hidden(Some(AnsiCode::Reset)), - [29, ..] => *self = self.strike(Some(AnsiCode::Reset)), - [38, ..] => { - let ansi_code = AnsiCode::Code(( - ansi_params.get(1).map(|p| *p as u16), - ansi_params.get(2).map(|p| *p as u16), - )); - *self = self.foreground(Some(ansi_code)); - if ansi_params.len() > 2 { - params_used += ansi_params.len() - 1; + if ansi_params.is_empty() || ansi_params[0] == 0 { + self.reset_all(); + } else if ansi_params[0] == 39 { + *self = self.foreground(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 49 { + *self = self.background(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 21 { + *self = self.bold(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 22 { + *self = self.bold(Some(AnsiCode::Reset)); + *self = self.dim(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 23 { + *self = self.italic(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 24 { + *self = self.underline(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 25 { + *self = self.blink_slow(Some(AnsiCode::Reset)); + *self = self.blink_fast(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 27 { + *self = self.reverse(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 28 { + *self = self.hidden(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 29 { + *self = self.strike(Some(AnsiCode::Reset)); + } else if ansi_params[0] == 38 { + // TODO: + // * if 1 is 2 it is RGB, get it and next 3 + // * if 1 is 5, do what we did until now + match ansi_params.get(1) { + Some(2) => { + let ansi_code = AnsiCode::RGBCode(( + *ansi_params.get(2).unwrap() as u8, + *ansi_params.get(3).unwrap() as u8, + *ansi_params.get(4).unwrap() as u8, + )); + *self = self.foreground(Some(ansi_code)); + params_used += 4 // one for the indicator (2 in this case) and three for the rgb code + } + Some(5) => { + let ansi_code = AnsiCode::ColorIndex(*ansi_params.get(2).unwrap() as u8); + *self = self.foreground(Some(ansi_code)); + params_used += 2 // one for the indicator (5 in this case) and one for the color index + } + _ => { + // this is a bug + // it means we got a color encoding we don't know how to handle (or is invalid) + params_used += 1; // even if it's a bug, let's not create an endless loop, eh? } } - [48, ..] => { - let ansi_code = AnsiCode::Code(( - ansi_params.get(1).map(|p| *p as u16), - ansi_params.get(2).map(|p| *p as u16), - )); - *self = self.background(Some(ansi_code)); - if ansi_params.get(1).is_some() { - params_used += 1; + } else if ansi_params[0] == 48 { + match ansi_params.get(1) { + Some(2) => { + let ansi_code = AnsiCode::RGBCode(( + *ansi_params.get(2).unwrap() as u8, + *ansi_params.get(3).unwrap() as u8, + *ansi_params.get(4).unwrap() as u8, + )); + *self = self.background(Some(ansi_code)); + params_used += 4 // one for the indicator (2 in this case) and three for the rgb code } - if ansi_params.get(2).is_some() { - params_used += 1; + Some(5) => { + let ansi_code = AnsiCode::ColorIndex(*ansi_params.get(2).unwrap() as u8); + *self = self.background(Some(ansi_code)); + params_used += 2 // one for the indicator (5 in this case) and one for the color index + } + _ => { + // this is a bug + // it means we got a color encoding we don't know how to handle (or is invalid) + params_used += 1; // even if it's a bug, let's not create an endless loop, eh? } } - [1, ..] => *self = self.bold(Some(AnsiCode::Code((Some(1), None)))), - [2, ..] => *self = self.dim(Some(AnsiCode::Code((Some(2), None)))), - [3, ..] => *self = self.italic(Some(AnsiCode::Code((Some(3), None)))), - [4, ..] => *self = self.underline(Some(AnsiCode::Code((Some(4), None)))), - [5, ..] => *self = self.blink_slow(Some(AnsiCode::Code((Some(5), None)))), - [6, ..] => *self = self.blink_fast(Some(AnsiCode::Code((Some(6), None)))), - [7, ..] => *self = self.reverse(Some(AnsiCode::Code((Some(7), None)))), - [8, ..] => *self = self.hidden(Some(AnsiCode::Code((Some(8), None)))), - [9, ..] => *self = self.strike(Some(AnsiCode::Code((Some(9), None)))), - [30, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Black))), - [31, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Red))), - [32, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Green))), - [33, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Yellow))), - [34, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Blue))), - [35, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Magenta))), - [36, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan))), - [37, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::White))), - [40, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Black))), - [41, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Red))), - [42, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Green))), - [43, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Yellow))), - [44, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Blue))), - [45, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Magenta))), - [46, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Cyan))), - [47, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::White))), - _ => { - // if this happens, it's a bug - let _ = debug_log_to_file(format!("unhandled csi m code {:?}", ansi_params)); - return; - } + } else if ansi_params[0] == 1 { + *self = self.bold(Some(AnsiCode::On)); + } else if ansi_params[0] == 2 { + *self = self.dim(Some(AnsiCode::On)); + } else if ansi_params[0] == 3 { + *self = self.italic(Some(AnsiCode::On)); + } else if ansi_params[0] == 4 { + *self = self.underline(Some(AnsiCode::On)); + } else if ansi_params[0] == 5 { + *self = self.blink_slow(Some(AnsiCode::On)); + } else if ansi_params[0] == 6 { + *self = self.blink_fast(Some(AnsiCode::On)); + } else if ansi_params[0] == 7 { + *self = self.reverse(Some(AnsiCode::On)); + } else if ansi_params[0] == 8 { + *self = self.hidden(Some(AnsiCode::On)); + } else if ansi_params[0] == 9 { + *self = self.strike(Some(AnsiCode::On)); + } else if ansi_params[0] == 30 { + *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Black))); + } else if ansi_params[0] == 31 { + *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Red))); + } else if ansi_params[0] == 32 { + *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Green))); + } else if ansi_params[0] == 33 { + *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Yellow))); + } else if ansi_params[0] == 34 { + *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Blue))); + } else if ansi_params[0] == 35 { + *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Magenta))); + } else if ansi_params[0] == 36 { + *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan))); + } else if ansi_params[0] == 37 { + *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::White))); + } else if ansi_params[0] == 40 { + *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Black))); + } else if ansi_params[0] == 41 { + *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Red))); + } else if ansi_params[0] == 42 { + *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Green))); + } else if ansi_params[0] == 43 { + *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Yellow))); + } else if ansi_params[0] == 44 { + *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Blue))); + } else if ansi_params[0] == 45 { + *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Magenta))); + } else if ansi_params[0] == 46 { + *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Cyan))); + } else if ansi_params[0] == 47 { + *self = self.background(Some(AnsiCode::NamedColor(NamedColor::White))); + } else { + // if this happens, it's a bug + let _ = debug_log_to_file(format!("unhandled csi m code {:?}", ansi_params)); + return; } if let Some(next_params) = ansi_params.get(params_used..) { if next_params.len() > 0 { @@ -399,18 +455,11 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.foreground { match ansi_code { - AnsiCode::Code((param1, param2)) => { - match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[38;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[38;{}m", param1)?; - } - (_, _) => { - // TODO: can this happen? - } - } + AnsiCode::RGBCode((r, g, b)) => { + write!(f, "\u{1b}[38;2;{};{};{}m", r, g, b)?; + } + AnsiCode::ColorIndex(color_index) => { + write!(f, "\u{1b}[38;5;{}m", color_index)?; } AnsiCode::Reset => { write!(f, "\u{1b}[39m")?; @@ -418,22 +467,16 @@ impl Display for CharacterStyles { AnsiCode::NamedColor(named_color) => { write!(f, "\u{1b}[{}m", named_color.to_foreground_ansi_code())?; } + _ => {} } }; if let Some(ansi_code) = self.background { match ansi_code { - AnsiCode::Code((param1, param2)) => { - match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[48;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[48;{}m", param1)?; - } - (_, _) => { - // TODO: can this happen? - } - } + AnsiCode::RGBCode((r, g, b)) => { + write!(f, "\u{1b}[48;2;{};{};{}m", r, g, b)?; + } + AnsiCode::ColorIndex(color_index) => { + write!(f, "\u{1b}[48;5;{}m", color_index)?; } AnsiCode::Reset => { write!(f, "\u{1b}[49m")?; @@ -441,21 +484,14 @@ impl Display for CharacterStyles { AnsiCode::NamedColor(named_color) => { write!(f, "\u{1b}[{}m", named_color.to_background_ansi_code())?; } + _ => {} } } if let Some(ansi_code) = self.strike { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[9;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[9;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[9m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[9m")?; + } AnsiCode::Reset => { write!(f, "\u{1b}[29m")?; } @@ -464,17 +500,9 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.hidden { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[8;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[8;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[8m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[8m")?; + } AnsiCode::Reset => { write!(f, "\u{1b}[28m")?; } @@ -483,17 +511,9 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.reverse { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[7;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[7;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[7m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[7m")?; + } AnsiCode::Reset => { write!(f, "\u{1b}[27m")?; } @@ -502,17 +522,9 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.fast_blink { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[6;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[6;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[6m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[6m")?; + } AnsiCode::Reset => { write!(f, "\u{1b}[25m")?; } @@ -521,17 +533,9 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.slow_blink { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[5;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[5;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[5m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[5m")?; + } AnsiCode::Reset => { write!(f, "\u{1b}[25m")?; } @@ -540,20 +544,11 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.bold { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[1;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[1;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[1m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[1m")?; + } AnsiCode::Reset => { write!(f, "\u{1b}[22m\u{1b}[24m")?; - // character_ansi_codes.push_str(&format!("\u{1b}[22m")); // TODO: this cancels bold + underline, if this behaviour is indeed correct, we // need to properly handle it in the struct methods etc like dim } @@ -565,17 +560,9 @@ impl Display for CharacterStyles { // otherwise if let Some(ansi_code) = self.underline { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[4;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[4;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[4m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[4m")?; + } AnsiCode::Reset => { write!(f, "\u{1b}[24m")?; } @@ -584,17 +571,9 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.dim { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[2;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[2;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[2m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[2m")?; + } AnsiCode::Reset => { if let Some(bold) = self.bold { // we only reset dim if both dim and bold should be reset @@ -611,17 +590,9 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.italic { match ansi_code { - AnsiCode::Code((param1, param2)) => match (param1, param2) { - (Some(param1), Some(param2)) => { - write!(f, "\u{1b}[3;{};{}m", param1, param2)?; - } - (Some(param1), None) => { - write!(f, "\u{1b}[3;{}m", param1)?; - } - (_, _) => { - write!(f, "\u{1b}[3m")?; - } - }, + AnsiCode::On => { + write!(f, "\u{1b}[3m")?; + } AnsiCode::Reset => { write!(f, "\u{1b}[23m")?; }