mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
fix(tui): restore TUI after suspend (#28342)
## Why On Linux, suspending Codex with `Ctrl+Z` and returning with `fg` can leave the composer misaligned or inject terminal response bytes such as focus reports into the prompt. Shell job-control output moves the cursor while Codex is suspended, and terminal input polling can race with the responses used to restore the inline viewport. Fixes #26564. ## What changed - preserve and restore keyboard reporting without disturbing the parent terminal stack - pause terminal event polling while Codex is suspended and flush buffered input before resuming it - force crossterm's cached raw-mode state back in sync after the shell completes its `fg` handoff - probe the actual post-`fg` cursor position with the tolerant terminal-response parser, then realign the inline viewport before redrawing ## How to Test 1. On Linux, start the development TUI with `just c`. 2. Type text into the composer without submitting it. 3. Press `Ctrl+Z`, run any harmless shell command, then run `fg`. 4. Confirm the composer redraws below the shell output, the draft text is preserved, and no raw escape sequences appear. 5. Repeat the suspend/resume cycle and confirm normal typing still works. Targeted tests: - `cargo test -p codex-tui --lib parses_cursor_position_as_zero_based -j 1` - `cargo test -p codex-tui --lib tui::event_stream::tests -j 1`
This commit is contained in:
1 parent
7162030b37
commit
76135cbe7e
4 files changed
+82
-25
No files matched your search
+14
-2
@@ -281,6 +281,18 @@ pub fn restore() -> Result<()> {
|
||||
restore_common(RawModeRestore::Disable, KeyboardRestore::PopStack)
|
||||
}
|
||||
|
||||
/// Force crossterm's cached raw-mode state back in sync with the terminal after `fg`.
|
||||
///
|
||||
/// A shell may restore the job's saved termios after the process receives `SIGCONT`. When that
|
||||
/// races with [`set_modes`], crossterm still believes raw mode is enabled even though the terminal
|
||||
/// has returned to canonical, echoing mode. Clearing crossterm's saved state before enabling raw
|
||||
/// mode again makes the kernel state authoritative once the shell has completed its handoff.
|
||||
#[cfg(unix)]
|
||||
pub(super) fn reapply_raw_mode_after_resume() -> Result<()> {
|
||||
disable_raw_mode()?;
|
||||
enable_raw_mode()
|
||||
}
|
||||
|
||||
/// Restore the terminal after Codex is exiting.
|
||||
///
|
||||
/// Uses a stronger keyboard reset than [`restore`] so the parent shell recovers even if a
|
||||
@@ -873,7 +885,7 @@ impl Tui {
|
||||
#[cfg(unix)]
|
||||
let mut prepared_resume = self
|
||||
.suspend_context
|
||||
.prepare_resume_action(&mut self.terminal, &mut self.alt_saved_viewport);
|
||||
.prepare_resume_action(&mut self.alt_saved_viewport);
|
||||
|
||||
// Precompute any viewport updates that need a cursor-position query before entering
|
||||
// the synchronized update, to avoid racing with the event reader.
|
||||
@@ -1009,7 +1021,7 @@ impl Tui {
|
||||
#[cfg(unix)]
|
||||
let mut prepared_resume = self
|
||||
.suspend_context
|
||||
.prepare_resume_action(&mut self.terminal, &mut self.alt_saved_viewport);
|
||||
.prepare_resume_action(&mut self.alt_saved_viewport);
|
||||
|
||||
ensure_virtual_terminal_processing()?;
|
||||
|
||||
|
||||
Reference in new issue
Block a user