Skip to content

Commit 320f150

Browse files
authored
fix: update ctrl-z to suspend tui (#2113)
- Lean on ctrl-c and esc to interrupt. - (Only on unix.) https://github.com/user-attachments/assets/7ce6c57f-6ee2-40c2-8cd2-b31265f16c1c
1 parent 7051a52 commit 320f150

File tree

4 files changed

+25
-6
lines changed

4 files changed

+25
-6
lines changed

codex-rs/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codex-rs/tui/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ unicode-segmentation = "1.12.0"
7272
unicode-width = "0.1"
7373
uuid = "1"
7474

75+
[target.'cfg(unix)'.dependencies]
76+
libc = "0.2"
77+
7578

7679
[dev-dependencies]
7780
chrono = { version = "0.4", features = ["serde"] }

codex-rs/tui/src/app.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,11 @@ impl App<'_> {
255255
kind: KeyEventKind::Press,
256256
..
257257
} => {
258-
if let AppState::Chat { widget } = &mut self.app_state {
259-
widget.on_ctrl_z();
258+
#[cfg(unix)]
259+
{
260+
self.suspend(terminal)?;
260261
}
262+
// No-op on non-Unix platforms.
261263
}
262264
KeyEvent {
263265
code: KeyCode::Char('d'),
@@ -459,6 +461,23 @@ impl App<'_> {
459461
Ok(())
460462
}
461463

464+
#[cfg(unix)]
465+
fn suspend(&mut self, terminal: &mut tui::Tui) -> Result<()> {
466+
tui::restore()?;
467+
// SAFETY: Unix-only code path. We intentionally send SIGTSTP to the
468+
// current process group (pid 0) to trigger standard job-control
469+
// suspension semantics. This FFI does not involve any raw pointers,
470+
// is not called from a signal handler, and uses a constant signal.
471+
// Errors from kill are acceptable (e.g., if already stopped) — the
472+
// subsequent re-init path will still leave the terminal in a good state.
473+
// We considered `nix`, but didn't think it was worth pulling in for this one call.
474+
unsafe { libc::kill(0, libc::SIGTSTP) };
475+
*terminal = tui::init(&self.config)?;
476+
terminal.clear()?;
477+
self.app_event_tx.send(AppEvent::RequestRedraw);
478+
Ok(())
479+
}
480+
462481
pub(crate) fn token_usage(&self) -> codex_core::protocol::TokenUsage {
463482
match &self.app_state {
464483
AppState::Chat { widget } => widget.token_usage().clone(),

codex-rs/tui/src/chatwidget.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -652,10 +652,6 @@ impl ChatWidget<'_> {
652652
}
653653
}
654654

655-
pub(crate) fn on_ctrl_z(&mut self) {
656-
self.interrupt_running_task();
657-
}
658-
659655
pub(crate) fn composer_is_empty(&self) -> bool {
660656
self.bottom_pane.composer_is_empty()
661657
}

0 commit comments

Comments
 (0)