Use platform-specific modifier labels in TUI shortcut hints (#49804)

## What changed

Render Control, Shift, and Alt as `⌃`, `⇧`, and `⌥` on macOS, and Control as `^` on Linux. Keep textual modifier labels on other platforms.

Route hard-coded shortcut hints through the shared key-label formatter so footers, overlays, pickers, and transcript notices use consistent notation.

## Testing

Update modifier-combination and chord label assertions, along with rendering snapshots and narrow-layout expectations for the shorter hints.

GitOrigin-RevId: 0d20fa218e4a11dfe7a81c8de64f8d25e093af03
This commit is contained in:
Benjamin Carlsson
2026-10-01 01:35:40 +00:00
committed by copyberry
parent 33aea33b39
commit d2f2c40095
199 changed files with 687 additions and 656 deletions
+7 -3
View File
@@ -97,7 +97,10 @@ impl AnalyticsView {
pub(super) fn help_lines(&self, width: usize) -> Vec<Line<'static>> {
let mut controls = vec![
"Tab / Shift+Tab · next / previous report".to_owned(),
format!(
"Tab / {} · next / previous report",
crate::key_hint::shift(crossterm::event::KeyCode::Tab).display_label()
),
format!(
"1–{} · open a report directly",
self.visible_sections().len()
@@ -145,8 +148,9 @@ impl AnalyticsView {
self.hint(ListAction::Accept)
),
format!(
"{} · back; q / ctrl+c · close usage",
self.hint(ListAction::Cancel)
"{} · back; q / {} · close usage",
self.hint(ListAction::Cancel),
crate::key_hint::ctrl(crossterm::event::KeyCode::Char('c')).display_label()
),
]);
if self.help_shortcut_available() {
@@ -8,13 +8,13 @@ expression: help
" Usage shortcuts "
" "
" "
" Tab / Shift+Tab · next / previous "
" report "
" Tab / ⇧tab · next / previous report "
" 1–5 · open a report directly "
" ← / → · select chart day or plan "
" window "
" ↑ / ↓ · select chat or plan period; "
" scroll Overview "
" enter · expand or collapse details "
" pgup / pgdn · scroll report "
" esc back · pgup/pgdn scroll "
" ? close help "
@@ -260,7 +260,7 @@ async fn browsing_details_use_the_remapped_chord_without_cancelling_preview() ->
.expect("footer")
.text
.to_string()
.contains("ctrl+x ctrl+t")
.contains("⌃x ⌃t")
);
for (keys, expected_details) in [
(
@@ -998,7 +998,7 @@ async fn offline_find_closes_before_the_next_ctrl_c_quits() -> Result<()> {
rendered.lines().nth(usize::from(cursor.y)).map(str::trim),
Some("Find: needle")
);
assert!(!rendered.contains("ctrl+c quit"));
assert!(!rendered.contains("⌃c quit"));
let close = TuiEvent::Key(KeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL));
assert!(matches!(
app.handle_tui_event(&mut tui, &mut app_server, close)
+6 -6
View File
@@ -164,8 +164,8 @@ async fn capped_resize_reflow_prepends_transcript_notice_without_changing_transc
.map(rendered_line_text)
.collect::<Vec<_>>()
.join("\n"),
@r"
Earlier messages are available — press ctrl+t to view the full transcript
@"
Earlier messages are available — press ⌃t to view the full transcript
cell 8
cell 9
@@ -195,8 +195,8 @@ async fn capped_resize_reflow_counts_wrapped_notice_rows() {
.join("\n"),
@"
Earlier messages are
available — press ctrl+t to
view the full transcript
available — press ⌃t to view
the full transcript
cell 9
cell 10
@@ -243,8 +243,8 @@ async fn paginated_resize_reflow_prepends_transcript_notice_for_unloaded_history
.map(rendered_line_text)
.collect::<Vec<_>>()
.join("\n"),
@r"
Earlier messages are available — press ctrl+t to view the full transcript
@"
Earlier messages are available — press ⌃t to view the full transcript
cell 0
cell 1
+4 -1
View File
@@ -281,7 +281,10 @@ impl App {
) {
label_parts.push(format!("{} to switch", binding.display_label()));
}
label_parts.push("ctrl+c to close".to_string());
label_parts.push(format!(
"{} to close",
crate::key_hint::ctrl(KeyCode::Char('c')).display_label()
));
self.chat_widget
.set_side_conversation_context_label(Some(format!("Side {}", label_parts.join(" · "))));
}
@@ -3,7 +3,7 @@ source: tui/src/app/agents_overview_tests.rs
expression: normalize_agent_center_snapshot(&cached)
---
" Agent command center Group: Project g "
" All 1 Needs you 0 Working 0 Ready 1 Inactive 0 tab/shift+tab filter "
" All 1 Needs you 0 Working 0 Ready 1 Inactive 0 tab/⇧tab filter "
" ──────────────────────────────────────────────────────────────────────────────────────────── "
" Tasks │ Task details "
" /tmp/project 1 │ "
@@ -3,7 +3,7 @@ source: tui/src/app/agents_overview_tests.rs
expression: "normalize_agent_center_snapshot(render_bottom_popup(&app.chat_widget, 96))"
---
Agent command center Group: Project g
All 1 Needs you 0 Working 0 Ready 1 Inactive 0 tab/shift+tab filter
All 1 Needs you 0 Working 0 Ready 1 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────
Tasks │ Task details
/tmp/project 1 │
@@ -3,7 +3,7 @@ source: tui/src/app/agents_overview_tests.rs
expression: "normalize_agent_center_snapshot(render_bottom_popup(&app.chat_widget, 96))"
---
Agent command center Group: Project g
All 1 Needs you 0 Working 0 Ready 1 Inactive 0 tab/shift+tab filter
All 1 Needs you 0 Working 0 Ready 1 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────
Tasks │ Task details
/tmp/project 1 │
@@ -3,7 +3,7 @@ source: tui/src/app/agents_overview_tests.rs
expression: "render_bottom_popup(&app.chat_widget,\n100).replace(&test_path_display(\"/tmp/project\"),\n\"/tmp/project\").replace(\"fwd del\", \"del\")"
---
Agent command center Group: Model g
All 4 Needs you 0 Working 0 Ready 4 Inactive 0 tab/shift+tab filter
All 4 Needs you 0 Working 0 Ready 4 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────────
Tasks │ Task details
Unknown 1 │
@@ -3,7 +3,7 @@ source: tui/src/app/agent_center_tests.rs
expression: "screen(&view, 160, 22)"
---
Agent command center Group: Project g
All 6 Needs you 2 Working 1 Ready 2 Inactive 1 tab/shift+tab filter
All 6 Needs you 2 Working 1 Ready 2 Inactive 1 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Tasks Status Updated │ Task details
/tmp/project 6 │
@@ -3,7 +3,7 @@ source: tui/src/app/agent_center_tests.rs
expression: "screen(&view, 100, 12)"
---
Agent command center Group: Project g
All 0 Needs you 0 Working 0 Ready 0 Inactive 0 tab/shift+tab filter
All 0 Needs you 0 Working 0 Ready 0 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────────
No tasks yet │
│
@@ -1,20 +1,21 @@
---
source: tui/src/app/agent_center_tests.rs
assertion_line: 450
expression: "screen(&view, 100, 24)"
---
Agent command center Group: Project g
All 0 Needs you 0 Working 0 Ready 0 Inactive 0 tab/shift+tab filter
All 0 Needs you 0 Working 0 Ready 0 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────────
Task shortcuts
Navigate Tasks View
k Up n New tab/shift+tab Filter
j Down o Resume f3 Search
enter Open f Fork g Group
pgdn Page down z r Rename
ctrl+c Quit x Stop
h Hide
backspace Delete
Navigate Tasks View
k Up n New tab/⇧tab Filter
j Down o Resume f3 Search
enter Open f Fork g Group
pgdn Page down z r Rename
⌃c Quit x Stop
h Hide
backspace Delete
@@ -8,12 +8,12 @@ expression: "screen(&view, width, height)"
Task shortcuts
Navigate
↑ Up
↓ Down
enter Open
pgup Page up
pgdn Page down
ctrl+c Quit
↑ Up
↓ Down
enter Open
pgup Page up
pgdn Page down
⌃c Quit
Tasks
n New
@@ -27,9 +27,9 @@ expression: "screen(&view, width, height)"
backspace Delete
View
tab/shift+tab Filter
f3 Search
g Group
tab/⇧tab Filter
f3 Search
g Group
@@ -1,22 +1,23 @@
---
source: tui/src/app/agent_center_tests.rs
assertion_line: 328
expression: "screen(&view, width, height)"
---
Agent command center Group: Project g
All 3 Needs you 1 Working 0 Ready 1 Inactive 1 tab/shift+tab filter
All 3 Needs you 1 Working 0 Ready 1 Inactive 1 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────────
Task shortcuts
Navigate Tasks View
↑ Up n New tab/shift+tab Filter
↓ Down w New worktree f3 Search
enter Open o Resume g Group
pgup Page up f Fork
pgdn Page down r Rename
ctrl+c Quit x Stop
a Archive
h Hide
backspace Delete
Navigate Tasks View
↑ Up n New tab/⇧tab Filter
↓ Down w New worktree f3 Search
enter Open o Resume g Group
pgup Page up f Fork
pgdn Page down r Rename
⌃c Quit x Stop
a Archive
h Hide
backspace Delete
@@ -7,21 +7,21 @@ expression: "screen(&view, width, height)"
────────────────────────────────────────────────────────
Task shortcuts
Navigate Tasks
↑ Up n New
↓ Down w New worktree
enter Open o Resume
pgup Page up f Fork
pgdn Page down r Rename
ctrl+c Quit x Stop
a Archive
h Hide
backspace Delete
Navigate Tasks
↑ Up n New
↓ Down w New worktree
enter Open o Resume
pgup Page up f Fork
pgdn Page down r Rename
⌃c Quit x Stop
a Archive
h Hide
backspace Delete
View
tab/shift+tab Filter
f3 Search
g Group
View
tab/⇧tab Filter
f3 Search
g Group
@@ -8,12 +8,12 @@ expression: "screen(&view, width, height)"
Task shortcuts
Navigate
↑ Up
↓ Down
enter Open
pgup Page up
pgdn Page down
ctrl+c Quit
↑ Up
↓ Down
enter Open
pgup Page up
pgdn Page down
⌃c Quit
Tasks
n New
@@ -3,7 +3,7 @@ source: tui/src/app/agents_overview_usage_tests.rs
expression: "render_bottom_popup(&app.chat_widget,\n96).replace(&format!(\"{project} 2\"),\n&group).replace(&project, \"/tmp/project\").replace(\"fwd del\", \"del\")"
---
Agent command center Group: Project g
All 2 Needs you 1 Working 0 Ready 1 Inactive 0 tab/shift+tab filter
All 2 Needs you 1 Working 0 Ready 1 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────
Tasks │ Task details
/tmp/project 2 │
@@ -63,7 +63,7 @@ Conversation row 19
• Queued follow-up inputs
↳ queued follow-up
shift+← edit last queued message
⇧← edit last queued message
⚠ 5h limit: only 2% left · /status
› draft stays
@@ -77,7 +77,7 @@ Conversation row 19
• Queued follow-up inputs
↳ queued follow-up
shift+← edit last queued message
⇧← edit last queued message
› draft stays
second line
@@ -1,6 +1,5 @@
---
source: tui/src/app/owned_transcript_browsing_tests.rs
assertion_line: 169
expression: "snapshots.join(\"\\n\\n\")"
---
80 columns
@@ -11,7 +10,7 @@ expression: "snapshots.join(\"\\n\\n\")"
› second prompt
Browsing · ↑↓/jk scroll · ←→/hl prompts · ctrl+t details · ↵ rewind · esc back
Browsing · ↑↓/jk scroll · ←→/hl prompts · ⌃t details · ↵ rewind · esc back
32 columns
/ T R A N S C R I P T / / / / /
@@ -3,7 +3,7 @@ source: tui/src/app/owned_transcript_tests.rs
expression: "crate::chatwidget::tests::helpers::normalize_agent_center_snapshot(crate::chatwidget::tests::helpers::render_bottom_popup(&app.chat_widget,\n96,))"
---
Agent command center Group: Project g
All 0 Needs you 0 Working 0 Ready 0 Inactive 0 tab/shift+tab filter
All 0 Needs you 0 Working 0 Ready 0 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────
Loading tasks… │
│
@@ -3,7 +3,7 @@ source: tui/src/app/owned_transcript_tests.rs
expression: "crate::chatwidget::tests::helpers::normalize_agent_center_snapshot(crate::chatwidget::tests::helpers::render_bottom_popup(&app.chat_widget,\n96,))"
---
Agent command center Group: Project g
All 0 Needs you 0 Working 0 Ready 0 Inactive 0 tab/shift+tab filter
All 0 Needs you 0 Working 0 Ready 0 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────
Reconnecting… │
│
@@ -3,4 +3,4 @@ source: tui/src/app/owned_transcript_tests.rs
expression: "rendered.lines().skip(usize::from(cursor.y)).take(2).map(str::trim).collect::<Vec<_>>().join(\"\\n\")"
---
Find: alpha betax
ctrl+x then · h move line start · esc cancel
⌃x then · h move line start · esc cancel
@@ -9,7 +9,7 @@ expression: "snapshots.join(\"\\n\\n\")"
↑ Loading earlier messages… · esc latest
80 columns · Failed
Retry history: ⌥</ctrl+home. esc latest
Retry history: ⌥</⌃home. esc latest
80 columns · Complete
esc latest
@@ -21,7 +21,7 @@ expression: "snapshots.join(\"\\n\\n\")"
↑ Loading… · esc latest
40 columns · Failed
Retry: ⌥</ctrl+home
Retry history: ⌥</⌃home. esc latest
40 columns · Complete
esc latest
@@ -33,7 +33,7 @@ expression: "snapshots.join(\"\\n\\n\")"
↑ Loading… · esc latest
28 columns · Failed
Retry: ⌥</ctrl+home
Retry: ⌥</⌃home
28 columns · Complete
esc latest
@@ -1,6 +1,5 @@
---
source: tui/src/app/owned_transcript_tests.rs
assertion_line: 1074
expression: "normalize_snapshot_paths(buffer_text(crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal)))"
---
@@ -18,4 +17,4 @@ expression: "normalize_snapshot_paths(buffer_text(crate::custom_terminal::test_s
› Ask Codex to do anything
gpt-test default · /tmp/project
Browsing · ↑↓/jk scroll · ←→/hl prompts · ctrl+t details · ↵ rewind · esc back
Browsing · ↑↓/jk scroll · ←→/hl prompts · ⌃t details · ↵ rewind · esc back
@@ -25,4 +25,4 @@ Earlier transcript row 22
k keep & next · esc dismiss & close · ctrl+o copy · ←/→ warning · ↓ scroll
k keep & next · esc dismiss & close · ⌃o copy · ←/→ warning · ↓ scroll
+6 -6
View File
@@ -5241,11 +5241,11 @@ async fn side_parent_status_prioritizes_input_over_approval() -> Result<()> {
);
assert_snapshot!(
format!("{input_footer}\n{approval_footer}\n{cleared_footer}"),
@r"
Side from main thread · main needs input · ctrl+/ to switch · ctrl+c to close
Side from main thread · main needs approval · ctrl+/ to switch · ctrl+c to close
Side from main thread · ctrl+/ to switch · ctrl+c to close
"
@"
Side from main thread · main needs input · ⌃/ to switch · ⌃c to close
Side from main thread · main needs approval · ⌃/ to switch · ⌃c to close
Side from main thread · ⌃/ to switch · ⌃c to close
"
);
Ok(())
@@ -6710,7 +6710,7 @@ async fn capped_resize_reflow_renders_recent_suffix_only() {
.map(rendered_line_text)
.collect::<Vec<_>>(),
vec![
"Earlier messages are available — press ctrl+t to view the full transcript".to_string(),
"Earlier messages are available — press ⌃t to view the full transcript".to_string(),
String::new(),
"cell 18".to_string(),
String::new(),
+5 -5
View File
@@ -110,11 +110,11 @@ async fn global_chord_keeps_hints_and_completes_before_deadline() -> Result<()>
insta::assert_snapshot!(
render_bottom_popup(&app.chat_widget, /*width*/ 80)
.replace(&test_path_display("/tmp/project"), "/tmp/project"),
@r"
› Ask Codex to do anything
@"
› Ask Codex to do anything
ctrl+x then · ctrl+t open transcript · ctrl+u interrupt turn · esc cancel
"
⌃x then · ⌃t open transcript · ⌃u interrupt turn · esc cancel
"
);
press(&mut app, &mut tui, &mut app_server, ctrl('t')).await?;
@@ -693,7 +693,7 @@ async fn dashboard_chord_hint_survives_refresh_and_clears_on_cancel() -> Result<
let _ = app.agents_overview_view(Vec::new(), /*selected_thread_id*/ None);
insta::assert_snapshot!(
render_bottom_popup(&app.chat_widget, /*width*/ 80).lines().last().unwrap(),
@" ctrl+x then n new task esc cancel"
@" ⌃x then n new task esc cancel"
);
assert_eq!(
app.route_key_chord_event(&mut tui, KeyCode::Esc.into()),
@@ -7,4 +7,4 @@ expression: "render_bottom_popup(&app.chat_widget, 80)"
› Ask Codex to do anything
ctrl+c quit
⌃c quit
@@ -4,4 +4,4 @@ expression: "render_bottom_popup(&app.chat_widget, 80)"
---
› kept draft
gpt-test default Plan mode (shift+tab to cycle)
gpt-test default Plan mode (⇧tab to cycle)
@@ -5,4 +5,4 @@ expression: "render_bottom_popup(&app.chat_widget, 96)"
🔒 This conversation is open in another app r to retry
Close it there and press R to continue here.
r retry f fork esc command center ctrl+c/q exit ← transcript
r retry f fork esc command center ⌃c/q exit ← transcript
@@ -4,7 +4,7 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&app.chat_widget, 80))
---
• Queued follow-up inputs
↳ keep queued
shift+← edit last queued message
⇧← edit last queued message
› keep draft
@@ -9,8 +9,8 @@ expression: "format!(\"{}\\n{}\",\nlines_to_single_string(&app.transcript_cells.
• Queued follow-up inputs
↳ queued before disconnect
shift+← edit last queued message
⇧← edit last queued message
› keep this draft!
ctrl+c quit
⌃c quit
@@ -3,7 +3,7 @@ source: tui/src/app/tests/navigation_reconnect_tests.rs
expression: "render_bottom_popup(&app.chat_widget, 100)"
---
Agent command center Group: Project g
All 2 Needs you 0 Working 1 Ready 1 Inactive 0 tab/shift+tab filter
All 2 Needs you 0 Working 1 Ready 1 Inactive 0 tab/⇧tab filter
────────────────────────────────────────────────────────────────────────────────────────────────
Tasks │ Task details
/tmp/project 2 │
@@ -2,7 +2,7 @@
source: tui/src/app/tests/pagination_completion_tests.rs
expression: "afternoon_clock.replace_all(&snapshots.join(\"\\n\\n--- next overlapping page ---\\n\\n\"),\n\"at 2:$1 PM\",)"
---
Earlier messages are available — press ctrl+t to view the full transcript
Earlier messages are available — press ⌃t to view the full transcript
• Middle answer
Worked for 2m 5s • Sep 6, 2000 at 2:33 PM
@@ -1,6 +1,5 @@
---
source: tui/src/app/tests/realtime_requests.rs
assertion_line: 479
expression: "normalize_voice_snapshot_directory(&format!(\"Other task:\\n{other_ui}\\nRestored owner:\\n{}\\n{rendered}\",\nrender_bottom_popup(&app.chat_widget, 80)), &app.config.cwd,)"
---
Other task:
@@ -8,7 +7,7 @@ Other task:
gpt-test default · /tmp/project
Restored owner:
voice ● listening ctrl+x mute /voice stop
voice ● listening ⌃x mute /voice stop
mic ▁▁▁▁▁▁ codex ▁▁▁▁▁▁
› Ask Codex to do anything
@@ -13,7 +13,7 @@ Buffer {
"› Hello ",
" Please say hello. ",
" ",
"Ctrl+Space select ",
"⌃space select ",
" ↑/↓ to scroll · pgup/pgdn to page · home/end to jump ",
" q close · f3 find · esc browse prompts ",
" ",
@@ -28,8 +28,8 @@ Buffer {
x: 0, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD | DIM,
x: 2, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 8, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 10, y: 8, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 17, y: 8, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 6, y: 8, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 13, y: 8, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 1, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 4, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
@@ -1,6 +1,5 @@
---
source: tui/src/app/tests/transcript_composer.rs
assertion_line: 267
expression: buffer_text(&buffer)
---
/ T R A N S C R I P T / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
@@ -11,6 +10,6 @@ expression: buffer_text(&buffer)
› second
Ctrl+Space select
⌃space select
↑/↓ to scroll · pgup/pgdn to page · home/end to jump
q close · f3 find · esc browse prompts
@@ -54,7 +54,7 @@ fn clipped_exec_approval_opens_the_complete_command() {
})
.collect();
let elision = rows.iter().find(|row| row.contains("[…")).unwrap();
assert_eq!(elision.contains("ctrl+g view all"), binding.is_some());
assert_eq!(elision.contains("⌃g view all"), binding.is_some());
assert!(rows.last().unwrap().contains("cancel"));
assert!(!rows.iter().any(|row| row.contains("destructive_suffix")));
assert!(!rows.iter().any(|row| row.contains("reason_suffix")));
@@ -1,6 +1,5 @@
---
source: tui/src/bottom_pane/approval_overlay/clipping_tests.rs
assertion_line: 100
expression: "snapshots.join(\"\\n\\n\")"
---
bound=true 80x14
@@ -14,7 +13,7 @@ bound=true 80x14
reason requiring review.A reason requiring review.A reason requiring
review.A reason requiring review.A reason requiring review.A reason
requiring review.A reason requiring review.A reason requiring review.A
[… 34 lines] ctrl+g view all
[… 34 lines] ⌃g view all
› 1. Yes, proceed (y)
2. No, and tell Codex what to do differently (esc)
Press enter to confirm or esc to cancel
@@ -24,7 +23,7 @@ bound=true 40x10
Would you like to run the following
command?
[… 43 lines] ctrl+g view all
[… 43 lines] ⌃g view all
› 1. Yes, proceed (y)
2. No, and tell Codex what to do
differently (esc)
@@ -34,7 +33,7 @@ bound=true 40x10
bound=true 40x8
Would you like to run the following
[… 43 lines] ctrl+g view all
[… 43 lines] ⌃g view all
› 1. Yes, proceed (y)
2. No, and tell Codex what to do
differently (esc)
@@ -43,7 +42,7 @@ bound=true 40x8
bound=true 40x7
[… 43 lines] ctrl+g view all
[… 43 lines] ⌃g view all
› 1. Yes, proceed (y)
2. No, and tell Codex what to do
differently (esc)
@@ -16,5 +16,4 @@ expression: buffer_text(&buffer)
long draft
enter submit ctrl+] skip
shift+→ main prompt
enter submit ⌃] skip ⇧→ main prompt
@@ -11,5 +11,5 @@ expression: buffer_text(&buffer)
› 13. earlier answer
reverse-i-search: e enter accept · esc
enter submit ctrl+] skip option 13/13
shift+→ prev question
enter submit ⌃] skip option 13/13
⇧→ prev question
@@ -9,5 +9,4 @@ expression: buffer_text(&buffer)
› 1. Other
2. Other (write an answer)
enter submit ctrl+] skip
shift+→ prev question
enter submit ⌃] skip ⇧→ prev question
@@ -8,4 +8,4 @@ expression: buffer_text(&buffer)
d
› x
ente…
ctrl…
⌃]…
@@ -13,8 +13,8 @@ Full height:
3. Other
enter submit
ctrl+] skip
shift+→ main prompt
⌃] skip
⇧→ main prompt
Clipped:
@@ -11,5 +11,5 @@ expression: buffer_text(&buffer)
2. Option 2 is long enough to wrap across
rows
f9 submit ctrl+] skip option 1/13
shift+→ prev question
f9 submit ⌃] skip option 1/13
⇧→ prev question
@@ -10,5 +10,5 @@ expression: buffer_text(&buffer)
multiple rows
2. Other
enter submit ctrl+] skip
shift+→ main prompt
enter submit ⌃] skip
⇧→ main prompt
@@ -12,5 +12,5 @@ expression: buffer_text(&buffer)
wraps across several option
rows
enter submit ctrl+] skip
shift+→ main prompt
enter submit ⌃] skip
⇧→ main prompt
@@ -9,5 +9,5 @@ expression: buffer_text(&clipped)
long enough to wrap across
multiple rows
enter submit ctrl+] skip
option 2/3 shift+→ main prompt
enter submit ⌃] skip
option 2/3 ⇧→ main prompt
@@ -445,7 +445,7 @@ fn existing_cross_context_keymaps_load_without_misleading_submit_hints() {
let mut editor = editor();
editor.navigate(/*forward*/ true);
editor.set_keymap(&keymap);
insta::allow_duplicates! { insta::assert_snapshot!(editor.footer_lines(/*width*/ 100, /*option_tip*/ None)[0].to_string(), @"ctrl+] skip shift+→ prev question"); }
insta::allow_duplicates! { insta::assert_snapshot!(editor.footer_lines(/*width*/ 100, /*option_tip*/ None)[0].to_string(), @"⌃] skip ⇧→ prev question"); }
editor.handle_key_event(KeyEvent::from(KeyCode::F(12)));
assert!(editor.submission.is_none());
}
@@ -12,19 +12,19 @@ shortcut help:
Keyboard shortcuts
Compose Session
/ Commands tab Send message
@ Mention files ⌥, Less reasoning
! Shell command ⌥. More reasoning
ctrl+j New line f4 Inspect activity
ctrl+v Paste image ctrl+c Quit
ctrl+g External editor
ctrl+r Search history Transcript (open first)
esc esc Edit last message ctrl+t Open transcript
f3 Find text
pgup / pgdn Scroll
ctrl+space Start selection
ctrl+home / ctrl+end Top / latest
shift+⌥, / shift+⌥. Top / latest
/ Commands tab Send message
@ Mention files ⌥, Less reasoning
! Shell command ⌥. More reasoning
⌃j New line f4 Inspect activity
⌃v Paste image ⌃c Quit
⌃g External editor
⌃r Search history Transcript (open first)
esc esc Edit last message ⌃t Open transcript
f3 Find text
pgup / pgdn Scroll
⌃space Start selection
⌃home / ⌃end Top / latest
⇧⌥, / ⇧⌥. Top / latest
/keymap customize
@@ -47,19 +47,19 @@ shortcut help:
Keyboard shortcuts
Compose Session
/ Commands tab Send message
@ Mention files ⌥, Less reasoning
! Shell command ⌥. More reasoning
ctrl+j New line f4 Inspect activity
ctrl+v Paste image ctrl+c Quit
ctrl+g External editor
ctrl+r Search history Transcript (open first)
esc esc Edit last message ctrl+t Open transcript
f3 Find text
pgup / pgdn Scroll
ctrl+space Start selection
ctrl+home / ctrl+end Top / latest
shift+⌥, / shift+⌥. Top / latest
/ Commands tab Send message
@ Mention files ⌥, Less reasoning
! Shell command ⌥. More reasoning
⌃j New line f4 Inspect activity
⌃v Paste image ⌃c Quit
⌃g External editor
⌃r Search history Transcript (open first)
esc esc Edit last message ⌃t Open transcript
f3 Find text
pgup / pgdn Scroll
⌃space Start selection
⌃home / ⌃end Top / latest
⇧⌥, / ⇧⌥. Top / latest
/keymap customize
@@ -6,19 +6,19 @@ shortcut help:
Keyboard shortcuts
Compose Session
/ Commands tab Send message
@ Mention files ⌥, Less reasoning
! Shell command ⌥. More reasoning
ctrl+j New line f4 Inspect activity
ctrl+v Paste image ctrl+c Quit
ctrl+g External editor
ctrl+r Search history Transcript (open first)
esc esc Edit last message ctrl+t Open transcript
f3 Find text
pgup / pgdn Scroll
ctrl+space Start selection
ctrl+home / ctrl+end Top / latest
shift+⌥, / shift+⌥. Top / latest
/ Commands tab Send message
@ Mention files ⌥, Less reasoning
! Shell command ⌥. More reasoning
⌃j New line f4 Inspect activity
⌃v Paste image ⌃c Quit
⌃g External editor
⌃r Search history Transcript (open first)
esc esc Edit last message ⌃t Open transcript
f3 Find text
pgup / pgdn Scroll
⌃space Start selection
⌃home / ⌃end Top / latest
⇧⌥, / ⇧⌥. Top / latest
/keymap customize
@@ -13,14 +13,14 @@ expression: "snapshots.join(\"\\n---\\n\")"
Keyboard shortcuts
Compose Session Transcript (open first)
/ Commands tab Send message ctrl+t Open transcript
@ Mention files ⌥, Less reasoning f3 Find text
! Shell command ⌥. More reasoning pgup / pgdn Scroll
ctrl+j New line f4 Inspect activity ctrl+space Start selection
ctrl+v Paste image ctrl+c Quit ctrl+home / ctrl+end Top / latest
ctrl+g External editor shift+⌥, / shift+⌥. Top / latest
ctrl+r Search history
Compose Session Transcript (open first)
/ Commands tab Send message ⌃t Open transcript
@ Mention files ⌥, Less reasoning f3 Find text
! Shell command ⌥. More reasoning pgup / pgdn Scroll
⌃j New line f4 Inspect activity ⌃space Start selection
⌃v Paste image ⌃c Quit ⌃home / ⌃end Top / latest
⌃g External editor ⇧⌥, / ⇧⌥. Top / latest
⌃r Search history
esc esc Edit last message
/keymap customize
@@ -41,14 +41,14 @@ expression: "snapshots.join(\"\\n---\\n\")"
Keyboard shortcuts
Compose Session Transcript (open first)
/ Commands tab Send message ctrl+t Open transcript
@ Mention files ⌥, Less reasoning f3 Find text
! Shell command ⌥. More reasoning pgup / pgdn Scroll
ctrl+j New line ctrl+x t Inspect activity ctrl+space Start selection
ctrl+v Paste image ctrl+c Quit ctrl+home / ctrl+end Top / latest
ctrl+g External editor shift+⌥, / shift+⌥. Top / latest
ctrl+r Search history
Compose Session Transcript (open first)
/ Commands tab Send message ⌃t Open transcript
@ Mention files ⌥, Less reasoning f3 Find text
! Shell command ⌥. More reasoning pgup / pgdn Scroll
⌃j New line ⌃x t Inspect activity ⌃space Start selection
⌃v Paste image ⌃c Quit ⌃home / ⌃end Top / latest
⌃g External editor ⇧⌥, / ⇧⌥. Top / latest
⌃r Search history
esc esc Edit last message
/keymap customize
@@ -69,14 +69,14 @@ expression: "snapshots.join(\"\\n---\\n\")"
Keyboard shortcuts
Compose Session Transcript (open first)
/ Commands tab Send message ctrl+t Open transcript
@ Mention files ⌥, Less reasoning f3 Find text
! Shell command ⌥. More reasoning pgup / pgdn Scroll
ctrl+j New line ctrl+c Quit ctrl+space Start selection
ctrl+v Paste image ctrl+home / ctrl+end Top / latest
ctrl+g External editor shift+⌥, / shift+⌥. Top / latest
ctrl+r Search history
Compose Session Transcript (open first)
/ Commands tab Send message ⌃t Open transcript
@ Mention files ⌥, Less reasoning f3 Find text
! Shell command ⌥. More reasoning pgup / pgdn Scroll
⌃j New line ⌃c Quit ⌃space Start selection
⌃v Paste image ⌃home / ⌃end Top / latest
⌃g External editor ⇧⌥, / ⇧⌥. Top / latest
⌃r Search history
esc esc Edit last message
/keymap customize
@@ -1,6 +1,5 @@
---
source: tui/src/bottom_pane/chat_composer/status_surface_tests.rs
assertion_line: 102
expression: wide
---
@@ -14,5 +13,5 @@ expression: wide
› Ask Codex
MODEL · ~/project · Context 20% used Plan mode (shift+tab to cycle)
MODEL · ~/project · Context 20% used Plan mode (⇧tab to cycle)
? for shortcuts
@@ -16,26 +16,26 @@ expression: text
/ Commands
@ Mention files
! Shell command
ctrl+j New line
ctrl+v Paste image
ctrl+g External editor
ctrl+r Search history
⌃j New line
⌃v Paste image
⌃g External editor
⌃r Search history
esc esc Edit last message
Session
tab Send message
⌥, Less reasoning
⌥. More reasoning
f4 Inspect activity
ctrl+c Quit
tab Send message
⌥, Less reasoning
⌥. More reasoning
f4 Inspect activity
⌃c Quit
Transcript (open first)
ctrl+t Open transcript
f3 Find text
pgup / pgdn Scroll
ctrl+space Start selection
ctrl+home / ctrl+end Top / latest
shift+⌥, / shift+⌥. Top / latest
⌃t Open transcript
f3 Find text
pgup / pgdn Scroll
⌃space Start selection
⌃home / ⌃end Top / latest
⇧⌥, / ⇧⌥. Top / latest
/keymap customize
@@ -12,14 +12,14 @@ expression: text
Keyboard shortcuts
Compose Session Transcript (open first)
/ Commands tab Send message ctrl+t Open transcript
@ Mention files ⌥, Less reasoning f3 Find text
! Shell command ⌥. More reasoning pgup / pgdn Scroll
ctrl+j New line f4 Inspect activity ctrl+space Start selection
ctrl+v Paste image ctrl+c Quit ctrl+home / ctrl+end Top / latest
ctrl+g External editor shift+⌥, / shift+⌥. Top / latest
ctrl+r Search history
Compose Session Transcript (open first)
/ Commands tab Send message ⌃t Open transcript
@ Mention files ⌥, Less reasoning f3 Find text
! Shell command ⌥. More reasoning pgup / pgdn Scroll
⌃j New line f4 Inspect activity ⌃space Start selection
⌃v Paste image ⌃c Quit ⌃home / ⌃end Top / latest
⌃g External editor ⇧⌥, / ⇧⌥. Top / latest
⌃r Search history
esc esc Edit last message
/keymap customize
@@ -96,19 +96,19 @@ fn fullscreen_plan_indicator_keeps_the_cycle_hint_when_it_fits() {
composer.set_collaboration_mode_indicator(Some(CollaborationModeIndicator::Plan));
let (wide, _) = render(&composer, /*width*/ 100, /*footer*/ None);
assert!(
wide.contains("Plan mode (shift+tab to cycle)"),
wide.contains("Plan mode (⇧tab to cycle)"),
"idle fullscreen must explain how to leave Plan mode: {wide}"
);
insta::assert_snapshot!("fullscreen_plan_cycle_hint", wide);
let (narrow, _) = render(&composer, /*width*/ 44, /*footer*/ None);
assert!(narrow.contains("Plan mode"), "{narrow}");
assert!(!narrow.contains("shift+tab"), "{narrow}");
assert!(!narrow.contains("⇧tab"), "{narrow}");
composer.set_task_running(/*running*/ true);
let (running, _) = render(&composer, /*width*/ 100, /*footer*/ None);
assert!(running.contains("Plan mode"), "{running}");
assert!(!running.contains("shift+tab"), "{running}");
assert!(!running.contains("⇧tab"), "{running}");
composer.set_task_running(/*running*/ false);
let footer = TranscriptFooter {
@@ -118,7 +118,7 @@ fn fullscreen_plan_indicator_keeps_the_cycle_hint_when_it_fits() {
};
let (search, _) = render(&composer, /*width*/ 100, Some(&footer));
assert!(search.contains("Plan mode"), "{search}");
assert!(!search.contains("shift+tab"), "{search}");
assert!(!search.contains("⇧tab"), "{search}");
// Configured items such as git-branch can have no value outside a repository.
composer.set_status_line(/*status_line*/ None);
@@ -129,7 +129,7 @@ fn fullscreen_plan_indicator_keeps_the_cycle_hint_when_it_fits() {
);
let (empty_wide, _) = render(&composer, /*width*/ 100, /*footer*/ None);
assert!(
empty_wide.contains("Plan mode (shift+tab to cycle)"),
empty_wide.contains("Plan mode (⇧tab to cycle)"),
"{empty_wide}"
);
@@ -271,10 +271,13 @@ fn shortcut_help_keeps_input_and_close_hint_visible_when_height_is_tiny() {
fn shortcut_help_close_row_uses_runtime_binding_and_narrow_fallback() {
let chord = Some(key_hint::ShortcutHint::Chord {
prefix: key_hint::ctrl(KeyCode::Char('x')),
completion: key_hint::ctrl(KeyCode::Char('h')),
completion: key_hint::KeyBinding::new(
KeyCode::F(12),
KeyModifiers::CONTROL | KeyModifiers::SHIFT | KeyModifiers::ALT,
),
});
for (width, binding, expected) in [
(80, chord, "ctrl+x ctrl+h / esc close"),
(80, chord, "⌃x ⌃⇧⌥f12 / esc close"),
(22, chord, "esc close"),
(80, None, "esc close"),
] {
+6 -4
View File
@@ -107,7 +107,6 @@ pub(crate) enum GoalStatusIndicator {
Complete { usage: Option<String> },
}
const MODE_CYCLE_HINT: &str = "shift+tab to cycle";
const FOOTER_CONTEXT_GAP_COLS: u16 = 1;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -151,7 +150,10 @@ impl FooterKeyHints {
impl CollaborationModeIndicator {
fn label(self, show_cycle_hint: bool) -> String {
let suffix = if show_cycle_hint {
format!(" ({MODE_CYCLE_HINT})")
format!(
" ({} to cycle)",
key_hint::shift(KeyCode::Tab).display_label()
)
} else {
String::new()
};
@@ -1502,7 +1504,7 @@ mod tests {
snapshot_footer_with_mode_indicator(
"footer_mode_indicator_narrow_overlap_hides",
/*width*/ 50,
/*width*/ 40,
&props,
Some(CollaborationModeIndicator::Plan),
);
@@ -1739,7 +1741,7 @@ mod tests {
"mode indicator should remain visible"
);
assert!(
!collapsed.contains("shift+tab to cycle"),
!collapsed.contains("⇧tab to cycle"),
"compact mode indicator should be used when space is tight"
);
assert!(
@@ -989,7 +989,14 @@ impl McpServerElicitationOverlay {
if self.current_field_is_select() {
tips.push(shortcut("←/→", "to navigate fields"));
} else {
tips.push(shortcut("ctrl+p / ctrl+n", "change field"));
tips.push(shortcut(
&format!(
"{} / {}",
crate::key_hint::ctrl(KeyCode::Char('p')).display_label(),
crate::key_hint::ctrl(KeyCode::Char('n')).display_label()
),
"change field",
));
}
}
tips.push(shortcut("esc", "to cancel"));
@@ -612,7 +612,14 @@ impl RequestUserInputOverlay {
if self.has_options() && !self.focus_is_notes() {
tips.push(shortcut("←/→", "to navigate questions"));
} else if !self.has_options() {
tips.push(shortcut("ctrl+p / ctrl+n", "change question"));
tips.push(shortcut(
&format!(
"{} / {}",
crate::key_hint::ctrl(KeyCode::Char('p')).display_label(),
crate::key_hint::ctrl(KeyCode::Char('n')).display_label()
),
"change question",
));
}
}
if let Some(interrupt_key) = self.interrupt_turn_hint
@@ -2477,7 +2484,7 @@ mod tests {
tip_texts,
vec![
"enter to submit all",
"ctrl+p / ctrl+n change question",
"⌃p / ⌃n change question",
"esc to interrupt",
]
);
@@ -2499,10 +2506,7 @@ mod tests {
let tips = overlay.footer_tips();
let tip_texts = tips.iter().map(ToString::to_string).collect::<Vec<_>>();
assert_eq!(
tip_texts,
vec!["ctrl+j to submit answer", "esc to interrupt"]
);
assert_eq!(tip_texts, vec!["⌃j to submit answer", "esc to interrupt"]);
}
#[test]
@@ -2510,21 +2514,21 @@ mod tests {
for (specs, expected_tips) in [
(
KeybindingsSpec::One(KeybindingSpec("ctrl-x enter".to_string())),
vec!["ctrl+x enter to submit answer", "esc to interrupt"],
vec!["⌃x enter to submit answer", "esc to interrupt"],
),
(
KeybindingsSpec::Many(vec![
KeybindingSpec("ctrl-enter".to_string()),
KeybindingSpec("ctrl-x enter".to_string()),
]),
vec!["ctrl+enter to submit answer", "esc to interrupt"],
vec!["⌃enter to submit answer", "esc to interrupt"],
),
(
KeybindingsSpec::Many(vec![
KeybindingSpec("ctrl-x enter".to_string()),
KeybindingSpec("ctrl-enter".to_string()),
]),
vec!["ctrl+x enter to submit answer", "esc to interrupt"],
vec!["⌃x enter to submit answer", "esc to interrupt"],
),
] {
let (tx, _rx) = test_sender();
@@ -3747,16 +3751,16 @@ mod tests {
.collect::<Vec<_>>()
.join("\n");
insta::assert_snapshot!(snapshot, @r"
insta::assert_snapshot!(snapshot, @"
Question 1/1 (1 unanswered)
Share details.
Question 1/1 (1 unanswered)
Share details.
› Type your answer (optional)
› Type your answer (optional)
ctrl+x enter to submit answer | esc to interrupt
⌃x enter to submit answer | esc to interrupt
");
}
@@ -1,6 +1,5 @@
---
source: tui/src/bottom_pane/request_user_input/mod.rs
assertion_line: 3785
expression: "render_snapshot(&overlay, area)"
---
@@ -11,4 +10,4 @@ expression: "render_snapshot(&overlay, area)"
ctrl+j to submit answer | esc to interrupt
⌃j to submit answer | esc to interrupt
@@ -1,6 +1,5 @@
---
source: tui/src/bottom_pane/request_user_input/mod.rs
assertion_line: 3852
expression: "render_snapshot(&overlay, area)"
---
@@ -13,4 +12,4 @@ expression: "render_snapshot(&overlay, area)"
enter to submit all | ctrl+p / ctrl+n change question | esc to interrupt
enter to submit all | ⌃p / ⌃n change question | esc to interrupt
@@ -98,7 +98,11 @@ pub(super) fn lines(props: &FooterProps, width: u16) -> Vec<Line<'static>> {
},
Shortcut::new(key_hint::ctrl(KeyCode::Char(' ')), "Start selection"),
Shortcut {
key: "ctrl+home / ctrl+end".into(),
key: format!(
"{} / {}",
key_hint::ctrl(KeyCode::Home).display_label(),
key_hint::ctrl(KeyCode::End).display_label()
),
action: "Top / latest",
},
// Keep both jump alternatives: the terminal may be on another OS over SSH.
@@ -568,8 +568,8 @@ mod tests {
let view = SkillsToggleView::new(Vec::new(), tx, keymap);
let rendered = render_lines(&view, /*width*/ 72);
assert!(rendered.contains("ctrl+t"));
assert!(rendered.contains("ctrl+x"));
assert!(rendered.contains("⌃t"));
assert!(rendered.contains("⌃x"));
assert!(!rendered.contains("enter"));
assert!(!rendered.contains("esc"));
}
@@ -5,20 +5,20 @@ expression: terminal.backend()
" Keyboard shortcuts "
" "
" Compose Session "
" / Commands tab Send message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" ctrl+j New line ← Agents (empty prompt) "
" ctrl+v Paste image f4 Inspect activity "
" ctrl+g External editor ctrl+c Quit "
" ctrl+r Search history "
" / Commands tab Send message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" ⌃j New line ← Agents (empty prompt) "
" ⌃v Paste image f4 Inspect activity "
" ⌃g External editor ⌃c Quit "
" ⌃r Search history "
" esc esc Edit last message Transcript (open first) "
" ctrl+t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ctrl+space Start selection "
" ctrl+home / ctrl+end Top / latest "
" shift+⌥, / shift+⌥. Top / latest "
" ⌃t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ⌃space Start selection "
" ⌃home / ⌃end Top / latest "
" ⇧⌥, / ⇧⌥. Top / latest "
" "
" /keymap customize "
" "
@@ -10,4 +10,4 @@ expression: terminal.backend()
" "
" "
" "
" ? for shortcuts · Plan mode (shift+tab to cycle) 100% context left "
" ? for shortcuts · Plan mode (⇧tab to cycle) 100% context left "
@@ -10,4 +10,4 @@ expression: terminal.backend()
" "
" "
" "
" Plan mode (shift+tab to cycle) 100% context left "
" Plan mode (⇧tab to cycle) 100% context left "
@@ -10,4 +10,4 @@ expression: terminal.backend()
" "
" "
" "
" Plan mode (shift+tab to cycle) "
" Plan mode (⇧tab to cycle) "
@@ -4,20 +4,15 @@ expression: terminal.backend()
---
" Keyboard shortcuts "
" "
" Compose Session "
" / Commands tab Send message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" ctrl+x enter New line f4 Inspect activity "
" ctrl+v Paste image ctrl+c Quit "
" ctrl+g ctrl+g External editor "
" ctrl+r Search history Transcript (open first) "
" esc esc Edit last message ctrl+t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ctrl+space Start selection "
" ctrl+home / ctrl+end Top / latest "
" shift+⌥, / shift+⌥. Top / latest "
" Compose Session Transcript (open first) "
" / Commands tab Send message ⌃t Open transcript "
" @ Mention files ⌥, Less reasoning f3 Find text "
" ! Shell command ⌥. More reasoning pgup / pgdn Scroll "
" ⌃x enter New line f4 Inspect activity ⌃space Start selection "
" ⌃v Paste image ⌃c Quit ⌃home / ⌃end Top / latest "
" ⌃g ⌃g External editor ⇧⌥, / ⇧⌥. Top / latest "
" ⌃r Search history "
" esc esc Edit last message "
" "
" /keymap customize "
" "
@@ -10,4 +10,4 @@ expression: terminal.backend()
" "
" "
" "
" ctrl+c again to quit "
" ⌃c again to quit "
@@ -10,4 +10,4 @@ expression: terminal.backend()
" "
" "
" "
" ctrl+c again to quit "
" ⌃c again to quit "
@@ -4,20 +4,15 @@ expression: terminal.backend()
---
" Keyboard shortcuts "
" "
" Compose Session "
" / Commands tab Send message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" shift+enter New line f4 Inspect activity "
" ctrl+v Paste image ctrl+c Quit "
" ctrl+g External editor "
" ctrl+r Search history Transcript (open first) "
" esc Edit last message ctrl+t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ctrl+space Start selection "
" ctrl+home / ctrl+end Top / latest "
" shift+⌥, / shift+⌥. Top / latest "
" Compose Session Transcript (open first) "
" / Commands tab Send message ⌃t Open transcript "
" @ Mention files ⌥, Less reasoning f3 Find text "
" ! Shell command ⌥. More reasoning pgup / pgdn Scroll "
" ⇧enter New line f4 Inspect activity ⌃space Start selection "
" ⌃v Paste image ⌃c Quit ⌃home / ⌃end Top / latest "
" ⌃g External editor ⇧⌥, / ⇧⌥. Top / latest "
" ⌃r Search history "
" esc Edit last message "
" "
" /keymap customize "
" "
@@ -4,20 +4,15 @@ expression: terminal.backend()
---
" Keyboard shortcuts "
" "
" Compose Session "
" / Commands tab Queue message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" shift+enter New line f4 Inspect activity "
" ctrl+v Paste image ctrl+c Quit "
" ctrl+g External editor "
" ctrl+r Search history Transcript (open first) "
" esc esc Edit last message ctrl+t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ctrl+space Start selection "
" ctrl+home / ctrl+end Top / latest "
" shift+⌥, / shift+⌥. Top / latest "
" Compose Session Transcript (open first) "
" / Commands tab Queue message ⌃t Open transcript "
" @ Mention files ⌥, Less reasoning f3 Find text "
" ! Shell command ⌥. More reasoning pgup / pgdn Scroll "
" ⇧enter New line f4 Inspect activity ⌃space Start selection "
" ⌃v Paste image ⌃c Quit ⌃home / ⌃end Top / latest "
" ⌃g External editor ⇧⌥, / ⇧⌥. Top / latest "
" ⌃r Search history "
" esc esc Edit last message "
" "
" /keymap customize "
" "
@@ -2,4 +2,4 @@
source: tui/src/bottom_pane/footer.rs
expression: terminal.backend()
---
" ctrl+c again to quit "
" ⌃c again to quit "
@@ -2,4 +2,4 @@
source: tui/src/bottom_pane/footer.rs
expression: terminal.backend()
---
" ctrl+c again to quit "
" ⌃c again to quit "
@@ -2,4 +2,4 @@
source: tui/src/bottom_pane/footer.rs
expression: terminal.backend()
---
" Plan mode (shift+tab to cycle) "
" Plan mode (⇧tab to cycle) "
@@ -2,4 +2,4 @@
source: tui/src/bottom_pane/footer.rs
expression: terminal.backend()
---
" ? for shortcuts · Plan mode (shift+tab to cycle) 100% context left "
" ? for shortcuts · Plan mode (⇧tab to cycle) 100% context left "
@@ -5,20 +5,20 @@ expression: terminal.backend()
" Keyboard shortcuts "
" "
" Compose Session "
" / Commands tab Send message "
" @ Mention files shift+tab Change mode "
" ! Shell command ⌥, Less reasoning "
" ctrl+j New line ⌥. More reasoning "
" ctrl+v Paste image f8 Voice "
" ctrl+g External editor f4 Inspect activity "
" ctrl+r Search history ctrl+c Quit "
" / Commands tab Send message "
" @ Mention files ⇧tab Change mode "
" ! Shell command ⌥, Less reasoning "
" ⌃j New line ⌥. More reasoning "
" ⌃v Paste image f8 Voice "
" ⌃g External editor f4 Inspect activity "
" ⌃r Search history ⌃c Quit "
" esc esc Edit last message "
" Transcript (open first) "
" ctrl+t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ctrl+space Start selection "
" ctrl+home / ctrl+end Top / latest "
" shift+⌥, / shift+⌥. Top / latest "
" ⌃t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ⌃space Start selection "
" ⌃home / ⌃end Top / latest "
" ⇧⌥, / ⇧⌥. Top / latest "
" "
" /keymap customize "
@@ -5,19 +5,19 @@ expression: terminal.backend()
" Keyboard shortcuts "
" "
" Compose Session "
" / Commands tab Queue message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" ctrl+j New line f8 Voice "
" ctrl+v Paste image f4 Inspect activity "
" ctrl+g External editor ctrl+c Interrupt "
" ctrl+r Search history "
" / Commands tab Queue message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" ⌃j New line f8 Voice "
" ⌃v Paste image f4 Inspect activity "
" ⌃g External editor ⌃c Interrupt "
" ⌃r Search history "
" esc esc Edit last message Transcript (open first) "
" ctrl+t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ctrl+space Start selection "
" ctrl+home / ctrl+end Top / latest "
" shift+⌥, / shift+⌥. Top / latest "
" ⌃t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ⌃space Start selection "
" ⌃home / ⌃end Top / latest "
" ⇧⌥, / ⇧⌥. Top / latest "
" "
" /keymap customize "
@@ -4,20 +4,20 @@ expression: terminal.backend()
---
" Keyboard shortcuts "
" "
" Compose Session "
" / Commands tab Send message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" shift+enter New line f8 Voice "
" ctrl+v Paste image f4 Inspect activity "
" ctrl+g External editor ctrl+c Quit "
" ctrl+r Search history "
" esc Edit last message Transcript (open first) "
" ctrl+t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ctrl+space Start selection "
" ctrl+home / ctrl+end Top / latest "
" shift+⌥, / shift+⌥. Top / latest "
" Compose Session "
" / Commands tab Send message "
" @ Mention files ⌥, Less reasoning "
" ! Shell command ⌥. More reasoning "
" ⇧enter New line f8 Voice "
" ⌃v Paste image f4 Inspect activity "
" ⌃g External editor ⌃c Quit "
" ⌃r Search history "
" esc Edit last message Transcript (open first) "
" ⌃t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ⌃space Start selection "
" ⌃home / ⌃end Top / latest "
" ⇧⌥, / ⇧⌥. Top / latest "
" "
" /keymap customize "
@@ -2,4 +2,4 @@
source: tui/src/bottom_pane/footer.rs
expression: terminal.backend()
---
" ? for shortcuts · Plan mode (shift+tab to cycle) 50% context left "
" ? for shortcuts · Plan mode (⇧tab to cycle) 50% context left "
@@ -2,4 +2,4 @@
source: tui/src/bottom_pane/footer.rs
expression: terminal.backend()
---
" Plan mode (shift+tab to cycle) · IDE context "
" Plan mode (⇧tab to cycle) · IDE context "
@@ -2,4 +2,4 @@
source: tui/src/bottom_pane/footer.rs
expression: terminal.backend()
---
" Plan mode (shift+tab to cycle) "
" Plan mode (⇧tab to cycle) "
@@ -10,4 +10,4 @@ expression: snapshot
› Type your answer
ctrl+x enter to submit | esc to cancel
⌃x enter to submit | esc to cancel
@@ -10,7 +10,7 @@ Buffer {
" a message ",
" with many ",
" … ",
" shift+← edit last queued message ",
" ⇧← edit last queued message ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
@@ -25,7 +25,7 @@ Buffer {
x: 0, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: DIM | ITALIC,
x: 5, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 4, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 11, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 6, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 31, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
@@ -10,7 +10,7 @@ Buffer {
" ↳ This is another message ",
" ↳ This is a third message ",
" ↳ This is a fourth message ",
" shift+← edit last queued message ",
" ⇧← edit last queued message ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
@@ -28,7 +28,7 @@ Buffer {
x: 4, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: DIM | ITALIC,
x: 28, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 4, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 11, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 6, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 31, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
@@ -7,7 +7,7 @@ Buffer {
content: [
"• Queued follow-up inputs ",
" ↳ Hello, world! ",
" shift+← edit last queued message ",
" ⇧← edit last queued message ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
@@ -16,7 +16,7 @@ Buffer {
x: 4, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: DIM | ITALIC,
x: 17, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 4, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 11, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 6, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 31, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
@@ -7,7 +7,7 @@ Buffer {
content: [
"• Queued follow-up inputs ",
" ↳ Hello, world! ",
" shift+← edit last queued message ",
" ⇧← edit last queued message ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
@@ -16,7 +16,7 @@ Buffer {
x: 4, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: DIM | ITALIC,
x: 17, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 4, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 11, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 6, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 31, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
@@ -15,7 +15,7 @@ Buffer {
" ",
"• Queued follow-up inputs ",
" ↳ Queued follow-up question ",
" shift+← edit last queued message ",
" ⇧← edit last queued message ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
@@ -38,7 +38,7 @@ Buffer {
x: 4, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: DIM | ITALIC,
x: 29, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 4, y: 10, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 11, y: 10, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 10, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 6, y: 10, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 31, y: 10, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
@@ -8,7 +8,7 @@ Buffer {
"• Queued follow-up inputs ",
" ↳ Hello, world! ",
" ↳ This is another message ",
" shift+← edit last queued message ",
" ⇧← edit last queued message ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
@@ -20,7 +20,7 @@ Buffer {
x: 4, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: DIM | ITALIC,
x: 27, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 4, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 11, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 6, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 31, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
@@ -9,7 +9,7 @@ Buffer {
" ↳ This is a longer message that should",
" be wrapped ",
" ↳ This is another message ",
" shift+← edit last queued message ",
" ⇧← edit last queued message ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
@@ -23,7 +23,7 @@ Buffer {
x: 4, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: DIM | ITALIC,
x: 27, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 4, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
x: 11, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 6, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 31, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
@@ -3,4 +3,4 @@ source: tui/src/bottom_pane/questions_tests.rs
expression: "pane.question_summary(now).unwrap().iter().map(ToString::to_string).collect::<Vec<_>>().join(\"\\n\")"
---
? 2 questions · 15s
shift+← to answer
⇧← to answer
@@ -4,21 +4,21 @@ expression: terminal.backend()
---
" Keyboard shortcuts "
" "
" Compose Session "
" / Commands tab Send message "
" @ Mention files shift+tab Change mode "
" ! Shell command ⌥. More reasoning "
" shift+enter New line f8 Voice "
" ctrl+⌥v Paste image ← Agents (empty prompt) "
" ctrl+x ctrl+e External editor f4 Inspect activity "
" esc Edit last message ctrl+c Quit "
" Compose Session "
" / Commands tab Send message "
" @ Mention files ⇧tab Change mode "
" ! Shell command ⌥. More reasoning "
" ⇧enter New line f8 Voice "
" ⌃⌥v Paste image ← Agents (empty prompt) "
" ⌃x ⌃e External editor f4 Inspect activity "
" esc Edit last message ⌃c Quit "
" "
" Transcript (open first) "
" ctrl+t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ctrl+space Start selection "
" ctrl+home / ctrl+end Top / latest "
" shift+⌥, / shift+⌥. Top / latest "
" Transcript (open first) "
" ⌃t Open transcript "
" f3 Find text "
" pgup / pgdn Scroll "
" ⌃space Start selection "
" ⌃home / ⌃end Top / latest "
" ⇧⌥, / ⇧⌥. Top / latest "
" "
" /keymap customize "
@@ -4,7 +4,7 @@ expression: "render_snapshot(&pane, area)"
---
• Queued follow-up inputs
↳ Queued follow-up question
shift+← edit last queued message
⇧← edit last queued message
› Ask Codex to do anything
@@ -6,7 +6,7 @@ expression: "render_snapshot(&pane, area)"
• Queued follow-up inputs
↳ Queued follow-up question
shift+← edit last queued message
⇧← edit last queued message
› Ask Codex to do anything
@@ -8,7 +8,7 @@ expression: "render_snapshot(&pane, area)"
• Queued follow-up inputs
↳ Queued follow-up question
shift+← edit last queued message
⇧← edit last queued message
› Ask Codex to do anything
@@ -5,7 +5,7 @@ expression: "render_view_lines(&view, 40, 8)"
Production deployment needs your
approval.
[… 7 lines] ctrl+a view all
[… 7 lines] ⌃a view all
› 1. Verify and approve (y)
2. Cancel this request (c)
Press enter to confirm or esc to
@@ -1,6 +1,5 @@
---
source: tui/src/bottom_pane/voice_strip_tests.rs
assertion_line: 165
expression: "layouts.join(\"\\n\\n\")"
---
'f8', muted=false, width=80:
@@ -20,7 +19,7 @@ expression: "layouts.join(\"\\n\\n\")"
mic ▁▁▁ codex ▅▆█
'ctrl-x m', muted=false, width=80:
voice ● listening ctrl+x m mute /voice stop
voice ● listening ⌃x m mute /voice stop
mic ▆▅▄▃▂▁ codex ▁▃▄▅▆█
'ctrl-x m', muted=false, width=22:
@@ -28,7 +27,7 @@ expression: "layouts.join(\"\\n\\n\")"
mic ▃▂▁ codex ▅▆█
'ctrl-x m', muted=true, width=80:
voice ◌ muted ctrl+x m unmute /voice stop
voice ◌ muted ⌃x m unmute /voice stop
mic ▁▁▁▁▁▁ codex ▁▃▄▅▆█
'ctrl-x m', muted=true, width=22:
@@ -54,8 +54,8 @@ fn active_dashboard_preserves_live_colors_controls_and_width() {
assert_eq!(buffer[(46, 0)].symbol(), " ");
assert!(actual.starts_with(" voice "));
assert!(actual.lines().nth(1).unwrap().starts_with(" mic "));
insta::assert_snapshot!(actual, @r"
voice ● listening ctrl+x mute /voice stop
insta::assert_snapshot!(actual, @"
voice ● listening ⌃x mute /voice stop
mic ▆▅▄▃▂▁ codex ▁▃▄▅▆█
");
assert_eq!(buffer[(7, 0)].fg, Color::Red);
@@ -63,7 +63,7 @@ fn active_dashboard_preserves_live_colors_controls_and_width() {
assert_eq!(buffer[(22, 1)].fg, Color::Magenta);
assert!(actual.contains("/voice stop"));
let (compact, buffer) = rows(&strip, /*width*/ 37);
assert!(compact.contains("ctrl+x mute") && compact.contains("/voice stop"));
assert!(compact.contains("⌃x mute") && compact.contains("/voice stop"));
assert_eq!(buffer[(36, 0)].symbol(), " ");
let (narrow, buffer) = rows(&strip, /*width*/ 22);
assert!(narrow.contains("/voice stop"));
@@ -89,7 +89,7 @@ fn connecting_and_muted_indicators_follow_actual_capture() {
strip.state.animations = false;
let (connecting, buffer) = rows(&strip, /*width*/ 45);
assert!(connecting.contains("voice ◌ connecting"));
assert!(!connecting.contains("ctrl+x mute"));
assert!(!connecting.contains("⌃x mute"));
assert_ne!(buffer[(7, 0)].fg, Color::Red);
strip.state.microphone_live = true;
let (_, buffer) = rows(&strip, /*width*/ 45);
@@ -143,7 +143,7 @@ fn voice_controls_follow_configured_mute_binding_and_unbinding() {
let mut layouts = Vec::new();
for (binding, expected) in [
("'f8'", "f8 mute"),
("'ctrl-x m'", "ctrl+x m mute"),
("'ctrl-x m'", "⌃x m mute"),
("[]", "/voice mute"),
] {
let config = toml::from_str(&format!("[chat]\ntoggle_voice_mute = {binding}")).unwrap();
@@ -153,7 +153,7 @@ fn warnings_keep_current_and_next_without_dismissing_unvisited_pages() {
assert!(!key(&mut view, KeyCode::Char('k')));
let screen = draw(&view, /*width*/ 80, /*height*/ 12);
assert!(screen.contains("2 of 3"));
assert!(screen.contains("ctrl+c dismiss & close"));
assert!(screen.contains("⌃c dismiss & close"));
let repeat =
KeyEvent::new_with_kind(KeyCode::Char('k'), KeyModifiers::NONE, KeyEventKind::Repeat);
assert!(!view.handle_key(repeat));

Some files were not shown because too many files have changed in this diff Show More