From 94d6f3dbf6c75730b69a8dbb008f6450f2c21e16 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Tue, 8 Dec 2020 16:42:26 +0100 Subject: [PATCH] refactor(ansi-codes): treat ansi codes properly and also make things clearer (#85) --- src/terminal_pane/terminal_character.rs | 109 ++++++++ src/terminal_pane/terminal_pane.rs | 337 +----------------------- 2 files changed, 111 insertions(+), 335 deletions(-) diff --git a/src/terminal_pane/terminal_character.rs b/src/terminal_pane/terminal_character.rs index 2c5fe3ac..27c09105 100644 --- a/src/terminal_pane/terminal_character.rs +++ b/src/terminal_pane/terminal_character.rs @@ -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 { diff --git a/src/terminal_pane/terminal_pane.rs b/src/terminal_pane/terminal_pane.rs index 348a9fe0..a6b4b346 100644 --- a/src/terminal_pane/terminal_pane.rs +++ b/src/terminal_pane/terminal_pane.rs @@ -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 {