diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index f34ad14345..ec2d7e9b71 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -699,6 +699,12 @@ impl Grid { } self.cursor.y = new_cursor_y; self.cursor.x = new_cursor_x; + self.saved_cursor_position + .as_mut() + .map(|saved_cursor_position| { + saved_cursor_position.y = new_cursor_y; + saved_cursor_position.x = new_cursor_x; + }); } else if new_columns != self.width && self.alternate_lines_above_viewport_and_cursor.is_some() { @@ -723,13 +729,24 @@ impl Grid { ); let rows_pulled = self.viewport.len() - current_viewport_row_count; self.cursor.y += rows_pulled; + self.saved_cursor_position + .as_mut() + .map(|saved_cursor_position| saved_cursor_position.y += rows_pulled); } Ordering::Greater => { let row_count_to_transfer = current_viewport_row_count - new_rows; if row_count_to_transfer > self.cursor.y { self.cursor.y = 0; + self.saved_cursor_position + .as_mut() + .map(|saved_cursor_position| saved_cursor_position.y = 0); } else { self.cursor.y -= row_count_to_transfer; + self.saved_cursor_position + .as_mut() + .map(|saved_cursor_position| { + saved_cursor_position.y -= row_count_to_transfer + }); } if self.alternate_lines_above_viewport_and_cursor.is_none() { transfer_rows_from_viewport_to_lines_above( 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 new file mode 100644 index 0000000000..278b856a26 --- /dev/null +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__save_cursor_position_across_resizes.snap @@ -0,0 +1,11 @@ +--- +source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 1153 +expression: snapshot +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────────── SCROLL: 0/4 ┐ +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 636d9ba682..352efadc72 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -1117,3 +1117,29 @@ fn wide_characters_in_left_title_side() { ); assert_snapshot!(snapshot); } + +#[test] +fn save_cursor_position_across_resizes() { + // the save cursor position ANSI instruction (CSI s) needs to point to the same character after we + // resize the pane + let size = Size { cols: 100, rows: 5 }; + let client_id = 1; + let mut tab = create_new_tab(size); + let mut output = Output::default(); + + 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()), + ); + tab.resize_whole_tab(Size { cols: 100, rows: 3 }); + tab.handle_pty_bytes(1, Vec::from("\u{1b}[uthis overwrote me!".as_bytes())); + + tab.render(&mut output, None); + let snapshot = take_snapshot( + output.serialize().get(&client_id).unwrap(), + size.rows, + size.cols, + Palette::default(), + ); + assert_snapshot!(snapshot); +}