aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-19 04:49:57 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-19 04:49:57 +0300
commitb580103b956ef9cdf39798947a46ce4e8b78c322 (patch)
treea768cd24fba97e19049c646f481f2ccc3f821cd3 /src
parenta51a15914a5b29155022a1fd589d2bcc6409cadf (diff)
fix: preserve terminal live follow through resize
Diffstat (limited to 'src')
-rw-r--r--src/pane/terminal.rs50
1 files changed, 49 insertions, 1 deletions
diff --git a/src/pane/terminal.rs b/src/pane/terminal.rs
index 8e33b1b3..2c83f8f2 100644
--- a/src/pane/terminal.rs
+++ b/src/pane/terminal.rs
@@ -2390,7 +2390,12 @@ fn ghostty_set_scroll_offset_from_bottom(
return;
};
let max_offset = scrollbar.total.saturating_sub(scrollbar.len);
- terminal.scroll_viewport_row(max_offset.saturating_sub(offset_from_bottom));
+ let offset_from_bottom = offset_from_bottom.min(max_offset);
+ if offset_from_bottom == 0 {
+ terminal.scroll_viewport_bottom();
+ } else {
+ terminal.scroll_viewport_row(max_offset - offset_from_bottom);
+ }
}
fn ghostty_extract_selection(
@@ -4193,6 +4198,49 @@ mod tests {
}
#[test]
+ fn empty_or_short_resize_keeps_following_bottom_when_output_creates_scrollback() {
+ for initial in [b"".as_slice(), b"seed\r\n".as_slice()] {
+ let (tx, _rx) = mpsc::channel(4);
+ let mut terminal = crate::ghostty::Terminal::new(10, 3, 100).unwrap();
+ terminal.write(initial);
+ let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap();
+ let pane_id = PaneId::from_raw(1);
+
+ pane.resize(3, 10, 0, 0);
+ pane.process_pty_bytes(
+ pane_id,
+ 0,
+ b"000000\r\n000001\r\n000002\r\n000003\r\n000004",
+ &tx,
+ );
+
+ let metrics = pane.scroll_metrics().expect("scroll metrics after output");
+ assert_eq!(metrics.offset_from_bottom, 0);
+ assert!(pane.visible_text().contains("000004"));
+ }
+ }
+
+ #[test]
+ fn resize_that_removes_scrollback_restores_live_follow() {
+ let (tx, _rx) = mpsc::channel(4);
+ let mut terminal = crate::ghostty::Terminal::new(10, 3, 100).unwrap();
+ terminal.write(b"000000\r\n000001\r\n000002\r\n000003\r\n000004");
+ let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap();
+ let pane_id = PaneId::from_raw(1);
+
+ pane.set_scroll_offset_from_bottom(1);
+ pane.resize(5, 10, 0, 0);
+ let resized = pane.scroll_metrics().expect("scroll metrics after resize");
+ assert_eq!(resized.max_offset_from_bottom, 0);
+
+ pane.process_pty_bytes(pane_id, 0, b"\r\n000005\r\n000006", &tx);
+
+ let metrics = pane.scroll_metrics().expect("scroll metrics after output");
+ assert_eq!(metrics.offset_from_bottom, 0);
+ assert!(pane.visible_text().contains("000006"));
+ }
+
+ #[test]
fn detection_text_stays_at_bottom_when_viewport_is_scrolled() {
let (tx, _rx) = mpsc::channel(4);
let mut terminal = crate::ghostty::Terminal::new(80, 3, 100).unwrap();