mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat(tui): make turn interruption keybind configurable (#24766)
## Why Interrupting an active turn is currently fixed to `Esc`, which is easy to hit accidentally and cannot be customized through `/keymap`. This gives users a less accidental binding while preserving the existing default. ## What Changed - Adds `tui.keymap.chat.interrupt_turn` to `/keymap`, defaulting to `esc` and supporting remapping or unbinding. - Uses the configured interrupt binding for running-turn status, queued steer interruption, and `request_user_input`, including the visible hints. - Preserves local `Esc` behavior for popups, Vim insert mode, and `/agent` editing while validating conflicts with fixed/backtrack and request-input navigation bindings. - Adds behavior and snapshot coverage for remapped interruption paths. ## How to Test 1. Run Codex and open `/keymap`, then set **Interrupt Turn** to `f12`. 2. Start a turn and confirm `Esc` no longer interrupts it while `f12` does; the running hint should display `f12 to interrupt`. 3. Queue a steer while a turn is running and confirm the preview displays `f12`; pressing it should interrupt and submit the steer immediately. 4. Trigger a `request_user_input` prompt and confirm its footer uses `f12`; with notes open, `Esc` should still clear notes while `f12` interrupts the turn. 5. Clear the Interrupt Turn binding and confirm the key-specific interrupt hint is removed while `Ctrl+C` remains available. Targeted validation: - `just write-config-schema` - `just fix -p codex-config` - `just fix -p codex-tui` - `just fmt` - `just argument-comment-lint-from-source -p codex-config -p codex-tui` - `just test -p codex-config` - `cargo insta pending-snapshots --manifest-path tui/Cargo.toml` - `just test -p codex-tui keymap_setup::tests` - `just test -p codex-tui` (fails in two pre-existing guardian feature-flag tests unrelated to this diff; the intentional picker snapshot updates were reviewed and accepted)
This commit is contained in:
committed by
GitHub
Unverified
parent
8d398d3c52
commit
2d1ad374a7
@@ -112,8 +112,7 @@ impl ChatWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
if matches!(key_event.code, KeyCode::Esc)
|
||||
&& matches!(key_event.kind, KeyEventKind::Press | KeyEventKind::Repeat)
|
||||
if self.chat_keymap.interrupt_turn.is_pressed(key_event)
|
||||
&& !self.input_queue.pending_steers.is_empty()
|
||||
&& self.bottom_pane.is_task_running()
|
||||
&& self.bottom_pane.no_modal_or_popup_active()
|
||||
|
||||
@@ -953,6 +953,32 @@ async fn pending_steer_esc_does_not_steal_vim_insert_escape() {
|
||||
assert!(chat.input_queue.submit_pending_steers_after_interrupt);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn pending_steer_interrupt_uses_remapped_binding() {
|
||||
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
let mut keymap = crate::keymap::RuntimeKeymap::defaults();
|
||||
keymap.chat.interrupt_turn = vec![crate::key_hint::plain(KeyCode::F(12))];
|
||||
chat.chat_keymap = keymap.chat.clone();
|
||||
chat.bottom_pane.set_keymap_bindings(&keymap);
|
||||
chat.bottom_pane.set_task_running(/*running*/ true);
|
||||
chat.input_queue
|
||||
.pending_steers
|
||||
.push_back(pending_steer("queued steer"));
|
||||
|
||||
chat.handle_key_event(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE));
|
||||
|
||||
assert!(!chat.input_queue.submit_pending_steers_after_interrupt);
|
||||
assert!(op_rx.try_recv().is_err());
|
||||
|
||||
chat.handle_key_event(KeyEvent::new(KeyCode::F(12), KeyModifiers::NONE));
|
||||
|
||||
match op_rx.try_recv() {
|
||||
Ok(Op::Interrupt) => {}
|
||||
other => panic!("expected Op::Interrupt, got {other:?}"),
|
||||
}
|
||||
assert!(chat.input_queue.submit_pending_steers_after_interrupt);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn restore_thread_input_state_syncs_sleep_inhibitor_state() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
|
||||
Reference in New Issue
Block a user