feat(tui): configurable leader key via keybindings.json#718
Conversation
Add auto-seeded keybindings.json next to config.json for leader prefix and slash-command chords. Reserve Ctrl+N/P for menu nav and Ctrl+G as Esc; move togglePlan default to Ctrl+Y.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughThe change adds persisted, layered ChangesLeader keybindings
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CLI
participant Config
participant TUI
User->>CLI: Start interactive TUI
CLI->>Config: Load user and project keybindings
Config-->>CLI: Resolve layered keybindings
CLI->>TUI: Provide resolved keybindings
User->>TUI: Press leader prefix and chord
TUI->>TUI: Execute mapped slash command
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/config/keybindings_file.go`:
- Around line 126-137: Update the keybindings creation flow around the existing
os.Stat check and writeKeybindingsFile so creation uses an atomic
create-if-absent operation, preventing concurrent processes from overwriting an
existing keybindings file. Preserve the current seed/default behavior, handle an
already-created file as a no-op, and add a test covering concurrent creation.
In `@internal/tui/leader_config.go`:
- Around line 44-53: Update the leader-key resolution flow around
leaderKeyConflictsToggle so the fallback selected after a conflict is not itself
reserved or conflicting with any global toggle. Sanitize the conflicting binding
or choose a genuinely available alternative, ensuring leader dispatch cannot
shadow a configured toggle and the existing notice behavior remains accurate.
In `@internal/tui/leader.go`:
- Around line 74-80: Update matchesLeaderKey to accept control-byte
representations of Ctrl-letter leader keys in addition to the resolved
leaderKey.Matcher() result. Preserve the existing keyCtrl(msg, 'x') fallback for
the built-in leader and ensure custom Ctrl-letter leaders also match when
terminals omit ModCtrl.
In `@internal/tui/model.go`:
- Around line 2804-2805: Update the resolved-leader hint returned by the
surrounding model-rendering method to avoid hardcoded “m model” and “p provider”
commands. Derive the displayed examples from m.leaderCommands so remapped or
unbound commands are reflected, or use a generic hint when no suitable commands
are configured; preserve the existing label and cancel/list guidance.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f0d2807f-df56-4f72-b630-2662b81d7289
📒 Files selected for processing (21)
README.mdinternal/cli/app.gointernal/config/keybindings_file.gointernal/config/keybindings_file_test.gointernal/config/types.gointernal/config/writer.gointernal/tui/binding_test.gointernal/tui/commands.gointernal/tui/input_compat.gointernal/tui/input_compat_test.gointernal/tui/keybinding_help.gointernal/tui/keybinding_help_test.gointernal/tui/keybindings.gointernal/tui/leader.gointernal/tui/leader_config.gointernal/tui/leader_config_test.gointernal/tui/leader_test.gointernal/tui/modal_selection_test.gointernal/tui/model.gointernal/tui/options.gointernal/tui/plan_panel.go
Use O_CREATE|O_EXCL so concurrent EnsureKeybindingsFile races cannot overwrite an existing keybindings file via rename.
When a configured leaderKey is rejected, pick a usable fallback (default Ctrl+X, or free it by clearing a remapped toggle that claimed it) so leader dispatch cannot collide with reserved chords or global toggles.
Show remapped/unbound leader examples from leaderCommands instead of hardcoded m/p shortcuts; keep ? list and Esc cancel guidance.
Some terminals emit Ctrl+letter as a C0 code without ModCtrl; accept that form for the default and custom ctrl-letter leader keys.
Vasanthdev2004
left a comment
There was a problem hiding this comment.
Took a careful look — this is solid, well-built work. go build/vet/gofmt clean, the config suite passes, and the file handling is genuinely careful: keybindings.json is seeded with O_CREATE|O_EXCL so a concurrent process or an existing user file is never overwritten, a missing file loads as empty (no hard fail), a parse error is surfaced instead of silently resetting, and the defaults←user←project overlay handles ""-to-unassign correctly. The leader sanitize path is thorough too — modifier required, reserved-chord and toggle-conflict rejection, deterministic duplicate-letter resolution, and soft-fail-to-default with user-facing notices rather than a startup crash. No correctness blockers from me.
Two things that are really the maintainer's call, not code issues — flagging so they're conscious decisions:
- Contribution gate. This is a ~1,400-line feature from an external contributor with no linked approved issue. It's clearly a continuation of already-merged work (the leader chords from #699) and it's good work, so I'd lean toward welcoming it — but per the contribution process that's kevin's nod to give, not an auto-yes.
- User-visible default change. The plan toggle moves
Ctrl+P→Ctrl+YsoCtrl+P/Ctrl+Ncan become list navigation (andCtrl+Gan Esc synonym). Sensible and conventional, but it does change an existing default and adds a new auto-seeded config file besideconfig.json— both worth a deliberate yes rather than sliding in unnoticed.
One tiny, optional nit: encodeKeybindingsJSON (keybindings_file.go:222-232) manually sorts the leader map "because maps encode in insertion order" — but encoding/json already sorts map keys alphabetically, so that block is redundant (output is identical either way). Harmless; drop it if you're in the file anyway.
Net: on correctness/safety this is ready — careful, tested, and it fails safe. My only holds are the two product/process calls above, which are the maintainer's to make.
Makes the TUI leader prefix and slash-command chords configurable via a sibling
keybindings.jsonfile (notconfig.json), auto-seeded next to config when missing.keybindings.jsonat~/.config/zero/keybindings.json(and project.zero/keybindings.json)config.jsonon write and at TUI start; never overwrites an existing file""leaderKey+leadermap as slash → letter (or""to unassign)leaderKey,/edit, unknown slash, duplicate letters)Reserved chords (hardcoded)
Ctrl+P/Ctrl+NCtrl+GSummary by CodeRabbit
keybindings.json, with support for user and project/workspace overrides.keybindings.jsoninitialization/merging, including seeding sibling keybindings and avoiding overwriting existing edits.