From 5beb6167c800cdf0611edaed8cba07a2d51c5c01 Mon Sep 17 00:00:00 2001
From: "Raduan A." <36044389+0xRaduan@users.noreply.github.com>
Date: Sat, 8 Nov 2025 18:08:42 +0100
Subject: [PATCH] feat(tui): Display keyboard shortcuts inline for approval
options (#5889)
Shows single-key shortcuts (y, a, n) next to approval options to make
them more discoverable. Previously these shortcuts worked but were
hidden, making the feature hard to discover.
Changes:
- "Yes, proceed" now shows "y" shortcut
- "Yes, and don't ask again" now shows "a" shortcut
- "No, and tell Codex..." continues to show "esc" shortcut
This improves UX by surfacing the quick keyboard shortcuts that were
already functional but undiscoverable in the UI.
---
Update:
added parentheses for better visual clarity
---------
Co-authored-by: Claude
Co-authored-by: Eric Traut
---
codex-rs/tui/src/bottom_pane/approval_overlay.rs | 4 +++-
.../tui/src/bottom_pane/selection_popup_common.rs | 7 +++++--
...i__chatwidget__tests__approval_modal_exec.snap | 6 +++---
...get__tests__approval_modal_exec_no_reason.snap | 6 +++---
...__chatwidget__tests__approval_modal_patch.snap | 4 ++--
...atwidget__tests__exec_approval_modal_exec.snap | 15 ++++++++-------
...__tests__status_widget_and_approval_modal.snap | 6 +++---
7 files changed, 27 insertions(+), 21 deletions(-)
diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs
index d1d434c0..ef709f00 100644
--- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs
+++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs
@@ -117,7 +117,9 @@ impl ApprovalOverlay {
.iter()
.map(|opt| SelectionItem {
name: opt.label.clone(),
- display_shortcut: opt.display_shortcut,
+ display_shortcut: opt
+ .display_shortcut
+ .or_else(|| opt.additional_shortcuts.first().copied()),
dismiss_on_select: false,
..Default::default()
})
diff --git a/codex-rs/tui/src/bottom_pane/selection_popup_common.rs b/codex-rs/tui/src/bottom_pane/selection_popup_common.rs
index 4246adf4..8042a75b 100644
--- a/codex-rs/tui/src/bottom_pane/selection_popup_common.rs
+++ b/codex-rs/tui/src/bottom_pane/selection_popup_common.rs
@@ -3,6 +3,7 @@ use ratatui::layout::Rect;
// Note: Table-based layout previously used Constraint; the manual renderer
// below no longer requires it.
use ratatui::style::Color;
+use ratatui::style::Style;
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::text::Span;
@@ -96,8 +97,9 @@ fn build_full_line(row: &GenericDisplayRow, desc_col: usize) -> Line<'static> {
let this_name_width = Line::from(name_spans.clone()).width();
let mut full_spans: Vec = name_spans;
if let Some(display_shortcut) = row.display_shortcut {
- full_spans.push(" ".into());
+ full_spans.push(" (".into());
full_spans.push(display_shortcut.into());
+ full_spans.push(")".into());
}
if let Some(desc) = row.description.as_ref() {
let gap = desc_col.saturating_sub(this_name_width);
@@ -179,8 +181,9 @@ pub(crate) fn render_rows(
);
if Some(i) == state.selected_idx {
// Match previous behavior: cyan + bold for the selected row.
+ // Reset the style first to avoid inheriting dim from keyboard shortcuts.
full_line.spans.iter_mut().for_each(|span| {
- span.style = span.style.fg(Color::Cyan).bold();
+ span.style = Style::default().fg(Color::Cyan).bold();
});
}
diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_exec.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_exec.snap
index d0990fa9..b84588e3 100644
--- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_exec.snap
+++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_exec.snap
@@ -9,8 +9,8 @@ expression: terminal.backend().vt100().screen().contents()
$ echo hello world
-› 1. Yes, proceed
- 2. Yes, and don't ask again for this command
- 3. No, and tell Codex what to do differently esc
+› 1. Yes, proceed (y)
+ 2. Yes, and don't ask again for this command (a)
+ 3. No, and tell Codex what to do differently (esc)
Press enter to confirm or esc to cancel
diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_exec_no_reason.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_exec_no_reason.snap
index 3a557bf6..543d367d 100644
--- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_exec_no_reason.snap
+++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_exec_no_reason.snap
@@ -6,8 +6,8 @@ expression: terminal.backend().vt100().screen().contents()
$ echo hello world
-› 1. Yes, proceed
- 2. Yes, and don't ask again for this command
- 3. No, and tell Codex what to do differently esc
+› 1. Yes, proceed (y)
+ 2. Yes, and don't ask again for this command (a)
+ 3. No, and tell Codex what to do differently (esc)
Press enter to confirm or esc to cancel
diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_patch.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_patch.snap
index 96dde8fb..ed18675a 100644
--- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_patch.snap
+++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__approval_modal_patch.snap
@@ -11,7 +11,7 @@ expression: terminal.backend().vt100().screen().contents()
1 +hello
2 +world
-› 1. Yes, proceed
- 2. No, and tell Codex what to do differently esc
+› 1. Yes, proceed (y)
+ 2. No, and tell Codex what to do differently (esc)
Press enter to confirm or esc to cancel
diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__exec_approval_modal_exec.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__exec_approval_modal_exec.snap
index f0cf3a2d..f986a927 100644
--- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__exec_approval_modal_exec.snap
+++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__exec_approval_modal_exec.snap
@@ -1,6 +1,5 @@
---
source: tui/src/chatwidget/tests.rs
-assertion_line: 409
expression: "format!(\"{buf:?}\")"
---
Buffer {
@@ -15,9 +14,9 @@ Buffer {
" ",
" $ echo hello world ",
" ",
- "› 1. Yes, proceed ",
- " 2. Yes, and don't ask again for this command ",
- " 3. No, and tell Codex what to do differently esc ",
+ "› 1. Yes, proceed (y) ",
+ " 2. Yes, and don't ask again for this command (a) ",
+ " 3. No, and tell Codex what to do differently (esc) ",
" ",
" Press enter to confirm or esc to cancel ",
],
@@ -30,9 +29,11 @@ Buffer {
x: 2, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: ITALIC,
x: 7, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 9, fg: Cyan, bg: Reset, underline: Reset, modifier: BOLD,
- x: 17, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
- x: 47, y: 11, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
- x: 50, y: 11, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
+ x: 21, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
+ x: 48, y: 10, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
+ x: 49, y: 10, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
+ x: 48, y: 11, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
+ x: 51, y: 11, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 2, y: 13, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
]
}
diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_and_approval_modal.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_and_approval_modal.snap
index 086a3a8c..f98c8078 100644
--- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_and_approval_modal.snap
+++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_and_approval_modal.snap
@@ -12,8 +12,8 @@ expression: terminal.backend()
" "
" $ echo 'hello world' "
" "
-"› 1. Yes, proceed "
-" 2. Yes, and don't ask again for this command "
-" 3. No, and tell Codex what to do differently esc "
+"› 1. Yes, proceed (y) "
+" 2. Yes, and don't ask again for this command (a) "
+" 3. No, and tell Codex what to do differently (esc) "
" "
" Press enter to confirm or esc to cancel "