aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-11-10 06:17:09 -0500
committerJesse Luehrs <doy@tozt.net>2019-11-10 08:08:14 -0500
commit168a91a9ddc331cd3b8e5c32f7701f2b0973b147 (patch)
tree6b2df47bf18a731a9814bb875ce231e28cad1bf0
parentb04c0e6e97765aeb888479c5e0bc27d54de60659 (diff)
downloadvt100-rust-168a91a9ddc331cd3b8e5c32f7701f2b0973b147.tar.gz
vt100-rust-168a91a9ddc331cd3b8e5c32f7701f2b0973b147.zip
optimize attribute setting a bit
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/attrs.rs6
-rw-r--r--src/cell.rs13
-rw-r--r--src/grid.rs21
-rw-r--r--src/row.rs28
-rw-r--r--src/screen.rs10
-rw-r--r--src/term.rs35
-rw-r--r--tests/escape.rs5
-rw-r--r--tests/text.rs17
-rw-r--r--tests/window_contents.rs26
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) {
diff --git a/src/row.rs b/src/row.rs
index f7d4485..1f10872 100644
--- a/src/row.rs
+++ b/src/row.rs
@@ -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,