diff --git a/src/terminal/panel.rs b/src/terminal/panel.rs index 898061e..8290a44 100644 --- a/src/terminal/panel.rs +++ b/src/terminal/panel.rs @@ -608,6 +608,11 @@ impl TerminalPanel { .pty .as_ref() .is_some_and(|pty| pty.should_hide_cursor_for_streaming_output()); + if hide_cursor_for_output { + // Schedule repaint so cursor reappears promptly when streaming stops + ui.ctx() + .request_repaint_after(std::time::Duration::from_millis(150)); + } if let Some(pty) = &self.pty { // Check pending mode reset: if Ctrl+C was sent while in ALT_SCREEN diff --git a/src/terminal/pty.rs b/src/terminal/pty.rs index 5a87811..5085aca 100644 --- a/src/terminal/pty.rs +++ b/src/terminal/pty.rs @@ -271,9 +271,24 @@ impl PtyHandle { } pub fn should_hide_cursor_for_streaming_output(&self) -> bool { - // Cursor is always visible — hiding it during output caused - // the cursor to flicker/disappear while the user was typing. - false + let last_input = self + .last_input_at + .lock() + .map(|t| t.elapsed()) + .unwrap_or(Duration::from_secs(999)); + let last_output = self + .last_output_at + .lock() + .map(|t| t.elapsed()) + .unwrap_or(Duration::from_secs(999)); + + // Hide cursor when output is actively streaming and the user isn't typing. + // This keeps the cursor clean during AI tool output (Codex, Claude, etc.) + // while ensuring it stays visible when the user is interacting. + let streaming = last_output < Duration::from_millis(100); + let user_idle = last_input > Duration::from_millis(150); + + streaming && user_idle } }