refactor(ansi-codes): treat ansi codes properly and also make things clearer (#85)

This commit is contained in:
Aram Drevekenin 2020-12-08 16:42:26 +01:00 committed by GitHub
parent 576876b475
commit 94d6f3dbf6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 111 additions and 335 deletions

View File

@ -1,3 +1,4 @@
use crate::utils::logging::debug_log_to_file;
use ::std::fmt::{self, Debug, Display, Formatter};
pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter {
@ -297,6 +298,114 @@ impl CharacterStyles {
self.hidden = Some(AnsiCode::Reset);
self.strike = Some(AnsiCode::Reset);
}
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
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 {
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;
}
} else if ansi_params[0] == 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;
}
if ansi_params.get(2).is_some() {
params_used += 1;
}
} else if ansi_params[0] == 1 {
*self = self.bold(Some(AnsiCode::Code((Some(1), None))));
} else if ansi_params[0] == 2 {
*self = self.dim(Some(AnsiCode::Code((Some(2), None))));
} else if ansi_params[0] == 3 {
*self = self.italic(Some(AnsiCode::Code((Some(3), None))));
} else if ansi_params[0] == 4 {
*self = self.underline(Some(AnsiCode::Code((Some(4), None))));
} else if ansi_params[0] == 5 {
*self = self.blink_slow(Some(AnsiCode::Code((Some(5), None))));
} else if ansi_params[0] == 6 {
*self = self.blink_fast(Some(AnsiCode::Code((Some(6), None))));
} else if ansi_params[0] == 7 {
*self = self.reverse(Some(AnsiCode::Code((Some(7), None))));
} else if ansi_params[0] == 8 {
*self = self.hidden(Some(AnsiCode::Code((Some(8), None))));
} else if ansi_params[0] == 9 {
*self = self.strike(Some(AnsiCode::Code((Some(9), None))));
} 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);
}
}
}
}
impl Display for CharacterStyles {

View File

@ -9,7 +9,7 @@ use crate::terminal_pane::terminal_character::{
AnsiCode, CharacterStyles, NamedColor, TerminalCharacter,
};
use crate::terminal_pane::Scroll;
use crate::utils::logging::{debug_log_to_file, debug_log_to_file_pid_3};
use crate::utils::logging::debug_log_to_file;
use crate::VteEvent;
#[derive(Clone, Copy, Debug)]
@ -398,340 +398,7 @@ impl vte::Perform for TerminalPane {
fn csi_dispatch(&mut self, params: &[i64], _intermediates: &[u8], _ignore: bool, c: char) {
if c == 'm' {
if params.is_empty() || params[0] == 0 {
// reset all
self.pending_styles.reset_all();
if let Some(param1) = params.get(1) {
// TODO: this is a case currently found in eg. htop where we get two different
// csi 'm' codes in one event.
// We should understand why these are happening and then make a more generic
// solution for them
if *param1 == 1 {
// bold
self.pending_styles = self
.pending_styles
.bold(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
}
} else if params[0] == 39 {
self.pending_styles = self.pending_styles.foreground(Some(AnsiCode::Reset));
if let Some(param1) = params.get(1) {
// TODO: this is a case currently found in eg. htop where we get two different
// csi 'm' codes in one event.
// We should understand why these are happening and then make a more generic
// solution for them
if *param1 == 49 {
// TODO: if we need this to fix the bug, we need to make collecting the
// second argument in such cases generic
self.pending_styles = self.pending_styles.background(Some(AnsiCode::Reset));
}
}
} else if params[0] == 49 {
self.pending_styles = self.pending_styles.background(Some(AnsiCode::Reset));
} else if params[0] == 21 {
// reset bold
self.pending_styles = self.pending_styles.bold(Some(AnsiCode::Reset));
} else if params[0] == 22 {
// reset bold and dim
self.pending_styles = self.pending_styles.bold(Some(AnsiCode::Reset));
self.pending_styles = self.pending_styles.dim(Some(AnsiCode::Reset));
} else if params[0] == 23 {
// reset italic
self.pending_styles = self.pending_styles.italic(Some(AnsiCode::Reset));
} else if params[0] == 24 {
// reset underline
self.pending_styles = self.pending_styles.underline(Some(AnsiCode::Reset));
} else if params[0] == 25 {
// reset blink
self.pending_styles = self.pending_styles.blink_slow(Some(AnsiCode::Reset));
self.pending_styles = self.pending_styles.blink_fast(Some(AnsiCode::Reset));
} else if params[0] == 27 {
// reset reverse
self.pending_styles = self.pending_styles.reverse(Some(AnsiCode::Reset));
} else if params[0] == 28 {
// reset hidden
self.pending_styles = self.pending_styles.hidden(Some(AnsiCode::Reset));
} else if params[0] == 29 {
// reset strike
self.pending_styles = self.pending_styles.strike(Some(AnsiCode::Reset));
} else if params[0] == 38 {
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.foreground(Some(AnsiCode::Code(
(Some(*param1 as u16), Some(*param2 as u16)),
)));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 48 {
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.background(Some(AnsiCode::Code(
(Some(*param1 as u16), Some(*param2 as u16)),
)));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 1 {
// bold
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.bold(Some(AnsiCode::Code((
Some(*param1 as u16),
Some(*param2 as u16),
))));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.bold(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles =
self.pending_styles.bold(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 2 {
// dim
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.dim(Some(AnsiCode::Code((
Some(*param1 as u16),
Some(*param2 as u16),
))));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.dim(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles =
self.pending_styles.dim(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 3 {
// italic
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.italic(Some(AnsiCode::Code((
Some(*param1 as u16),
Some(*param2 as u16),
))));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.italic(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.italic(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 4 {
// underline
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.underline(Some(AnsiCode::Code(
(Some(*param1 as u16), Some(*param2 as u16)),
)));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.underline(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.underline(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 5 {
// blink slow
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.blink_slow(Some(AnsiCode::Code(
(Some(*param1 as u16), Some(*param2 as u16)),
)));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.blink_slow(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.blink_slow(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 6 {
// blink fast
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.blink_fast(Some(AnsiCode::Code(
(Some(*param1 as u16), Some(*param2 as u16)),
)));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.blink_fast(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.blink_fast(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 7 {
// reverse
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.reverse(Some(AnsiCode::Code((
Some(*param1 as u16),
Some(*param2 as u16),
))));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.reverse(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.reverse(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 8 {
// hidden
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.hidden(Some(AnsiCode::Code((
Some(*param1 as u16),
Some(*param2 as u16),
))));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.hidden(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.hidden(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 9 {
// strike
match (params.get(1), params.get(2)) {
(Some(param1), Some(param2)) => {
self.pending_styles = self.pending_styles.strike(Some(AnsiCode::Code((
Some(*param1 as u16),
Some(*param2 as u16),
))));
}
(Some(param1), None) => {
self.pending_styles = self
.pending_styles
.strike(Some(AnsiCode::Code((Some(*param1 as u16), None))));
}
(_, _) => {
self.pending_styles = self
.pending_styles
.strike(Some(AnsiCode::Code((None, None))));
}
};
} else if params[0] == 30 {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::NamedColor(NamedColor::Black)));
} else if params[0] == 31 {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::NamedColor(NamedColor::Red)));
} else if params[0] == 32 {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::NamedColor(NamedColor::Green)));
} else if params[0] == 33 {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::NamedColor(NamedColor::Yellow)));
} else if params[0] == 34 {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::NamedColor(NamedColor::Blue)));
} else if params[0] == 35 {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::NamedColor(NamedColor::Magenta)));
} else if params[0] == 36 {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan)));
} else if params[0] == 37 {
self.pending_styles = self
.pending_styles
.foreground(Some(AnsiCode::NamedColor(NamedColor::White)));
} else if params[0] == 40 {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::NamedColor(NamedColor::Black)));
} else if params[0] == 41 {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::NamedColor(NamedColor::Red)));
} else if params[0] == 42 {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::NamedColor(NamedColor::Green)));
} else if params[0] == 43 {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::NamedColor(NamedColor::Yellow)));
} else if params[0] == 44 {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::NamedColor(NamedColor::Blue)));
} else if params[0] == 45 {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::NamedColor(NamedColor::Magenta)));
} else if params[0] == 46 {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::NamedColor(NamedColor::Cyan)));
} else if params[0] == 47 {
self.pending_styles = self
.pending_styles
.background(Some(AnsiCode::NamedColor(NamedColor::White)));
} else {
let _ = debug_log_to_file(format!("unhandled csi m code {:?}", params));
}
self.pending_styles.add_style_from_ansi_params(params);
} else if c == 'C' {
// move cursor forward
let move_by = if params[0] == 0 {