Skip to content

Commit

Permalink
fix(compatibility): do not set scroll buffer in alternate screen (#1032)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tlinford authored Feb 2, 2022
1 parent 0737a5a commit 143bbfb
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 56 deletions.
21 changes: 21 additions & 0 deletions src/tests/fixtures/alternate_screen_change_size
Original file line number Diff line number Diff line change
@@ -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🦀🦀🦀🦀🦀🦀🦀
120 changes: 64 additions & 56 deletions zellij-server/src/panes/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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![],
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand All @@ -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 => {}
}
Expand Down Expand Up @@ -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]);
Expand All @@ -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);
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 16 additions & 0 deletions zellij-server/src/panes/unit/grid_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Original file line number Diff line number Diff line change
@@ -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🦀🦀

0 comments on commit 143bbfb

Please sign in to comment.