fix(compatibility): do not set scroll buffer in alternate screen (#1032)
avoid moving lines to lines_above when in alternate screen. adjust resizing when in alternate screen: * remove extra lines instead of sending to lines_above * truncate excess characters
This commit is contained in:
parent
0737a5a215
commit
143bbfb0bb
4 changed files with 117 additions and 56 deletions
21
src/tests/fixtures/alternate_screen_change_size
vendored
Normal file
21
src/tests/fixtures/alternate_screen_change_size
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[?1049hline1aaaaaaaaaaaaaaa
|
||||
line2aaaaaaaaaaaaaaa
|
||||
line3aaaaaaaaaaaaaaa
|
||||
line4aaaaaaaaaaaaaaa
|
||||
line5aaaaaaaaaaaaaaa
|
||||
line6aaaaaaaaaaaaaaa
|
||||
line7aaaaaaaaaaaaaaa
|
||||
line8aaaaaaaaaaaaaaa
|
||||
line9aaaaaaaaaaaaaaa
|
||||
line10aaaaaaaaaaaaaa
|
||||
line11aaaaaaaaaaaaaa
|
||||
line12aaaaaaaaaaaaaa
|
||||
line13aaaaaaaaaaaaaa
|
||||
line14aaaaaaaaaaaaaa
|
||||
line15aaaaaaaaaaaaaa
|
||||
line16aaaaaaaaaaaaaa
|
||||
line17aaaaaaaaaaaaaa
|
||||
line18aaaaaaaaaaaaaa
|
||||
line19a🦀aaaaaaaaaaa
|
||||
line20a🦀🦀aaaaaaaaa
|
||||
line21🦀🦀🦀🦀🦀🦀🦀
|
||||
|
|
@ -374,7 +374,7 @@ pub struct Grid {
|
|||
viewport: Vec<Row>,
|
||||
lines_below: Vec<Row>,
|
||||
horizontal_tabstops: BTreeSet<usize>,
|
||||
alternative_lines_above_viewport_and_cursor: Option<(VecDeque<Row>, Vec<Row>, Cursor)>,
|
||||
alternate_lines_above_viewport_and_cursor: Option<(VecDeque<Row>, Vec<Row>, Cursor)>,
|
||||
cursor: Cursor,
|
||||
saved_cursor_position: Option<Cursor>,
|
||||
// FIXME: change scroll_region to be (usize, usize) - where the top line is always the first
|
||||
|
|
@ -442,7 +442,7 @@ impl Grid {
|
|||
erasure_mode: false,
|
||||
insert_mode: false,
|
||||
disable_linewrap: false,
|
||||
alternative_lines_above_viewport_and_cursor: None,
|
||||
alternate_lines_above_viewport_and_cursor: None,
|
||||
clear_viewport_before_rendering: false,
|
||||
active_charset: Default::default(),
|
||||
pending_messages_to_pty: vec![],
|
||||
|
|
@ -673,7 +673,7 @@ impl Grid {
|
|||
return;
|
||||
}
|
||||
self.selection.reset();
|
||||
if new_columns != self.width {
|
||||
if new_columns != self.width && self.alternate_lines_above_viewport_and_cursor.is_none() {
|
||||
self.horizontal_tabstops = create_horizontal_tabstops(new_columns);
|
||||
let mut cursor_canonical_line_index = self.cursor_canonical_line_index();
|
||||
let cursor_index_in_canonical_line = self.cursor_index_in_canonical_line();
|
||||
|
|
@ -786,6 +786,16 @@ impl Grid {
|
|||
}
|
||||
self.cursor.y = new_cursor_y;
|
||||
self.cursor.x = new_cursor_x;
|
||||
} else if new_columns != self.width
|
||||
&& self.alternate_lines_above_viewport_and_cursor.is_some()
|
||||
{
|
||||
// in alternate screen just truncate exceeding width
|
||||
for row in &mut self.viewport {
|
||||
if row.width() >= new_columns {
|
||||
let truncate_at = row.position_accounting_for_widechars(new_columns);
|
||||
row.columns.truncate(truncate_at);
|
||||
}
|
||||
}
|
||||
}
|
||||
if new_rows != self.height {
|
||||
let current_viewport_row_count = self.viewport.len();
|
||||
|
|
@ -808,12 +818,17 @@ impl Grid {
|
|||
} else {
|
||||
self.cursor.y -= row_count_to_transfer;
|
||||
}
|
||||
transfer_rows_from_viewport_to_lines_above(
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
row_count_to_transfer,
|
||||
new_columns,
|
||||
);
|
||||
if self.alternate_lines_above_viewport_and_cursor.is_none() {
|
||||
transfer_rows_from_viewport_to_lines_above(
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
row_count_to_transfer,
|
||||
new_columns,
|
||||
);
|
||||
} else {
|
||||
// in alternate screen, no scroll buffer, so just remove lines
|
||||
self.viewport.drain(0..row_count_to_transfer);
|
||||
}
|
||||
}
|
||||
Ordering::Equal => {}
|
||||
}
|
||||
|
|
@ -916,16 +931,11 @@ impl Grid {
|
|||
}
|
||||
}
|
||||
pub fn fill_viewport(&mut self, character: TerminalCharacter) {
|
||||
let row_count_to_transfer = self.viewport.len();
|
||||
let transferred_rows_count = transfer_rows_from_viewport_to_lines_above(
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
row_count_to_transfer,
|
||||
self.width,
|
||||
);
|
||||
|
||||
self.scrollback_buffer_lines =
|
||||
subtract_isize_from_usize(self.scrollback_buffer_lines, transferred_rows_count);
|
||||
if self.alternate_lines_above_viewport_and_cursor.is_some() {
|
||||
self.viewport.clear();
|
||||
} else {
|
||||
self.transfer_rows_to_lines_above(self.viewport.len())
|
||||
};
|
||||
|
||||
for _ in 0..self.height {
|
||||
let columns = VecDeque::from(vec![character; self.width]);
|
||||
|
|
@ -947,17 +957,12 @@ impl Grid {
|
|||
return;
|
||||
}
|
||||
if scroll_region_bottom == self.height - 1 && scroll_region_top == 0 {
|
||||
let row_count_to_transfer = 1;
|
||||
let transferred_rows_count = transfer_rows_from_viewport_to_lines_above(
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
row_count_to_transfer,
|
||||
self.width,
|
||||
);
|
||||
self.scrollback_buffer_lines = subtract_isize_from_usize(
|
||||
self.scrollback_buffer_lines,
|
||||
transferred_rows_count,
|
||||
);
|
||||
if self.alternate_lines_above_viewport_and_cursor.is_none() {
|
||||
self.transfer_rows_to_lines_above(1);
|
||||
} else {
|
||||
self.viewport.remove(0);
|
||||
}
|
||||
|
||||
let columns = VecDeque::from(vec![EMPTY_TERMINAL_CHARACTER; self.width]);
|
||||
self.viewport.push(Row::from_columns(columns).canonical());
|
||||
self.selection.move_up(1);
|
||||
|
|
@ -984,15 +989,11 @@ impl Grid {
|
|||
}
|
||||
if self.cursor.y == self.height - 1 {
|
||||
if self.scroll_region.is_none() {
|
||||
let row_count_to_transfer = 1;
|
||||
let transferred_rows_count = transfer_rows_from_viewport_to_lines_above(
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
row_count_to_transfer,
|
||||
self.width,
|
||||
);
|
||||
self.scrollback_buffer_lines =
|
||||
subtract_isize_from_usize(self.scrollback_buffer_lines, transferred_rows_count);
|
||||
if self.alternate_lines_above_viewport_and_cursor.is_none() {
|
||||
self.transfer_rows_to_lines_above(1);
|
||||
} else {
|
||||
self.viewport.remove(0);
|
||||
}
|
||||
|
||||
self.selection.move_up(1);
|
||||
}
|
||||
|
|
@ -1062,15 +1063,11 @@ impl Grid {
|
|||
// line wrap
|
||||
self.cursor.x = 0;
|
||||
if self.cursor.y == self.height - 1 {
|
||||
let row_count_to_transfer = 1;
|
||||
let transferred_rows_count = transfer_rows_from_viewport_to_lines_above(
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
row_count_to_transfer,
|
||||
self.width,
|
||||
);
|
||||
self.scrollback_buffer_lines =
|
||||
subtract_isize_from_usize(self.scrollback_buffer_lines, transferred_rows_count);
|
||||
if self.alternate_lines_above_viewport_and_cursor.is_none() {
|
||||
self.transfer_rows_to_lines_above(1);
|
||||
} else {
|
||||
self.viewport.remove(0);
|
||||
}
|
||||
let wrapped_row = Row::new(self.width);
|
||||
self.viewport.push(wrapped_row);
|
||||
self.selection.move_up(1);
|
||||
|
|
@ -1365,7 +1362,7 @@ impl Grid {
|
|||
self.lines_above = VecDeque::with_capacity(*SCROLL_BUFFER_SIZE.get().unwrap());
|
||||
self.lines_below = vec![];
|
||||
self.viewport = vec![Row::new(self.width).canonical()];
|
||||
self.alternative_lines_above_viewport_and_cursor = None;
|
||||
self.alternate_lines_above_viewport_and_cursor = None;
|
||||
self.cursor_key_mode = false;
|
||||
self.scroll_region = None;
|
||||
self.clear_viewport_before_rendering = true;
|
||||
|
|
@ -1501,6 +1498,17 @@ impl Grid {
|
|||
self.title = Some(popped_title);
|
||||
}
|
||||
}
|
||||
fn transfer_rows_to_lines_above(&mut self, count: usize) {
|
||||
let transferred_rows_count = transfer_rows_from_viewport_to_lines_above(
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
count,
|
||||
self.width,
|
||||
);
|
||||
|
||||
self.scrollback_buffer_lines =
|
||||
subtract_isize_from_usize(self.scrollback_buffer_lines, transferred_rows_count);
|
||||
}
|
||||
}
|
||||
|
||||
impl Perform for Grid {
|
||||
|
|
@ -1805,17 +1813,18 @@ impl Perform for Grid {
|
|||
self.bracketed_paste_mode = false;
|
||||
}
|
||||
Some(1049) => {
|
||||
// leave alternate buffer
|
||||
if let Some((
|
||||
alternative_lines_above,
|
||||
alternative_viewport,
|
||||
alternative_cursor,
|
||||
)) = &mut self.alternative_lines_above_viewport_and_cursor
|
||||
)) = &mut self.alternate_lines_above_viewport_and_cursor
|
||||
{
|
||||
std::mem::swap(&mut self.lines_above, alternative_lines_above);
|
||||
std::mem::swap(&mut self.viewport, alternative_viewport);
|
||||
std::mem::swap(&mut self.cursor, alternative_cursor);
|
||||
}
|
||||
self.alternative_lines_above_viewport_and_cursor = None;
|
||||
self.alternate_lines_above_viewport_and_cursor = None;
|
||||
self.clear_viewport_before_rendering = true;
|
||||
self.force_change_size(self.height, self.width); // the alternative_viewport might have been of a different size...
|
||||
self.mark_for_rerender();
|
||||
|
|
@ -1861,18 +1870,17 @@ impl Perform for Grid {
|
|||
self.bracketed_paste_mode = true;
|
||||
}
|
||||
Some(1049) => {
|
||||
// enter alternate buffer
|
||||
let current_lines_above = std::mem::replace(
|
||||
&mut self.lines_above,
|
||||
VecDeque::with_capacity(*SCROLL_BUFFER_SIZE.get().unwrap()),
|
||||
);
|
||||
let current_viewport = std::mem::replace(
|
||||
&mut self.viewport,
|
||||
vec![Row::new(self.width).canonical()],
|
||||
);
|
||||
let current_viewport = std::mem::take(&mut self.viewport);
|
||||
let current_cursor = std::mem::replace(&mut self.cursor, Cursor::new(0, 0));
|
||||
self.alternative_lines_above_viewport_and_cursor =
|
||||
self.alternate_lines_above_viewport_and_cursor =
|
||||
Some((current_lines_above, current_viewport, current_cursor));
|
||||
self.clear_viewport_before_rendering = true;
|
||||
self.scrollback_buffer_lines = self.recalculate_scrollback_buffer_count();
|
||||
}
|
||||
Some(1) => {
|
||||
self.cursor_key_mode = true;
|
||||
|
|
|
|||
|
|
@ -1090,3 +1090,19 @@ pub fn ring_bell() {
|
|||
}
|
||||
assert!(grid.ring_bell);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn alternate_screen_change_size() {
|
||||
let mut vte_parser = vte::Parser::new();
|
||||
let mut grid = Grid::new(20, 20, Palette::default());
|
||||
let fixture_name = "alternate_screen_change_size";
|
||||
let content = read_fixture(fixture_name);
|
||||
for byte in content {
|
||||
vte_parser.advance(&mut grid, byte);
|
||||
}
|
||||
// no scrollback in alternate screen
|
||||
assert_eq!(grid.scrollback_position_and_length(), (0, 0));
|
||||
grid.change_size(10, 10);
|
||||
assert_snapshot!(format!("{:?}", grid));
|
||||
assert_eq!(grid.scrollback_position_and_length(), (0, 0))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||
expression: "format!(\"{:?}\", grid)"
|
||||
|
||||
---
|
||||
00 (C): line12aaaa
|
||||
01 (C): line13aaaa
|
||||
02 (C): line14aaaa
|
||||
03 (C): line15aaaa
|
||||
04 (C): line16aaaa
|
||||
05 (C): line17aaaa
|
||||
06 (C): line18aaaa
|
||||
07 (C): line19a🦀a
|
||||
08 (C): line20a🦀
|
||||
09 (C): line21🦀🦀
|
||||
|
||||
Loading…
Add table
Reference in a new issue