fix(compatibility): support rgb color notation (#90)

* fix(compatibility): support rgb color notation

* fix(style): remove comments
This commit is contained in:
Aram Drevekenin 2020-12-09 18:02:11 +01:00 committed by GitHub
parent 92d1bcff4c
commit a933b8320b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

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