From abe0cbd31b3c0b5c12a6fd691b8a0dae061c4ecb Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Mon, 20 Feb 2023 16:41:03 +0100 Subject: [PATCH 1/2] fix(grid): glitchy resizes --- zellij-server/src/panes/grid.rs | 55 ++++++++++++++++++- zellij-server/src/panes/terminal_pane.rs | 2 +- ...__save_cursor_position_across_resizes.snap | 4 +- .../src/tab/unit/tab_integration_tests.rs | 2 +- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index b71687ea2e..8a535b0eb1 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -626,6 +626,25 @@ impl Grid { } cursor_index_in_canonical_line } + fn saved_cursor_index_in_canonical_line(&self) -> Option { + if let Some(saved_cursor_position) = self.saved_cursor_position.as_ref() { + let mut cursor_canonical_line_index = 0; + let mut cursor_index_in_canonical_line = 0; + for (i, line) in self.viewport.iter().enumerate() { + if line.is_canonical { + cursor_canonical_line_index = i; + } + if i == saved_cursor_position.y { + let line_wrap_position_in_line = saved_cursor_position.y - cursor_canonical_line_index; + cursor_index_in_canonical_line = line_wrap_position_in_line + saved_cursor_position.x; + break; + } + } + Some(cursor_index_in_canonical_line) + } else { + None + } + } fn canonical_line_y_coordinates(&self, canonical_line_index: usize) -> usize { let mut canonical_lines_traversed = 0; let mut y_coordinates = 0; @@ -713,7 +732,7 @@ impl Grid { } found_something } - fn force_change_size(&mut self, new_rows: usize, new_columns: usize) { + pub fn force_change_size(&mut self, new_rows: usize, new_columns: usize) { // this is an ugly hack - it's here because sometimes we need to change_size to the // existing size (eg. when resizing an alternative_grid to the current height/width) and // the change_size method is a no-op in that case. Should be fixed by making the @@ -742,6 +761,7 @@ impl Grid { 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(); + let saved_cursor_index_in_canonical_line = self.saved_cursor_index_in_canonical_line(); let mut viewport_canonical_lines = vec![]; for mut row in self.viewport.drain(..) { if !row.is_canonical @@ -817,9 +837,20 @@ impl Grid { self.viewport = new_viewport_rows; let mut new_cursor_y = self.canonical_line_y_coordinates(cursor_canonical_line_index); + let mut saved_cursor_y_coordinates = if let Some(saved_cursor) = self.saved_cursor_position.as_ref() { + Some(self.canonical_line_y_coordinates(saved_cursor.y)) + } else { + None + }; let new_cursor_x = (cursor_index_in_canonical_line / new_columns) + (cursor_index_in_canonical_line % new_columns); + let saved_cursor_x_coordinates = if let Some(saved_cursor_index_in_canonical_line) = saved_cursor_index_in_canonical_line.as_ref() { + Some((*saved_cursor_index_in_canonical_line / new_columns) + + (*saved_cursor_index_in_canonical_line % new_columns)) + } else { + None + }; let current_viewport_row_count = self.viewport.len(); match current_viewport_row_count.cmp(&self.height) { Ordering::Less => { @@ -834,6 +865,9 @@ impl Grid { ); let rows_pulled = self.viewport.len() - current_viewport_row_count; new_cursor_y += rows_pulled; + if let Some(saved_cursor_y_coordinates) = saved_cursor_y_coordinates.as_mut() { + *saved_cursor_y_coordinates += rows_pulled; + } }, Ordering::Greater => { let row_count_to_transfer = current_viewport_row_count - self.height; @@ -842,6 +876,13 @@ impl Grid { } else { new_cursor_y -= row_count_to_transfer; } + if let Some(saved_cursor_y_coordinates) = saved_cursor_y_coordinates.as_mut() { + if row_count_to_transfer > *saved_cursor_y_coordinates { + *saved_cursor_y_coordinates = 0; + } else { + *saved_cursor_y_coordinates -= row_count_to_transfer; + } + } transfer_rows_from_viewport_to_lines_above( &mut self.viewport, &mut self.lines_above, @@ -855,8 +896,16 @@ impl Grid { self.cursor.y = new_cursor_y; self.cursor.x = new_cursor_x; if let Some(saved_cursor_position) = self.saved_cursor_position.as_mut() { - saved_cursor_position.y = new_cursor_y; - saved_cursor_position.x = new_cursor_x; + match (saved_cursor_x_coordinates, saved_cursor_y_coordinates) { + (Some(saved_cursor_x_coordinates), Some(saved_cursor_y_coordinates)) => { + saved_cursor_position.x = saved_cursor_x_coordinates; + saved_cursor_position.y = saved_cursor_y_coordinates; + }, + _ => { + saved_cursor_position.x = new_cursor_x; + saved_cursor_position.y = new_cursor_y; + } + } }; } else if new_columns != self.width && self.alternate_screen_state.is_some() { // in alternate screen just truncate exceeding width diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index e9fffb1861..be14b74f5e 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -794,7 +794,7 @@ impl TerminalPane { fn reflow_lines(&mut self) { let rows = self.get_content_rows(); let cols = self.get_content_columns(); - self.grid.change_size(rows, cols); + self.grid.force_change_size(rows, cols); if self.banner.is_some() { self.grid.reset_terminal_state(); self.render_first_run_banner(); diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__save_cursor_position_across_resizes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__save_cursor_position_across_resizes.snap index 278b856a26..dbd6426a65 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__save_cursor_position_across_resizes.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__save_cursor_position_across_resizes.snap @@ -1,10 +1,10 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1153 +assertion_line: 1952 expression: snapshot --- 00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────── SCROLL: 0/4 ┐ -01 (C): │ Let's save the cursor position here this overwrote me!tten │ +01 (C): │Let's save the cursor position here this overwrote me!tten │ 02 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘ 03 (C): 04 (C): diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index 3defa1e6be..89e8564449 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -1935,7 +1935,7 @@ fn save_cursor_position_across_resizes() { tab.handle_pty_bytes( 1, - Vec::from("\n\nI am some text\nI am another line of text\nLet's save the cursor position here \u{1b}[sI should be ovewritten".as_bytes()), + Vec::from("\n\n\rI am some text\n\rI am another line of text\n\rLet's save the cursor position here \u{1b}[sI should be ovewritten".as_bytes()), ).unwrap(); tab.resize_whole_tab(Size { cols: 100, rows: 3 }).unwrap(); tab.handle_pty_bytes(1, Vec::from("\u{1b}[uthis overwrote me!".as_bytes())) From bfbbc563e83355115712a5e917233d28a7bbd249 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Mon, 20 Feb 2023 16:41:22 +0100 Subject: [PATCH 2/2] style(fmt): rustfmt --- zellij-server/src/panes/grid.rs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index 8a535b0eb1..a3b37722b9 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -635,8 +635,10 @@ impl Grid { cursor_canonical_line_index = i; } if i == saved_cursor_position.y { - let line_wrap_position_in_line = saved_cursor_position.y - cursor_canonical_line_index; - cursor_index_in_canonical_line = line_wrap_position_in_line + saved_cursor_position.x; + let line_wrap_position_in_line = + saved_cursor_position.y - cursor_canonical_line_index; + cursor_index_in_canonical_line = + line_wrap_position_in_line + saved_cursor_position.x; break; } } @@ -837,17 +839,22 @@ impl Grid { self.viewport = new_viewport_rows; let mut new_cursor_y = self.canonical_line_y_coordinates(cursor_canonical_line_index); - let mut saved_cursor_y_coordinates = if let Some(saved_cursor) = self.saved_cursor_position.as_ref() { - Some(self.canonical_line_y_coordinates(saved_cursor.y)) - } else { - None - }; + let mut saved_cursor_y_coordinates = + if let Some(saved_cursor) = self.saved_cursor_position.as_ref() { + Some(self.canonical_line_y_coordinates(saved_cursor.y)) + } else { + None + }; let new_cursor_x = (cursor_index_in_canonical_line / new_columns) + (cursor_index_in_canonical_line % new_columns); - let saved_cursor_x_coordinates = if let Some(saved_cursor_index_in_canonical_line) = saved_cursor_index_in_canonical_line.as_ref() { - Some((*saved_cursor_index_in_canonical_line / new_columns) - + (*saved_cursor_index_in_canonical_line % new_columns)) + let saved_cursor_x_coordinates = if let Some(saved_cursor_index_in_canonical_line) = + saved_cursor_index_in_canonical_line.as_ref() + { + Some( + (*saved_cursor_index_in_canonical_line / new_columns) + + (*saved_cursor_index_in_canonical_line % new_columns), + ) } else { None }; @@ -904,7 +911,7 @@ impl Grid { _ => { saved_cursor_position.x = new_cursor_x; saved_cursor_position.y = new_cursor_y; - } + }, } }; } else if new_columns != self.width && self.alternate_screen_state.is_some() {