Skip to content

Commit 08eafb9

Browse files
author
SqlRush
committed
Accept keybinding collection aliases
1 parent 77cf38c commit 08eafb9

5 files changed

Lines changed: 92 additions & 2 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ M7 补充:keybinding config 和脚本 named-key 输入现在接受 `backtab`/`
162162

163163
M7 补充:keybinding JSON loader 现在递归解包 `data`/`payload`/`settings`/`config`/`keyboard`/`keymap` 等外层 wrapper,嵌套 preference export 中的 `bindings`/`shortcuts` 不需要手工扁平化。
164164

165+
M7 补充:keybinding JSON loader 现在接受 `keymap`/`keymaps``keyboardShortcuts``hotkeys``userKeybindings``customKeybindings` 等集合字段别名,并同时支持直接 object-map 和嵌套 `bindings` wrapper。
166+
165167
M7 补充:interaction script 的 `keys` 字段现在支持 printable text chunk 和空格分隔 named-key sequence,例如 `ctrl-x ctrl-k`,减少官方脚本把连续输入拆成数组的改写成本。
166168

167169
M7 补充:interaction script key input 现在接受 press-style aliases,包括 `press``keyPress``keypress``shortcutKey``presses``keyPresses``shortcuts`
@@ -494,6 +496,8 @@ M7 补充:prompt history `LogEntry` 读取现在接受 `sessionID`/`session`/`
494496

495497
本轮补充:keybinding JSON loader 现在递归解包 `data`/`payload`/`settings`/`config`/`keyboard`/`keymap` 等外层 wrapper,嵌套 preference export 中的 `bindings`/`shortcuts` 不需要手工扁平化。
496498

499+
本轮补充:keybinding JSON loader 现在接受 `keymap`/`keymaps``keyboardShortcuts``hotkeys``userKeybindings``customKeybindings` 等集合字段别名,并同时支持直接 object-map 和嵌套 `bindings` wrapper。
500+
497501
本轮补充:interaction script 的 `keys` 字段现在支持 printable text chunk 和空格分隔 named-key sequence,例如 `ctrl-x ctrl-k`,减少官方脚本把连续输入拆成数组的改写成本。
498502

499503
本轮补充:interaction script key input 现在接受 press-style aliases,包括 `press``keyPress``keypress``shortcutKey``presses``keyPresses``shortcuts`

docs/claude-code-go-rewrite-plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ test/parity/ # golden tests against TS/official behavior
268268
- 本轮补充:keybinding config 和脚本 named-key 输入接受短修饰符别名,包括 `c-`/`m-`/`a-`/`opt-`/`s-` 以及 compact/camel 形式,可覆盖 control、meta、alt、option 和 shift key names。
269269
- 本轮补充:keybinding config 和脚本 named-key 输入现在接受 `backtab`/`back-tab`/`btab` 等 Shift-Tab terminfo/fixture 别名,并映射到既有 focus-previous key surface。
270270
- 本轮补充:keybinding JSON loader 现在递归解包 `data`/`payload`/`settings`/`config`/`keyboard`/`keymap` 等外层 wrapper,嵌套 preference export 中的 `bindings`/`shortcuts` 不需要手工扁平化。
271+
- 本轮补充:keybinding JSON loader 现在接受 `keymap`/`keymaps``keyboardShortcuts``hotkeys``userKeybindings``customKeybindings` 等集合字段别名,并同时支持直接 object-map 和嵌套 `bindings` wrapper。
271272
- 本轮补充:interaction script 的 `keys` 字段支持 printable text chunk 和空格分隔 named-key sequence,例如 `ctrl-x ctrl-k`,减少官方脚本把连续输入拆成数组的改写成本。
272273
- 本轮补充:interaction script key input 接受 press-style aliases,包括 `press``keyPress``keypress``shortcutKey``presses``keyPresses``shortcuts`
273274
- 本轮补充:interaction script action/type/kind/name/operation 动作判别字段接受 compact/camel fixture aliases,包括 `typeText``inputText``insertText``keyPress``pressKey``keySequence``pasteText``pastedText``clipboardText``setStatus``statusLine``terminalSize``screenSize`

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ M7 progress now includes:
298298
- `internal/tui`: prompt submitted events now retain display text and pasted-content metadata, so downstream runtime code can build text/image content-block messages instead of receiving only the expanded prompt string.
299299
- `internal/tui`: keybinding JSON loading now accepts wrapper object maps, `shortcuts`/`shortcutBindings`, object action fields such as `commandName`/`commandId`, string-array key sequences/chords, and `null`/`false` unbind entries.
300300
- `internal/tui`: keybinding JSON loading now recurses through outer wrappers such as `data`, `payload`, `settings`, `config`, `keyboard`, and `keymap`, so nested official or third-party preference exports can expose `bindings`/`shortcuts` without manual flattening.
301+
- `internal/tui`: keybinding JSON loading now accepts collection aliases such as `keymap`, `keymaps`, `keyboardShortcuts`, `hotkeys`, `userKeybindings`, and `customKeybindings`, including both direct object maps and nested `bindings` wrappers.
301302
- `internal/tui`: mouse parsing now accepts legacy X10/normal tracking `ESC[M...` press/release/wheel sequences in addition to SGR mouse events.
302303
- `internal/tui`: mouse parsing now accepts urxvt/xterm 1015 numeric mouse `CSI button;x;yM` sequences and normalizes button codes to the existing SGR/X10 mouse surface.
303304
- `internal/tui`: interaction scripts now accept structured `mouse`/`mouse_event` steps with expanded button aliases such as `buttonMask`/`btn`/`code`, coordinate aliases such as `mouseX`/`clientX`/`screenX`/`pageX`/`offsetX`/`viewportX` and Y/row/line variants, release aliases such as `mouseUp`/`isRelease`/`mouseRelease`/`releaseEvent`, and dispatch them through the normal screen event path.

internal/tui/keybinding_loader.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,31 @@ func ParseKeyBindingSpecs(data []byte) ([]BindingSpec, error) {
4242
return specs, nil
4343
}
4444

45-
var keyBindingCollectionFields = []string{"bindings", "keybindings", "keyBindings", "keyboardBindings", "keybinding_specs", "keybindingSpecs", "shortcuts", "shortcutBindings"}
45+
var keyBindingCollectionFields = []string{
46+
"bindings",
47+
"keybindings",
48+
"keyBindings",
49+
"keyboardBindings",
50+
"keyboardShortcuts",
51+
"keyboard_shortcuts",
52+
"keybinding_specs",
53+
"keybindingSpecs",
54+
"keymap",
55+
"keyMap",
56+
"keymaps",
57+
"keyMaps",
58+
"shortcuts",
59+
"shortcutBindings",
60+
"hotkeys",
61+
"hotKeys",
62+
"hot_keys",
63+
"userKeybindings",
64+
"userKeyBindings",
65+
"user_keybindings",
66+
"customKeybindings",
67+
"customKeyBindings",
68+
"custom_keybindings",
69+
}
4670

4771
var keyBindingOuterWrapperFields = []string{"data", "payload", "body", "result", "response", "settings", "config", "configuration", "keyboard", "keymap", "preferences", "userPreferences"}
4872

@@ -103,7 +127,11 @@ func parseKeyBindingSpecValue(name string, data json.RawMessage) ([]BindingSpec,
103127
}
104128
return specs, nil
105129
case '{':
106-
specs, err := parseKeyBindingMap(data)
130+
specs, ok, err := parseKeyBindingWrapper(data)
131+
if ok || err != nil {
132+
return specs, err
133+
}
134+
specs, err = parseKeyBindingMap(data)
107135
if err != nil {
108136
return nil, fmt.Errorf("parse %s map: %w", name, err)
109137
}

internal/tui/tui_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,6 +1650,62 @@ func TestParseKeyBindingSpecsAcceptsNestedWrappers(t *testing.T) {
16501650
}
16511651
}
16521652

1653+
func TestParseKeyBindingSpecsAcceptsCollectionAliases(t *testing.T) {
1654+
specs, err := ParseKeyBindingSpecs([]byte(`{
1655+
"keymap": {
1656+
"ctrl-r": "pageDown",
1657+
"ctrl-x ctrl-k": false
1658+
}
1659+
}`))
1660+
if err != nil {
1661+
t.Fatal(err)
1662+
}
1663+
if len(specs) != 2 || specs[0].Key != "ctrl-r" || specs[0].Action != Action("pageDown") || specs[1].Key != "ctrl-x ctrl-k" || specs[1].Action != ActionNone {
1664+
t.Fatalf("keymap specs = %#v", specs)
1665+
}
1666+
keymap, err := KeymapFromSpecs(DefaultKeymap(), specs)
1667+
if err != nil {
1668+
t.Fatal(err)
1669+
}
1670+
if action := keymap.Resolve(ParseKey("\x12")); action != ActionPageDown {
1671+
t.Fatalf("keymap ctrl-r action = %q", action)
1672+
}
1673+
if action := keymap.Resolve(ParseKey("\x18")); action != ActionNone {
1674+
t.Fatalf("keymap ctrl-x prefix action = %q", action)
1675+
}
1676+
if action := keymap.Resolve(ParseKey("\x0b")); action != ActionNone {
1677+
t.Fatalf("keymap ctrl-x ctrl-k action = %q", action)
1678+
}
1679+
1680+
specs, err = ParseKeyBindingSpecs([]byte(`{
1681+
"keymap": {
1682+
"bindings": [
1683+
{"shortcut": "shift-enter", "command": "insertNewline"}
1684+
]
1685+
}
1686+
}`))
1687+
if err != nil {
1688+
t.Fatal(err)
1689+
}
1690+
if len(specs) != 1 || specs[0].Key != "shift-enter" || specs[0].Action != Action("insertNewline") {
1691+
t.Fatalf("wrapped keymap specs = %#v", specs)
1692+
}
1693+
1694+
specs, err = ParseKeyBindingSpecs([]byte(`{
1695+
"preferences": {
1696+
"keyboardShortcuts": {
1697+
"ctrl-w": {"commandName": "deleteWordBackward"}
1698+
}
1699+
}
1700+
}`))
1701+
if err != nil {
1702+
t.Fatal(err)
1703+
}
1704+
if len(specs) != 1 || specs[0].Key != "ctrl-w" || specs[0].Action != Action("deleteWordBackward") {
1705+
t.Fatalf("keyboardShortcuts specs = %#v", specs)
1706+
}
1707+
}
1708+
16531709
func TestParseKeyBindingSpecsAcceptsArrayKeySequences(t *testing.T) {
16541710
specs, err := ParseKeyBindingSpecs([]byte(`[
16551711
{"keys": ["ctrl-x", "ctrl-k"], "command": "pageDown"},

0 commit comments

Comments
 (0)