From 4e540b107690989ea20832f85cd7f121492f5b74 Mon Sep 17 00:00:00 2001 From: Felipe Coury Date: Mon, 1 Jun 2026 19:41:22 -0300 Subject: [PATCH] fix(tui): clarify footer shortcut overlay hints (#25625) ## Why The TUI shortcut overlay used static labels for `Tab` and `Ctrl+C`, even though both keys change behavior while a task is running. That made the visible help misleading: idle `Tab` submits rather than queues, and active-turn `Ctrl+C` interrupts rather than exits. Closes #25531. Closes #25564. ## What Changed - Pass task-running state into the shortcut overlay renderer. - Render `Tab` as `submit message` while idle and `queue message` while work is running. - Render `Ctrl+C` as `exit` while idle and `interrupt` while work is running. - Add snapshot coverage for the active-work shortcut overlay and update idle overlay snapshots. ## How to Test 1. Start Codex and open the shortcut overlay with `?` while no task is running. 2. Confirm the overlay shows `tab to submit message` and `ctrl + c to exit`. 3. Start a task, then open or keep the shortcut overlay visible while work is running. 4. Confirm the overlay shows `tab to queue message` and `ctrl + c to interrupt`. 5. Type a follow-up prompt during active work and press `Tab`; confirm it queues rather than submitting immediately. Targeted tests: - `just test -p codex-tui footer_snapshots` - `just test -p codex-tui footer_mode_snapshots` ## Validation Notes `just test -p codex-tui` currently has two unrelated guardian feature-flag test failures on this base: - `app::tests::update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history` - `app::tests::update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default` `just argument-comment-lint codex-rs/tui/src/bottom_pane/footer.rs` could not run locally because the prebuilt wrapper requires `dotslash`; the touched Rust diff was manually inspected for opaque positional literals. --- codex-rs/tui/src/bottom_pane/chat_composer.rs | 11 ++++ codex-rs/tui/src/bottom_pane/footer.rs | 61 +++++++++++++++++++ ...__tests__footer_mode_shortcut_overlay.snap | 2 +- ...de_shortcut_overlay_queue_submissions.snap | 21 +++++++ ...shortcuts_collaboration_modes_enabled.snap | 2 +- ...oter__tests__footer_shortcuts_running.snap | 13 ++++ ...tests__footer_shortcuts_shift_and_esc.snap | 2 +- 7 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay_queue_submissions.snap create mode 100644 codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_running.snap diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index ec3284866..5a39b53aa 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -3410,6 +3410,7 @@ impl ChatComposer { esc_backtrack_hint: self.footer.esc_backtrack_hint, use_shift_enter_hint: self.footer.use_shift_enter_hint, is_task_running: self.is_task_running, + queue_submissions: self.queue_submissions, quit_shortcut_key: self.footer.quit_shortcut_key, collaboration_modes_enabled: self.collaboration_modes_enabled, is_wsl, @@ -4691,6 +4692,16 @@ mod tests { }, ); + snapshot_composer_state( + "footer_mode_shortcut_overlay_queue_submissions", + /*enhanced_keys_supported*/ true, + |composer| { + composer.set_queue_submissions(/*queue_submissions*/ true); + let _ = composer + .handle_key_event(KeyEvent::new(KeyCode::Char('?'), KeyModifiers::NONE)); + }, + ); + snapshot_composer_state( "footer_mode_ctrl_c_quit", /*enhanced_keys_supported*/ true, diff --git a/codex-rs/tui/src/bottom_pane/footer.rs b/codex-rs/tui/src/bottom_pane/footer.rs index 8035881e8..e11534ac8 100644 --- a/codex-rs/tui/src/bottom_pane/footer.rs +++ b/codex-rs/tui/src/bottom_pane/footer.rs @@ -68,6 +68,7 @@ pub(crate) struct FooterProps { pub(crate) esc_backtrack_hint: bool, pub(crate) use_shift_enter_hint: bool, pub(crate) is_task_running: bool, + pub(crate) queue_submissions: bool, pub(crate) collaboration_modes_enabled: bool, pub(crate) is_wsl: bool, /// Which key the user must press again to quit. @@ -742,6 +743,8 @@ fn footer_from_props_lines( let state = ShortcutsState { use_shift_enter_hint: props.use_shift_enter_hint, esc_backtrack_hint: props.esc_backtrack_hint, + is_task_running: props.is_task_running, + queue_submissions: props.queue_submissions, is_wsl: props.is_wsl, collaboration_modes_enabled: props.collaboration_modes_enabled, key_hints, @@ -864,6 +867,8 @@ fn footer_hint_items_line(items: &[(String, String)]) -> Line<'static> { struct ShortcutsState { use_shift_enter_hint: bool, esc_backtrack_hint: bool, + is_task_running: bool, + queue_submissions: bool, is_wsl: bool, collaboration_modes_enabled: bool, key_hints: FooterKeyHints, @@ -1096,6 +1101,13 @@ impl ShortcutDescriptor { }?; let mut line = Line::from(vec![self.prefix.into(), key.into()]); match self.id { + ShortcutId::QueueMessageTab => { + if state.is_task_running || state.queue_submissions { + line.push_span(" to queue message"); + } else { + line.push_span(" to submit message"); + } + } ShortcutId::EditPrevious => { if state.esc_backtrack_hint { line.push_span(" again to edit previous message"); @@ -1107,6 +1119,13 @@ impl ShortcutDescriptor { ]); } } + ShortcutId::Quit => { + if state.is_task_running { + line.push_span(" to interrupt"); + } else { + line.push_span(" to exit"); + } + } _ => line.push_span(self.label), }; Some(line) @@ -1542,6 +1561,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1559,6 +1579,7 @@ mod tests { esc_backtrack_hint: true, use_shift_enter_hint: true, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1579,6 +1600,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: true, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1589,6 +1611,24 @@ mod tests { }, ); + snapshot_footer( + "footer_shortcuts_running", + FooterProps { + mode: FooterMode::ShortcutOverlay, + esc_backtrack_hint: false, + use_shift_enter_hint: false, + is_task_running: true, + queue_submissions: false, + collaboration_modes_enabled: false, + is_wsl: false, + quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), + status_line_value: None, + status_line_enabled: false, + key_hints: FooterKeyHints::default_bindings(), + active_agent_label: None, + }, + ); + snapshot_footer( "footer_ctrl_c_quit_idle", FooterProps { @@ -1596,6 +1636,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1613,6 +1654,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: true, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1630,6 +1672,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1647,6 +1690,7 @@ mod tests { esc_backtrack_hint: true, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1664,6 +1708,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: true, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1683,6 +1728,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1702,6 +1748,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: true, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1717,6 +1764,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: true, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1745,6 +1793,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: true, + queue_submissions: false, collaboration_modes_enabled: true, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1766,6 +1815,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1782,6 +1832,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: true, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1798,6 +1849,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1814,6 +1866,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: true, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1844,6 +1897,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: true, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1866,6 +1920,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1889,6 +1944,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: true, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1913,6 +1969,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1929,6 +1986,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: false, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -1948,6 +2006,7 @@ mod tests { esc_backtrack_hint: false, use_shift_enter_hint: false, is_task_running: false, + queue_submissions: false, collaboration_modes_enabled: true, is_wsl: false, quit_shortcut_key: key_hint::ctrl(KeyCode::Char('c')), @@ -2009,6 +2068,8 @@ mod tests { .binding_for(ShortcutsState { use_shift_enter_hint: false, esc_backtrack_hint: false, + is_task_running: false, + queue_submissions: false, is_wsl, collaboration_modes_enabled: false, key_hints: FooterKeyHints::default_bindings(), diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay.snap index b5508114f..5239a34bd 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay.snap @@ -11,7 +11,7 @@ expression: terminal.backend() " " " " " / for commands ! for shell commands " -" shift + enter for newline tab to queue message " +" shift + enter for newline tab to submit message " " @ for file paths ctrl + v to paste images " " ctrl + g to edit in external editor esc again to edit previous message " " ctrl + r search history ctrl + c to exit " diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay_queue_submissions.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay_queue_submissions.snap new file mode 100644 index 000000000..582724eea --- /dev/null +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shortcut_overlay_queue_submissions.snap @@ -0,0 +1,21 @@ +--- +source: tui/src/bottom_pane/chat_composer.rs +expression: terminal.backend() +--- +" " +"› Ask Codex to do anything " +" " +" " +" " +" " +" " +" " +" / for commands ! for shell commands " +" shift + enter for newline tab to queue message " +" @ for file paths ctrl + v to paste images " +" ctrl + g to edit in external editor esc esc to edit previous message " +" ctrl + r search history ctrl + c to exit " +" ⌥ + , reasoning down ⌥ + . reasoning up " +" ctrl + t to view transcript " +" " +" customize shortcuts with /keymap " diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_collaboration_modes_enabled.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_collaboration_modes_enabled.snap index dc2f89609..3b67a9068 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_collaboration_modes_enabled.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_collaboration_modes_enabled.snap @@ -3,7 +3,7 @@ source: tui/src/bottom_pane/footer.rs expression: terminal.backend() --- " / for commands ! for shell commands " -" ctrl + j for newline tab to queue message " +" ctrl + j for newline tab to submit message " " @ for file paths ctrl + v to paste images " " ctrl + g to edit in external editor esc esc to edit previous message " " ctrl + r search history ctrl + c to exit " diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_running.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_running.snap new file mode 100644 index 000000000..7c733bd13 --- /dev/null +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_running.snap @@ -0,0 +1,13 @@ +--- +source: tui/src/bottom_pane/footer.rs +expression: terminal.backend() +--- +" / for commands ! for shell commands " +" ctrl + j for newline tab to queue message " +" @ for file paths ctrl + v to paste images " +" ctrl + g to edit in external editor esc esc to edit previous message " +" ctrl + r search history ctrl + c to interrupt " +" ⌥ + , reasoning down ⌥ + . reasoning up " +" ctrl + t to view transcript " +" " +" customize shortcuts with /keymap " diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_shift_and_esc.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_shift_and_esc.snap index 52c26826e..07e970628 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_shift_and_esc.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__footer_shortcuts_shift_and_esc.snap @@ -3,7 +3,7 @@ source: tui/src/bottom_pane/footer.rs expression: terminal.backend() --- " / for commands ! for shell commands " -" shift + enter for newline tab to queue message " +" shift + enter for newline tab to submit message " " @ for file paths ctrl + v to paste images " " ctrl + g to edit in external editor esc again to edit previous message " " ctrl + r search history ctrl + c to exit "