diff options
author | Jesse Luehrs <doy@tozt.net> | 2019-11-10 06:17:09 -0500 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2019-11-10 08:08:14 -0500 |
commit | 168a91a9ddc331cd3b8e5c32f7701f2b0973b147 (patch) | |
tree | 6b2df47bf18a731a9814bb875ce231e28cad1bf0 | |
parent | b04c0e6e97765aeb888479c5e0bc27d54de60659 (diff) | |
download | vt100-rust-168a91a9ddc331cd3b8e5c32f7701f2b0973b147.tar.gz vt100-rust-168a91a9ddc331cd3b8e5c32f7701f2b0973b147.zip |
optimize attribute setting a bit
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/attrs.rs | 6 | ||||
-rw-r--r-- | src/cell.rs | 13 | ||||
-rw-r--r-- | src/grid.rs | 21 | ||||
-rw-r--r-- | src/row.rs | 28 | ||||
-rw-r--r-- | src/screen.rs | 10 | ||||
-rw-r--r-- | src/term.rs | 35 | ||||
-rw-r--r-- | tests/escape.rs | 5 | ||||
-rw-r--r-- | tests/text.rs | 17 | ||||
-rw-r--r-- | tests/window_contents.rs | 26 |
10 files changed, 107 insertions, 56 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index ecebb08..5713c5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ ### Fixed -* Lots of performance optimizations. +* Lots of performance and output optimizations. ## [0.4.0] - 2019-11-08 diff --git a/src/attrs.rs b/src/attrs.rs index dc46646..4b78771 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -94,13 +94,13 @@ impl Attrs { contents: &mut Vec<u8>, other: &Self, ) { - let attrs = crate::term::Attrs::default(); - if self != other && self == &Self::default() { - write!(contents, "{}", attrs).unwrap(); + write!(contents, "{}", crate::term::ClearAttrs::new()).unwrap(); return; } + let attrs = crate::term::Attrs::default(); + let attrs = if self.fgcolor == other.fgcolor { attrs } else { diff --git a/src/cell.rs b/src/cell.rs index 61a3cd3..b9d7168 100644 --- a/src/cell.rs +++ b/src/cell.rs @@ -11,15 +11,22 @@ pub struct Cell { attrs: crate::attrs::Attrs, } +#[allow(clippy::collapsible_if)] impl PartialEq<Cell> for Cell { fn eq(&self, other: &Self) -> bool { - if self.attrs != other.attrs { - return false; - } if self.len != other.len { return false; } let len = self.len as usize; + if len > 0 { + if self.attrs != other.attrs { + return false; + } + } else { + if self.attrs.bgcolor != other.attrs.bgcolor { + return false; + } + } self.contents[..len] == other.contents[..len] } } diff --git a/src/grid.rs b/src/grid.rs index 1cc4daf..a546c43 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -179,11 +179,14 @@ impl Grid { } } - pub fn write_contents_formatted(&self, contents: &mut Vec<u8>) { + pub fn write_contents_formatted( + &self, + contents: &mut Vec<u8>, + ) -> crate::attrs::Attrs { write!( contents, "{}{}", - crate::term::Attrs::new(), + crate::term::ClearAttrs::new(), crate::term::ClearScreen::new() ) .unwrap(); @@ -211,13 +214,17 @@ impl Grid { write!(contents, "{}", crate::term::MoveTo::new(self.pos)) .unwrap(); } - } - pub fn write_contents_diff(&self, contents: &mut Vec<u8>, prev: &Self) { - write!(contents, "{}", crate::term::Attrs::default()).unwrap(); + prev_attrs + } + pub fn write_contents_diff( + &self, + contents: &mut Vec<u8>, + prev: &Self, + mut prev_attrs: crate::attrs::Attrs, + ) -> crate::attrs::Attrs { let mut prev_pos = prev.pos; - let mut prev_attrs = crate::attrs::Attrs::default(); let mut wrapping = false; for (i, (row, prev_row)) in self.visible_rows().zip(prev.visible_rows()).enumerate() @@ -242,6 +249,8 @@ impl Grid { write!(contents, "{}", crate::term::MoveTo::new(self.pos)) .unwrap(); } + + prev_attrs } pub fn erase_all(&mut self, bgcolor: crate::attrs::Color) { @@ -165,12 +165,13 @@ impl Row { } let attrs = cell.attrs(); - if &prev_attrs != attrs { - attrs.write_escape_code_diff(contents, &prev_attrs); - prev_attrs = *attrs; - } if has_contents { + if &prev_attrs != attrs { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; + } + // using write! here is significantly slower, for some // reason // write!(contents, "{}", cell.contents()).unwrap(); @@ -179,6 +180,11 @@ impl Row { prev_pos.col += width; new_pos.col += width; } else { + if prev_attrs.bgcolor != attrs.bgcolor { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; + } + write!( contents, "{}", @@ -262,12 +268,13 @@ impl Row { } let attrs = cell.attrs(); - if &prev_attrs != attrs { - attrs.write_escape_code_diff(contents, &prev_attrs); - prev_attrs = *attrs; - } if cell.has_contents() { + if &prev_attrs != attrs { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; + } + // using write! here is significantly slower, for some // reason // write!(contents, "{}", cell.contents()).unwrap(); @@ -276,6 +283,11 @@ impl Row { prev_pos.col += width; new_pos.col += width; } else { + if prev_attrs.bgcolor != attrs.bgcolor { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; + } + write!( contents, "{}", diff --git a/src/screen.rs b/src/screen.rs index b774c10..c2fef6b 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -189,7 +189,8 @@ impl Screen { crate::term::HideCursor::new(self.hide_cursor()) ) .unwrap(); - self.grid().write_contents_formatted(contents); + let prev_attrs = self.grid().write_contents_formatted(contents); + self.attrs.write_escape_code_diff(contents, &prev_attrs); } /// Returns the formatted contents of the terminal by row, restricted to @@ -247,7 +248,12 @@ impl Screen { ) .unwrap(); } - self.grid().write_contents_diff(contents, prev.grid()); + let prev_attrs = self.grid().write_contents_diff( + contents, + prev.grid(), + prev.attrs, + ); + self.attrs.write_escape_code_diff(contents, &prev_attrs); } /// Returns a sequence of terminal byte streams sufficient to turn the diff --git a/src/term.rs b/src/term.rs index ef6c546..074f177 100644 --- a/src/term.rs +++ b/src/term.rs @@ -56,6 +56,21 @@ impl std::fmt::Display for MoveTo { } #[derive(Default, Debug)] +pub struct ClearAttrs; + +impl ClearAttrs { + pub fn new() -> Self { + Self::default() + } +} + +impl std::fmt::Display for ClearAttrs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("\x1b[m") + } +} + +#[derive(Default, Debug)] pub struct Attrs { fgcolor: Option<crate::attrs::Color>, bgcolor: Option<crate::attrs::Color>, @@ -66,10 +81,6 @@ pub struct Attrs { } impl Attrs { - pub fn new() -> Self { - Self::default() - } - pub fn fgcolor(mut self, fgcolor: crate::attrs::Color) -> Self { self.fgcolor = Some(fgcolor); self @@ -102,8 +113,22 @@ impl Attrs { } impl std::fmt::Display for Attrs { - #[allow(unused_assignments, clippy::cognitive_complexity)] + #[allow( + unused_assignments, + clippy::cognitive_complexity, + clippy::too_many_lines + )] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.fgcolor.is_none() + && self.bgcolor.is_none() + && self.bold.is_none() + && self.italic.is_none() + && self.underline.is_none() + && self.inverse.is_none() + { + return Ok(()); + } + f.write_str("\x1b[")?; let mut first = true; diff --git a/tests/escape.rs b/tests/escape.rs index 1800ce8..cf28c0f 100644 --- a/tests/escape.rs +++ b/tests/escape.rs @@ -65,7 +65,8 @@ fn ris() { assert_eq!(parser.screen().contents(), "foo"); assert_eq!( parser.screen().contents_formatted(), - &b"\x1b[?25l\x1b[m\x1b[H\x1b[Jf\x1b[31;47;1;3;4moo\x1b[21;21H"[..] + &b"\x1b[?25l\x1b[m\x1b[H\x1b[Jf\x1b[31;47;1;3;4moo\x1b[21;21H\x1b[7m" + [..] ); assert_eq!(parser.screen().title(), "window title"); @@ -160,7 +161,7 @@ fn decsc() { assert_eq!(parser.screen().cursor_position(), (0, 3)); assert_eq!( parser.screen().contents_formatted(), - &b"\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[32mbar\x1b[5;1H\x1b[31mfoo\x1b[1;4H"[..] + &b"\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[32mbar\x1b[5;1H\x1b[31mfoo\x1b[1;4H\x1b[32m"[..] ); parser.process(b"\x1b8\x1b[Hz"); diff --git a/tests/text.rs b/tests/text.rs index 8578567..49cde5b 100644 --- a/tests/text.rs +++ b/tests/text.rs @@ -62,10 +62,7 @@ fn wide() { parser.screen().contents_formatted(), "\x1b[?25h\x1b[m\x1b[H\x1b[Jaデbネ".as_bytes() ); - assert_eq!( - parser.screen().contents_diff(&screen), - "\x1b[maデbネ".as_bytes() - ); + assert_eq!(parser.screen().contents_diff(&screen), "aデbネ".as_bytes()); let screen = parser.screen().clone(); parser.process(b"\x1b[1;1H\x1b[3Cc"); @@ -77,7 +74,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[1;4Hc".as_bytes() + "\x1b[1;4Hc".as_bytes() ); let screen = parser.screen().clone(); @@ -90,7 +87,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[2Cfoobar".as_bytes() + "\x1b[2Cfoobar".as_bytes() ); let screen = parser.screen().clone(); @@ -103,7 +100,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[Hデcネfo\x1b[Cbar\x1b[X".as_bytes() + "\x1b[Hデcネfo\x1b[Cbar\x1b[X".as_bytes() ); let screen = parser.screen().clone(); @@ -116,7 +113,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[Haデcネf\x1b[Cobar".as_bytes() + "\x1b[Haデcネf\x1b[Cobar".as_bytes() ); let screen = parser.screen().clone(); @@ -129,7 +126,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[Hデcネfo\x1b[Cbar\x1b[X".as_bytes() + "\x1b[Hデcネfo\x1b[Cbar\x1b[X".as_bytes() ); } @@ -156,7 +153,7 @@ fn combining() { assert_eq!(parser.screen().contents(), "abcdefg"); let screen = parser.screen().clone(); parser.process(b"\x1bcabcdefg"); - assert_eq!(parser.screen().contents_diff(&screen), b"\x1b[m"); + assert_eq!(parser.screen().contents_diff(&screen), b""); } #[test] diff --git a/tests/window_contents.rs b/tests/window_contents.rs index 0df62ef..a1607bd 100644 --- a/tests/window_contents.rs +++ b/tests/window_contents.rs @@ -28,7 +28,7 @@ fn formatted() { assert!(!parser.screen().cell(0, 5).unwrap().bold()); assert_eq!( parser.screen().contents_formatted(), - &b"\x1b[?25h\x1b[m\x1b[H\x1b[Jfoo\x1b[33;1;7mb\x1b[mar\x1b[1;5H"[..] + &b"\x1b[?25h\x1b[m\x1b[H\x1b[Jfoo\x1b[33;1;7mb\x1b[mar\x1b[1;5H\x1b[33;1;7m"[..] ); parser.process(b"\x1b[1;5H\x1b[22;42ma"); @@ -39,7 +39,7 @@ fn formatted() { assert!(!parser.screen().cell(0, 5).unwrap().bold()); assert_eq!( parser.screen().contents_formatted(), - &b"\x1b[?25h\x1b[m\x1b[H\x1b[Jfoo\x1b[33;1;7mb\x1b[42;22ma\x1b[mr\x1b[1;6H" + &b"\x1b[?25h\x1b[m\x1b[H\x1b[Jfoo\x1b[33;1;7mb\x1b[42;22ma\x1b[mr\x1b[1;6H\x1b[33;42;7m" [..] ); @@ -71,7 +71,7 @@ fn empty_cells() { assert_eq!(parser.screen().contents(), "foo bar"); assert_eq!( parser.screen().contents_formatted(), - &b"\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[31mfoo\x1b[2C\x1b[32m bar\x1b[1;4H"[..] + &b"\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[31mfoo\x1b[2C\x1b[32m bar\x1b[1;4H\x1b[31m"[..] ); } @@ -87,7 +87,7 @@ fn cursor_positioning() { parser.screen().contents_formatted(), b"\x1b[?25h\x1b[m\x1b[H\x1b[J:" ); - assert_eq!(parser.screen().contents_diff(&screen1), b"\x1b[m:"); + assert_eq!(parser.screen().contents_diff(&screen1), b":"); parser.process(b"a"); let screen3 = parser.screen().clone(); @@ -96,7 +96,7 @@ fn cursor_positioning() { parser.screen().contents_formatted(), b"\x1b[?25h\x1b[m\x1b[H\x1b[J:a" ); - assert_eq!(parser.screen().contents_diff(&screen2), b"\x1b[ma"); + assert_eq!(parser.screen().contents_diff(&screen2), b"a"); parser.process(b"\x1b[1;2H\x1b[K"); assert_eq!(parser.screen().cursor_position(), (0, 1)); @@ -104,10 +104,7 @@ fn cursor_positioning() { parser.screen().contents_formatted(), b"\x1b[?25h\x1b[m\x1b[H\x1b[J:" ); - assert_eq!( - parser.screen().contents_diff(&screen3), - b"\x1b[m\x1b[1;2H\x1b[X" - ); + assert_eq!(parser.screen().contents_diff(&screen3), b"\x1b[1;2H\x1b[X"); } #[test] @@ -420,25 +417,22 @@ fn diff() { let screen1 = parser.screen().clone(); parser.process(b"\x1b[5C\x1b[32m bar"); let screen2 = parser.screen().clone(); - assert_eq!( - screen2.contents_diff(&screen1), - b"\x1b[m\x1b[5C\x1b[32m bar" - ); + assert_eq!(screen2.contents_diff(&screen1), b"\x1b[5C\x1b[32m bar"); compare_diff(&screen1, &screen2, b""); parser.process(b"\x1b[H\x1b[31mfoo"); let screen3 = parser.screen().clone(); - assert_eq!(screen3.contents_diff(&screen2), b"\x1b[m\x1b[H\x1b[31mfoo"); + assert_eq!(screen3.contents_diff(&screen2), b"\x1b[H\x1b[31mfoo"); compare_diff(&screen2, &screen3, b"\x1b[5C\x1b[32m bar"); parser.process(b"\x1b[1;7H\x1b[32mbaz"); let screen4 = parser.screen().clone(); - assert_eq!(screen4.contents_diff(&screen3), b"\x1b[m\x1b[5C\x1b[32mz"); + assert_eq!(screen4.contents_diff(&screen3), b"\x1b[5C\x1b[32mz"); compare_diff(&screen3, &screen4, b"\x1b[5C\x1b[32m bar\x1b[H\x1b[31mfoo"); parser.process(b"\x1b[1;8H\x1b[X"); let screen5 = parser.screen().clone(); - assert_eq!(screen5.contents_diff(&screen4), b"\x1b[m\x1b[1;8H\x1b[X"); + assert_eq!(screen5.contents_diff(&screen4), b"\x1b[1;8H\x1b[X"); compare_diff( &screen4, &screen5, |