From 4227bdedde837347ecd83510b976ab13d474b2b9 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Fri, 19 Nov 2021 03:40:51 -0500 Subject: fix up some more issues with row_formatted handle cursor positioning and wrapping a bit better --- src/grid.rs | 24 ++++++++++++++++++++---- src/row.rs | 16 ++++++++++++++-- src/screen.rs | 28 ++++++++++++++++++++-------- 3 files changed, 54 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/grid.rs b/src/grid.rs index 021a787..f550f9e 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -214,15 +214,19 @@ impl Grid { self.size.cols, i, wrapping, - prev_pos, - prev_attrs, + Some(prev_pos), + Some(prev_attrs), ); prev_pos = new_pos; prev_attrs = new_attrs; wrapping = row.wrapped(); } - self.write_cursor_position_formatted(contents, Some(prev_pos)); + self.write_cursor_position_formatted( + contents, + Some(prev_pos), + Some(prev_attrs), + ); prev_attrs } @@ -254,7 +258,11 @@ impl Grid { wrapping = row.wrapped(); } - self.write_cursor_position_formatted(contents, Some(prev_pos)); + self.write_cursor_position_formatted( + contents, + Some(prev_pos), + Some(prev_attrs), + ); prev_attrs } @@ -263,6 +271,7 @@ impl Grid { &self, contents: &mut Vec, prev_pos: Option, + prev_attrs: Option, ) { // writing a character to the last column of a row doesn't wrap the // cursor immediately - it waits until the next character is actually @@ -285,7 +294,14 @@ impl Grid { } else { crate::term::MoveTo::new(pos).write_buf(contents); } + cell.attrs().write_escape_code_diff( + contents, + &prev_attrs.unwrap_or_default(), + ); contents.extend(cell.contents().as_bytes()); + if let Some(prev_attrs) = prev_attrs { + prev_attrs.write_escape_code_diff(contents, cell.attrs()); + } } else { // if the cell doesn't have contents, we can't have gotten // here by drawing a character in the last column. this means diff --git a/src/row.rs b/src/row.rs index cbd73ae..6f1cc0b 100644 --- a/src/row.rs +++ b/src/row.rs @@ -135,12 +135,24 @@ impl Row { width: u16, row: u16, wrapping: bool, - mut prev_pos: crate::grid::Pos, - mut prev_attrs: crate::attrs::Attrs, + prev_pos: Option, + prev_attrs: Option, ) -> (crate::grid::Pos, crate::attrs::Attrs) { let mut prev_was_wide = false; let default_cell = crate::cell::Cell::default(); + let mut prev_pos = if let Some(prev_pos) = prev_pos { + prev_pos + } else if wrapping { + crate::grid::Pos { + row: row - 1, + col: self.cols(), + } + } else { + crate::grid::Pos { row, col: start } + }; + let mut prev_attrs = prev_attrs.unwrap_or_default(); + let first_cell = self.get(start).unwrap(); if wrapping && first_cell == &default_cell { contents.push(b' '); diff --git a/src/screen.rs b/src/screen.rs index 56bd963..57d1d1c 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -294,10 +294,12 @@ impl Screen { width, i, wrapping, - crate::grid::Pos { row: i, col: start }, - crate::attrs::Attrs::default(), + None, + None, ); - wrapping = row.wrapped(); + if start == 0 && width == self.grid.size().cols { + wrapping = row.wrapped(); + } contents }) } @@ -551,10 +553,12 @@ impl Screen { /// need to restore the terminal state without the terminal contents /// necessarily being the same. /// - /// Note that this is more complicated than it sounds, because the cursor - /// position's state includes more than just the data returned by - /// `cursor_position`, since moving the cursor to the next row during text - /// wrapping is delayed until a character is written. + /// Note that the bytes returned by this function may alter the active + /// drawing attributes, because it may require redrawing existing cells in + /// order to position the cursor correctly (for instance, in the case + /// where the cursor is past the end of a row). Therefore, you should + /// ensure to reset the active drawing attributes if necessary after + /// processing this data, for instance by using `attributes_formatted`. #[must_use] pub fn cursor_state_formatted(&self) -> Vec { let mut contents = vec![]; @@ -564,7 +568,15 @@ impl Screen { fn write_cursor_state_formatted(&self, contents: &mut Vec) { crate::term::HideCursor::new(self.hide_cursor()).write_buf(contents); - self.grid().write_cursor_position_formatted(contents, None); + self.grid() + .write_cursor_position_formatted(contents, None, None); + + // we don't just call write_attributes_formatted here, because that + // would still be confusing - consider the case where the user sets + // their own unrelated drawing attributes (on a different parser + // instance) and then calls cursor_state_formatted. just documenting + // it and letting the user handle it on their own is more + // straightforward. } /// Returns the `Cell` object at the given location in the terminal, if it -- cgit v1.2.3-54-g00ecf