mirror of
https://github.com/openai/codex.git
synced 2026-05-05 05:42:33 +03:00
feat(tui): add configurable keymap support (#18593)
## Why The TUI currently handles keyboard shortcuts as hard-coded event matches spread across app, composer, pager, list, approval, and navigation code. That makes shortcuts hard to customize, makes displayed hints easy to drift from actual behavior, and makes future keymap work riskier because there is no central action inventory. This PR adds the foundation for configurable, action-based keymaps without adding the interactive remapping UI yet. Onboarding intentionally stays on fixed startup shortcuts because users cannot reasonably configure keymaps before completing onboarding. This is PR1 in the keymap stack: - PR1: #18593: configurable keymap foundation - PR2: #18594: `/keymap` picker and guided remapping UI - PR3: #18595: Vim composer mode and the remap option ## Design Notes The new model resolves named actions into concrete runtime bindings once from config, then passes those bindings to the UI surfaces that handle input or render shortcut hints. The main concepts are: - **Context**: a scope where an action is active, such as `global`, `chat`, `composer`, `editor`, `pager`, `list`, or `approval`. - **Action**: a named operation inside a context, such as `global.open_transcript`, `composer.submit`, or `pager.close`. - **Binding**: one or more single-key shortcuts assigned to an action, written as config strings such as `ctrl-t`, `alt-backspace`, or `page-down`. Multi-step sequences such as `ctrl-x ctrl-s`, `g g`, or leader-key flows are not part of this PR. - **Resolution order**: context-specific config wins first, supported global fallbacks come next, and built-in defaults fill in anything unset. - **Explicit unbinding**: an empty array removes an action binding in that scope and does not fall through to a fallback binding. - **Conflict validation**: a resolved keymap rejects duplicate active bindings inside the same scope so one keypress cannot dispatch two actions. ## What Changed - Added `TuiKeymap` config support under `[tui.keymap]`, including typed contexts/actions, key alias normalization, generated schema coverage, and user-facing config errors. - Added `RuntimeKeymap` resolution in `codex-rs/tui/src/keymap.rs`, including fallback precedence, built-in defaults, explicit unbinding, and per-context conflict validation. - Rewired existing TUI handlers to consume resolved keymap actions instead of directly matching hard-coded keys in each component. - Updated key hint rendering and footer/pager/list surfaces so displayed shortcuts follow the resolved keymap. - Kept onboarding shortcuts fixed in `codex-rs/tui/src/onboarding/keys.rs` instead of exposing them through `[tui.keymap]`. ## Validation The branch includes focused coverage for config parsing, key normalization, runtime fallback resolution, explicit unbinding, duplicate-key conflict validation, default keymap consistency, onboarding startup key behavior, and UI hint snapshots affected by resolved key bindings.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
---
|
||||
source: tui/src/keymap_setup.rs
|
||||
expression: snapshot
|
||||
---
|
||||
unbound:
|
||||
Set key | Capture a key for this unbound action. | enabled
|
||||
Remove custom binding | Restore the default keymap binding. | enabled
|
||||
Back to shortcuts | Return to the shortcut list. | enabled
|
||||
|
||||
single:
|
||||
Replace binding | Capture a replacement key. | enabled
|
||||
Add alternate binding | Keep the current binding and add another key. | enabled
|
||||
Remove custom binding | Restore the default keymap binding. | enabled
|
||||
Back to shortcuts | Return to the shortcut list. | enabled
|
||||
|
||||
multi:
|
||||
Replace one binding... | Choose which existing binding to replace. | enabled
|
||||
Replace all bindings | Replace every current binding with one key. | enabled
|
||||
Add alternate binding | Keep current bindings and add another key. | enabled
|
||||
Remove custom binding | Restore the default keymap binding. | enabled
|
||||
Back to shortcuts | Return to the shortcut list. | enabled
|
||||
|
||||
replace picker:
|
||||
ctrl-enter | Replace this binding. | enabled
|
||||
alt-enter | Replace this binding. | enabled
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
source: tui/src/keymap_setup.rs
|
||||
expression: "format!(\"{:?}\", render_capture(&view, 80, 8))"
|
||||
---
|
||||
Buffer {
|
||||
area: Rect { x: 0, y: 0, width: 80, height: 8 },
|
||||
content: [
|
||||
"Remap Shortcut ",
|
||||
"Action: Submit composer.submit ",
|
||||
"Current: enter ",
|
||||
"Press the new key now. Esc cancels. ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
],
|
||||
styles: [
|
||||
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: BOLD,
|
||||
x: 14, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
|
||||
x: 0, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
|
||||
x: 8, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
|
||||
x: 16, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
|
||||
x: 31, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
|
||||
x: 0, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
|
||||
x: 9, y: 2, fg: Cyan, bg: Reset, underline: Reset, modifier: NONE,
|
||||
x: 14, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
|
||||
x: 0, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
|
||||
x: 35, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
source: tui/src/keymap_setup.rs
|
||||
expression: snapshot
|
||||
---
|
||||
Open Transcript | ctrl-t | Global open_transcript Open Transcript Open the transcript overlay. ctrl-t Default
|
||||
Open External Editor | ctrl-g | Global open_external_editor Open External Editor Open the current draft in an external editor. ctrl-g Default
|
||||
Copy | ctrl-o | Global copy Copy Copy the last agent response to the clipboard. ctrl-o Default
|
||||
Clear Terminal | ctrl-l | Global clear_terminal Clear Terminal Clear the terminal UI. ctrl-l Default
|
||||
Decrease Reasoning Effort | alt-, | Chat decrease_reasoning_effort Decrease Reasoning Effort Decrease reasoning effort. alt-, Default
|
||||
Increase Reasoning Effort | alt-. | Chat increase_reasoning_effort Increase Reasoning Effort Increase reasoning effort. alt-. Default
|
||||
Edit Queued Message | alt-up, shift-left | Chat edit_queued_message Edit Queued Message Edit the most recently queued message. alt-up, shift-left Default
|
||||
Submit | enter | Composer submit Submit Submit the current composer draft. enter Default
|
||||
Queue | tab | Composer queue Queue Queue the draft while a task is running. tab Default
|
||||
Toggle Shortcuts | ?, shift-? | Composer toggle_shortcuts Toggle Shortcuts Show or hide the composer shortcut overlay. ?, shift-? Default
|
||||
History Search Previous | ctrl-r | Composer history_search_previous History Search Previous Open history search or move to the previous match. ctrl-r Default
|
||||
History Search Next | ctrl-s | Composer history_search_next History Search Next Move to the next history search match. ctrl-s Default
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
source: tui/src/keymap_setup.rs
|
||||
expression: "render_picker(params, 120)"
|
||||
---
|
||||
|
||||
Keymap
|
||||
All configurable shortcuts.
|
||||
50 actions, 1 customized, 0 unbound.
|
||||
|
||||
[All] Common Customized (1) Unbound (0) App Composer Editor Navigation Approval
|
||||
|
||||
Type to search shortcuts
|
||||
› Global Open Transcript ctrl-t
|
||||
Global Open External Editor ctrl-g
|
||||
Global Copy ctrl-o
|
||||
Global Clear Terminal ctrl-l
|
||||
Chat Decrease Reasoning Effort alt-,
|
||||
Chat Increase Reasoning Effort alt-.
|
||||
Chat Edit Queued Message alt-up, shift-left
|
||||
Composer * Submit ctrl-enter
|
||||
|
||||
left/right group · enter edit shortcut · * custom · - unbound · esc close
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
source: tui/src/keymap_setup.rs
|
||||
expression: snapshot
|
||||
---
|
||||
tab: All (50 selectable)
|
||||
tab: Common (18 selectable)
|
||||
tab: Customized (0) (0 selectable)
|
||||
tab: Unbound (0) (0 selectable)
|
||||
tab: App (7 selectable)
|
||||
tab: Composer (5 selectable)
|
||||
tab: Editor (16 selectable)
|
||||
tab: Navigation (14 selectable)
|
||||
tab: Approval (8 selectable)
|
||||
Open Transcript | ctrl-t | Global open_transcript Open Transcript Open the transcript overlay. ctrl-t Default
|
||||
Open External Editor | ctrl-g | Global open_external_editor Open External Editor Open the current draft in an external editor. ctrl-g Default
|
||||
Copy | ctrl-o | Global copy Copy Copy the last agent response to the clipboard. ctrl-o Default
|
||||
Clear Terminal | ctrl-l | Global clear_terminal Clear Terminal Clear the terminal UI. ctrl-l Default
|
||||
Decrease Reasoning Effort | alt-, | Chat decrease_reasoning_effort Decrease Reasoning Effort Decrease reasoning effort. alt-, Default
|
||||
Increase Reasoning Effort | alt-. | Chat increase_reasoning_effort Increase Reasoning Effort Increase reasoning effort. alt-. Default
|
||||
Edit Queued Message | alt-up, shift-left | Chat edit_queued_message Edit Queued Message Edit the most recently queued message. alt-up, shift-left Default
|
||||
Submit | enter | Composer submit Submit Submit the current composer draft. enter Default
|
||||
Queue | tab | Composer queue Queue Queue the draft while a task is running. tab Default
|
||||
Toggle Shortcuts | ?, shift-? | Composer toggle_shortcuts Toggle Shortcuts Show or hide the composer shortcut overlay. ?, shift-? Default
|
||||
History Search Previous | ctrl-r | Composer history_search_previous History Search Previous Open history search or move to the previous match. ctrl-r Default
|
||||
History Search Next | ctrl-s | Composer history_search_next History Search Next Move to the next history search match. ctrl-s Default
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
source: tui/src/keymap_setup.rs
|
||||
expression: "render_picker(params, 78)"
|
||||
---
|
||||
|
||||
Keymap
|
||||
All configurable shortcuts.
|
||||
50 actions, 0 customized, 0 unbound.
|
||||
|
||||
[All] Common Customized (0) Unbound (0) App Composer Editor
|
||||
Navigation Approval
|
||||
|
||||
Type to search shortcuts
|
||||
› Global Open Transcript ctrl-t
|
||||
Global Open External Editor ctrl-g
|
||||
Global Copy ctrl-o
|
||||
Global Clear Terminal ctrl-l
|
||||
Chat Decrease Reasoning Effort alt-,
|
||||
Chat Increase Reasoning Effort alt-.
|
||||
Chat Edit Queued Message alt-up, shift-left
|
||||
Composer Submit enter
|
||||
|
||||
left/right group · enter edit shortcut · * custom · - unbound · esc close
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
source: tui/src/keymap_setup.rs
|
||||
expression: "render_picker(params, 120)"
|
||||
---
|
||||
|
||||
Keymap
|
||||
All configurable shortcuts.
|
||||
50 actions, 0 customized, 0 unbound.
|
||||
|
||||
[All] Common Customized (0) Unbound (0) App Composer Editor Navigation Approval
|
||||
|
||||
Type to search shortcuts
|
||||
› Global Open Transcript ctrl-t
|
||||
Global Open External Editor ctrl-g
|
||||
Global Copy ctrl-o
|
||||
Global Clear Terminal ctrl-l
|
||||
Chat Decrease Reasoning Effort alt-,
|
||||
Chat Increase Reasoning Effort alt-.
|
||||
Chat Edit Queued Message alt-up, shift-left
|
||||
Composer Submit enter
|
||||
|
||||
left/right group · enter edit shortcut · * custom · - unbound · esc close
|
||||
Reference in New Issue
Block a user