aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-04-09 16:53:00 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-04-09 17:28:02 +0300
commit1cbd3129363d2ad867d2753ef176a944554591f6 (patch)
tree1febffab2d6b6033625127fb8b20d285ce35350c /src
parent8ae7ccc5b28b4c0eb46a659841d31b488bd3f7bc (diff)
fix: detect agent state from terminal tail instead of viewport
Diffstat (limited to 'src')
-rw-r--r--src/pane.rs43
1 files changed, 42 insertions, 1 deletions
diff --git a/src/pane.rs b/src/pane.rs
index 9552e1c6..a578eb33 100644
--- a/src/pane.rs
+++ b/src/pane.rs
@@ -19,6 +19,7 @@ use crate::layout::PaneId;
const CLAUDE_WORKING_HOLD: std::time::Duration = std::time::Duration::from_millis(1200);
const RELEASE_REACQUIRE_SUPPRESSION: std::time::Duration = std::time::Duration::from_secs(1);
+const DEFAULT_DETECTION_ROWS: usize = 24;
#[derive(Debug, Clone, Copy)]
struct PendingAgentRelease {
@@ -342,6 +343,10 @@ impl PaneTerminal {
self.ghostty.visible_text()
}
+ fn detection_text(&self) -> String {
+ self.ghostty.detection_text()
+ }
+
fn recent_text(&self, lines: usize) -> String {
self.ghostty.recent_text(lines)
}
@@ -646,6 +651,14 @@ impl GhosttyPaneTerminal {
.unwrap_or_default()
}
+ fn detection_text(&self) -> String {
+ self.core
+ .lock()
+ .ok()
+ .and_then(|core| ghostty_detection_text(&core).ok())
+ .unwrap_or_default()
+ }
+
fn recent_text(&self, lines: usize) -> String {
self.core
.lock()
@@ -1054,6 +1067,16 @@ fn ghostty_visible_text(core: &mut GhosttyPaneCore) -> Result<String, crate::gho
Ok(lines_to_text(lines))
}
+fn ghostty_detection_text(core: &GhosttyPaneCore) -> Result<String, crate::ghostty::Error> {
+ let lines = core
+ .terminal
+ .rows()
+ .ok()
+ .map(|rows| usize::from(rows).max(1))
+ .unwrap_or(DEFAULT_DETECTION_ROWS);
+ ghostty_recent_text(core, lines)
+}
+
fn ghostty_recent_text(
core: &GhosttyPaneCore,
lines: usize,
@@ -1572,7 +1595,7 @@ impl PaneRuntime {
}
}
- let content = terminal.visible_text();
+ let content = terminal.detection_text();
let raw_state = detect::detect_state(agent, &content);
let new_state = stabilize_agent_state(
agent,
@@ -2126,6 +2149,24 @@ mod tests {
}
#[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();
+ write_numbered_lines(&mut terminal, 10);
+ let pane = GhosttyPaneTerminal::new(terminal, tx).unwrap();
+
+ let bottom_snapshot = pane.detection_text();
+ assert_eq!(bottom_snapshot, pane.recent_text(3));
+ assert!(bottom_snapshot.contains("000009"));
+
+ let before = pane.scroll_metrics().expect("scroll metrics before scroll");
+ pane.set_scroll_offset_from_bottom(before.max_offset_from_bottom);
+
+ assert!(pane.visible_text().contains("000000"));
+ assert_eq!(pane.detection_text(), bottom_snapshot);
+ }
+
+ #[test]
fn recent_unwrapped_text_ignores_soft_wraps() {
let (tx, _rx) = mpsc::channel(4);
let mut terminal = crate::ghostty::Terminal::new(5, 3, 100).unwrap();