From 5970f3f473b915f61f8306263c15c70e2f962f7c Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 9 Nov 2019 02:23:54 -0500 Subject: refactor terminal writing --- src/attrs.rs | 120 +++++++------------- src/grid.rs | 86 +++++++++------ src/lib.rs | 1 + src/row.rs | 107 +++++++++++------- src/screen.rs | 68 ++++++++---- src/term.rs | 277 +++++++++++++++++++++++++++++++++++++++++++++++ tests/text.rs | 12 +- tests/window_contents.rs | 17 ++- 8 files changed, 499 insertions(+), 189 deletions(-) create mode 100644 src/term.rs diff --git a/src/attrs.rs b/src/attrs.rs index 95a5e76..dc46646 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -1,3 +1,5 @@ +use std::io::Write as _; + /// Represents a foreground or background color for cells. #[derive(Eq, PartialEq, Debug, Copy, Clone)] pub enum Color { @@ -87,89 +89,49 @@ impl Attrs { } } - pub fn escape_code_diff(&self, other: &Self) -> Vec { - let mut opts = vec![]; + pub fn write_escape_code_diff( + &self, + contents: &mut Vec, + other: &Self, + ) { + let attrs = crate::term::Attrs::default(); if self != other && self == &Self::default() { - return b"\x1b[m".to_vec(); - } - - if self.fgcolor != other.fgcolor { - match self.fgcolor { - Color::Default => { - opts.push(39); - } - Color::Idx(i) => { - if i < 8 { - opts.push(i + 30); - } else if i < 16 { - opts.push(i + 82); - } else { - opts.push(38); - opts.push(5); - opts.push(i); - } - } - Color::Rgb(r, g, b) => { - opts.push(38); - opts.push(2); - opts.push(r); - opts.push(g); - opts.push(b); - } - } - } - - if self.bgcolor != other.bgcolor { - match self.bgcolor { - Color::Default => { - opts.push(49); - } - Color::Idx(i) => { - if i < 8 { - opts.push(i + 40); - } else if i < 16 { - opts.push(i + 92); - } else { - opts.push(48); - opts.push(5); - opts.push(i); - } - } - Color::Rgb(r, g, b) => { - opts.push(48); - opts.push(2); - opts.push(r); - opts.push(g); - opts.push(b); - } - } + write!(contents, "{}", attrs).unwrap(); + return; } - if self.bold() != other.bold() { - opts.push(if self.bold() { 1 } else { 22 }); - } - if self.italic() != other.italic() { - opts.push(if self.italic() { 3 } else { 23 }); - } - if self.underline() != other.underline() { - opts.push(if self.underline() { 4 } else { 24 }); - } - if self.inverse() != other.inverse() { - opts.push(if self.inverse() { 7 } else { 27 }); - } + let attrs = if self.fgcolor == other.fgcolor { + attrs + } else { + attrs.fgcolor(self.fgcolor) + }; + let attrs = if self.bgcolor == other.bgcolor { + attrs + } else { + attrs.bgcolor(self.bgcolor) + }; + let attrs = if self.bold() == other.bold() { + attrs + } else { + attrs.bold(self.bold()) + }; + let attrs = if self.italic() == other.italic() { + attrs + } else { + attrs.italic(self.italic()) + }; + let attrs = if self.underline() == other.underline() { + attrs + } else { + attrs.underline(self.underline()) + }; + let attrs = if self.inverse() == other.inverse() { + attrs + } else { + attrs.inverse(self.inverse()) + }; - let mut bytes = b"\x1b[".to_vec(); - let mut first = true; - for opt in opts { - if first { - first = false; - } else { - bytes.push(b';'); - } - bytes.extend(opt.to_string().as_bytes()); - } - bytes.push(b'm'); - bytes + write!(contents, "{}", attrs).unwrap(); } } diff --git a/src/grid.rs b/src/grid.rs index fa5d437..287e5e4 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -1,4 +1,6 @@ use std::convert::TryInto as _; +use std::fmt::Write as _; +use std::io::Write as _; #[derive(Clone, Debug)] pub struct Grid { @@ -125,30 +127,42 @@ impl Grid { .expect("cursor not pointing to a cell") } - pub fn contents(&self) -> String { - let mut contents = String::new(); + pub fn write_contents(&self, contents: &mut String) { for row in self.rows() { - contents += &row.contents(0, self.size.cols); + row.write_contents(contents, 0, self.size.cols); if !row.wrapped() { - contents += "\n"; + writeln!(contents).unwrap(); } } - contents.trim_end().to_string() + + while contents.ends_with('\n') { + contents.truncate(contents.len() - 1); + } } - pub fn contents_formatted(&self) -> Vec { - let mut contents = b"\x1b[m\x1b[H\x1b[J".to_vec(); + pub fn write_contents_formatted(&self, contents: &mut Vec) { + write!( + contents, + "{}{}", + crate::term::Attrs::new(), + crate::term::ClearScreen::new() + ) + .unwrap(); + let mut prev_attrs = crate::attrs::Attrs::default(); let mut final_col = 0; for row in self.rows() { - let (mut new_contents, new_attrs, new_col) = - row.contents_formatted(0, self.size.cols, prev_attrs); - if !new_contents.is_empty() { - final_col = new_col; + let (new_attrs, new_col) = row.write_contents_formatted( + contents, + 0, + self.size.cols, + prev_attrs, + ); + if let Some(col) = new_col { + final_col = col; } - contents.append(&mut new_contents); if !row.wrapped() { - contents.extend(b"\r\n"); + write!(contents, "{}", crate::term::CRLF::new()).unwrap(); } prev_attrs = new_attrs; } @@ -160,41 +174,45 @@ impl Grid { } if final_row != self.pos.row || final_col != self.pos.col { - contents.extend( - format!("\x1b[{};{}H", self.pos.row + 1, self.pos.col + 1) - .as_bytes(), - ); + write!(contents, "{}", crate::term::MoveTo::new(self.pos)) + .unwrap(); } - - contents } - pub fn contents_diff(&self, prev: &Self) -> Vec { - let mut contents = b"\x1b[m".to_vec(); + pub fn write_contents_diff(&self, contents: &mut Vec, prev: &Self) { + write!(contents, "{}", crate::term::Attrs::default()).unwrap(); let mut prev_attrs = crate::attrs::Attrs::default(); let mut final_row = prev.pos.row; let mut final_col = prev.pos.col; 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, 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(); - final_col = new_col; + let idx = idx.try_into().unwrap(); + let (new_attrs, new_col) = row.write_contents_diff( + contents, + prev_row, + |contents| { + write!( + contents, + "{}", + crate::term::MoveTo::new(Pos { row: idx, col: 0 }) + ) + .unwrap(); + }, + 0, + self.size.cols, + prev_attrs, + ); + if let Some(col) = new_col { + final_row = idx; + final_col = col; } - contents.append(&mut new_contents); prev_attrs = new_attrs; } if self.pos.row != final_row || self.pos.col != final_col { - contents.extend( - format!("\x1b[{};{}H", self.pos.row + 1, self.pos.col + 1) - .as_bytes(), - ); + write!(contents, "{}", crate::term::MoveTo::new(self.pos)) + .unwrap(); } - - contents } pub fn erase_all(&mut self, bgcolor: crate::attrs::Color) { diff --git a/src/lib.rs b/src/lib.rs index 48dee07..9424fb9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ mod grid; mod parser; mod row; mod screen; +mod term; pub use attrs::Color; pub use cell::Cell; diff --git a/src/row.rs b/src/row.rs index 0b834ce..4655f48 100644 --- a/src/row.rs +++ b/src/row.rs @@ -1,4 +1,5 @@ use std::convert::TryInto as _; +use std::io::Write as _; #[derive(Clone, Debug)] pub struct Row { @@ -63,46 +64,51 @@ impl Row { self.wrapped } - pub fn contents(&self, start: u16, width: u16) -> String { + pub fn write_contents( + &self, + contents: &mut String, + start: u16, + width: u16, + ) { let mut prev_was_wide = false; - let mut contents = String::new(); for cell in self .cells() .skip(start as usize) - .take(width.min(self.content_width(start)) as usize) + .take(width.min(self.content_width(start, false)) as usize) { if prev_was_wide { prev_was_wide = false; continue; } - contents += if cell.has_contents() { - cell.contents() + if cell.has_contents() { + // using write! here is significantly slower, for some reason + // write!(contents, "{}", cell.contents()).unwrap(); + contents.push_str(cell.contents()); } else { - " " - }; + contents.push(' '); + } + prev_was_wide = cell.is_wide(); } - - contents.trim_end().to_string() } - pub fn contents_formatted( + pub fn write_contents_formatted( &self, + contents: &mut Vec, start: u16, width: u16, attrs: crate::attrs::Attrs, - ) -> (Vec, crate::attrs::Attrs, u16) { + ) -> (crate::attrs::Attrs, Option) { let mut prev_was_wide = false; - let mut contents = vec![]; let mut prev_attrs = attrs; - let mut cols = 0; + let mut cols = None; for cell in self .cells() .skip(start as usize) - .take(width.min(self.content_width(start)) as usize) + .take(width.min(self.content_width(start, true)) as usize) { if prev_was_wide { prev_was_wide = false; @@ -111,37 +117,49 @@ impl Row { let attrs = cell.attrs(); if &prev_attrs != attrs { - contents.append(&mut attrs.escape_code_diff(&prev_attrs)); + attrs.write_escape_code_diff(contents, &prev_attrs); prev_attrs = *attrs; } - contents.extend(if cell.has_contents() { - cell.contents().as_bytes() + if cell.has_contents() { + // using write! here is significantly slower, for some reason + // write!(contents, "{}", cell.contents()).unwrap(); + contents.extend(cell.contents().as_bytes()); } else if cell.bgcolor() == crate::attrs::Color::Default { - &b"\x1b[C"[..] + write!(contents, "{}", crate::term::MoveRight::default()) + .unwrap(); } else { - &b"\x1b[X\x1b[C"[..] - }); + write!( + contents, + "{}{}", + crate::term::EraseChar::default(), + crate::term::MoveRight::default() + ) + .unwrap(); + } prev_was_wide = cell.is_wide(); - cols += if prev_was_wide { 2 } else { 1 }; + cols = + Some(cols.unwrap_or(0) + if prev_was_wide { 2 } else { 1 }); } - (contents, prev_attrs, cols) + (prev_attrs, cols) } - pub fn contents_diff( + pub fn write_contents_diff Fn(&'a mut Vec)>( &self, + contents: &mut Vec, prev: &Self, + initial_pos: F, start: u16, width: u16, attrs: crate::attrs::Attrs, - ) -> (Vec, crate::attrs::Attrs, u16) { + ) -> (crate::attrs::Attrs, Option) { let mut prev_was_wide = false; - let mut skip = 0; - let mut contents = vec![]; let mut prev_attrs = attrs; - let mut cols = 0; + let mut skip = 0; + let mut cols = None; + let mut initial_pos = Some(initial_pos); for (cell, prev_cell) in self .cells() @@ -158,38 +176,51 @@ impl Row { prev_was_wide = cell.is_wide(); skip += if prev_was_wide { 2 } else { 1 }; } else { + if let Some(f) = initial_pos.take() { + f(contents) + } if skip > 0 { - contents.extend(format!("\x1b[{}C", skip).as_bytes()); - cols += skip; + write!(contents, "{}", crate::term::MoveRight::new(skip)) + .unwrap(); + cols = Some(cols.unwrap_or(0) + skip); skip = 0; } let attrs = cell.attrs(); if &prev_attrs != attrs { - contents.append(&mut attrs.escape_code_diff(&prev_attrs)); + attrs.write_escape_code_diff(contents, &prev_attrs); prev_attrs = *attrs; } - contents.extend(if cell.has_contents() { - cell.contents().as_bytes() + if cell.has_contents() { + write!(contents, "{}", cell.contents()).unwrap(); } else { - b"\x1b[X\x1b[C" - }); + write!( + contents, + "{}{}", + crate::term::EraseChar::default(), + crate::term::MoveRight::default() + ) + .unwrap(); + } prev_was_wide = cell.is_wide(); - cols += if prev_was_wide { 2 } else { 1 }; + cols = Some( + cols.unwrap_or(0) + if prev_was_wide { 2 } else { 1 }, + ); } } - (contents, prev_attrs, cols) + (prev_attrs, cols) } - fn content_width(&self, start: u16) -> u16 { + fn content_width(&self, start: u16, formatting: bool) -> u16 { for (col, cell) in self.cells.iter().skip(start as usize).enumerate().rev() { if cell.has_contents() - || cell.bgcolor() != crate::attrs::Color::Default + || (formatting + && cell.bgcolor() != crate::attrs::Color::Default) { let width: u16 = col.try_into().unwrap(); return width + 1; diff --git a/src/screen.rs b/src/screen.rs index 88e5b44..4ed065b 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1,4 +1,5 @@ use std::convert::TryInto as _; +use std::io::Write as _; use unicode_width::UnicodeWidthChar as _; const DEFAULT_MULTI_PARAMS: &[i64] = &[0]; @@ -128,7 +129,13 @@ impl Screen { /// This will not include any formatting information, and will be in plain /// text format. pub fn contents(&self) -> String { - self.grid().contents() + let mut contents = String::new(); + self.write_contents(&mut contents); + contents + } + + fn write_contents(&self, contents: &mut String) { + self.grid().write_contents(contents); } /// Returns the text contents of the terminal by row, restricted to the @@ -143,9 +150,11 @@ impl Screen { start: u16, width: u16, ) -> impl Iterator + '_ { - self.grid() - .rows() - .map(move |row| row.contents(start, width)) + self.grid().rows().map(move |row| { + let mut contents = String::new(); + row.write_contents(&mut contents, start, width); + contents + }) } /// Returns the formatted contents of the terminal. @@ -157,14 +166,19 @@ impl Screen { /// mode) will not be included here, but modes that affect the visible /// output (such as hidden cursor mode) will. pub fn contents_formatted(&self) -> Vec { - let mut grid_contents = if self.hide_cursor() { - b"\x1b[?25l" - } else { - b"\x1b[?25h" - } - .to_vec(); - grid_contents.append(&mut self.grid().contents_formatted()); - grid_contents + let mut contents = vec![]; + self.write_contents_formatted(&mut contents); + contents + } + + fn write_contents_formatted(&self, contents: &mut Vec) { + write!( + contents, + "{}", + crate::term::HideCursor::new(self.hide_cursor()) + ) + .unwrap(); + self.grid().write_contents_formatted(contents); } /// Returns the formatted contents of the terminal by row, restricted to @@ -183,7 +197,9 @@ impl Screen { width: u16, ) -> impl Iterator> + '_ { self.grid().rows().map(move |row| { - let (contents, ..) = row.contents_formatted( + let mut contents = vec![]; + row.write_contents_formatted( + &mut contents, start, width, crate::attrs::Attrs::default(), @@ -202,16 +218,21 @@ impl Screen { /// since the diff will likely require less memory and cause less /// flickering than redrawing the entire screen contents. pub fn contents_diff(&self, prev: &Self) -> Vec { - let mut grid_contents = vec![]; + let mut contents = vec![]; + self.write_contents_diff(&mut contents, prev); + contents + } + + fn write_contents_diff(&self, contents: &mut Vec, prev: &Self) { if self.hide_cursor() != prev.hide_cursor() { - grid_contents.extend(if self.hide_cursor() { - b"\x1b[?25l" - } else { - b"\x1b[?25h" - }); + write!( + contents, + "{}", + crate::term::HideCursor::new(self.hide_cursor()) + ) + .unwrap(); } - grid_contents.append(&mut self.grid().contents_diff(prev.grid())); - grid_contents + self.grid().write_contents_diff(contents, prev.grid()); } /// Returns a sequence of terminal byte streams sufficient to turn the @@ -230,8 +251,11 @@ impl Screen { ) -> impl Iterator> + 'a { self.grid().rows().zip(prev.grid().rows()).map( move |(row, prev_row)| { - let (contents, ..) = row.contents_diff( + let mut contents = vec![]; + row.write_contents_diff( + &mut contents, prev_row, + |_| (), start, width, crate::attrs::Attrs::default(), diff --git a/src/term.rs b/src/term.rs new file mode 100644 index 0000000..ef6c546 --- /dev/null +++ b/src/term.rs @@ -0,0 +1,277 @@ +// TODO: read all of this from terminfo + +#[derive(Default, Debug)] +pub struct ClearScreen; + +impl ClearScreen { + pub fn new() -> Self { + Self::default() + } +} + +impl std::fmt::Display for ClearScreen { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("\x1b[H\x1b[J") + } +} + +#[derive(Default, Debug)] +pub struct CRLF; + +impl CRLF { + pub fn new() -> Self { + Self::default() + } +} + +impl std::fmt::Display for CRLF { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("\r\n") + } +} + +#[derive(Default, Debug)] +pub struct MoveTo { + row: u16, + col: u16, +} + +impl MoveTo { + pub fn new(pos: crate::grid::Pos) -> Self { + Self { + row: pos.row, + col: pos.col, + } + } +} + +impl std::fmt::Display for MoveTo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.row == 0 && self.col == 0 { + f.write_str("\x1b[H") + } else { + write!(f, "\x1b[{};{}H", self.row + 1, self.col + 1) + } + } +} + +#[derive(Default, Debug)] +pub struct Attrs { + fgcolor: Option, + bgcolor: Option, + bold: Option, + italic: Option, + underline: Option, + inverse: Option, +} + +impl Attrs { + pub fn new() -> Self { + Self::default() + } + + pub fn fgcolor(mut self, fgcolor: crate::attrs::Color) -> Self { + self.fgcolor = Some(fgcolor); + self + } + + pub fn bgcolor(mut self, bgcolor: crate::attrs::Color) -> Self { + self.bgcolor = Some(bgcolor); + self + } + + pub fn bold(mut self, bold: bool) -> Self { + self.bold = Some(bold); + self + } + + pub fn italic(mut self, italic: bool) -> Self { + self.italic = Some(italic); + self + } + + pub fn underline(mut self, underline: bool) -> Self { + self.underline = Some(underline); + self + } + + pub fn inverse(mut self, inverse: bool) -> Self { + self.inverse = Some(inverse); + self + } +} + +impl std::fmt::Display for Attrs { + #[allow(unused_assignments, clippy::cognitive_complexity)] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("\x1b[")?; + let mut first = true; + + macro_rules! write_param { + ($i:expr) => { + if first { + first = false; + } else { + f.write_str(";")?; + } + write!(f, "{}", $i)?; + }; + } + + if let Some(fgcolor) = self.fgcolor { + match fgcolor { + crate::attrs::Color::Default => { + write_param!(39); + } + crate::attrs::Color::Idx(i) => { + if i < 8 { + write_param!(i + 30); + } else if i < 16 { + write_param!(i + 82); + } else { + write_param!(38); + write_param!(5); + write_param!(i); + } + } + crate::attrs::Color::Rgb(r, g, b) => { + write_param!(38); + write_param!(2); + write_param!(r); + write_param!(g); + write_param!(b); + } + } + } + + if let Some(bgcolor) = self.bgcolor { + match bgcolor { + crate::attrs::Color::Default => { + write_param!(49); + } + crate::attrs::Color::Idx(i) => { + if i < 8 { + write_param!(i + 40); + } else if i < 16 { + write_param!(i + 92); + } else { + write_param!(48); + write_param!(5); + write_param!(i); + } + } + crate::attrs::Color::Rgb(r, g, b) => { + write_param!(48); + write_param!(2); + write_param!(r); + write_param!(g); + write_param!(b); + } + } + } + + if let Some(bold) = self.bold { + if bold { + write_param!(1); + } else { + write_param!(22); + } + } + + if let Some(italic) = self.italic { + if italic { + write_param!(3); + } else { + write_param!(23); + } + } + + if let Some(underline) = self.underline { + if underline { + write_param!(4); + } else { + write_param!(24); + } + } + + if let Some(inverse) = self.inverse { + if inverse { + write_param!(7); + } else { + write_param!(27); + } + } + + f.write_str("m")?; + Ok(()) + } +} + +#[derive(Debug)] +pub struct MoveRight { + count: u16, +} + +impl MoveRight { + pub fn new(count: u16) -> Self { + Self { count } + } +} + +impl Default for MoveRight { + fn default() -> Self { + Self { count: 1 } + } +} + +impl std::fmt::Display for MoveRight { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.count { + 0 => Ok(()), + 1 => f.write_str("\x1b[C"), + n => write!(f, "\x1b[{}C", n), + } + } +} + +#[derive(Debug)] +pub struct EraseChar { + count: u16, +} + +impl Default for EraseChar { + fn default() -> Self { + Self { count: 1 } + } +} + +impl std::fmt::Display for EraseChar { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.count { + 0 => Ok(()), + 1 => f.write_str("\x1b[X"), + n => write!(f, "\x1b[{}X", n), + } + } +} + +#[derive(Default, Debug)] +pub struct HideCursor { + hide: bool, +} + +impl HideCursor { + pub fn new(hide: bool) -> Self { + Self { hide } + } +} + +impl std::fmt::Display for HideCursor { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.hide { + f.write_str("\x1b[?25l") + } else { + f.write_str("\x1b[?25h") + } + } +} diff --git a/tests/text.rs b/tests/text.rs index 245a87f..5c16039 100644 --- a/tests/text.rs +++ b/tests/text.rs @@ -64,7 +64,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[1;1Haデbネ".as_bytes() + "\x1b[m\x1b[Haデbネ".as_bytes() ); let screen = parser.screen().clone(); @@ -77,7 +77,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[1;1H\x1b[3Cc".as_bytes() + "\x1b[m\x1b[H\x1b[3Cc".as_bytes() ); let screen = parser.screen().clone(); @@ -90,7 +90,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[1;1H\x1b[6Cfoobar".as_bytes() + "\x1b[m\x1b[H\x1b[6Cfoobar".as_bytes() ); let screen = parser.screen().clone(); @@ -103,7 +103,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[1;1Hデcネfo\x1b[1Cbar\x1b[X\x1b[C\x1b[1;12H".as_bytes() + "\x1b[m\x1b[Hデcネfo\x1b[Cbar\x1b[X\x1b[C\x1b[1;12H".as_bytes() ); let screen = parser.screen().clone(); @@ -116,7 +116,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[1;1Haデcネf\x1b[1Cobar".as_bytes() + "\x1b[m\x1b[Haデcネf\x1b[Cobar".as_bytes() ); let screen = parser.screen().clone(); @@ -129,7 +129,7 @@ fn wide() { ); assert_eq!( parser.screen().contents_diff(&screen), - "\x1b[m\x1b[1;1Hデcネfo\x1b[1Cbar\x1b[X\x1b[C\x1b[1;12H".as_bytes() + "\x1b[m\x1b[Hデcネfo\x1b[Cbar\x1b[X\x1b[C\x1b[1;12H".as_bytes() ); } diff --git a/tests/window_contents.rs b/tests/window_contents.rs index 851b128..6c0e7db 100644 --- a/tests/window_contents.rs +++ b/tests/window_contents.rs @@ -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\x1b[1;1H:"); + assert_eq!(parser.screen().contents_diff(&screen1), b"\x1b[m\x1b[H:"); parser.process(b"a"); let screen3 = parser.screen().clone(); @@ -98,7 +98,7 @@ fn cursor_positioning() { ); assert_eq!( parser.screen().contents_diff(&screen2), - b"\x1b[m\x1b[1;1H\x1b[1Ca" + b"\x1b[m\x1b[H\x1b[Ca" ); parser.process(b"\x1b[1;2H\x1b[K"); @@ -109,7 +109,7 @@ fn cursor_positioning() { ); assert_eq!( parser.screen().contents_diff(&screen3), - b"\x1b[m\x1b[1;1H\x1b[1C\x1b[X\x1b[C\x1b[1;2H" + b"\x1b[m\x1b[H\x1b[C\x1b[X\x1b[C\x1b[1;2H" ); } @@ -429,23 +429,20 @@ fn diff() { let screen2 = parser.screen().clone(); assert_eq!( screen2.contents_diff(&screen1), - b"\x1b[m\x1b[1;1H\x1b[5C\x1b[32m bar" + b"\x1b[m\x1b[H\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[1;1H\x1b[31mfoo" - ); + assert_eq!(screen3.contents_diff(&screen2), b"\x1b[m\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[1;1H\x1b[8C\x1b[32mz" + b"\x1b[m\x1b[H\x1b[8C\x1b[32mz" ); compare_diff(&screen3, &screen4, b"\x1b[5C\x1b[32m bar\x1b[H\x1b[31mfoo"); @@ -453,7 +450,7 @@ fn diff() { let screen5 = parser.screen().clone(); assert_eq!( screen5.contents_diff(&screen4), - b"\x1b[m\x1b[1;1H\x1b[7C\x1b[X\x1b[C\x1b[1;8H" + b"\x1b[m\x1b[H\x1b[7C\x1b[X\x1b[C\x1b[1;8H" ); compare_diff( &screen4, -- cgit v1.2.3-54-g00ecf