diff options
| author | Aram Drevekenin <aram@poor.dev> | 2020-10-17 20:45:20 +0200 |
|---|---|---|
| committer | Aram Drevekenin <aram@poor.dev> | 2020-10-17 20:45:20 +0200 |
| commit | 049ff1a6dc52ffc0749c2f51744be4d8760359a9 (patch) | |
| tree | a2f492e5a546a9f2f5c5f32ccf4d70236e224ca7 /src | |
| parent | feat(performance): some improvements by reducing string allocations (diff) | |
| download | sl0ppij-049ff1a6dc52ffc0749c2f51744be4d8760359a9.tar.gz sl0ppij-049ff1a6dc52ffc0749c2f51744be4d8760359a9.tar.xz sl0ppij-049ff1a6dc52ffc0749c2f51744be4d8760359a9.zip | |
feat(performance): some more improvements by reducing even more allocations
Diffstat (limited to 'src')
| -rw-r--r-- | src/screen.rs | 1 | ||||
| -rw-r--r-- | src/terminal_pane.rs | 411 |
2 files changed, 387 insertions, 25 deletions
diff --git a/src/screen.rs b/src/screen.rs index 0c68bfa4..816af406 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -3,6 +3,7 @@ use std::collections::{HashSet, BTreeMap}; use nix::pty::Winsize; use std::os::unix::io::RawFd; use std::sync::mpsc::{channel, Sender, Receiver}; +use std::time::{Instant, Duration}; use crate::os_input_output::OsApi; use crate::terminal_pane::TerminalOutput; diff --git a/src/terminal_pane.rs b/src/terminal_pane.rs index 34c9c2ca..2b1707b6 100644 --- a/src/terminal_pane.rs +++ b/src/terminal_pane.rs @@ -69,9 +69,8 @@ impl NamedColor { } } -#[derive(Clone, Copy)] -pub struct TerminalCharacter { - pub character: char, +#[derive(Clone, Copy, Debug)] +pub struct CharacterStyles { pub foreground: Option<AnsiCode>, pub background: Option<AnsiCode>, pub strike: Option<AnsiCode>, @@ -85,10 +84,9 @@ pub struct TerminalCharacter { pub italic: Option<AnsiCode>, } -impl TerminalCharacter { - pub fn new (character: char) -> Self { - TerminalCharacter { - character, +impl CharacterStyles { + pub fn new() -> Self { + CharacterStyles { foreground: None, background: None, strike: None, @@ -146,14 +144,27 @@ impl TerminalCharacter { self.strike = strike_code; self } - pub fn update_styles_and_return_diff(&mut self, new_styles: &TerminalCharacter) -> Option<String> { - let mut diff: Option<TerminalCharacter> = None; + pub fn clear(&mut self) { + self.foreground = None; + self.background = None; + self.strike = None; + self.hidden = None; + self.reverse = None; + self.slow_blink = None; + self.fast_blink = None; + self.underline = None; + self.bold = None; + self.dim = None; + self.italic = None; + } + pub fn update_and_return_diff(&mut self, new_styles: &TerminalCharacter) -> Option<CharacterStyles> { + let mut diff: Option<CharacterStyles> = None; if self.foreground != new_styles.foreground { if let Some(new_diff) = diff.as_mut() { diff = Some(new_diff.foreground(new_styles.foreground)); self.foreground = new_styles.foreground; } else { - diff = Some(TerminalCharacter::new(self.character).foreground(new_styles.foreground)); + diff = Some(CharacterStyles::new().foreground(new_styles.foreground)); self.foreground = new_styles.foreground; } } @@ -162,7 +173,7 @@ impl TerminalCharacter { diff = Some(new_diff.background(new_styles.background)); self.background = new_styles.background; } else { - diff = Some(TerminalCharacter::new(self.character).background(new_styles.background)); + diff = Some(CharacterStyles::new().background(new_styles.background)); self.background = new_styles.background; } } @@ -171,7 +182,7 @@ impl TerminalCharacter { diff = Some(new_diff.strike(new_styles.strike)); self.strike = new_styles.strike; } else { - diff = Some(TerminalCharacter::new(self.character).strike(new_styles.strike)); + diff = Some(CharacterStyles::new().strike(new_styles.strike)); self.strike = new_styles.strike; } } @@ -180,7 +191,7 @@ impl TerminalCharacter { diff = Some(new_diff.hidden(new_styles.hidden)); self.hidden = new_styles.hidden; } else { - diff = Some(TerminalCharacter::new(self.character).hidden(new_styles.hidden)); + diff = Some(CharacterStyles::new().hidden(new_styles.hidden)); self.hidden = new_styles.hidden; } } @@ -189,7 +200,7 @@ impl TerminalCharacter { diff = Some(new_diff.reverse(new_styles.reverse)); self.reverse= new_styles.reverse; } else { - diff = Some(TerminalCharacter::new(self.character).reverse(new_styles.reverse)); + diff = Some(CharacterStyles::new().reverse(new_styles.reverse)); self.reverse= new_styles.reverse; } } @@ -198,7 +209,7 @@ impl TerminalCharacter { diff = Some(new_diff.blink_slow(new_styles.slow_blink)); self.slow_blink = new_styles.slow_blink; } else { - diff = Some(TerminalCharacter::new(self.character).blink_slow(new_styles.slow_blink)); + diff = Some(CharacterStyles::new().blink_slow(new_styles.slow_blink)); self.slow_blink = new_styles.slow_blink; } } @@ -207,7 +218,7 @@ impl TerminalCharacter { diff = Some(new_diff.blink_fast(new_styles.fast_blink)); self.fast_blink = new_styles.fast_blink; } else { - diff = Some(TerminalCharacter::new(self.character).blink_fast(new_styles.fast_blink)); + diff = Some(CharacterStyles::new().blink_fast(new_styles.fast_blink)); self.fast_blink = new_styles.fast_blink; } } @@ -216,7 +227,7 @@ impl TerminalCharacter { diff = Some(new_diff.underline(new_styles.underline)); self.underline= new_styles.underline; } else { - diff = Some(TerminalCharacter::new(self.character).underline(new_styles.underline)); + diff = Some(CharacterStyles::new().underline(new_styles.underline)); self.underline= new_styles.underline; } } @@ -225,7 +236,7 @@ impl TerminalCharacter { diff = Some(new_diff.bold(new_styles.bold)); self.bold= new_styles.bold; } else { - diff = Some(TerminalCharacter::new(self.character).bold(new_styles.bold)); + diff = Some(CharacterStyles::new().bold(new_styles.bold)); self.bold= new_styles.bold; } } @@ -234,7 +245,7 @@ impl TerminalCharacter { diff = Some(new_diff.dim(new_styles.dim)); self.dim= new_styles.dim; } else { - diff = Some(TerminalCharacter::new(self.character).dim(new_styles.dim)); + diff = Some(CharacterStyles::new().dim(new_styles.dim)); self.dim= new_styles.dim; } } @@ -243,11 +254,360 @@ impl TerminalCharacter { diff = Some(new_diff.italic(new_styles.italic)); self.italic = new_styles.italic; } else { - diff = Some(TerminalCharacter::new(self.character).italic(new_styles.italic)); + diff = Some(CharacterStyles::new().italic(new_styles.italic)); self.italic = new_styles.italic; } } - diff.and_then(|d| Some(d.to_string())) + diff + } +} + +impl Display for CharacterStyles { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if self.foreground == Some(AnsiCode::Reset) && + self.background == Some(AnsiCode::Reset) && + self.strike == Some(AnsiCode::Reset) && + self.hidden == Some(AnsiCode::Reset) && + self.reverse == Some(AnsiCode::Reset) && + self.fast_blink == Some(AnsiCode::Reset) && + self.slow_blink == Some(AnsiCode::Reset) && + self.underline == Some(AnsiCode::Reset) && + self.bold == Some(AnsiCode::Reset) && + self.dim == Some(AnsiCode::Reset) && + self.italic == Some(AnsiCode::Reset) { + + write!(f, "\u{1b}[m")?; // reset all + return Ok(()); + } + 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::Reset => { + write!(f, "\u{1b}[39m")?; + }, + 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::Reset => { + write!(f, "\u{1b}[49m")?; + } + 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::Reset => { + write!(f, "\u{1b}[29m")?; + }, + _ => {} + } + } + 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::Reset => { + write!(f, "\u{1b}[28m")?; + }, + _ => {} + } + } + 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::Reset => { + write!(f, "\u{1b}[27m")?; + }, + _ => {} + } + } + 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::Reset => { + write!(f, "\u{1b}[25m")?; + }, + _ => {} + } + } + 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::Reset => { + write!(f, "\u{1b}[25m")?; + }, + _ => {} + } + } + 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::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 + }, + _ => {} + } + } + // notice the order is important here, bold must be before underline + // because the bold reset also resets underline, and would override it + // 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::Reset => { + write!(f, "\u{1b}[24m")?; + }, + _ => {} + } + } + 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::Reset => { + if let Some(bold) = self.bold { + // we only reset dim if both dim and bold should be reset + match bold { + AnsiCode::Reset => { + write!(f, "\u{1b}[22m")?; + }, + _ => {} + } + } + }, + _ => {} + } + } + 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::Reset => { + write!(f, "\u{1b}[23m")?; + }, + _ => {} + } + }; + Ok(()) + } +} + +#[derive(Clone, Copy)] +pub struct TerminalCharacter { + pub character: char, + pub foreground: Option<AnsiCode>, + pub background: Option<AnsiCode>, + pub strike: Option<AnsiCode>, + pub hidden: Option<AnsiCode>, + pub reverse: Option<AnsiCode>, + pub slow_blink: Option<AnsiCode>, + pub fast_blink: Option<AnsiCode>, + pub underline: Option<AnsiCode>, + pub bold: Option<AnsiCode>, + pub dim: Option<AnsiCode>, + pub italic: Option<AnsiCode>, +} + +impl TerminalCharacter { + pub fn new (character: char) -> Self { + TerminalCharacter { + character, + foreground: None, + background: None, + strike: None, + hidden: None, + reverse: None, + slow_blink: None, + fast_blink: None, + underline: None, + bold: None, + dim: None, + italic: None, + } + } + pub fn foreground(mut self, foreground_code: Option<AnsiCode>) -> Self { + self.foreground = foreground_code; + self + } + pub fn background(mut self, background_code: Option<AnsiCode>) -> Self { + self.background = background_code; + self + } + pub fn bold(mut self, bold_code: Option<AnsiCode>) -> Self { + self.bold = bold_code; + self + } + pub fn dim(mut self, dim_code: Option<AnsiCode>) -> Self { + self.dim = dim_code; + self + } + pub fn italic(mut self, italic_code: Option<AnsiCode>) -> Self { + self.italic = italic_code; + self + } + pub fn underline(mut self, underline_code: Option<AnsiCode>) -> Self { + self.underline = underline_code; + self + } + pub fn blink_slow(mut self, slow_blink_code: Option<AnsiCode>) -> Self { + self.slow_blink = slow_blink_code; + self + } + pub fn blink_fast(mut self, fast_blink_code: Option<AnsiCode>) -> Self { + self.fast_blink = fast_blink_code; + self + } + pub fn reverse(mut self, reverse_code: Option<AnsiCode>) -> Self { + self.reverse = reverse_code; + self + } + pub fn hidden(mut self, hidden_code: Option<AnsiCode>) -> Self { + self.hidden = hidden_code; + self + } + pub fn strike(mut self, strike_code: Option<AnsiCode>) -> Self { + self.strike = strike_code; + self } } @@ -820,20 +1180,21 @@ impl TerminalOutput { let mut vte_output = String::new(); let buffer_lines = &self.read_buffer_as_lines(); let display_cols = &self.display_cols; + let mut character_styles = CharacterStyles::new(); for (row, line) in buffer_lines.iter().enumerate() { - vte_output.push_str(&format!("\u{1b}[{};{}H\u{1b}[m", self.y_coords as usize + row + 1, self.x_coords + 1)); // goto row/col - let mut terminal_character_styles = TerminalCharacter::new(' '); + vte_output = format!("{}\u{1b}[{};{}H\u{1b}[m", vte_output, self.y_coords as usize + row + 1, self.x_coords + 1); // goto row/col for (col, t_character) in line.iter().enumerate() { if (col as u16) < *display_cols { // in some cases (eg. while resizing) some characters will spill over // before they are corrected by the shell (for the prompt) or by reflowing // lines - if let Some(new_styles) = terminal_character_styles.update_styles_and_return_diff(&t_character) { - vte_output.push_str(&new_styles); + if let Some(new_styles) = character_styles.update_and_return_diff(&t_character) { + vte_output = format!("{}{}", vte_output, new_styles); } vte_output.push(t_character.character); } } + character_styles.clear(); } self.should_render = false; Some(vte_output) |
