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 --- CHANGELOG.md | 2 ++ src/grid.rs | 24 ++++++++++++++++++++---- src/row.rs | 16 ++++++++++++++-- src/screen.rs | 28 ++++++++++++++++++++-------- tests/data/fixtures/attrs.in | 1 + tests/data/fixtures/attrs/10.json | 17 +++++++++++++++++ tests/data/fixtures/attrs/10.typescript | 1 + 7 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 tests/data/fixtures/attrs/10.json create mode 100644 tests/data/fixtures/attrs/10.typescript diff --git a/CHANGELOG.md b/CHANGELOG.md index c863506..dc9a22a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * Fixed some line wrapping state issues with `contents_diff` * Fixed cursor positioning after writing zero width characters at the end of the line +* Fixed `Screen::cursor_state_formatted` to draw the last character in a line + with the appropriate drawing attributes if it needs to redraw it ## [0.13.0] - 2021-11-17 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 diff --git a/tests/data/fixtures/attrs.in b/tests/data/fixtures/attrs.in index 0edae4e..4fe65cb 100644 --- a/tests/data/fixtures/attrs.in +++ b/tests/data/fixtures/attrs.in @@ -7,3 +7,4 @@ f\x1b[1mo\x1b[3mo\x1b[4mo\x1b[7mo \x1bcfoo \x1b[1;2H\x1b[4;7mo\x1b[m \x1b[1;1H\x1b[4;7m\x1b[X\x1b[m +\x1bc\x1b[1;79H\x1b[31mab diff --git a/tests/data/fixtures/attrs/10.json b/tests/data/fixtures/attrs/10.json new file mode 100644 index 0000000..b6cb478 --- /dev/null +++ b/tests/data/fixtures/attrs/10.json @@ -0,0 +1,17 @@ +{ + "contents": " ab", + "cells": { + "0,78": { + "contents": "a", + "fgcolor": "1" + }, + "0,79": { + "contents": "b", + "fgcolor": "1" + } + }, + "cursor_position": [ + 0, + 80 + ] +} \ No newline at end of file diff --git a/tests/data/fixtures/attrs/10.typescript b/tests/data/fixtures/attrs/10.typescript new file mode 100644 index 0000000..ba2cb07 --- /dev/null +++ b/tests/data/fixtures/attrs/10.typescript @@ -0,0 +1 @@ +cab \ No newline at end of file -- cgit v1.2.3-54-g00ecf