From 30c8ad23f51a8bdc067e3a76da7004ba5be8682f Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 11 Nov 2019 15:36:46 -0500 Subject: optimize erases a bit more --- src/row.rs | 126 ++++++++++++++++++++++++++++++++++------------- src/term.rs | 15 ++++++ tests/csi.rs | 34 ++++--------- tests/text.rs | 4 +- tests/window_contents.rs | 2 +- 5 files changed, 119 insertions(+), 62 deletions(-) diff --git a/src/row.rs b/src/row.rs index da5b398..52b6823 100644 --- a/src/row.rs +++ b/src/row.rs @@ -115,6 +115,7 @@ impl Row { let mut prev_was_wide = false; let default_cell = crate::cell::Cell::default(); + let mut erase: Option<(u16, &crate::attrs::Attrs)> = None; for (col, cell) in self .cells() .enumerate() @@ -131,33 +132,61 @@ impl Row { row, col: col.try_into().unwrap(), }; - if cell != &default_cell { - if pos != prev_pos { - if !wrapping - || prev_pos.row + 1 != pos.row - || prev_pos.col != self.cols() - || pos.col != 0 - { - crate::term::MoveFromTo::new(prev_pos, pos) - .write_buf(contents); + + if let Some((prev_col, attrs)) = erase { + if cell.has_contents() || cell.attrs() != attrs { + let new_pos = crate::grid::Pos { row, col: prev_col }; + crate::term::MoveFromTo::new(prev_pos, new_pos) + .write_buf(contents); + prev_pos = new_pos; + if &prev_attrs != attrs { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; } - prev_pos = pos; + crate::term::EraseChar::new(pos.col - prev_col) + .write_buf(contents); + erase = None; } + } + if cell != &default_cell { let attrs = cell.attrs(); - if &prev_attrs != attrs { - attrs.write_escape_code_diff(contents, &prev_attrs); - prev_attrs = *attrs; - } - if cell.has_contents() { + if pos != prev_pos { + if !wrapping + || prev_pos.row + 1 != pos.row + || prev_pos.col != self.cols() + || pos.col != 0 + { + crate::term::MoveFromTo::new(prev_pos, pos) + .write_buf(contents); + } + prev_pos = pos; + } + + if &prev_attrs != attrs { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; + } + contents.extend(cell.contents().as_bytes()); prev_pos.col += if cell.is_wide() { 2 } else { 1 }; - } else { - crate::term::EraseChar::default().write_buf(contents); + } else if erase.is_none() { + erase = Some((pos.col, attrs)); } } } + if let Some((prev_col, attrs)) = erase { + let new_pos = crate::grid::Pos { row, col: prev_col }; + crate::term::MoveFromTo::new(prev_pos, new_pos) + .write_buf(contents); + prev_pos = new_pos; + if &prev_attrs != attrs { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; + } + crate::term::ClearRowForward::default().write_buf(contents); + } (prev_pos, prev_attrs) } @@ -178,6 +207,7 @@ impl Row { ) -> (crate::grid::Pos, crate::attrs::Attrs) { let mut prev_was_wide = false; + let mut erase: Option<(u16, &crate::attrs::Attrs)> = None; for (col, (cell, prev_cell)) in self .cells() .zip(prev.cells()) @@ -195,33 +225,61 @@ impl Row { row, col: col.try_into().unwrap(), }; - if cell != prev_cell { - if pos != prev_pos { - if !wrapping - || prev_pos.row + 1 != pos.row - || prev_pos.col != self.cols() - || pos.col != 0 - { - crate::term::MoveFromTo::new(prev_pos, pos) - .write_buf(contents); + + if let Some((prev_col, attrs)) = erase { + if cell.has_contents() || cell.attrs() != attrs { + let new_pos = crate::grid::Pos { row, col: prev_col }; + crate::term::MoveFromTo::new(prev_pos, new_pos) + .write_buf(contents); + prev_pos = new_pos; + if &prev_attrs != attrs { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; } - prev_pos = pos; + crate::term::EraseChar::new(pos.col - prev_col) + .write_buf(contents); + erase = None; } + } + if cell != prev_cell { let attrs = cell.attrs(); - if &prev_attrs != attrs { - attrs.write_escape_code_diff(contents, &prev_attrs); - prev_attrs = *attrs; - } - if cell.has_contents() { + if pos != prev_pos { + if !wrapping + || prev_pos.row + 1 != pos.row + || prev_pos.col != self.cols() + || pos.col != 0 + { + crate::term::MoveFromTo::new(prev_pos, pos) + .write_buf(contents); + } + prev_pos = pos; + } + + if &prev_attrs != attrs { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; + } + contents.extend(cell.contents().as_bytes()); prev_pos.col += if cell.is_wide() { 2 } else { 1 }; - } else { - crate::term::EraseChar::default().write_buf(contents); + } else if erase.is_none() { + erase = Some((pos.col, attrs)); } } } + if let Some((prev_col, attrs)) = erase { + let new_pos = crate::grid::Pos { row, col: prev_col }; + crate::term::MoveFromTo::new(prev_pos, new_pos) + .write_buf(contents); + prev_pos = new_pos; + if &prev_attrs != attrs { + attrs.write_escape_code_diff(contents, &prev_attrs); + prev_attrs = *attrs; + } + crate::term::ClearRowForward::default().write_buf(contents); + } (prev_pos, prev_attrs) } diff --git a/src/term.rs b/src/term.rs index 170e2ca..cb5488a 100644 --- a/src/term.rs +++ b/src/term.rs @@ -13,6 +13,15 @@ impl BufWrite for ClearScreen { } } +#[derive(Default, Debug)] +pub struct ClearRowForward; + +impl BufWrite for ClearRowForward { + fn write_buf(&self, buf: &mut Vec) { + buf.extend_from_slice(b"\x1b[K"); + } +} + #[derive(Default, Debug)] pub struct CRLF; @@ -253,6 +262,12 @@ pub struct EraseChar { count: u16, } +impl EraseChar { + pub fn new(count: u16) -> Self { + Self { count } + } +} + impl Default for EraseChar { fn default() -> Self { Self { count: 1 } diff --git a/tests/csi.rs b/tests/csi.rs index a57a578..1129ee1 100644 --- a/tests/csi.rs +++ b/tests/csi.rs @@ -209,10 +209,8 @@ fn ed() { assert_eq!( parser.screen().contents_formatted(), format!( - "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[5;5H\x1b[41m{}\x1b[X\r\n{}{}\x1b[X\x1b[5;5H", - "\x1b[X\x1b[C".repeat(75), - format!("{}\x1b[X\r\n", "\x1b[X\x1b[C".repeat(79)).repeat(18), - "\x1b[X\x1b[C".repeat(79), + "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[5;5H\x1b[41m{}\x1b[K\x1b[5;5H", + "\x1b[K\r\n".repeat(19), ) .as_bytes() ); @@ -259,9 +257,8 @@ fn ed() { assert_eq!( parser.screen().contents_formatted(), format!( - "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[41m{}{}\x1b[X", - format!("{}\x1b[X\r\n", "\x1b[X\x1b[C".repeat(79)).repeat(4), - "\x1b[X\x1b[C".repeat(4), + "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[41m{}\x1b[5X\x1b[4C", + "\x1b[K\r\n".repeat(4), ) .as_bytes() ); @@ -308,9 +305,8 @@ fn ed() { assert_eq!( parser.screen().contents_formatted(), format!( - "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[41m{}{}\x1b[5;5H", - format!("{}\x1b[X\r\n", "\x1b[X\x1b[C".repeat(79)).repeat(23), - format!("{}\x1b[X", "\x1b[X\x1b[C".repeat(79)), + "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[41m{}\x1b[K\x1b[5;5H", + "\x1b[K\r\n".repeat(23), ) .as_bytes() ); @@ -421,11 +417,7 @@ fn el() { ); assert_eq!( parser.screen().contents_formatted(), - format!( - "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[5;5H\x1b[41m{}\x1b[X\x1b[5;5H", - "\x1b[X\x1b[C".repeat(75) - ) - .as_bytes() + &b"\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[5;5H\x1b[41m\x1b[K"[..], ); parser.process(b"\x1bc\x1b[5;5H"); @@ -461,11 +453,7 @@ fn el() { ); assert_eq!( parser.screen().contents_formatted(), - format!( - "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[5;1H\x1b[41m{}\x1b[X", - "\x1b[X\x1b[C".repeat(4), - ) - .as_bytes() + &b"\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[5;1H\x1b[41m\x1b[5X\x1b[4C"[..], ); parser.process(b"\x1bc\x1b[5;5H"); @@ -501,11 +489,7 @@ fn el() { ); assert_eq!( parser.screen().contents_formatted(), - format!( - "\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[5;1H\x1b[41m{}\x1b[X\x1b[5;5H", - "\x1b[X\x1b[C".repeat(79), - ) - .as_bytes() + &b"\x1b[?25h\x1b[m\x1b[H\x1b[J\x1b[5;1H\x1b[41m\x1b[K\x1b[4C"[..], ); } diff --git a/tests/text.rs b/tests/text.rs index c49ded4..e0b4cee 100644 --- a/tests/text.rs +++ b/tests/text.rs @@ -100,7 +100,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[Hデcネfo\x1b[Cbar\x1b[X".as_bytes() + "\x1b[Hデcネfo\x1b[Cbar\x1b[K".as_bytes() ); let screen = parser.screen().clone(); @@ -126,7 +126,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[Hデcネfo\x1b[Cbar\x1b[X".as_bytes() + "\x1b[Hデcネfo\x1b[Cbar\x1b[K".as_bytes() ); } diff --git a/tests/window_contents.rs b/tests/window_contents.rs index 161402e..1bad9ed 100644 --- a/tests/window_contents.rs +++ b/tests/window_contents.rs @@ -106,7 +106,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[1;2H\x1b[X"); + assert_eq!(parser.screen().contents_diff(&screen3), b"\x1b[1;2H\x1b[K"); } #[test] -- cgit v1.2.3-54-g00ecf