diff --git a/src/tests/fixtures/alternate_screen_change_size b/src/tests/fixtures/alternate_screen_change_size new file mode 100644 index 0000000000..3be1990313 --- /dev/null +++ b/src/tests/fixtures/alternate_screen_change_size @@ -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🦀🦀🦀🦀🦀🦀🦀 \ No newline at end of file diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index bd898aa694..8669cfe661 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -374,7 +374,7 @@ pub struct Grid { viewport: Vec, lines_below: Vec, horizontal_tabstops: BTreeSet, - alternative_lines_above_viewport_and_cursor: Option<(VecDeque, Vec, Cursor)>, + alternate_lines_above_viewport_and_cursor: Option<(VecDeque, Vec, Cursor)>, cursor: Cursor, saved_cursor_position: Option, // 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; diff --git a/zellij-server/src/panes/unit/grid_tests.rs b/zellij-server/src/panes/unit/grid_tests.rs index 45fdb77697..7fbfd11924 100644 --- a/zellij-server/src/panes/unit/grid_tests.rs +++ b/zellij-server/src/panes/unit/grid_tests.rs @@ -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)) +} diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__alternate_screen_change_size.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__alternate_screen_change_size.snap new file mode 100644 index 0000000000..df16b28c34 --- /dev/null +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__alternate_screen_change_size.snap @@ -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🦀🦀 +