@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.
- package/dist/autocomplete.d.ts.map +1 -1
- package/dist/autocomplete.js +49 -10
- package/dist/autocomplete.js.map +1 -1
- package/dist/components/cancellable-loader.d.ts.map +1 -1
- package/dist/components/cancellable-loader.js +3 -3
- package/dist/components/cancellable-loader.js.map +1 -1
- package/dist/components/editor.d.ts +9 -1
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +200 -71
- package/dist/components/editor.js.map +1 -1
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +19 -19
- package/dist/components/input.js.map +1 -1
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +25 -16
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/select-list.d.ts +19 -1
- package/dist/components/select-list.d.ts.map +1 -1
- package/dist/components/select-list.js +74 -67
- package/dist/components/select-list.js.map +1 -1
- package/dist/components/settings-list.d.ts.map +1 -1
- package/dist/components/settings-list.js +6 -6
- package/dist/components/settings-list.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/keybindings.d.ts +187 -33
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js +156 -99
- package/dist/keybindings.js.map +1 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +46 -7
- package/dist/keys.js.map +1 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +17 -1
- package/dist/terminal.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +15 -4
- package/dist/tui.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +201 -56
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/keybindings.d.ts
CHANGED
|
@@ -1,39 +1,193 @@
|
|
|
1
1
|
import { type KeyId } from "./keys.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Global keybinding registry.
|
|
4
|
+
* Downstream packages can add keybindings via declaration merging.
|
|
4
5
|
*/
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
constructor(
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
38
|
-
export declare function
|
|
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":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAc,MAAM,WAAW,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAE3B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,uBAAuB,EAAE,IAAI,CAAC;IAC9B,uBAAuB,EAAE,IAAI,CAAC;IAC9B,wBAAwB,EAAE,IAAI,CAAC;IAC/B,2BAA2B,EAAE,IAAI,CAAC;IAClC,4BAA4B,EAAE,IAAI,CAAC;IACnC,4BAA4B,EAAE,IAAI,CAAC;IACnC,0BAA0B,EAAE,IAAI,CAAC;IACjC,wBAAwB,EAAE,IAAI,CAAC;IAC/B,yBAAyB,EAAE,IAAI,CAAC;IAChC,mBAAmB,EAAE,IAAI,CAAC;IAC1B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,+BAA+B,EAAE,IAAI,CAAC;IACtC,8BAA8B,EAAE,IAAI,CAAC;IACrC,+BAA+B,EAAE,IAAI,CAAC;IACtC,8BAA8B,EAAE,IAAI,CAAC;IACrC,8BAA8B,EAAE,IAAI,CAAC;IACrC,4BAA4B,EAAE,IAAI,CAAC;IACnC,iBAAiB,EAAE,IAAI,CAAC;IACxB,oBAAoB,EAAE,IAAI,CAAC;IAC3B,iBAAiB,EAAE,IAAI,CAAC;IAExB,mBAAmB,EAAE,IAAI,CAAC;IAC1B,kBAAkB,EAAE,IAAI,CAAC;IACzB,eAAe,EAAE,IAAI,CAAC;IACtB,gBAAgB,EAAE,IAAI,CAAC;IAEvB,eAAe,EAAE,IAAI,CAAC;IACtB,iBAAiB,EAAE,IAAI,CAAC;IACxB,mBAAmB,EAAE,IAAI,CAAC;IAC1B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,oBAAoB,EAAE,IAAI,CAAC;IAC3B,mBAAmB,EAAE,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,oBAAoB;IACpC,WAAW,EAAE,KAAK,GAAG,KAAK,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AACzE,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;AAE5E,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgFc,CAAC;AAE3C,MAAM,WAAW,kBAAkB;IAClC,GAAG,EAAE,KAAK,CAAC;IACX,WAAW,EAAE,MAAM,EAAE,CAAC;CACtB;AAgBD,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,SAAS,CAA4B;IAE7C,YAAY,WAAW,EAAE,qBAAqB,EAAE,YAAY,GAAE,iBAAsB,EAInF;IAED,OAAO,CAAC,OAAO;IA2Bf,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAMrD;IAED,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,KAAK,EAAE,CAEvC;IAED,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,oBAAoB,CAE1D;IAED,YAAY,IAAI,kBAAkB,EAAE,CAEnC;IAED,eAAe,CAAC,YAAY,EAAE,iBAAiB,GAAG,IAAI,CAGrD;IAED,eAAe,IAAI,iBAAiB,CAEnC;IAED,mBAAmB,IAAI,iBAAiB,CAOvC;CACD;AAID,wBAAgB,cAAc,CAAC,WAAW,EAAE,kBAAkB,GAAG,IAAI,CAEpE;AAED,wBAAgB,cAAc,IAAI,kBAAkB,CAKnD","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"]}
|
package/dist/keybindings.js
CHANGED
|
@@ -1,117 +1,174 @@
|
|
|
1
1
|
import { matchesKey } from "./keys.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
95
|
-
*/
|
|
96
|
-
getKeys(action) {
|
|
97
|
-
return this.actionToKeys.get(action) ?? [];
|
|
139
|
+
getKeys(keybinding) {
|
|
140
|
+
return [...(this.keysById.get(keybinding) ?? [])];
|
|
98
141
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
*/
|
|
102
|
-
setConfig(config) {
|
|
103
|
-
this.buildMaps(config);
|
|
142
|
+
getDefinition(keybinding) {
|
|
143
|
+
return this.definitions[keybinding];
|
|
104
144
|
}
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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
|
|
115
|
-
|
|
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
|
package/dist/keybindings.js.map
CHANGED
|
@@ -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"]}
|