diff options
-rw-r--r-- | src/grid.rs | 2 | ||||
-rw-r--r-- | src/row.rs | 11 | ||||
-rw-r--r-- | src/screen.rs | 27 | ||||
-rw-r--r-- | tests/window_contents.rs | 88 |
4 files changed, 109 insertions, 19 deletions
diff --git a/src/grid.rs b/src/grid.rs index 075e604..fa6b4b9 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -177,7 +177,7 @@ impl Grid { for (idx, (row, prev_row)) in self.rows().zip(prev.rows()).enumerate() { let (mut new_contents, new_attrs, new_col) = - row.contents_diff(prev_row, prev_attrs); + row.contents_diff(prev_row, 0, self.size.cols, prev_attrs); if !new_contents.is_empty() { contents.extend(format!("\x1b[{};1H", idx + 1).as_bytes()); final_row = idx.try_into().unwrap(); @@ -126,14 +126,21 @@ impl Row { pub fn contents_diff( &self, prev: &Self, + start: u16, + width: u16, attrs: crate::attrs::Attrs, ) -> (Vec<u8>, crate::attrs::Attrs, u16) { let mut skip = 0; let mut contents = vec![]; let mut prev_attrs = attrs; let mut final_col = 0; - for (idx, (cell, prev_cell)) in - self.cells().zip(prev.cells()).enumerate() + + for (idx, (cell, prev_cell)) in self + .cells() + .zip(prev.cells()) + .skip(start as usize) + .take(width as usize) + .enumerate() { if cell == prev_cell { skip += 1; diff --git a/src/screen.rs b/src/screen.rs index 6aa80ba..873eeb3 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -211,6 +211,33 @@ impl Screen { grid_contents } + /// Returns a sequence of terminal byte streams sufficient to turn the + /// subset of each row from `prev` (as described by `start` and `width`) + /// into the corresponding row subset in `self`. + /// + /// You must handle the initial row positioning yourself - each row diff + /// expects to start out positioned at the start of that row. Internal + /// terminal modes (such as application keypad mode or alternate screen + /// mode) will not be included here. + pub fn rows_diff<'a>( + &'a self, + prev: &'a Self, + start: u16, + width: u16, + ) -> impl Iterator<Item = Vec<u8>> + 'a { + self.grid().rows().zip(prev.grid().rows()).map( + move |(row, prev_row)| { + let (contents, ..) = row.contents_diff( + prev_row, + start, + width, + crate::attrs::Attrs::default(), + ); + contents + }, + ) + } + /// Returns the `Cell` object at the given location in the terminal, if it /// exists. pub fn cell(&self, row: u16, col: u16) -> Option<&crate::cell::Cell> { diff --git a/tests/window_contents.rs b/tests/window_contents.rs index 1d351cb..07a656d 100644 --- a/tests/window_contents.rs +++ b/tests/window_contents.rs @@ -72,8 +72,9 @@ fn empty_cells() { #[test] fn rows() { let mut parser = vt100::Parser::new(24, 80); + let screen1 = parser.screen().clone(); assert_eq!( - parser.screen().rows(0, 80).collect::<Vec<String>>(), + screen1.rows(0, 80).collect::<Vec<String>>(), vec![ String::new(), String::new(), @@ -102,10 +103,7 @@ fn rows() { ] ); assert_eq!( - parser - .screen() - .rows_formatted(0, 80) - .collect::<Vec<Vec<u8>>>(), + screen1.rows_formatted(0, 80).collect::<Vec<Vec<u8>>>(), vec![ vec![], vec![], @@ -134,7 +132,7 @@ fn rows() { ] ); assert_eq!( - parser.screen().rows(5, 15).collect::<Vec<String>>(), + screen1.rows(5, 15).collect::<Vec<String>>(), vec![ String::new(), String::new(), @@ -163,10 +161,7 @@ fn rows() { ] ); assert_eq!( - parser - .screen() - .rows_formatted(5, 15) - .collect::<Vec<Vec<u8>>>(), + screen1.rows_formatted(5, 15).collect::<Vec<Vec<u8>>>(), vec![ vec![], vec![], @@ -197,8 +192,9 @@ fn rows() { parser .process(b"\x1b[31mfoo\x1b[10;10H\x1b[32mbar\x1b[20;20H\x1b[33mbaz"); + let screen2 = parser.screen().clone(); assert_eq!( - parser.screen().rows(0, 80).collect::<Vec<String>>(), + screen2.rows(0, 80).collect::<Vec<String>>(), vec![ "foo".to_string(), String::new(), @@ -227,8 +223,7 @@ fn rows() { ] ); assert_eq!( - parser - .screen() + screen2 .rows_formatted(0, 80) .collect::<Vec<Vec<u8>>>(), vec![ @@ -259,7 +254,7 @@ fn rows() { ] ); assert_eq!( - parser.screen().rows(5, 15).collect::<Vec<String>>(), + screen2.rows(5, 15).collect::<Vec<String>>(), vec![ String::new(), String::new(), @@ -288,8 +283,7 @@ fn rows() { ] ); assert_eq!( - parser - .screen() + screen2 .rows_formatted(5, 15) .collect::<Vec<Vec<u8>>>(), vec![ @@ -319,6 +313,68 @@ fn rows() { vec![], ] ); + + assert_eq!( + screen2.rows_diff(&screen1, 0, 80).collect::<Vec<Vec<u8>>>(), + vec![ + b"\x1b[31mfoo".to_vec(), + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + b"\x1b[9C\x1b[32mbar".to_vec(), + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + b"\x1b[19C\x1b[33mbaz".to_vec(), + vec![], + vec![], + vec![], + vec![], + ] + ); + + parser.process(b"\x1b[10;11Ho"); + let screen3 = parser.screen().clone(); + assert_eq!( + screen3.rows_diff(&screen2, 0, 80).collect::<Vec<Vec<u8>>>(), + vec![ + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + b"\x1b[10C\x1b[33mo".to_vec(), + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + vec![], + ] + ); } #[test] |