@draht/tui 2026.3.14 → 2026.3.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/autocomplete.d.ts.map +1 -1
  2. package/dist/autocomplete.js +49 -10
  3. package/dist/autocomplete.js.map +1 -1
  4. package/dist/components/cancellable-loader.d.ts.map +1 -1
  5. package/dist/components/cancellable-loader.js +3 -3
  6. package/dist/components/cancellable-loader.js.map +1 -1
  7. package/dist/components/editor.d.ts +9 -1
  8. package/dist/components/editor.d.ts.map +1 -1
  9. package/dist/components/editor.js +200 -71
  10. package/dist/components/editor.js.map +1 -1
  11. package/dist/components/input.d.ts.map +1 -1
  12. package/dist/components/input.js +19 -19
  13. package/dist/components/input.js.map +1 -1
  14. package/dist/components/markdown.d.ts.map +1 -1
  15. package/dist/components/markdown.js +25 -16
  16. package/dist/components/markdown.js.map +1 -1
  17. package/dist/components/select-list.d.ts +19 -1
  18. package/dist/components/select-list.d.ts.map +1 -1
  19. package/dist/components/select-list.js +74 -67
  20. package/dist/components/select-list.js.map +1 -1
  21. package/dist/components/settings-list.d.ts.map +1 -1
  22. package/dist/components/settings-list.js +6 -6
  23. package/dist/components/settings-list.js.map +1 -1
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/keybindings.d.ts +187 -33
  29. package/dist/keybindings.d.ts.map +1 -1
  30. package/dist/keybindings.js +156 -99
  31. package/dist/keybindings.js.map +1 -1
  32. package/dist/keys.d.ts.map +1 -1
  33. package/dist/keys.js +46 -7
  34. package/dist/keys.js.map +1 -1
  35. package/dist/terminal.d.ts.map +1 -1
  36. package/dist/terminal.js +17 -1
  37. package/dist/terminal.js.map +1 -1
  38. package/dist/tui.d.ts.map +1 -1
  39. package/dist/tui.js +15 -4
  40. package/dist/tui.js.map +1 -1
  41. package/dist/utils.d.ts.map +1 -1
  42. package/dist/utils.js +201 -56
  43. package/dist/utils.js.map +1 -1
  44. package/package.json +1 -1
@@ -1,39 +1,193 @@
1
1
  import { type KeyId } from "./keys.js";
2
2
  /**
3
- * Editor actions that can be bound to keys.
3
+ * Global keybinding registry.
4
+ * Downstream packages can add keybindings via declaration merging.
4
5
  */
5
- export type EditorAction = "cursorUp" | "cursorDown" | "cursorLeft" | "cursorRight" | "cursorWordLeft" | "cursorWordRight" | "cursorLineStart" | "cursorLineEnd" | "jumpForward" | "jumpBackward" | "pageUp" | "pageDown" | "deleteCharBackward" | "deleteCharForward" | "deleteWordBackward" | "deleteWordForward" | "deleteToLineStart" | "deleteToLineEnd" | "newLine" | "submit" | "tab" | "selectUp" | "selectDown" | "selectPageUp" | "selectPageDown" | "selectConfirm" | "selectCancel" | "copy" | "yank" | "yankPop" | "undo" | "expandTools" | "treeFoldOrUp" | "treeUnfoldOrDown" | "toggleSessionPath" | "toggleSessionSort" | "renameSession" | "deleteSession" | "deleteSessionNoninvasive";
6
- export type { KeyId };
7
- /**
8
- * Editor keybindings configuration.
9
- */
10
- export type EditorKeybindingsConfig = {
11
- [K in EditorAction]?: KeyId | KeyId[];
6
+ export interface Keybindings {
7
+ "tui.editor.cursorUp": true;
8
+ "tui.editor.cursorDown": true;
9
+ "tui.editor.cursorLeft": true;
10
+ "tui.editor.cursorRight": true;
11
+ "tui.editor.cursorWordLeft": true;
12
+ "tui.editor.cursorWordRight": true;
13
+ "tui.editor.cursorLineStart": true;
14
+ "tui.editor.cursorLineEnd": true;
15
+ "tui.editor.jumpForward": true;
16
+ "tui.editor.jumpBackward": true;
17
+ "tui.editor.pageUp": true;
18
+ "tui.editor.pageDown": true;
19
+ "tui.editor.deleteCharBackward": true;
20
+ "tui.editor.deleteCharForward": true;
21
+ "tui.editor.deleteWordBackward": true;
22
+ "tui.editor.deleteWordForward": true;
23
+ "tui.editor.deleteToLineStart": true;
24
+ "tui.editor.deleteToLineEnd": true;
25
+ "tui.editor.yank": true;
26
+ "tui.editor.yankPop": true;
27
+ "tui.editor.undo": true;
28
+ "tui.input.newLine": true;
29
+ "tui.input.submit": true;
30
+ "tui.input.tab": true;
31
+ "tui.input.copy": true;
32
+ "tui.select.up": true;
33
+ "tui.select.down": true;
34
+ "tui.select.pageUp": true;
35
+ "tui.select.pageDown": true;
36
+ "tui.select.confirm": true;
37
+ "tui.select.cancel": true;
38
+ }
39
+ export type Keybinding = keyof Keybindings;
40
+ export interface KeybindingDefinition {
41
+ defaultKeys: KeyId | KeyId[];
42
+ description?: string;
43
+ }
44
+ export type KeybindingDefinitions = Record<string, KeybindingDefinition>;
45
+ export type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;
46
+ export declare const TUI_KEYBINDINGS: {
47
+ readonly "tui.editor.cursorUp": {
48
+ readonly defaultKeys: "up";
49
+ readonly description: "Move cursor up";
50
+ };
51
+ readonly "tui.editor.cursorDown": {
52
+ readonly defaultKeys: "down";
53
+ readonly description: "Move cursor down";
54
+ };
55
+ readonly "tui.editor.cursorLeft": {
56
+ readonly defaultKeys: ["left", "ctrl+b"];
57
+ readonly description: "Move cursor left";
58
+ };
59
+ readonly "tui.editor.cursorRight": {
60
+ readonly defaultKeys: ["right", "ctrl+f"];
61
+ readonly description: "Move cursor right";
62
+ };
63
+ readonly "tui.editor.cursorWordLeft": {
64
+ readonly defaultKeys: ["alt+left", "ctrl+left", "alt+b"];
65
+ readonly description: "Move cursor word left";
66
+ };
67
+ readonly "tui.editor.cursorWordRight": {
68
+ readonly defaultKeys: ["alt+right", "ctrl+right", "alt+f"];
69
+ readonly description: "Move cursor word right";
70
+ };
71
+ readonly "tui.editor.cursorLineStart": {
72
+ readonly defaultKeys: ["home", "ctrl+a"];
73
+ readonly description: "Move to line start";
74
+ };
75
+ readonly "tui.editor.cursorLineEnd": {
76
+ readonly defaultKeys: ["end", "ctrl+e"];
77
+ readonly description: "Move to line end";
78
+ };
79
+ readonly "tui.editor.jumpForward": {
80
+ readonly defaultKeys: "ctrl+]";
81
+ readonly description: "Jump forward to character";
82
+ };
83
+ readonly "tui.editor.jumpBackward": {
84
+ readonly defaultKeys: "ctrl+alt+]";
85
+ readonly description: "Jump backward to character";
86
+ };
87
+ readonly "tui.editor.pageUp": {
88
+ readonly defaultKeys: "pageUp";
89
+ readonly description: "Page up";
90
+ };
91
+ readonly "tui.editor.pageDown": {
92
+ readonly defaultKeys: "pageDown";
93
+ readonly description: "Page down";
94
+ };
95
+ readonly "tui.editor.deleteCharBackward": {
96
+ readonly defaultKeys: "backspace";
97
+ readonly description: "Delete character backward";
98
+ };
99
+ readonly "tui.editor.deleteCharForward": {
100
+ readonly defaultKeys: ["delete", "ctrl+d"];
101
+ readonly description: "Delete character forward";
102
+ };
103
+ readonly "tui.editor.deleteWordBackward": {
104
+ readonly defaultKeys: ["ctrl+w", "alt+backspace"];
105
+ readonly description: "Delete word backward";
106
+ };
107
+ readonly "tui.editor.deleteWordForward": {
108
+ readonly defaultKeys: ["alt+d", "alt+delete"];
109
+ readonly description: "Delete word forward";
110
+ };
111
+ readonly "tui.editor.deleteToLineStart": {
112
+ readonly defaultKeys: "ctrl+u";
113
+ readonly description: "Delete to line start";
114
+ };
115
+ readonly "tui.editor.deleteToLineEnd": {
116
+ readonly defaultKeys: "ctrl+k";
117
+ readonly description: "Delete to line end";
118
+ };
119
+ readonly "tui.editor.yank": {
120
+ readonly defaultKeys: "ctrl+y";
121
+ readonly description: "Yank";
122
+ };
123
+ readonly "tui.editor.yankPop": {
124
+ readonly defaultKeys: "alt+y";
125
+ readonly description: "Yank pop";
126
+ };
127
+ readonly "tui.editor.undo": {
128
+ readonly defaultKeys: "ctrl+-";
129
+ readonly description: "Undo";
130
+ };
131
+ readonly "tui.input.newLine": {
132
+ readonly defaultKeys: "shift+enter";
133
+ readonly description: "Insert newline";
134
+ };
135
+ readonly "tui.input.submit": {
136
+ readonly defaultKeys: "enter";
137
+ readonly description: "Submit input";
138
+ };
139
+ readonly "tui.input.tab": {
140
+ readonly defaultKeys: "tab";
141
+ readonly description: "Tab / autocomplete";
142
+ };
143
+ readonly "tui.input.copy": {
144
+ readonly defaultKeys: "ctrl+c";
145
+ readonly description: "Copy selection";
146
+ };
147
+ readonly "tui.select.up": {
148
+ readonly defaultKeys: "up";
149
+ readonly description: "Move selection up";
150
+ };
151
+ readonly "tui.select.down": {
152
+ readonly defaultKeys: "down";
153
+ readonly description: "Move selection down";
154
+ };
155
+ readonly "tui.select.pageUp": {
156
+ readonly defaultKeys: "pageUp";
157
+ readonly description: "Selection page up";
158
+ };
159
+ readonly "tui.select.pageDown": {
160
+ readonly defaultKeys: "pageDown";
161
+ readonly description: "Selection page down";
162
+ };
163
+ readonly "tui.select.confirm": {
164
+ readonly defaultKeys: "enter";
165
+ readonly description: "Confirm selection";
166
+ };
167
+ readonly "tui.select.cancel": {
168
+ readonly defaultKeys: ["escape", "ctrl+c"];
169
+ readonly description: "Cancel selection";
170
+ };
12
171
  };
13
- /**
14
- * Default editor keybindings.
15
- */
16
- export declare const DEFAULT_EDITOR_KEYBINDINGS: Required<EditorKeybindingsConfig>;
17
- /**
18
- * Manages keybindings for the editor.
19
- */
20
- export declare class EditorKeybindingsManager {
21
- private actionToKeys;
22
- constructor(config?: EditorKeybindingsConfig);
23
- private buildMaps;
24
- /**
25
- * Check if input matches a specific action.
26
- */
27
- matches(data: string, action: EditorAction): boolean;
28
- /**
29
- * Get keys bound to an action.
30
- */
31
- getKeys(action: EditorAction): KeyId[];
32
- /**
33
- * Update configuration.
34
- */
35
- setConfig(config: EditorKeybindingsConfig): void;
172
+ export interface KeybindingConflict {
173
+ key: KeyId;
174
+ keybindings: string[];
175
+ }
176
+ export declare class KeybindingsManager {
177
+ private definitions;
178
+ private userBindings;
179
+ private keysById;
180
+ private conflicts;
181
+ constructor(definitions: KeybindingDefinitions, userBindings?: KeybindingsConfig);
182
+ private rebuild;
183
+ matches(data: string, keybinding: Keybinding): boolean;
184
+ getKeys(keybinding: Keybinding): KeyId[];
185
+ getDefinition(keybinding: Keybinding): KeybindingDefinition;
186
+ getConflicts(): KeybindingConflict[];
187
+ setUserBindings(userBindings: KeybindingsConfig): void;
188
+ getUserBindings(): KeybindingsConfig;
189
+ getResolvedBindings(): KeybindingsConfig;
36
190
  }
37
- export declare function getEditorKeybindings(): EditorKeybindingsManager;
38
- export declare function setEditorKeybindings(manager: EditorKeybindingsManager): void;
191
+ export declare function setKeybindings(keybindings: KeybindingsManager): void;
192
+ export declare function getKeybindings(): KeybindingsManager;
39
193
  //# sourceMappingURL=keybindings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAc,MAAM,WAAW,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,YAAY,GAErB,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,eAAe,GACf,aAAa,GACb,cAAc,GACd,QAAQ,GACR,UAAU,GAEV,oBAAoB,GACpB,mBAAmB,GACnB,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GAEjB,SAAS,GACT,QAAQ,GACR,KAAK,GAEL,UAAU,GACV,YAAY,GACZ,cAAc,GACd,gBAAgB,GAChB,eAAe,GACf,cAAc,GAEd,MAAM,GAEN,MAAM,GACN,SAAS,GAET,MAAM,GAEN,aAAa,GAEb,cAAc,GACd,kBAAkB,GAElB,mBAAmB,GACnB,mBAAmB,GACnB,eAAe,GACf,eAAe,GACf,0BAA0B,CAAC;AAG9B,YAAY,EAAE,KAAK,EAAE,CAAC;AAEtB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;KACpC,CAAC,IAAI,YAAY,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE;CACrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,uBAAuB,CAkDxE,CAAC;AAEF;;GAEG;AACH,qBAAa,wBAAwB;IACpC,OAAO,CAAC,YAAY,CAA6B;IAEjD,YAAY,MAAM,GAAE,uBAA4B,EAG/C;IAED,OAAO,CAAC,SAAS;IAiBjB;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAOnD;IAED;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,CAErC;IAED;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,CAE/C;CACD;AAKD,wBAAgB,oBAAoB,IAAI,wBAAwB,CAK/D;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAE5E","sourcesContent":["import { type KeyId, matchesKey } from \"./keys.js\";\n\n/**\n * Editor actions that can be bound to keys.\n */\nexport type EditorAction =\n\t// Cursor movement\n\t| \"cursorUp\"\n\t| \"cursorDown\"\n\t| \"cursorLeft\"\n\t| \"cursorRight\"\n\t| \"cursorWordLeft\"\n\t| \"cursorWordRight\"\n\t| \"cursorLineStart\"\n\t| \"cursorLineEnd\"\n\t| \"jumpForward\"\n\t| \"jumpBackward\"\n\t| \"pageUp\"\n\t| \"pageDown\"\n\t// Deletion\n\t| \"deleteCharBackward\"\n\t| \"deleteCharForward\"\n\t| \"deleteWordBackward\"\n\t| \"deleteWordForward\"\n\t| \"deleteToLineStart\"\n\t| \"deleteToLineEnd\"\n\t// Text input\n\t| \"newLine\"\n\t| \"submit\"\n\t| \"tab\"\n\t// Selection/autocomplete\n\t| \"selectUp\"\n\t| \"selectDown\"\n\t| \"selectPageUp\"\n\t| \"selectPageDown\"\n\t| \"selectConfirm\"\n\t| \"selectCancel\"\n\t// Clipboard\n\t| \"copy\"\n\t// Kill ring\n\t| \"yank\"\n\t| \"yankPop\"\n\t// Undo\n\t| \"undo\"\n\t// Tool output\n\t| \"expandTools\"\n\t// Tree navigation\n\t| \"treeFoldOrUp\"\n\t| \"treeUnfoldOrDown\"\n\t// Session\n\t| \"toggleSessionPath\"\n\t| \"toggleSessionSort\"\n\t| \"renameSession\"\n\t| \"deleteSession\"\n\t| \"deleteSessionNoninvasive\";\n\n// Re-export KeyId from keys.ts\nexport type { KeyId };\n\n/**\n * Editor keybindings configuration.\n */\nexport type EditorKeybindingsConfig = {\n\t[K in EditorAction]?: KeyId | KeyId[];\n};\n\n/**\n * Default editor keybindings.\n */\nexport const DEFAULT_EDITOR_KEYBINDINGS: Required<EditorKeybindingsConfig> = {\n\t// Cursor movement\n\tcursorUp: \"up\",\n\tcursorDown: \"down\",\n\tcursorLeft: [\"left\", \"ctrl+b\"],\n\tcursorRight: [\"right\", \"ctrl+f\"],\n\tcursorWordLeft: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n\tcursorWordRight: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n\tcursorLineStart: [\"home\", \"ctrl+a\"],\n\tcursorLineEnd: [\"end\", \"ctrl+e\"],\n\tjumpForward: \"ctrl+]\",\n\tjumpBackward: \"ctrl+alt+]\",\n\tpageUp: \"pageUp\",\n\tpageDown: \"pageDown\",\n\t// Deletion\n\tdeleteCharBackward: \"backspace\",\n\tdeleteCharForward: [\"delete\", \"ctrl+d\"],\n\tdeleteWordBackward: [\"ctrl+w\", \"alt+backspace\"],\n\tdeleteWordForward: [\"alt+d\", \"alt+delete\"],\n\tdeleteToLineStart: \"ctrl+u\",\n\tdeleteToLineEnd: \"ctrl+k\",\n\t// Text input\n\tnewLine: \"shift+enter\",\n\tsubmit: \"enter\",\n\ttab: \"tab\",\n\t// Selection/autocomplete\n\tselectUp: \"up\",\n\tselectDown: \"down\",\n\tselectPageUp: \"pageUp\",\n\tselectPageDown: \"pageDown\",\n\tselectConfirm: \"enter\",\n\tselectCancel: [\"escape\", \"ctrl+c\"],\n\t// Clipboard\n\tcopy: \"ctrl+c\",\n\t// Kill ring\n\tyank: \"ctrl+y\",\n\tyankPop: \"alt+y\",\n\t// Undo\n\tundo: \"ctrl+-\",\n\t// Tool output\n\texpandTools: \"ctrl+o\",\n\t// Tree navigation\n\ttreeFoldOrUp: [\"ctrl+left\", \"alt+left\"],\n\ttreeUnfoldOrDown: [\"ctrl+right\", \"alt+right\"],\n\t// Session\n\ttoggleSessionPath: \"ctrl+p\",\n\ttoggleSessionSort: \"ctrl+s\",\n\trenameSession: \"ctrl+r\",\n\tdeleteSession: \"ctrl+d\",\n\tdeleteSessionNoninvasive: \"ctrl+backspace\",\n};\n\n/**\n * Manages keybindings for the editor.\n */\nexport class EditorKeybindingsManager {\n\tprivate actionToKeys: Map<EditorAction, KeyId[]>;\n\n\tconstructor(config: EditorKeybindingsConfig = {}) {\n\t\tthis.actionToKeys = new Map();\n\t\tthis.buildMaps(config);\n\t}\n\n\tprivate buildMaps(config: EditorKeybindingsConfig): void {\n\t\tthis.actionToKeys.clear();\n\n\t\t// Start with defaults\n\t\tfor (const [action, keys] of Object.entries(DEFAULT_EDITOR_KEYBINDINGS)) {\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.actionToKeys.set(action as EditorAction, [...keyArray]);\n\t\t}\n\n\t\t// Override with user config\n\t\tfor (const [action, keys] of Object.entries(config)) {\n\t\t\tif (keys === undefined) continue;\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.actionToKeys.set(action as EditorAction, keyArray);\n\t\t}\n\t}\n\n\t/**\n\t * Check if input matches a specific action.\n\t */\n\tmatches(data: string, action: EditorAction): boolean {\n\t\tconst keys = this.actionToKeys.get(action);\n\t\tif (!keys) return false;\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Get keys bound to an action.\n\t */\n\tgetKeys(action: EditorAction): KeyId[] {\n\t\treturn this.actionToKeys.get(action) ?? [];\n\t}\n\n\t/**\n\t * Update configuration.\n\t */\n\tsetConfig(config: EditorKeybindingsConfig): void {\n\t\tthis.buildMaps(config);\n\t}\n}\n\n// Global instance\nlet globalEditorKeybindings: EditorKeybindingsManager | null = null;\n\nexport function getEditorKeybindings(): EditorKeybindingsManager {\n\tif (!globalEditorKeybindings) {\n\t\tglobalEditorKeybindings = new EditorKeybindingsManager();\n\t}\n\treturn globalEditorKeybindings;\n}\n\nexport function setEditorKeybindings(manager: EditorKeybindingsManager): void {\n\tglobalEditorKeybindings = manager;\n}\n"]}
1
+ {"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { type KeyId, matchesKey } from \"./keys.js\";\n\n/**\n * Global keybinding registry.\n * Downstream packages can add keybindings via declaration merging.\n */\nexport interface Keybindings {\n\t// Editor navigation and editing\n\t\"tui.editor.cursorUp\": true;\n\t\"tui.editor.cursorDown\": true;\n\t\"tui.editor.cursorLeft\": true;\n\t\"tui.editor.cursorRight\": true;\n\t\"tui.editor.cursorWordLeft\": true;\n\t\"tui.editor.cursorWordRight\": true;\n\t\"tui.editor.cursorLineStart\": true;\n\t\"tui.editor.cursorLineEnd\": true;\n\t\"tui.editor.jumpForward\": true;\n\t\"tui.editor.jumpBackward\": true;\n\t\"tui.editor.pageUp\": true;\n\t\"tui.editor.pageDown\": true;\n\t\"tui.editor.deleteCharBackward\": true;\n\t\"tui.editor.deleteCharForward\": true;\n\t\"tui.editor.deleteWordBackward\": true;\n\t\"tui.editor.deleteWordForward\": true;\n\t\"tui.editor.deleteToLineStart\": true;\n\t\"tui.editor.deleteToLineEnd\": true;\n\t\"tui.editor.yank\": true;\n\t\"tui.editor.yankPop\": true;\n\t\"tui.editor.undo\": true;\n\t// Generic input actions\n\t\"tui.input.newLine\": true;\n\t\"tui.input.submit\": true;\n\t\"tui.input.tab\": true;\n\t\"tui.input.copy\": true;\n\t// Generic selection actions\n\t\"tui.select.up\": true;\n\t\"tui.select.down\": true;\n\t\"tui.select.pageUp\": true;\n\t\"tui.select.pageDown\": true;\n\t\"tui.select.confirm\": true;\n\t\"tui.select.cancel\": true;\n}\n\nexport type Keybinding = keyof Keybindings;\n\nexport interface KeybindingDefinition {\n\tdefaultKeys: KeyId | KeyId[];\n\tdescription?: string;\n}\n\nexport type KeybindingDefinitions = Record<string, KeybindingDefinition>;\nexport type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;\n\nexport const TUI_KEYBINDINGS = {\n\t\"tui.editor.cursorUp\": { defaultKeys: \"up\", description: \"Move cursor up\" },\n\t\"tui.editor.cursorDown\": { defaultKeys: \"down\", description: \"Move cursor down\" },\n\t\"tui.editor.cursorLeft\": {\n\t\tdefaultKeys: [\"left\", \"ctrl+b\"],\n\t\tdescription: \"Move cursor left\",\n\t},\n\t\"tui.editor.cursorRight\": {\n\t\tdefaultKeys: [\"right\", \"ctrl+f\"],\n\t\tdescription: \"Move cursor right\",\n\t},\n\t\"tui.editor.cursorWordLeft\": {\n\t\tdefaultKeys: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n\t\tdescription: \"Move cursor word left\",\n\t},\n\t\"tui.editor.cursorWordRight\": {\n\t\tdefaultKeys: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n\t\tdescription: \"Move cursor word right\",\n\t},\n\t\"tui.editor.cursorLineStart\": {\n\t\tdefaultKeys: [\"home\", \"ctrl+a\"],\n\t\tdescription: \"Move to line start\",\n\t},\n\t\"tui.editor.cursorLineEnd\": {\n\t\tdefaultKeys: [\"end\", \"ctrl+e\"],\n\t\tdescription: \"Move to line end\",\n\t},\n\t\"tui.editor.jumpForward\": {\n\t\tdefaultKeys: \"ctrl+]\",\n\t\tdescription: \"Jump forward to character\",\n\t},\n\t\"tui.editor.jumpBackward\": {\n\t\tdefaultKeys: \"ctrl+alt+]\",\n\t\tdescription: \"Jump backward to character\",\n\t},\n\t\"tui.editor.pageUp\": { defaultKeys: \"pageUp\", description: \"Page up\" },\n\t\"tui.editor.pageDown\": { defaultKeys: \"pageDown\", description: \"Page down\" },\n\t\"tui.editor.deleteCharBackward\": {\n\t\tdefaultKeys: \"backspace\",\n\t\tdescription: \"Delete character backward\",\n\t},\n\t\"tui.editor.deleteCharForward\": {\n\t\tdefaultKeys: [\"delete\", \"ctrl+d\"],\n\t\tdescription: \"Delete character forward\",\n\t},\n\t\"tui.editor.deleteWordBackward\": {\n\t\tdefaultKeys: [\"ctrl+w\", \"alt+backspace\"],\n\t\tdescription: \"Delete word backward\",\n\t},\n\t\"tui.editor.deleteWordForward\": {\n\t\tdefaultKeys: [\"alt+d\", \"alt+delete\"],\n\t\tdescription: \"Delete word forward\",\n\t},\n\t\"tui.editor.deleteToLineStart\": {\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Delete to line start\",\n\t},\n\t\"tui.editor.deleteToLineEnd\": {\n\t\tdefaultKeys: \"ctrl+k\",\n\t\tdescription: \"Delete to line end\",\n\t},\n\t\"tui.editor.yank\": { defaultKeys: \"ctrl+y\", description: \"Yank\" },\n\t\"tui.editor.yankPop\": { defaultKeys: \"alt+y\", description: \"Yank pop\" },\n\t\"tui.editor.undo\": { defaultKeys: \"ctrl+-\", description: \"Undo\" },\n\t\"tui.input.newLine\": { defaultKeys: \"shift+enter\", description: \"Insert newline\" },\n\t\"tui.input.submit\": { defaultKeys: \"enter\", description: \"Submit input\" },\n\t\"tui.input.tab\": { defaultKeys: \"tab\", description: \"Tab / autocomplete\" },\n\t\"tui.input.copy\": { defaultKeys: \"ctrl+c\", description: \"Copy selection\" },\n\t\"tui.select.up\": { defaultKeys: \"up\", description: \"Move selection up\" },\n\t\"tui.select.down\": { defaultKeys: \"down\", description: \"Move selection down\" },\n\t\"tui.select.pageUp\": { defaultKeys: \"pageUp\", description: \"Selection page up\" },\n\t\"tui.select.pageDown\": {\n\t\tdefaultKeys: \"pageDown\",\n\t\tdescription: \"Selection page down\",\n\t},\n\t\"tui.select.confirm\": { defaultKeys: \"enter\", description: \"Confirm selection\" },\n\t\"tui.select.cancel\": {\n\t\tdefaultKeys: [\"escape\", \"ctrl+c\"],\n\t\tdescription: \"Cancel selection\",\n\t},\n} as const satisfies KeybindingDefinitions;\n\nexport interface KeybindingConflict {\n\tkey: KeyId;\n\tkeybindings: string[];\n}\n\nfunction normalizeKeys(keys: KeyId | KeyId[] | undefined): KeyId[] {\n\tif (keys === undefined) return [];\n\tconst keyList = Array.isArray(keys) ? keys : [keys];\n\tconst seen = new Set<KeyId>();\n\tconst result: KeyId[] = [];\n\tfor (const key of keyList) {\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n\nexport class KeybindingsManager {\n\tprivate definitions: KeybindingDefinitions;\n\tprivate userBindings: KeybindingsConfig;\n\tprivate keysById = new Map<Keybinding, KeyId[]>();\n\tprivate conflicts: KeybindingConflict[] = [];\n\n\tconstructor(definitions: KeybindingDefinitions, userBindings: KeybindingsConfig = {}) {\n\t\tthis.definitions = definitions;\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.keysById.clear();\n\t\tthis.conflicts = [];\n\n\t\tconst userClaims = new Map<KeyId, Set<Keybinding>>();\n\t\tfor (const [keybinding, keys] of Object.entries(this.userBindings)) {\n\t\t\tif (!(keybinding in this.definitions)) continue;\n\t\t\tfor (const key of normalizeKeys(keys)) {\n\t\t\t\tconst claimants = userClaims.get(key) ?? new Set<Keybinding>();\n\t\t\t\tclaimants.add(keybinding as Keybinding);\n\t\t\t\tuserClaims.set(key, claimants);\n\t\t\t}\n\t\t}\n\n\t\tfor (const [key, keybindings] of userClaims) {\n\t\t\tif (keybindings.size > 1) {\n\t\t\t\tthis.conflicts.push({ key, keybindings: [...keybindings] });\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, definition] of Object.entries(this.definitions)) {\n\t\t\tconst userKeys = this.userBindings[id];\n\t\t\tconst keys = userKeys === undefined ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);\n\t\t\tthis.keysById.set(id as Keybinding, keys);\n\t\t}\n\t}\n\n\tmatches(data: string, keybinding: Keybinding): boolean {\n\t\tconst keys = this.keysById.get(keybinding) ?? [];\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetKeys(keybinding: Keybinding): KeyId[] {\n\t\treturn [...(this.keysById.get(keybinding) ?? [])];\n\t}\n\n\tgetDefinition(keybinding: Keybinding): KeybindingDefinition {\n\t\treturn this.definitions[keybinding];\n\t}\n\n\tgetConflicts(): KeybindingConflict[] {\n\t\treturn this.conflicts.map((conflict) => ({ ...conflict, keybindings: [...conflict.keybindings] }));\n\t}\n\n\tsetUserBindings(userBindings: KeybindingsConfig): void {\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tgetUserBindings(): KeybindingsConfig {\n\t\treturn { ...this.userBindings };\n\t}\n\n\tgetResolvedBindings(): KeybindingsConfig {\n\t\tconst resolved: KeybindingsConfig = {};\n\t\tfor (const id of Object.keys(this.definitions)) {\n\t\t\tconst keys = this.keysById.get(id as Keybinding) ?? [];\n\t\t\tresolved[id] = keys.length === 1 ? keys[0]! : [...keys];\n\t\t}\n\t\treturn resolved;\n\t}\n}\n\nlet globalKeybindings: KeybindingsManager | null = null;\n\nexport function setKeybindings(keybindings: KeybindingsManager): void {\n\tglobalKeybindings = keybindings;\n}\n\nexport function getKeybindings(): KeybindingsManager {\n\tif (!globalKeybindings) {\n\t\tglobalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);\n\t}\n\treturn globalKeybindings;\n}\n"]}
@@ -1,117 +1,174 @@
1
1
  import { matchesKey } from "./keys.js";
2
- /**
3
- * Default editor keybindings.
4
- */
5
- export const DEFAULT_EDITOR_KEYBINDINGS = {
6
- // Cursor movement
7
- cursorUp: "up",
8
- cursorDown: "down",
9
- cursorLeft: ["left", "ctrl+b"],
10
- cursorRight: ["right", "ctrl+f"],
11
- cursorWordLeft: ["alt+left", "ctrl+left", "alt+b"],
12
- cursorWordRight: ["alt+right", "ctrl+right", "alt+f"],
13
- cursorLineStart: ["home", "ctrl+a"],
14
- cursorLineEnd: ["end", "ctrl+e"],
15
- jumpForward: "ctrl+]",
16
- jumpBackward: "ctrl+alt+]",
17
- pageUp: "pageUp",
18
- pageDown: "pageDown",
19
- // Deletion
20
- deleteCharBackward: "backspace",
21
- deleteCharForward: ["delete", "ctrl+d"],
22
- deleteWordBackward: ["ctrl+w", "alt+backspace"],
23
- deleteWordForward: ["alt+d", "alt+delete"],
24
- deleteToLineStart: "ctrl+u",
25
- deleteToLineEnd: "ctrl+k",
26
- // Text input
27
- newLine: "shift+enter",
28
- submit: "enter",
29
- tab: "tab",
30
- // Selection/autocomplete
31
- selectUp: "up",
32
- selectDown: "down",
33
- selectPageUp: "pageUp",
34
- selectPageDown: "pageDown",
35
- selectConfirm: "enter",
36
- selectCancel: ["escape", "ctrl+c"],
37
- // Clipboard
38
- copy: "ctrl+c",
39
- // Kill ring
40
- yank: "ctrl+y",
41
- yankPop: "alt+y",
42
- // Undo
43
- undo: "ctrl+-",
44
- // Tool output
45
- expandTools: "ctrl+o",
46
- // Tree navigation
47
- treeFoldOrUp: ["ctrl+left", "alt+left"],
48
- treeUnfoldOrDown: ["ctrl+right", "alt+right"],
49
- // Session
50
- toggleSessionPath: "ctrl+p",
51
- toggleSessionSort: "ctrl+s",
52
- renameSession: "ctrl+r",
53
- deleteSession: "ctrl+d",
54
- deleteSessionNoninvasive: "ctrl+backspace",
2
+ export const TUI_KEYBINDINGS = {
3
+ "tui.editor.cursorUp": { defaultKeys: "up", description: "Move cursor up" },
4
+ "tui.editor.cursorDown": { defaultKeys: "down", description: "Move cursor down" },
5
+ "tui.editor.cursorLeft": {
6
+ defaultKeys: ["left", "ctrl+b"],
7
+ description: "Move cursor left",
8
+ },
9
+ "tui.editor.cursorRight": {
10
+ defaultKeys: ["right", "ctrl+f"],
11
+ description: "Move cursor right",
12
+ },
13
+ "tui.editor.cursorWordLeft": {
14
+ defaultKeys: ["alt+left", "ctrl+left", "alt+b"],
15
+ description: "Move cursor word left",
16
+ },
17
+ "tui.editor.cursorWordRight": {
18
+ defaultKeys: ["alt+right", "ctrl+right", "alt+f"],
19
+ description: "Move cursor word right",
20
+ },
21
+ "tui.editor.cursorLineStart": {
22
+ defaultKeys: ["home", "ctrl+a"],
23
+ description: "Move to line start",
24
+ },
25
+ "tui.editor.cursorLineEnd": {
26
+ defaultKeys: ["end", "ctrl+e"],
27
+ description: "Move to line end",
28
+ },
29
+ "tui.editor.jumpForward": {
30
+ defaultKeys: "ctrl+]",
31
+ description: "Jump forward to character",
32
+ },
33
+ "tui.editor.jumpBackward": {
34
+ defaultKeys: "ctrl+alt+]",
35
+ description: "Jump backward to character",
36
+ },
37
+ "tui.editor.pageUp": { defaultKeys: "pageUp", description: "Page up" },
38
+ "tui.editor.pageDown": { defaultKeys: "pageDown", description: "Page down" },
39
+ "tui.editor.deleteCharBackward": {
40
+ defaultKeys: "backspace",
41
+ description: "Delete character backward",
42
+ },
43
+ "tui.editor.deleteCharForward": {
44
+ defaultKeys: ["delete", "ctrl+d"],
45
+ description: "Delete character forward",
46
+ },
47
+ "tui.editor.deleteWordBackward": {
48
+ defaultKeys: ["ctrl+w", "alt+backspace"],
49
+ description: "Delete word backward",
50
+ },
51
+ "tui.editor.deleteWordForward": {
52
+ defaultKeys: ["alt+d", "alt+delete"],
53
+ description: "Delete word forward",
54
+ },
55
+ "tui.editor.deleteToLineStart": {
56
+ defaultKeys: "ctrl+u",
57
+ description: "Delete to line start",
58
+ },
59
+ "tui.editor.deleteToLineEnd": {
60
+ defaultKeys: "ctrl+k",
61
+ description: "Delete to line end",
62
+ },
63
+ "tui.editor.yank": { defaultKeys: "ctrl+y", description: "Yank" },
64
+ "tui.editor.yankPop": { defaultKeys: "alt+y", description: "Yank pop" },
65
+ "tui.editor.undo": { defaultKeys: "ctrl+-", description: "Undo" },
66
+ "tui.input.newLine": { defaultKeys: "shift+enter", description: "Insert newline" },
67
+ "tui.input.submit": { defaultKeys: "enter", description: "Submit input" },
68
+ "tui.input.tab": { defaultKeys: "tab", description: "Tab / autocomplete" },
69
+ "tui.input.copy": { defaultKeys: "ctrl+c", description: "Copy selection" },
70
+ "tui.select.up": { defaultKeys: "up", description: "Move selection up" },
71
+ "tui.select.down": { defaultKeys: "down", description: "Move selection down" },
72
+ "tui.select.pageUp": { defaultKeys: "pageUp", description: "Selection page up" },
73
+ "tui.select.pageDown": {
74
+ defaultKeys: "pageDown",
75
+ description: "Selection page down",
76
+ },
77
+ "tui.select.confirm": { defaultKeys: "enter", description: "Confirm selection" },
78
+ "tui.select.cancel": {
79
+ defaultKeys: ["escape", "ctrl+c"],
80
+ description: "Cancel selection",
81
+ },
55
82
  };
56
- /**
57
- * Manages keybindings for the editor.
58
- */
59
- export class EditorKeybindingsManager {
60
- actionToKeys;
61
- constructor(config = {}) {
62
- this.actionToKeys = new Map();
63
- this.buildMaps(config);
64
- }
65
- buildMaps(config) {
66
- this.actionToKeys.clear();
67
- // Start with defaults
68
- for (const [action, keys] of Object.entries(DEFAULT_EDITOR_KEYBINDINGS)) {
69
- const keyArray = Array.isArray(keys) ? keys : [keys];
70
- this.actionToKeys.set(action, [...keyArray]);
83
+ function normalizeKeys(keys) {
84
+ if (keys === undefined)
85
+ return [];
86
+ const keyList = Array.isArray(keys) ? keys : [keys];
87
+ const seen = new Set();
88
+ const result = [];
89
+ for (const key of keyList) {
90
+ if (!seen.has(key)) {
91
+ seen.add(key);
92
+ result.push(key);
71
93
  }
72
- // Override with user config
73
- for (const [action, keys] of Object.entries(config)) {
74
- if (keys === undefined)
94
+ }
95
+ return result;
96
+ }
97
+ export class KeybindingsManager {
98
+ definitions;
99
+ userBindings;
100
+ keysById = new Map();
101
+ conflicts = [];
102
+ constructor(definitions, userBindings = {}) {
103
+ this.definitions = definitions;
104
+ this.userBindings = userBindings;
105
+ this.rebuild();
106
+ }
107
+ rebuild() {
108
+ this.keysById.clear();
109
+ this.conflicts = [];
110
+ const userClaims = new Map();
111
+ for (const [keybinding, keys] of Object.entries(this.userBindings)) {
112
+ if (!(keybinding in this.definitions))
75
113
  continue;
76
- const keyArray = Array.isArray(keys) ? keys : [keys];
77
- this.actionToKeys.set(action, keyArray);
114
+ for (const key of normalizeKeys(keys)) {
115
+ const claimants = userClaims.get(key) ?? new Set();
116
+ claimants.add(keybinding);
117
+ userClaims.set(key, claimants);
118
+ }
119
+ }
120
+ for (const [key, keybindings] of userClaims) {
121
+ if (keybindings.size > 1) {
122
+ this.conflicts.push({ key, keybindings: [...keybindings] });
123
+ }
124
+ }
125
+ for (const [id, definition] of Object.entries(this.definitions)) {
126
+ const userKeys = this.userBindings[id];
127
+ const keys = userKeys === undefined ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);
128
+ this.keysById.set(id, keys);
78
129
  }
79
130
  }
80
- /**
81
- * Check if input matches a specific action.
82
- */
83
- matches(data, action) {
84
- const keys = this.actionToKeys.get(action);
85
- if (!keys)
86
- return false;
131
+ matches(data, keybinding) {
132
+ const keys = this.keysById.get(keybinding) ?? [];
87
133
  for (const key of keys) {
88
134
  if (matchesKey(data, key))
89
135
  return true;
90
136
  }
91
137
  return false;
92
138
  }
93
- /**
94
- * Get keys bound to an action.
95
- */
96
- getKeys(action) {
97
- return this.actionToKeys.get(action) ?? [];
139
+ getKeys(keybinding) {
140
+ return [...(this.keysById.get(keybinding) ?? [])];
98
141
  }
99
- /**
100
- * Update configuration.
101
- */
102
- setConfig(config) {
103
- this.buildMaps(config);
142
+ getDefinition(keybinding) {
143
+ return this.definitions[keybinding];
104
144
  }
105
- }
106
- // Global instance
107
- let globalEditorKeybindings = null;
108
- export function getEditorKeybindings() {
109
- if (!globalEditorKeybindings) {
110
- globalEditorKeybindings = new EditorKeybindingsManager();
145
+ getConflicts() {
146
+ return this.conflicts.map((conflict) => ({ ...conflict, keybindings: [...conflict.keybindings] }));
111
147
  }
112
- return globalEditorKeybindings;
148
+ setUserBindings(userBindings) {
149
+ this.userBindings = userBindings;
150
+ this.rebuild();
151
+ }
152
+ getUserBindings() {
153
+ return { ...this.userBindings };
154
+ }
155
+ getResolvedBindings() {
156
+ const resolved = {};
157
+ for (const id of Object.keys(this.definitions)) {
158
+ const keys = this.keysById.get(id) ?? [];
159
+ resolved[id] = keys.length === 1 ? keys[0] : [...keys];
160
+ }
161
+ return resolved;
162
+ }
163
+ }
164
+ let globalKeybindings = null;
165
+ export function setKeybindings(keybindings) {
166
+ globalKeybindings = keybindings;
113
167
  }
114
- export function setEditorKeybindings(manager) {
115
- globalEditorKeybindings = manager;
168
+ export function getKeybindings() {
169
+ if (!globalKeybindings) {
170
+ globalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);
171
+ }
172
+ return globalKeybindings;
116
173
  }
117
174
  //# sourceMappingURL=keybindings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { type KeyId, matchesKey } from \"./keys.js\";\n\n/**\n * Editor actions that can be bound to keys.\n */\nexport type EditorAction =\n\t// Cursor movement\n\t| \"cursorUp\"\n\t| \"cursorDown\"\n\t| \"cursorLeft\"\n\t| \"cursorRight\"\n\t| \"cursorWordLeft\"\n\t| \"cursorWordRight\"\n\t| \"cursorLineStart\"\n\t| \"cursorLineEnd\"\n\t| \"jumpForward\"\n\t| \"jumpBackward\"\n\t| \"pageUp\"\n\t| \"pageDown\"\n\t// Deletion\n\t| \"deleteCharBackward\"\n\t| \"deleteCharForward\"\n\t| \"deleteWordBackward\"\n\t| \"deleteWordForward\"\n\t| \"deleteToLineStart\"\n\t| \"deleteToLineEnd\"\n\t// Text input\n\t| \"newLine\"\n\t| \"submit\"\n\t| \"tab\"\n\t// Selection/autocomplete\n\t| \"selectUp\"\n\t| \"selectDown\"\n\t| \"selectPageUp\"\n\t| \"selectPageDown\"\n\t| \"selectConfirm\"\n\t| \"selectCancel\"\n\t// Clipboard\n\t| \"copy\"\n\t// Kill ring\n\t| \"yank\"\n\t| \"yankPop\"\n\t// Undo\n\t| \"undo\"\n\t// Tool output\n\t| \"expandTools\"\n\t// Tree navigation\n\t| \"treeFoldOrUp\"\n\t| \"treeUnfoldOrDown\"\n\t// Session\n\t| \"toggleSessionPath\"\n\t| \"toggleSessionSort\"\n\t| \"renameSession\"\n\t| \"deleteSession\"\n\t| \"deleteSessionNoninvasive\";\n\n// Re-export KeyId from keys.ts\nexport type { KeyId };\n\n/**\n * Editor keybindings configuration.\n */\nexport type EditorKeybindingsConfig = {\n\t[K in EditorAction]?: KeyId | KeyId[];\n};\n\n/**\n * Default editor keybindings.\n */\nexport const DEFAULT_EDITOR_KEYBINDINGS: Required<EditorKeybindingsConfig> = {\n\t// Cursor movement\n\tcursorUp: \"up\",\n\tcursorDown: \"down\",\n\tcursorLeft: [\"left\", \"ctrl+b\"],\n\tcursorRight: [\"right\", \"ctrl+f\"],\n\tcursorWordLeft: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n\tcursorWordRight: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n\tcursorLineStart: [\"home\", \"ctrl+a\"],\n\tcursorLineEnd: [\"end\", \"ctrl+e\"],\n\tjumpForward: \"ctrl+]\",\n\tjumpBackward: \"ctrl+alt+]\",\n\tpageUp: \"pageUp\",\n\tpageDown: \"pageDown\",\n\t// Deletion\n\tdeleteCharBackward: \"backspace\",\n\tdeleteCharForward: [\"delete\", \"ctrl+d\"],\n\tdeleteWordBackward: [\"ctrl+w\", \"alt+backspace\"],\n\tdeleteWordForward: [\"alt+d\", \"alt+delete\"],\n\tdeleteToLineStart: \"ctrl+u\",\n\tdeleteToLineEnd: \"ctrl+k\",\n\t// Text input\n\tnewLine: \"shift+enter\",\n\tsubmit: \"enter\",\n\ttab: \"tab\",\n\t// Selection/autocomplete\n\tselectUp: \"up\",\n\tselectDown: \"down\",\n\tselectPageUp: \"pageUp\",\n\tselectPageDown: \"pageDown\",\n\tselectConfirm: \"enter\",\n\tselectCancel: [\"escape\", \"ctrl+c\"],\n\t// Clipboard\n\tcopy: \"ctrl+c\",\n\t// Kill ring\n\tyank: \"ctrl+y\",\n\tyankPop: \"alt+y\",\n\t// Undo\n\tundo: \"ctrl+-\",\n\t// Tool output\n\texpandTools: \"ctrl+o\",\n\t// Tree navigation\n\ttreeFoldOrUp: [\"ctrl+left\", \"alt+left\"],\n\ttreeUnfoldOrDown: [\"ctrl+right\", \"alt+right\"],\n\t// Session\n\ttoggleSessionPath: \"ctrl+p\",\n\ttoggleSessionSort: \"ctrl+s\",\n\trenameSession: \"ctrl+r\",\n\tdeleteSession: \"ctrl+d\",\n\tdeleteSessionNoninvasive: \"ctrl+backspace\",\n};\n\n/**\n * Manages keybindings for the editor.\n */\nexport class EditorKeybindingsManager {\n\tprivate actionToKeys: Map<EditorAction, KeyId[]>;\n\n\tconstructor(config: EditorKeybindingsConfig = {}) {\n\t\tthis.actionToKeys = new Map();\n\t\tthis.buildMaps(config);\n\t}\n\n\tprivate buildMaps(config: EditorKeybindingsConfig): void {\n\t\tthis.actionToKeys.clear();\n\n\t\t// Start with defaults\n\t\tfor (const [action, keys] of Object.entries(DEFAULT_EDITOR_KEYBINDINGS)) {\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.actionToKeys.set(action as EditorAction, [...keyArray]);\n\t\t}\n\n\t\t// Override with user config\n\t\tfor (const [action, keys] of Object.entries(config)) {\n\t\t\tif (keys === undefined) continue;\n\t\t\tconst keyArray = Array.isArray(keys) ? keys : [keys];\n\t\t\tthis.actionToKeys.set(action as EditorAction, keyArray);\n\t\t}\n\t}\n\n\t/**\n\t * Check if input matches a specific action.\n\t */\n\tmatches(data: string, action: EditorAction): boolean {\n\t\tconst keys = this.actionToKeys.get(action);\n\t\tif (!keys) return false;\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Get keys bound to an action.\n\t */\n\tgetKeys(action: EditorAction): KeyId[] {\n\t\treturn this.actionToKeys.get(action) ?? [];\n\t}\n\n\t/**\n\t * Update configuration.\n\t */\n\tsetConfig(config: EditorKeybindingsConfig): void {\n\t\tthis.buildMaps(config);\n\t}\n}\n\n// Global instance\nlet globalEditorKeybindings: EditorKeybindingsManager | null = null;\n\nexport function getEditorKeybindings(): EditorKeybindingsManager {\n\tif (!globalEditorKeybindings) {\n\t\tglobalEditorKeybindings = new EditorKeybindingsManager();\n\t}\n\treturn globalEditorKeybindings;\n}\n\nexport function setEditorKeybindings(manager: EditorKeybindingsManager): void {\n\tglobalEditorKeybindings = manager;\n}\n"]}
1
+ {"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { type KeyId, matchesKey } from \"./keys.js\";\n\n/**\n * Global keybinding registry.\n * Downstream packages can add keybindings via declaration merging.\n */\nexport interface Keybindings {\n\t// Editor navigation and editing\n\t\"tui.editor.cursorUp\": true;\n\t\"tui.editor.cursorDown\": true;\n\t\"tui.editor.cursorLeft\": true;\n\t\"tui.editor.cursorRight\": true;\n\t\"tui.editor.cursorWordLeft\": true;\n\t\"tui.editor.cursorWordRight\": true;\n\t\"tui.editor.cursorLineStart\": true;\n\t\"tui.editor.cursorLineEnd\": true;\n\t\"tui.editor.jumpForward\": true;\n\t\"tui.editor.jumpBackward\": true;\n\t\"tui.editor.pageUp\": true;\n\t\"tui.editor.pageDown\": true;\n\t\"tui.editor.deleteCharBackward\": true;\n\t\"tui.editor.deleteCharForward\": true;\n\t\"tui.editor.deleteWordBackward\": true;\n\t\"tui.editor.deleteWordForward\": true;\n\t\"tui.editor.deleteToLineStart\": true;\n\t\"tui.editor.deleteToLineEnd\": true;\n\t\"tui.editor.yank\": true;\n\t\"tui.editor.yankPop\": true;\n\t\"tui.editor.undo\": true;\n\t// Generic input actions\n\t\"tui.input.newLine\": true;\n\t\"tui.input.submit\": true;\n\t\"tui.input.tab\": true;\n\t\"tui.input.copy\": true;\n\t// Generic selection actions\n\t\"tui.select.up\": true;\n\t\"tui.select.down\": true;\n\t\"tui.select.pageUp\": true;\n\t\"tui.select.pageDown\": true;\n\t\"tui.select.confirm\": true;\n\t\"tui.select.cancel\": true;\n}\n\nexport type Keybinding = keyof Keybindings;\n\nexport interface KeybindingDefinition {\n\tdefaultKeys: KeyId | KeyId[];\n\tdescription?: string;\n}\n\nexport type KeybindingDefinitions = Record<string, KeybindingDefinition>;\nexport type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;\n\nexport const TUI_KEYBINDINGS = {\n\t\"tui.editor.cursorUp\": { defaultKeys: \"up\", description: \"Move cursor up\" },\n\t\"tui.editor.cursorDown\": { defaultKeys: \"down\", description: \"Move cursor down\" },\n\t\"tui.editor.cursorLeft\": {\n\t\tdefaultKeys: [\"left\", \"ctrl+b\"],\n\t\tdescription: \"Move cursor left\",\n\t},\n\t\"tui.editor.cursorRight\": {\n\t\tdefaultKeys: [\"right\", \"ctrl+f\"],\n\t\tdescription: \"Move cursor right\",\n\t},\n\t\"tui.editor.cursorWordLeft\": {\n\t\tdefaultKeys: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n\t\tdescription: \"Move cursor word left\",\n\t},\n\t\"tui.editor.cursorWordRight\": {\n\t\tdefaultKeys: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n\t\tdescription: \"Move cursor word right\",\n\t},\n\t\"tui.editor.cursorLineStart\": {\n\t\tdefaultKeys: [\"home\", \"ctrl+a\"],\n\t\tdescription: \"Move to line start\",\n\t},\n\t\"tui.editor.cursorLineEnd\": {\n\t\tdefaultKeys: [\"end\", \"ctrl+e\"],\n\t\tdescription: \"Move to line end\",\n\t},\n\t\"tui.editor.jumpForward\": {\n\t\tdefaultKeys: \"ctrl+]\",\n\t\tdescription: \"Jump forward to character\",\n\t},\n\t\"tui.editor.jumpBackward\": {\n\t\tdefaultKeys: \"ctrl+alt+]\",\n\t\tdescription: \"Jump backward to character\",\n\t},\n\t\"tui.editor.pageUp\": { defaultKeys: \"pageUp\", description: \"Page up\" },\n\t\"tui.editor.pageDown\": { defaultKeys: \"pageDown\", description: \"Page down\" },\n\t\"tui.editor.deleteCharBackward\": {\n\t\tdefaultKeys: \"backspace\",\n\t\tdescription: \"Delete character backward\",\n\t},\n\t\"tui.editor.deleteCharForward\": {\n\t\tdefaultKeys: [\"delete\", \"ctrl+d\"],\n\t\tdescription: \"Delete character forward\",\n\t},\n\t\"tui.editor.deleteWordBackward\": {\n\t\tdefaultKeys: [\"ctrl+w\", \"alt+backspace\"],\n\t\tdescription: \"Delete word backward\",\n\t},\n\t\"tui.editor.deleteWordForward\": {\n\t\tdefaultKeys: [\"alt+d\", \"alt+delete\"],\n\t\tdescription: \"Delete word forward\",\n\t},\n\t\"tui.editor.deleteToLineStart\": {\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Delete to line start\",\n\t},\n\t\"tui.editor.deleteToLineEnd\": {\n\t\tdefaultKeys: \"ctrl+k\",\n\t\tdescription: \"Delete to line end\",\n\t},\n\t\"tui.editor.yank\": { defaultKeys: \"ctrl+y\", description: \"Yank\" },\n\t\"tui.editor.yankPop\": { defaultKeys: \"alt+y\", description: \"Yank pop\" },\n\t\"tui.editor.undo\": { defaultKeys: \"ctrl+-\", description: \"Undo\" },\n\t\"tui.input.newLine\": { defaultKeys: \"shift+enter\", description: \"Insert newline\" },\n\t\"tui.input.submit\": { defaultKeys: \"enter\", description: \"Submit input\" },\n\t\"tui.input.tab\": { defaultKeys: \"tab\", description: \"Tab / autocomplete\" },\n\t\"tui.input.copy\": { defaultKeys: \"ctrl+c\", description: \"Copy selection\" },\n\t\"tui.select.up\": { defaultKeys: \"up\", description: \"Move selection up\" },\n\t\"tui.select.down\": { defaultKeys: \"down\", description: \"Move selection down\" },\n\t\"tui.select.pageUp\": { defaultKeys: \"pageUp\", description: \"Selection page up\" },\n\t\"tui.select.pageDown\": {\n\t\tdefaultKeys: \"pageDown\",\n\t\tdescription: \"Selection page down\",\n\t},\n\t\"tui.select.confirm\": { defaultKeys: \"enter\", description: \"Confirm selection\" },\n\t\"tui.select.cancel\": {\n\t\tdefaultKeys: [\"escape\", \"ctrl+c\"],\n\t\tdescription: \"Cancel selection\",\n\t},\n} as const satisfies KeybindingDefinitions;\n\nexport interface KeybindingConflict {\n\tkey: KeyId;\n\tkeybindings: string[];\n}\n\nfunction normalizeKeys(keys: KeyId | KeyId[] | undefined): KeyId[] {\n\tif (keys === undefined) return [];\n\tconst keyList = Array.isArray(keys) ? keys : [keys];\n\tconst seen = new Set<KeyId>();\n\tconst result: KeyId[] = [];\n\tfor (const key of keyList) {\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n\nexport class KeybindingsManager {\n\tprivate definitions: KeybindingDefinitions;\n\tprivate userBindings: KeybindingsConfig;\n\tprivate keysById = new Map<Keybinding, KeyId[]>();\n\tprivate conflicts: KeybindingConflict[] = [];\n\n\tconstructor(definitions: KeybindingDefinitions, userBindings: KeybindingsConfig = {}) {\n\t\tthis.definitions = definitions;\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.keysById.clear();\n\t\tthis.conflicts = [];\n\n\t\tconst userClaims = new Map<KeyId, Set<Keybinding>>();\n\t\tfor (const [keybinding, keys] of Object.entries(this.userBindings)) {\n\t\t\tif (!(keybinding in this.definitions)) continue;\n\t\t\tfor (const key of normalizeKeys(keys)) {\n\t\t\t\tconst claimants = userClaims.get(key) ?? new Set<Keybinding>();\n\t\t\t\tclaimants.add(keybinding as Keybinding);\n\t\t\t\tuserClaims.set(key, claimants);\n\t\t\t}\n\t\t}\n\n\t\tfor (const [key, keybindings] of userClaims) {\n\t\t\tif (keybindings.size > 1) {\n\t\t\t\tthis.conflicts.push({ key, keybindings: [...keybindings] });\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, definition] of Object.entries(this.definitions)) {\n\t\t\tconst userKeys = this.userBindings[id];\n\t\t\tconst keys = userKeys === undefined ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);\n\t\t\tthis.keysById.set(id as Keybinding, keys);\n\t\t}\n\t}\n\n\tmatches(data: string, keybinding: Keybinding): boolean {\n\t\tconst keys = this.keysById.get(keybinding) ?? [];\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetKeys(keybinding: Keybinding): KeyId[] {\n\t\treturn [...(this.keysById.get(keybinding) ?? [])];\n\t}\n\n\tgetDefinition(keybinding: Keybinding): KeybindingDefinition {\n\t\treturn this.definitions[keybinding];\n\t}\n\n\tgetConflicts(): KeybindingConflict[] {\n\t\treturn this.conflicts.map((conflict) => ({ ...conflict, keybindings: [...conflict.keybindings] }));\n\t}\n\n\tsetUserBindings(userBindings: KeybindingsConfig): void {\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tgetUserBindings(): KeybindingsConfig {\n\t\treturn { ...this.userBindings };\n\t}\n\n\tgetResolvedBindings(): KeybindingsConfig {\n\t\tconst resolved: KeybindingsConfig = {};\n\t\tfor (const id of Object.keys(this.definitions)) {\n\t\t\tconst keys = this.keysById.get(id as Keybinding) ?? [];\n\t\t\tresolved[id] = keys.length === 1 ? keys[0]! : [...keys];\n\t\t}\n\t\treturn resolved;\n\t}\n}\n\nlet globalKeybindings: KeybindingsManager | null = null;\n\nexport function setKeybindings(keybindings: KeybindingsManager): void {\n\tglobalKeybindings = keybindings;\n}\n\nexport function getKeybindings(): KeybindingsManager {\n\tif (!globalKeybindings) {\n\t\tglobalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);\n\t}\n\treturn globalKeybindings;\n}\n"]}