Preserve linewrap flag across alt screen switches

While neither VTE, URxvt nor Kitty handle this, preserving the linewrap
flag across alternate screen switches seems like the correct thing to
do. XTerm also does handle this correctly, which indicates that it is a
bug and not a feature.
This commit is contained in:
Christian Duerr 2020-07-06 05:08:36 +00:00 committed by GitHub
parent 92ea355eee
commit 72c916ff43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 30 additions and 19 deletions

View File

@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Dim escape (`CSI 2 m`) support for truecolor text
- Incorrectly deleted lines when increasing width with a prompt wrapped using spaces
- Documentation for class in `--help` missing information on setting general class
- Linewrap tracking when switching between primary and alternate screen buffer
## 0.4.3

View File

@ -71,6 +71,16 @@ pub struct Cursor {
/// Currently configured graphic character sets.
pub charsets: Charsets,
/// Tracks if the next call to input will need to first handle wrapping.
///
/// This is true after the last column is set with the input function. Any function that
/// implicitly sets the line or column needs to set this to false to avoid wrapping twice.
///
/// Tracking `input_needs_wrap` makes it possible to not store a cursor position that exceeds
/// the number of columns, which would lead to index out of bounds when interacting with arrays
/// without sanitization.
pub input_needs_wrap: bool,
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]

View File

@ -741,13 +741,6 @@ pub struct Term<T> {
pub selection: Option<Selection>,
/// Tracks if the next call to input will need to first handle wrapping.
/// This is true after the last column is set with the input function. Any function that
/// implicitly sets the line or column needs to set this to false to avoid wrapping twice.
/// input_needs_wrap ensures that cursor.col is always valid for use into indexing into
/// arrays. Without it we would have to sanitize cursor.col every time we used it.
input_needs_wrap: bool,
/// Currently active grid.
///
/// Tracks the screen buffer currently in use. While the alternate screen buffer is active,
@ -839,7 +832,6 @@ impl<T> Term<T> {
Term {
dirty: false,
visual_bell: VisualBell::new(config),
input_needs_wrap: false,
grid,
inactive_grid: alt,
active_charset: Default::default(),
@ -1079,6 +1071,9 @@ impl<T> Term<T> {
} else {
self.inactive_grid.saved_cursor = self.inactive_grid.cursor;
self.grid.saved_cursor = self.grid.cursor;
// Reset wrapline status flag.
self.inactive_grid.cursor.input_needs_wrap = false;
}
mem::swap(&mut self.grid, &mut self.inactive_grid);
@ -1235,7 +1230,7 @@ impl<T> Term<T> {
}
self.grid.cursor.point.col = Column(0);
self.input_needs_wrap = false;
self.grid.cursor.input_needs_wrap = false;
}
/// Write `c` to the cell at the cursor position.
@ -1347,7 +1342,7 @@ impl<T: EventListener> Handler for Term<T> {
}
// Move cursor to next line.
if self.input_needs_wrap {
if self.grid.cursor.input_needs_wrap {
self.wrapline();
}
@ -1376,7 +1371,7 @@ impl<T: EventListener> Handler for Term<T> {
self.wrapline();
} else {
// Prevent out of bounds crash when linewrapping is disabled.
self.input_needs_wrap = true;
self.grid.cursor.input_needs_wrap = true;
return;
}
}
@ -1392,7 +1387,7 @@ impl<T: EventListener> Handler for Term<T> {
if self.grid.cursor.point.col + 1 < num_cols {
self.grid.cursor.point.col += 1;
} else {
self.input_needs_wrap = true;
self.grid.cursor.input_needs_wrap = true;
}
}
@ -1415,7 +1410,7 @@ impl<T: EventListener> Handler for Term<T> {
self.grid.cursor.point.line = min(line + y_offset, max_y);
self.grid.cursor.point.col = min(col, self.grid.num_cols() - 1);
self.input_needs_wrap = false;
self.grid.cursor.input_needs_wrap = false;
}
#[inline]
@ -1476,14 +1471,14 @@ impl<T: EventListener> Handler for Term<T> {
trace!("Moving forward: {}", cols);
let num_cols = self.grid.num_cols();
self.grid.cursor.point.col = min(self.grid.cursor.point.col + cols, num_cols - 1);
self.input_needs_wrap = false;
self.grid.cursor.input_needs_wrap = false;
}
#[inline]
fn move_backward(&mut self, cols: Column) {
trace!("Moving backward: {}", cols);
self.grid.cursor.point.col = Column(self.grid.cursor.point.col.saturating_sub(cols.0));
self.input_needs_wrap = false;
self.grid.cursor.input_needs_wrap = false;
}
#[inline]
@ -1526,7 +1521,7 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn put_tab(&mut self, mut count: i64) {
// A tab after the last column is the same as a linebreak.
if self.input_needs_wrap {
if self.grid.cursor.input_needs_wrap {
self.wrapline();
return;
}
@ -1561,7 +1556,7 @@ impl<T: EventListener> Handler for Term<T> {
if self.grid.cursor.point.col > Column(0) {
self.grid.cursor.point.col -= 1;
self.input_needs_wrap = false;
self.grid.cursor.input_needs_wrap = false;
}
}
@ -1570,7 +1565,7 @@ impl<T: EventListener> Handler for Term<T> {
fn carriage_return(&mut self) {
trace!("Carriage return");
self.grid.cursor.point.col = Column(0);
self.input_needs_wrap = false;
self.grid.cursor.input_needs_wrap = false;
}
/// Linefeed.
@ -1933,7 +1928,6 @@ impl<T: EventListener> Handler for Term<T> {
if self.mode.contains(TermMode::ALT_SCREEN) {
mem::swap(&mut self.grid, &mut self.inactive_grid);
}
self.input_needs_wrap = false;
self.active_charset = Default::default();
self.mode = Default::default();
self.colors = self.original_colors;

View File

@ -63,6 +63,7 @@ ref_tests! {
scroll_up_reset
clear_underline
region_scroll_down
wrapline_alt_toggle
}
fn read_u8<P>(path: P) -> Vec<u8>

View File

@ -0,0 +1,2 @@
%  UL  /…/tests/ref/wrapline_alt_t…  fix_newline_flag    UL  /…/tests/ref/wrapline_alt_t…  fix_newline_flag  [?2004hfor i in {1..$(tput cols)}; do echo -ne "a"; done && echo -ne "\e[?1049h" && echo -ne "x" && echo -ne "\e[?1049l" && echo -ne "a"for i in {1..$(tput cols)}; do echo -ne "a"; done && echo -ne "\e[?1049h" && echo -ne "x" && echo -ne "\e[?1049l" && echo -ne "a"[?2004l
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[?1049hx[?1049la%  UL  /…/tests/ref/wrapline_alt_t…  fix_newline_flag    UL  /…/tests/ref/wrapline_alt_t…  fix_newline_flag  [?2004hexitexit[?2004l

View File

@ -0,0 +1 @@
{"history_size":0}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"width":1259.0,"height":683.0,"cell_width":9.0,"cell_height":19.0,"padding_x":4.0,"padding_y":9.0,"dpr":1.1666666666666667}