fix(compatibility): support rgb color notation (#90)
* fix(compatibility): support rgb color notation * fix(style): remove comments
This commit is contained in:
parent
92d1bcff4c
commit
a933b8320b
1 changed files with 162 additions and 191 deletions
|
|
@ -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<u16>, Option<u16>)),
|
||||
RGBCode((u8, u8, u8)),
|
||||
ColorIndex(u8),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
|
|
@ -300,78 +302,132 @@ 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, ..] => {
|
||||
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));
|
||||
}
|
||||
[23, ..] => *self = self.italic(Some(AnsiCode::Reset)),
|
||||
[24, ..] => *self = self.underline(Some(AnsiCode::Reset)),
|
||||
[25, ..] => {
|
||||
} 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));
|
||||
}
|
||||
[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),
|
||||
} 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));
|
||||
if ansi_params.len() > 2 {
|
||||
params_used += ansi_params.len() - 1;
|
||||
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),
|
||||
} 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));
|
||||
if ansi_params.get(1).is_some() {
|
||||
params_used += 1;
|
||||
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
|
||||
}
|
||||
}
|
||||
[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))),
|
||||
_ => {
|
||||
// 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?
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
self.add_style_from_ansi_params(next_params);
|
||||
|
|
@ -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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
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)?;
|
||||
}
|
||||
(_, _) => {
|
||||
AnsiCode::On => {
|
||||
write!(f, "\u{1b}[3m")?;
|
||||
}
|
||||
},
|
||||
AnsiCode::Reset => {
|
||||
write!(f, "\u{1b}[23m")?;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue