@m4ike1/ion-tui 0.1.0
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/README.md +114 -0
- package/dist/alt-screen-search.d.ts +46 -0
- package/dist/alt-screen-search.d.ts.map +1 -0
- package/dist/alt-screen-search.js +282 -0
- package/dist/alt-screen-search.js.map +1 -0
- package/dist/autocomplete.d.ts +75 -0
- package/dist/autocomplete.d.ts.map +1 -0
- package/dist/autocomplete.js +749 -0
- package/dist/autocomplete.js.map +1 -0
- package/dist/components/alt-screen-flash.d.ts +13 -0
- package/dist/components/alt-screen-flash.d.ts.map +1 -0
- package/dist/components/alt-screen-flash.js +37 -0
- package/dist/components/alt-screen-flash.js.map +1 -0
- package/dist/components/box.d.ts +24 -0
- package/dist/components/box.d.ts.map +1 -0
- package/dist/components/box.js +133 -0
- package/dist/components/box.js.map +1 -0
- package/dist/components/cancellable-loader.d.ts +22 -0
- package/dist/components/cancellable-loader.d.ts.map +1 -0
- package/dist/components/cancellable-loader.js +35 -0
- package/dist/components/cancellable-loader.js.map +1 -0
- package/dist/components/editor.d.ts +266 -0
- package/dist/components/editor.d.ts.map +1 -0
- package/dist/components/editor.js +2087 -0
- package/dist/components/editor.js.map +1 -0
- package/dist/components/h-stack.d.ts +7 -0
- package/dist/components/h-stack.d.ts.map +1 -0
- package/dist/components/h-stack.js +43 -0
- package/dist/components/h-stack.js.map +1 -0
- package/dist/components/image.d.ts +28 -0
- package/dist/components/image.d.ts.map +1 -0
- package/dist/components/image.js +90 -0
- package/dist/components/image.js.map +1 -0
- package/dist/components/input.d.ts +48 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +417 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/loader.d.ts +33 -0
- package/dist/components/loader.d.ts.map +1 -0
- package/dist/components/loader.js +76 -0
- package/dist/components/loader.js.map +1 -0
- package/dist/components/markdown.d.ts +103 -0
- package/dist/components/markdown.d.ts.map +1 -0
- package/dist/components/markdown.js +858 -0
- package/dist/components/markdown.js.map +1 -0
- package/dist/components/mouse-region.d.ts +12 -0
- package/dist/components/mouse-region.d.ts.map +1 -0
- package/dist/components/mouse-region.js +21 -0
- package/dist/components/mouse-region.js.map +1 -0
- package/dist/components/scroll-view.d.ts +68 -0
- package/dist/components/scroll-view.d.ts.map +1 -0
- package/dist/components/scroll-view.js +199 -0
- package/dist/components/scroll-view.js.map +1 -0
- package/dist/components/select-list.d.ts +53 -0
- package/dist/components/select-list.d.ts.map +1 -0
- package/dist/components/select-list.js +206 -0
- package/dist/components/select-list.js.map +1 -0
- package/dist/components/settings-list.d.ts +60 -0
- package/dist/components/settings-list.d.ts.map +1 -0
- package/dist/components/settings-list.js +252 -0
- package/dist/components/settings-list.js.map +1 -0
- package/dist/components/spacer.d.ts +12 -0
- package/dist/components/spacer.d.ts.map +1 -0
- package/dist/components/spacer.js +23 -0
- package/dist/components/spacer.js.map +1 -0
- package/dist/components/stack.d.ts +32 -0
- package/dist/components/stack.d.ts.map +1 -0
- package/dist/components/stack.js +111 -0
- package/dist/components/stack.js.map +1 -0
- package/dist/components/text.d.ts +19 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/components/text.js +90 -0
- package/dist/components/text.js.map +1 -0
- package/dist/components/truncated-text.d.ts +13 -0
- package/dist/components/truncated-text.d.ts.map +1 -0
- package/dist/components/truncated-text.js +51 -0
- package/dist/components/truncated-text.js.map +1 -0
- package/dist/components/v-stack.d.ts +8 -0
- package/dist/components/v-stack.d.ts.map +1 -0
- package/dist/components/v-stack.js +26 -0
- package/dist/components/v-stack.js.map +1 -0
- package/dist/components/virtual-list.d.ts +51 -0
- package/dist/components/virtual-list.d.ts.map +1 -0
- package/dist/components/virtual-list.js +170 -0
- package/dist/components/virtual-list.js.map +1 -0
- package/dist/editor-component.d.ts +39 -0
- package/dist/editor-component.d.ts.map +1 -0
- package/dist/editor-component.js +2 -0
- package/dist/editor-component.js.map +1 -0
- package/dist/fuzzy.d.ts +16 -0
- package/dist/fuzzy.d.ts.map +1 -0
- package/dist/fuzzy.js +110 -0
- package/dist/fuzzy.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/keybindings.d.ts +366 -0
- package/dist/keybindings.d.ts.map +1 -0
- package/dist/keybindings.js +331 -0
- package/dist/keybindings.js.map +1 -0
- package/dist/keys.d.ts +184 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +1174 -0
- package/dist/keys.js.map +1 -0
- package/dist/kill-ring.d.ts +28 -0
- package/dist/kill-ring.d.ts.map +1 -0
- package/dist/kill-ring.js +44 -0
- package/dist/kill-ring.js.map +1 -0
- package/dist/latex.d.ts +10 -0
- package/dist/latex.d.ts.map +1 -0
- package/dist/latex.js +1285 -0
- package/dist/latex.js.map +1 -0
- package/dist/layout-node.d.ts +59 -0
- package/dist/layout-node.d.ts.map +1 -0
- package/dist/layout-node.js +12 -0
- package/dist/layout-node.js.map +1 -0
- package/dist/layout.d.ts +42 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +404 -0
- package/dist/layout.js.map +1 -0
- package/dist/native-modifiers.d.ts +4 -0
- package/dist/native-modifiers.d.ts.map +1 -0
- package/dist/native-modifiers.js +13 -0
- package/dist/native-modifiers.js.map +1 -0
- package/dist/native-module-path.d.ts +7 -0
- package/dist/native-module-path.d.ts.map +1 -0
- package/dist/native-module-path.js +19 -0
- package/dist/native-module-path.js.map +1 -0
- package/dist/native-platform.d.ts +18 -0
- package/dist/native-platform.d.ts.map +1 -0
- package/dist/native-platform.js +42 -0
- package/dist/native-platform.js.map +1 -0
- package/dist/pty-host.d.ts +224 -0
- package/dist/pty-host.d.ts.map +1 -0
- package/dist/pty-host.js +347 -0
- package/dist/pty-host.js.map +1 -0
- package/dist/stdin-buffer.d.ts +56 -0
- package/dist/stdin-buffer.d.ts.map +1 -0
- package/dist/stdin-buffer.js +366 -0
- package/dist/stdin-buffer.js.map +1 -0
- package/dist/terminal-colors.d.ts +10 -0
- package/dist/terminal-colors.d.ts.map +1 -0
- package/dist/terminal-colors.js +59 -0
- package/dist/terminal-colors.js.map +1 -0
- package/dist/terminal-image.d.ts +118 -0
- package/dist/terminal-image.d.ts.map +1 -0
- package/dist/terminal-image.js +550 -0
- package/dist/terminal-image.js.map +1 -0
- package/dist/terminal.d.ts +123 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +442 -0
- package/dist/terminal.js.map +1 -0
- package/dist/tui-alt-screen.d.ts +165 -0
- package/dist/tui-alt-screen.d.ts.map +1 -0
- package/dist/tui-alt-screen.js +1515 -0
- package/dist/tui-alt-screen.js.map +1 -0
- package/dist/tui-main-screen.d.ts +39 -0
- package/dist/tui-main-screen.d.ts.map +1 -0
- package/dist/tui-main-screen.js +594 -0
- package/dist/tui-main-screen.js.map +1 -0
- package/dist/tui.d.ts +431 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +1142 -0
- package/dist/tui.js.map +1 -0
- package/dist/undo-stack.d.ts +17 -0
- package/dist/undo-stack.d.ts.map +1 -0
- package/dist/undo-stack.js +25 -0
- package/dist/undo-stack.js.map +1 -0
- package/dist/utils.d.ts +98 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +1200 -0
- package/dist/utils.js.map +1 -0
- package/dist/word-navigation.d.ts +25 -0
- package/dist/word-navigation.d.ts.map +1 -0
- package/dist/word-navigation.js +96 -0
- package/dist/word-navigation.js.map +1 -0
- package/native/clipboard.h +170 -0
- package/native/darwin/README.md +22 -0
- package/native/darwin/build.sh +69 -0
- package/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/native/darwin/src/darwin-platform.m +93 -0
- package/native/linux/README.md +23 -0
- package/native/linux/build.sh +65 -0
- package/native/linux/prebuilds/linux-arm64/linux-platform-x11.node +0 -0
- package/native/linux/prebuilds/linux-x64/linux-platform-x11.node +0 -0
- package/native/linux/src/clipboard-worker.h +70 -0
- package/native/linux/src/linux-platform-x11.c +274 -0
- package/native/napi.h +89 -0
- package/native/win32/README.md +31 -0
- package/native/win32/build.mjs +232 -0
- package/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
- package/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
- package/native/win32/src/win32-platform.c +241 -0
- package/package.json +62 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { type KeyId } from "./keys.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Global keybinding registry.
|
|
4
|
+
* Downstream packages can add keybindings via declaration merging.
|
|
5
|
+
*/
|
|
6
|
+
export interface Keybindings {
|
|
7
|
+
"tui.editor.cursorUp": true;
|
|
8
|
+
"tui.editor.cursorDown": true;
|
|
9
|
+
"tui.editor.historyPrevious": true;
|
|
10
|
+
"tui.editor.historyNext": true;
|
|
11
|
+
"tui.editor.cursorLeft": true;
|
|
12
|
+
"tui.editor.cursorRight": true;
|
|
13
|
+
"tui.editor.cursorWordLeft": true;
|
|
14
|
+
"tui.editor.cursorWordRight": true;
|
|
15
|
+
"tui.editor.cursorLineStart": true;
|
|
16
|
+
"tui.editor.cursorLineEnd": true;
|
|
17
|
+
"tui.editor.jumpForward": true;
|
|
18
|
+
"tui.editor.jumpBackward": true;
|
|
19
|
+
"tui.editor.pageUp": true;
|
|
20
|
+
"tui.editor.pageDown": true;
|
|
21
|
+
"tui.editor.deleteCharBackward": true;
|
|
22
|
+
"tui.editor.deleteCharForward": true;
|
|
23
|
+
"tui.editor.deleteWordBackward": true;
|
|
24
|
+
"tui.editor.deleteWordForward": true;
|
|
25
|
+
"tui.editor.deleteToLineStart": true;
|
|
26
|
+
"tui.editor.deleteToLineEnd": true;
|
|
27
|
+
"tui.editor.yank": true;
|
|
28
|
+
"tui.editor.yankPop": true;
|
|
29
|
+
"tui.editor.undo": true;
|
|
30
|
+
"tui.input.newLine": true;
|
|
31
|
+
"tui.input.submit": true;
|
|
32
|
+
"tui.input.tab": true;
|
|
33
|
+
"tui.input.copy": true;
|
|
34
|
+
"tui.select.up": true;
|
|
35
|
+
"tui.select.down": true;
|
|
36
|
+
"tui.select.pageUp": true;
|
|
37
|
+
"tui.select.pageDown": true;
|
|
38
|
+
"tui.select.confirm": true;
|
|
39
|
+
"tui.select.cancel": true;
|
|
40
|
+
"tui.altScreen.pageUp": true;
|
|
41
|
+
"tui.altScreen.pageDown": true;
|
|
42
|
+
"tui.altScreen.halfPageUp": true;
|
|
43
|
+
"tui.altScreen.halfPageDown": true;
|
|
44
|
+
"tui.altScreen.lineUp": true;
|
|
45
|
+
"tui.altScreen.lineDown": true;
|
|
46
|
+
"tui.altScreen.previousPrompt": true;
|
|
47
|
+
"tui.altScreen.nextPrompt": true;
|
|
48
|
+
"tui.altScreen.search": true;
|
|
49
|
+
"tui.altScreen.searchNext": true;
|
|
50
|
+
"tui.altScreen.searchPrevious": true;
|
|
51
|
+
"tui.altScreen.searchClose": true;
|
|
52
|
+
"tui.altScreen.top": true;
|
|
53
|
+
"tui.altScreen.bottom": true;
|
|
54
|
+
}
|
|
55
|
+
export type Keybinding = keyof Keybindings;
|
|
56
|
+
/**
|
|
57
|
+
* Routing context for a keybinding.
|
|
58
|
+
*
|
|
59
|
+
* - `global`: active regardless of focus. Reserved for downstream app bindings;
|
|
60
|
+
* no stock `tui.*` binding uses it.
|
|
61
|
+
* - `transcript`: fullscreen viewport navigation. Consumed by the viewport input
|
|
62
|
+
* listener before the focused component sees the key.
|
|
63
|
+
* - `editor`: prompt editing. Handled by the focused editor.
|
|
64
|
+
* - `dialog`: selection lists and modal prompts. Handled by the focused overlay.
|
|
65
|
+
*
|
|
66
|
+
* Same-key claims across different contexts are intentional sharing, resolved by
|
|
67
|
+
* the single focus owner. Same-key claims within one context are reported by
|
|
68
|
+
* {@link KeybindingsManager.getContextConflicts}.
|
|
69
|
+
*/
|
|
70
|
+
export type KeybindingContext = "global" | "transcript" | "editor" | "dialog";
|
|
71
|
+
export interface KeybindingDefinition {
|
|
72
|
+
defaultKeys: KeyId | KeyId[];
|
|
73
|
+
description?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Routing context for this binding. Required on every stock `tui.*` binding
|
|
76
|
+
* (enforced by test); optional for downstream extension bindings, which
|
|
77
|
+
* default to `global` when omitted.
|
|
78
|
+
*/
|
|
79
|
+
context?: KeybindingContext;
|
|
80
|
+
}
|
|
81
|
+
export type KeybindingDefinitions = Record<string, KeybindingDefinition>;
|
|
82
|
+
export type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;
|
|
83
|
+
export declare const TUI_KEYBINDINGS: {
|
|
84
|
+
readonly "tui.editor.cursorUp": {
|
|
85
|
+
readonly context: "editor";
|
|
86
|
+
readonly defaultKeys: "up";
|
|
87
|
+
readonly description: "Move cursor up";
|
|
88
|
+
};
|
|
89
|
+
readonly "tui.editor.cursorDown": {
|
|
90
|
+
readonly context: "editor";
|
|
91
|
+
readonly defaultKeys: "down";
|
|
92
|
+
readonly description: "Move cursor down";
|
|
93
|
+
};
|
|
94
|
+
readonly "tui.editor.historyPrevious": {
|
|
95
|
+
readonly context: "editor";
|
|
96
|
+
readonly defaultKeys: [];
|
|
97
|
+
readonly description: "Select previous prompt history entry";
|
|
98
|
+
};
|
|
99
|
+
readonly "tui.editor.historyNext": {
|
|
100
|
+
readonly context: "editor";
|
|
101
|
+
readonly defaultKeys: [];
|
|
102
|
+
readonly description: "Select next prompt history entry";
|
|
103
|
+
};
|
|
104
|
+
readonly "tui.editor.cursorLeft": {
|
|
105
|
+
readonly context: "editor";
|
|
106
|
+
readonly defaultKeys: ["left", "ctrl+b"];
|
|
107
|
+
readonly description: "Move cursor left";
|
|
108
|
+
};
|
|
109
|
+
readonly "tui.editor.cursorRight": {
|
|
110
|
+
readonly context: "editor";
|
|
111
|
+
readonly defaultKeys: ["right", "ctrl+f"];
|
|
112
|
+
readonly description: "Move cursor right";
|
|
113
|
+
};
|
|
114
|
+
readonly "tui.editor.cursorWordLeft": {
|
|
115
|
+
readonly context: "editor";
|
|
116
|
+
readonly defaultKeys: ["alt+left", "ctrl+left", "alt+b"];
|
|
117
|
+
readonly description: "Move cursor word left";
|
|
118
|
+
};
|
|
119
|
+
readonly "tui.editor.cursorWordRight": {
|
|
120
|
+
readonly context: "editor";
|
|
121
|
+
readonly defaultKeys: ["alt+right", "ctrl+right", "alt+f"];
|
|
122
|
+
readonly description: "Move cursor word right";
|
|
123
|
+
};
|
|
124
|
+
readonly "tui.editor.cursorLineStart": {
|
|
125
|
+
readonly context: "editor";
|
|
126
|
+
readonly defaultKeys: ["home", "ctrl+home", "ctrl+a"];
|
|
127
|
+
readonly description: "Move to line start";
|
|
128
|
+
};
|
|
129
|
+
readonly "tui.editor.cursorLineEnd": {
|
|
130
|
+
readonly context: "editor";
|
|
131
|
+
readonly defaultKeys: ["end", "ctrl+end", "ctrl+e"];
|
|
132
|
+
readonly description: "Move to line end";
|
|
133
|
+
};
|
|
134
|
+
readonly "tui.editor.jumpForward": {
|
|
135
|
+
readonly context: "editor";
|
|
136
|
+
readonly defaultKeys: "ctrl+]";
|
|
137
|
+
readonly description: "Jump forward to character";
|
|
138
|
+
};
|
|
139
|
+
readonly "tui.editor.jumpBackward": {
|
|
140
|
+
readonly context: "editor";
|
|
141
|
+
readonly defaultKeys: "ctrl+alt+]";
|
|
142
|
+
readonly description: "Jump backward to character";
|
|
143
|
+
};
|
|
144
|
+
readonly "tui.editor.pageUp": {
|
|
145
|
+
readonly context: "editor";
|
|
146
|
+
readonly defaultKeys: ["pageUp", "ctrl+pageUp"];
|
|
147
|
+
readonly description: "Page up";
|
|
148
|
+
};
|
|
149
|
+
readonly "tui.editor.pageDown": {
|
|
150
|
+
readonly context: "editor";
|
|
151
|
+
readonly defaultKeys: ["pageDown", "ctrl+pageDown"];
|
|
152
|
+
readonly description: "Page down";
|
|
153
|
+
};
|
|
154
|
+
readonly "tui.editor.deleteCharBackward": {
|
|
155
|
+
readonly context: "editor";
|
|
156
|
+
readonly defaultKeys: "backspace";
|
|
157
|
+
readonly description: "Delete character backward";
|
|
158
|
+
};
|
|
159
|
+
readonly "tui.editor.deleteCharForward": {
|
|
160
|
+
readonly context: "editor";
|
|
161
|
+
readonly defaultKeys: ["delete", "ctrl+d"];
|
|
162
|
+
readonly description: "Delete character forward";
|
|
163
|
+
};
|
|
164
|
+
readonly "tui.editor.deleteWordBackward": {
|
|
165
|
+
readonly context: "editor";
|
|
166
|
+
readonly defaultKeys: ["ctrl+w", "alt+backspace"];
|
|
167
|
+
readonly description: "Delete word backward";
|
|
168
|
+
};
|
|
169
|
+
readonly "tui.editor.deleteWordForward": {
|
|
170
|
+
readonly context: "editor";
|
|
171
|
+
readonly defaultKeys: ["alt+d", "alt+delete"];
|
|
172
|
+
readonly description: "Delete word forward";
|
|
173
|
+
};
|
|
174
|
+
readonly "tui.editor.deleteToLineStart": {
|
|
175
|
+
readonly context: "editor";
|
|
176
|
+
readonly defaultKeys: "ctrl+u";
|
|
177
|
+
readonly description: "Delete to line start";
|
|
178
|
+
};
|
|
179
|
+
readonly "tui.editor.deleteToLineEnd": {
|
|
180
|
+
readonly context: "editor";
|
|
181
|
+
readonly defaultKeys: "ctrl+k";
|
|
182
|
+
readonly description: "Delete to line end";
|
|
183
|
+
};
|
|
184
|
+
readonly "tui.editor.yank": {
|
|
185
|
+
readonly context: "editor";
|
|
186
|
+
readonly defaultKeys: "ctrl+y";
|
|
187
|
+
readonly description: "Yank";
|
|
188
|
+
};
|
|
189
|
+
readonly "tui.editor.yankPop": {
|
|
190
|
+
readonly context: "editor";
|
|
191
|
+
readonly defaultKeys: "alt+y";
|
|
192
|
+
readonly description: "Yank pop";
|
|
193
|
+
};
|
|
194
|
+
readonly "tui.editor.undo": {
|
|
195
|
+
readonly context: "editor";
|
|
196
|
+
readonly defaultKeys: "ctrl+-";
|
|
197
|
+
readonly description: "Undo";
|
|
198
|
+
};
|
|
199
|
+
readonly "tui.input.newLine": {
|
|
200
|
+
readonly context: "editor";
|
|
201
|
+
readonly defaultKeys: ["shift+enter", "ctrl+j"];
|
|
202
|
+
readonly description: "Insert newline";
|
|
203
|
+
};
|
|
204
|
+
readonly "tui.input.submit": {
|
|
205
|
+
readonly context: "editor";
|
|
206
|
+
readonly defaultKeys: "enter";
|
|
207
|
+
readonly description: "Submit input";
|
|
208
|
+
};
|
|
209
|
+
readonly "tui.input.tab": {
|
|
210
|
+
readonly context: "editor";
|
|
211
|
+
readonly defaultKeys: "tab";
|
|
212
|
+
readonly description: "Tab / autocomplete";
|
|
213
|
+
};
|
|
214
|
+
readonly "tui.input.copy": {
|
|
215
|
+
readonly context: "editor";
|
|
216
|
+
readonly defaultKeys: "ctrl+c";
|
|
217
|
+
readonly description: "Copy selection";
|
|
218
|
+
};
|
|
219
|
+
readonly "tui.select.up": {
|
|
220
|
+
readonly context: "dialog";
|
|
221
|
+
readonly defaultKeys: "up";
|
|
222
|
+
readonly description: "Move selection up";
|
|
223
|
+
};
|
|
224
|
+
readonly "tui.select.down": {
|
|
225
|
+
readonly context: "dialog";
|
|
226
|
+
readonly defaultKeys: "down";
|
|
227
|
+
readonly description: "Move selection down";
|
|
228
|
+
};
|
|
229
|
+
readonly "tui.select.pageUp": {
|
|
230
|
+
readonly context: "dialog";
|
|
231
|
+
readonly defaultKeys: "pageUp";
|
|
232
|
+
readonly description: "Selection page up";
|
|
233
|
+
};
|
|
234
|
+
readonly "tui.select.pageDown": {
|
|
235
|
+
readonly context: "dialog";
|
|
236
|
+
readonly defaultKeys: "pageDown";
|
|
237
|
+
readonly description: "Selection page down";
|
|
238
|
+
};
|
|
239
|
+
readonly "tui.select.confirm": {
|
|
240
|
+
readonly context: "dialog";
|
|
241
|
+
readonly defaultKeys: "enter";
|
|
242
|
+
readonly description: "Confirm selection";
|
|
243
|
+
};
|
|
244
|
+
readonly "tui.select.cancel": {
|
|
245
|
+
readonly context: "dialog";
|
|
246
|
+
readonly defaultKeys: ["escape", "ctrl+c"];
|
|
247
|
+
readonly description: "Cancel selection";
|
|
248
|
+
};
|
|
249
|
+
readonly "tui.altScreen.pageUp": {
|
|
250
|
+
readonly context: "transcript";
|
|
251
|
+
readonly defaultKeys: "pageUp";
|
|
252
|
+
readonly description: "Scroll viewport up one page";
|
|
253
|
+
};
|
|
254
|
+
readonly "tui.altScreen.pageDown": {
|
|
255
|
+
readonly context: "transcript";
|
|
256
|
+
readonly defaultKeys: "pageDown";
|
|
257
|
+
readonly description: "Scroll viewport down one page";
|
|
258
|
+
};
|
|
259
|
+
readonly "tui.altScreen.halfPageUp": {
|
|
260
|
+
readonly context: "transcript";
|
|
261
|
+
readonly defaultKeys: [];
|
|
262
|
+
readonly description: "Scroll viewport up half a page";
|
|
263
|
+
};
|
|
264
|
+
readonly "tui.altScreen.halfPageDown": {
|
|
265
|
+
readonly context: "transcript";
|
|
266
|
+
readonly defaultKeys: [];
|
|
267
|
+
readonly description: "Scroll viewport down half a page";
|
|
268
|
+
};
|
|
269
|
+
readonly "tui.altScreen.lineUp": {
|
|
270
|
+
readonly context: "transcript";
|
|
271
|
+
readonly defaultKeys: [];
|
|
272
|
+
readonly description: "Scroll viewport up one line";
|
|
273
|
+
};
|
|
274
|
+
readonly "tui.altScreen.lineDown": {
|
|
275
|
+
readonly context: "transcript";
|
|
276
|
+
readonly defaultKeys: [];
|
|
277
|
+
readonly description: "Scroll viewport down one line";
|
|
278
|
+
};
|
|
279
|
+
readonly "tui.altScreen.previousPrompt": {
|
|
280
|
+
readonly context: "transcript";
|
|
281
|
+
readonly defaultKeys: ["ctrl+shift+up", "ctrl+up"];
|
|
282
|
+
readonly description: "Jump to previous semantic prompt";
|
|
283
|
+
};
|
|
284
|
+
readonly "tui.altScreen.nextPrompt": {
|
|
285
|
+
readonly context: "transcript";
|
|
286
|
+
readonly defaultKeys: ["ctrl+shift+down", "ctrl+down"];
|
|
287
|
+
readonly description: "Jump to next semantic prompt";
|
|
288
|
+
};
|
|
289
|
+
readonly "tui.altScreen.search": {
|
|
290
|
+
readonly context: "transcript";
|
|
291
|
+
readonly defaultKeys: "ctrl+shift+f";
|
|
292
|
+
readonly description: "Search the primary scroll view";
|
|
293
|
+
};
|
|
294
|
+
readonly "tui.altScreen.searchNext": {
|
|
295
|
+
readonly context: "transcript";
|
|
296
|
+
readonly defaultKeys: ["enter", "ctrl+g"];
|
|
297
|
+
readonly description: "Select the next search match";
|
|
298
|
+
};
|
|
299
|
+
readonly "tui.altScreen.searchPrevious": {
|
|
300
|
+
readonly context: "transcript";
|
|
301
|
+
readonly defaultKeys: ["shift+enter", "ctrl+shift+g"];
|
|
302
|
+
readonly description: "Select the previous search match";
|
|
303
|
+
};
|
|
304
|
+
readonly "tui.altScreen.searchClose": {
|
|
305
|
+
readonly context: "transcript";
|
|
306
|
+
readonly defaultKeys: "escape";
|
|
307
|
+
readonly description: "Close transcript search";
|
|
308
|
+
};
|
|
309
|
+
readonly "tui.altScreen.top": {
|
|
310
|
+
readonly context: "transcript";
|
|
311
|
+
readonly defaultKeys: "home";
|
|
312
|
+
readonly description: "Scroll viewport to top";
|
|
313
|
+
};
|
|
314
|
+
readonly "tui.altScreen.bottom": {
|
|
315
|
+
readonly context: "transcript";
|
|
316
|
+
readonly defaultKeys: "end";
|
|
317
|
+
readonly description: "Scroll viewport to bottom";
|
|
318
|
+
};
|
|
319
|
+
};
|
|
320
|
+
export interface KeybindingConflict {
|
|
321
|
+
key: KeyId;
|
|
322
|
+
keybindings: string[];
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Same key claimed by multiple bindings within one routing context. Unlike
|
|
326
|
+
* {@link KeybindingConflict} (user overrides only), this covers resolved
|
|
327
|
+
* bindings including defaults, so a conflict is visible at the declaration
|
|
328
|
+
* site instead of being discovered at runtime.
|
|
329
|
+
*/
|
|
330
|
+
export interface KeybindingContextConflict {
|
|
331
|
+
key: KeyId;
|
|
332
|
+
context: KeybindingContext;
|
|
333
|
+
keybindings: string[];
|
|
334
|
+
}
|
|
335
|
+
export declare class KeybindingsManager {
|
|
336
|
+
private definitions;
|
|
337
|
+
private userBindings;
|
|
338
|
+
private keysById;
|
|
339
|
+
private conflicts;
|
|
340
|
+
constructor(definitions: KeybindingDefinitions, userBindings?: KeybindingsConfig);
|
|
341
|
+
private rebuild;
|
|
342
|
+
matches(data: string, keybinding: Keybinding): boolean;
|
|
343
|
+
getKeys(keybinding: Keybinding): KeyId[];
|
|
344
|
+
getDefinition(keybinding: Keybinding): KeybindingDefinition;
|
|
345
|
+
getConflicts(): KeybindingConflict[];
|
|
346
|
+
/**
|
|
347
|
+
* Routing context declared for a binding. Extension bindings without a
|
|
348
|
+
* declared context default to `global`.
|
|
349
|
+
*/
|
|
350
|
+
getContext(keybinding: Keybinding): KeybindingContext;
|
|
351
|
+
/** All binding ids declared for one routing context. */
|
|
352
|
+
getBindingsByContext(context: KeybindingContext): Keybinding[];
|
|
353
|
+
/**
|
|
354
|
+
* Same-key claims within a single routing context across resolved bindings
|
|
355
|
+
* (defaults plus user overrides). Cross-context sharing (e.g. `enter` for
|
|
356
|
+
* both editor submit and dialog confirm) is intentional and resolved by the
|
|
357
|
+
* focus owner, so it is not reported here.
|
|
358
|
+
*/
|
|
359
|
+
getContextConflicts(): KeybindingContextConflict[];
|
|
360
|
+
setUserBindings(userBindings: KeybindingsConfig): void;
|
|
361
|
+
getUserBindings(): KeybindingsConfig;
|
|
362
|
+
getResolvedBindings(): KeybindingsConfig;
|
|
363
|
+
}
|
|
364
|
+
export declare function setKeybindings(keybindings: KeybindingsManager): void;
|
|
365
|
+
export declare function getKeybindings(): KeybindingsManager;
|
|
366
|
+
//# sourceMappingURL=keybindings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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.ts\";\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.historyPrevious\": true;\n\t\"tui.editor.historyNext\": 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\t// Alternate-screen viewport navigation\n\t\"tui.altScreen.pageUp\": true;\n\t\"tui.altScreen.pageDown\": true;\n\t\"tui.altScreen.halfPageUp\": true;\n\t\"tui.altScreen.halfPageDown\": true;\n\t\"tui.altScreen.lineUp\": true;\n\t\"tui.altScreen.lineDown\": true;\n\t\"tui.altScreen.previousPrompt\": true;\n\t\"tui.altScreen.nextPrompt\": true;\n\t\"tui.altScreen.search\": true;\n\t\"tui.altScreen.searchNext\": true;\n\t\"tui.altScreen.searchPrevious\": true;\n\t\"tui.altScreen.searchClose\": true;\n\t\"tui.altScreen.top\": true;\n\t\"tui.altScreen.bottom\": true;\n}\n\nexport type Keybinding = keyof Keybindings;\n\n/**\n * Routing context for a keybinding.\n *\n * - `global`: active regardless of focus. Reserved for downstream app bindings;\n * no stock `tui.*` binding uses it.\n * - `transcript`: fullscreen viewport navigation. Consumed by the viewport input\n * listener before the focused component sees the key.\n * - `editor`: prompt editing. Handled by the focused editor.\n * - `dialog`: selection lists and modal prompts. Handled by the focused overlay.\n *\n * Same-key claims across different contexts are intentional sharing, resolved by\n * the single focus owner. Same-key claims within one context are reported by\n * {@link KeybindingsManager.getContextConflicts}.\n */\nexport type KeybindingContext = \"global\" | \"transcript\" | \"editor\" | \"dialog\";\n\nexport interface KeybindingDefinition {\n\tdefaultKeys: KeyId | KeyId[];\n\tdescription?: string;\n\t/**\n\t * Routing context for this binding. Required on every stock `tui.*` binding\n\t * (enforced by test); optional for downstream extension bindings, which\n\t * default to `global` when omitted.\n\t */\n\tcontext?: KeybindingContext;\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\": { context: \"editor\", defaultKeys: \"up\", description: \"Move cursor up\" },\n\t\"tui.editor.cursorDown\": { context: \"editor\", defaultKeys: \"down\", description: \"Move cursor down\" },\n\t\"tui.editor.historyPrevious\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [],\n\t\tdescription: \"Select previous prompt history entry\",\n\t},\n\t\"tui.editor.historyNext\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [],\n\t\tdescription: \"Select next prompt history entry\",\n\t},\n\t\"tui.editor.cursorLeft\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"left\", \"ctrl+b\"],\n\t\tdescription: \"Move cursor left\",\n\t},\n\t\"tui.editor.cursorRight\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"right\", \"ctrl+f\"],\n\t\tdescription: \"Move cursor right\",\n\t},\n\t\"tui.editor.cursorWordLeft\": {\n\t\tcontext: \"editor\",\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\tcontext: \"editor\",\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\tcontext: \"editor\",\n\t\tdefaultKeys: [\"home\", \"ctrl+home\", \"ctrl+a\"],\n\t\tdescription: \"Move to line start\",\n\t},\n\t\"tui.editor.cursorLineEnd\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"end\", \"ctrl+end\", \"ctrl+e\"],\n\t\tdescription: \"Move to line end\",\n\t},\n\t\"tui.editor.jumpForward\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: \"ctrl+]\",\n\t\tdescription: \"Jump forward to character\",\n\t},\n\t\"tui.editor.jumpBackward\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: \"ctrl+alt+]\",\n\t\tdescription: \"Jump backward to character\",\n\t},\n\t\"tui.editor.pageUp\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"pageUp\", \"ctrl+pageUp\"],\n\t\tdescription: \"Page up\",\n\t},\n\t\"tui.editor.pageDown\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"pageDown\", \"ctrl+pageDown\"],\n\t\tdescription: \"Page down\",\n\t},\n\t\"tui.editor.deleteCharBackward\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: \"backspace\",\n\t\tdescription: \"Delete character backward\",\n\t},\n\t\"tui.editor.deleteCharForward\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"delete\", \"ctrl+d\"],\n\t\tdescription: \"Delete character forward\",\n\t},\n\t\"tui.editor.deleteWordBackward\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"ctrl+w\", \"alt+backspace\"],\n\t\tdescription: \"Delete word backward\",\n\t},\n\t\"tui.editor.deleteWordForward\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"alt+d\", \"alt+delete\"],\n\t\tdescription: \"Delete word forward\",\n\t},\n\t\"tui.editor.deleteToLineStart\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Delete to line start\",\n\t},\n\t\"tui.editor.deleteToLineEnd\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: \"ctrl+k\",\n\t\tdescription: \"Delete to line end\",\n\t},\n\t\"tui.editor.yank\": { context: \"editor\", defaultKeys: \"ctrl+y\", description: \"Yank\" },\n\t\"tui.editor.yankPop\": { context: \"editor\", defaultKeys: \"alt+y\", description: \"Yank pop\" },\n\t\"tui.editor.undo\": { context: \"editor\", defaultKeys: \"ctrl+-\", description: \"Undo\" },\n\t\"tui.input.newLine\": {\n\t\tcontext: \"editor\",\n\t\tdefaultKeys: [\"shift+enter\", \"ctrl+j\"],\n\t\tdescription: \"Insert newline\",\n\t},\n\t\"tui.input.submit\": { context: \"editor\", defaultKeys: \"enter\", description: \"Submit input\" },\n\t\"tui.input.tab\": { context: \"editor\", defaultKeys: \"tab\", description: \"Tab / autocomplete\" },\n\t\"tui.input.copy\": { context: \"editor\", defaultKeys: \"ctrl+c\", description: \"Copy selection\" },\n\t// Selection lists share keys (up/down/enter/escape/...) with editor and\n\t// transcript bindings by design; the single focus owner resolves them.\n\t\"tui.select.up\": { context: \"dialog\", defaultKeys: \"up\", description: \"Move selection up\" },\n\t\"tui.select.down\": { context: \"dialog\", defaultKeys: \"down\", description: \"Move selection down\" },\n\t\"tui.select.pageUp\": { context: \"dialog\", defaultKeys: \"pageUp\", description: \"Selection page up\" },\n\t\"tui.select.pageDown\": {\n\t\tcontext: \"dialog\",\n\t\tdefaultKeys: \"pageDown\",\n\t\tdescription: \"Selection page down\",\n\t},\n\t\"tui.select.confirm\": { context: \"dialog\", defaultKeys: \"enter\", description: \"Confirm selection\" },\n\t\"tui.select.cancel\": {\n\t\tcontext: \"dialog\",\n\t\tdefaultKeys: [\"escape\", \"ctrl+c\"],\n\t\tdescription: \"Cancel selection\",\n\t},\n\t// These intentionally shadow the unmodified editor bindings in fullscreen mode.\n\t// Viewport navigation shares keys (pageUp/pageDown/home/end/enter/escape/...)\n\t// with editor and dialog bindings by design; the focus owner resolves them.\n\t\"tui.altScreen.pageUp\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: \"pageUp\",\n\t\tdescription: \"Scroll viewport up one page\",\n\t},\n\t\"tui.altScreen.pageDown\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: \"pageDown\",\n\t\tdescription: \"Scroll viewport down one page\",\n\t},\n\t\"tui.altScreen.halfPageUp\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: [],\n\t\tdescription: \"Scroll viewport up half a page\",\n\t},\n\t\"tui.altScreen.halfPageDown\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: [],\n\t\tdescription: \"Scroll viewport down half a page\",\n\t},\n\t\"tui.altScreen.lineUp\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: [],\n\t\tdescription: \"Scroll viewport up one line\",\n\t},\n\t\"tui.altScreen.lineDown\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: [],\n\t\tdescription: \"Scroll viewport down one line\",\n\t},\n\t\"tui.altScreen.previousPrompt\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: [\"ctrl+shift+up\", \"ctrl+up\"],\n\t\tdescription: \"Jump to previous semantic prompt\",\n\t},\n\t\"tui.altScreen.nextPrompt\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: [\"ctrl+shift+down\", \"ctrl+down\"],\n\t\tdescription: \"Jump to next semantic prompt\",\n\t},\n\t\"tui.altScreen.search\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: \"ctrl+shift+f\",\n\t\tdescription: \"Search the primary scroll view\",\n\t},\n\t\"tui.altScreen.searchNext\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: [\"enter\", \"ctrl+g\"],\n\t\tdescription: \"Select the next search match\",\n\t},\n\t\"tui.altScreen.searchPrevious\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: [\"shift+enter\", \"ctrl+shift+g\"],\n\t\tdescription: \"Select the previous search match\",\n\t},\n\t\"tui.altScreen.searchClose\": {\n\t\tcontext: \"transcript\",\n\t\tdefaultKeys: \"escape\",\n\t\tdescription: \"Close transcript search\",\n\t},\n\t\"tui.altScreen.top\": { context: \"transcript\", defaultKeys: \"home\", description: \"Scroll viewport to top\" },\n\t\"tui.altScreen.bottom\": { context: \"transcript\", defaultKeys: \"end\", description: \"Scroll viewport to bottom\" },\n} as const satisfies KeybindingDefinitions;\n\nexport interface KeybindingConflict {\n\tkey: KeyId;\n\tkeybindings: string[];\n}\n\n/**\n * Same key claimed by multiple bindings within one routing context. Unlike\n * {@link KeybindingConflict} (user overrides only), this covers resolved\n * bindings including defaults, so a conflict is visible at the declaration\n * site instead of being discovered at runtime.\n */\nexport interface KeybindingContextConflict {\n\tkey: KeyId;\n\tcontext: KeybindingContext;\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\t/**\n\t * Routing context declared for a binding. Extension bindings without a\n\t * declared context default to `global`.\n\t */\n\tgetContext(keybinding: Keybinding): KeybindingContext {\n\t\treturn this.definitions[keybinding]?.context ?? \"global\";\n\t}\n\n\t/** All binding ids declared for one routing context. */\n\tgetBindingsByContext(context: KeybindingContext): Keybinding[] {\n\t\tconst result: Keybinding[] = [];\n\t\tfor (const id of Object.keys(this.definitions)) {\n\t\t\tif (this.getContext(id as Keybinding) === context) {\n\t\t\t\tresult.push(id as Keybinding);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Same-key claims within a single routing context across resolved bindings\n\t * (defaults plus user overrides). Cross-context sharing (e.g. `enter` for\n\t * both editor submit and dialog confirm) is intentional and resolved by the\n\t * focus owner, so it is not reported here.\n\t */\n\tgetContextConflicts(): KeybindingContextConflict[] {\n\t\tconst claims = new Map<KeyId, Map<KeybindingContext, Set<string>>>();\n\t\tfor (const [id, keys] of this.keysById) {\n\t\t\tconst context = this.getContext(id);\n\t\t\tfor (const key of keys) {\n\t\t\t\tlet byContext = claims.get(key);\n\t\t\t\tif (!byContext) {\n\t\t\t\t\tbyContext = new Map<KeybindingContext, Set<string>>();\n\t\t\t\t\tclaims.set(key, byContext);\n\t\t\t\t}\n\t\t\t\tlet keybindings = byContext.get(context);\n\t\t\t\tif (!keybindings) {\n\t\t\t\t\tkeybindings = new Set<string>();\n\t\t\t\t\tbyContext.set(context, keybindings);\n\t\t\t\t}\n\t\t\t\tkeybindings.add(id);\n\t\t\t}\n\t\t}\n\t\tconst conflicts: KeybindingContextConflict[] = [];\n\t\tfor (const [key, byContext] of claims) {\n\t\t\tfor (const [context, keybindings] of byContext) {\n\t\t\t\tif (keybindings.size > 1) {\n\t\t\t\t\tconflicts.push({ key, context, keybindings: [...keybindings].sort() });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconflicts.sort((a, b) => a.context.localeCompare(b.context) || a.key.localeCompare(b.key));\n\t\treturn conflicts;\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"]}
|