@dungle-scrubs/tallow 0.9.4 → 0.9.7
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/cli.js +8 -5
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/interactive-mode-patch.d.ts +24 -12
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +229 -146
- package/dist/interactive-mode-patch.js.map +1 -1
- package/dist/interactive-reset.d.ts +49 -0
- package/dist/interactive-reset.d.ts.map +1 -0
- package/dist/interactive-reset.js +40 -0
- package/dist/interactive-reset.js.map +1 -0
- package/dist/pi-tui-editor-patch.d.ts +10 -0
- package/dist/pi-tui-editor-patch.d.ts.map +1 -0
- package/dist/pi-tui-editor-patch.js +159 -0
- package/dist/pi-tui-editor-patch.js.map +1 -0
- package/dist/pi-tui-patch.d.ts +2 -0
- package/dist/pi-tui-patch.d.ts.map +1 -0
- package/dist/pi-tui-patch.js +563 -0
- package/dist/pi-tui-patch.js.map +1 -0
- package/dist/pi-tui-settings-list-patch.d.ts +11 -0
- package/dist/pi-tui-settings-list-patch.d.ts.map +1 -0
- package/dist/pi-tui-settings-list-patch.js +38 -0
- package/dist/pi-tui-settings-list-patch.js.map +1 -0
- package/dist/process-cleanup.js +1 -1
- package/dist/process-cleanup.js.map +1 -1
- package/dist/reset-diagnostics.d.ts +69 -0
- package/dist/reset-diagnostics.d.ts.map +1 -0
- package/dist/reset-diagnostics.js +41 -0
- package/dist/reset-diagnostics.js.map +1 -0
- package/dist/sdk.d.ts +7 -23
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +211 -174
- package/dist/sdk.js.map +1 -1
- package/dist/workspace-transition-interactive.d.ts +1 -0
- package/dist/workspace-transition-interactive.d.ts.map +1 -1
- package/dist/workspace-transition-interactive.js +8 -18
- package/dist/workspace-transition-interactive.js.map +1 -1
- package/extensions/__integration__/audit-findings.test.ts +4 -5
- package/extensions/_icons/index.ts +2 -4
- package/extensions/_shared/__tests__/image-metadata.test.ts +33 -0
- package/extensions/_shared/__tests__/shell-policy.test.ts +19 -0
- package/extensions/_shared/__tests__/terminal-links.test.ts +18 -0
- package/extensions/_shared/image-metadata.ts +99 -0
- package/extensions/_shared/inline-preview.ts +1 -1
- package/extensions/_shared/shell-policy.ts +121 -1
- package/extensions/_shared/terminal-links.ts +22 -0
- package/extensions/ask-user-question-tool/index.ts +0 -3
- package/extensions/clear/__tests__/clear.test.ts +269 -2
- package/extensions/command-expansion/index.ts +9 -3
- package/extensions/context-files/index.ts +5 -1
- package/extensions/context-fork/__tests__/context-fork.test.ts +94 -1
- package/extensions/context-fork/extension.json +1 -1
- package/extensions/context-fork/frontmatter-index.ts +6 -1
- package/extensions/context-fork/index.ts +32 -0
- package/extensions/edit-tool-enhanced/index.ts +2 -1
- package/extensions/git-status/__tests__/git-status.test.ts +65 -2
- package/extensions/git-status/index.ts +268 -98
- package/extensions/hooks/index.ts +33 -11
- package/extensions/loop/index.ts +14 -1
- package/extensions/lsp/index.ts +64 -13
- package/extensions/lsp/package.json +2 -2
- package/extensions/minimal-skill-display/index.ts +7 -1
- package/extensions/random-spinner/index.ts +7 -642
- package/extensions/read-tool-enhanced/index.ts +13 -10
- package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +2 -3
- package/extensions/render-stabilizer/index.ts +6 -6
- package/extensions/rewind/__tests__/session-files.test.ts +115 -0
- package/extensions/rewind/__tests__/snapshots.test.ts +23 -0
- package/extensions/rewind/index.ts +5 -0
- package/extensions/rewind/session-files.ts +138 -0
- package/extensions/rewind/snapshots.ts +104 -5
- package/extensions/skill-commands/index.ts +6 -1
- package/extensions/slash-command-bridge/__tests__/slash-command-bridge.test.ts +26 -0
- package/extensions/slash-command-bridge/index.ts +14 -2
- package/extensions/subagent-tool/model-resolver.ts +274 -7
- package/extensions/subagent-tool/schema.ts +1 -2
- package/extensions/tasks/commands/register-tasks-extension.ts +9 -9
- package/extensions/teams-tool/tools/register-extension.ts +1 -3
- package/extensions/teams-tool/tools/teammate-tools.ts +1 -2
- package/extensions/web-search-tool/index.ts +2 -1
- package/extensions/wezterm-pane-control/index.ts +1 -2
- package/extensions/write-tool-enhanced/index.ts +2 -1
- package/node_modules/@mariozechner/pi-tui/README.md +56 -34
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts +18 -13
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js +182 -113
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js +3 -3
- package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts +45 -36
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.js +489 -325
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts +1 -99
- package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/image.js +17 -192
- package/node_modules/@mariozechner/pi-tui/dist/components/image.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/input.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/input.js +57 -60
- package/node_modules/@mariozechner/pi-tui/dist/components/input.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts +2 -69
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.js +5 -102
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js +111 -53
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts +19 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js +78 -67
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts +1 -25
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js +13 -50
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/index.d.ts +8 -10
- package/node_modules/@mariozechner/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/index.js +6 -9
- package/node_modules/@mariozechner/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts +108 -238
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.js +108 -365
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts +33 -48
- package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keys.js +239 -155
- package/node_modules/@mariozechner/pi-tui/dist/keys.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts +14 -94
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js +44 -186
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts +13 -58
- package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal.js +78 -111
- package/node_modules/@mariozechner/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +24 -110
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.js +188 -435
- package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts +0 -18
- package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/utils.js +251 -119
- package/node_modules/@mariozechner/pi-tui/dist/utils.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/package.json +6 -6
- package/node_modules/@mariozechner/pi-tui/src/__tests__/__snapshots__/render.test.ts.snap +3 -40
- package/node_modules/@mariozechner/pi-tui/src/__tests__/image-component.test.ts +71 -81
- package/node_modules/@mariozechner/pi-tui/src/__tests__/render.test.ts +0 -33
- package/node_modules/@mariozechner/pi-tui/src/__tests__/terminal-image.test.ts +93 -334
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-render-scheduling.test.ts +1 -1
- package/node_modules/@mariozechner/pi-tui/src/__tests__/utils.test.ts +11 -196
- package/node_modules/@mariozechner/pi-tui/src/autocomplete.ts +228 -142
- package/node_modules/@mariozechner/pi-tui/src/components/cancellable-loader.ts +3 -3
- package/node_modules/@mariozechner/pi-tui/src/components/editor.ts +624 -390
- package/node_modules/@mariozechner/pi-tui/src/components/image.ts +17 -227
- package/node_modules/@mariozechner/pi-tui/src/components/input.ts +71 -63
- package/node_modules/@mariozechner/pi-tui/src/components/loader.ts +5 -137
- package/node_modules/@mariozechner/pi-tui/src/components/markdown.ts +143 -52
- package/node_modules/@mariozechner/pi-tui/src/components/select-list.ts +136 -70
- package/node_modules/@mariozechner/pi-tui/src/components/settings-list.ts +12 -51
- package/node_modules/@mariozechner/pi-tui/src/index.ts +17 -36
- package/node_modules/@mariozechner/pi-tui/src/keybindings.ts +148 -421
- package/node_modules/@mariozechner/pi-tui/src/keys.ts +253 -181
- package/node_modules/@mariozechner/pi-tui/src/terminal-image.ts +51 -252
- package/node_modules/@mariozechner/pi-tui/src/terminal.ts +78 -133
- package/node_modules/@mariozechner/pi-tui/src/tui.ts +202 -478
- package/node_modules/@mariozechner/pi-tui/src/utils.ts +289 -125
- package/node_modules/@mariozechner/pi-tui/tsconfig.build.json +1 -0
- package/package.json +13 -13
- package/packages/tallow-tui/node_modules/@types/mime-types/README.md +8 -2
- package/packages/tallow-tui/node_modules/@types/mime-types/index.d.ts +6 -0
- package/packages/tallow-tui/node_modules/@types/mime-types/package.json +9 -3
- package/packages/tallow-tui/node_modules/get-east-asian-width/lookup-data.js +18 -0
- package/packages/tallow-tui/node_modules/get-east-asian-width/lookup.js +116 -384
- package/packages/tallow-tui/node_modules/get-east-asian-width/package.json +5 -4
- package/packages/tallow-tui/node_modules/get-east-asian-width/utilities.js +24 -0
- package/packages/tallow-tui/node_modules/marked/README.md +5 -4
- package/packages/tallow-tui/node_modules/marked/bin/main.js +10 -8
- package/packages/tallow-tui/node_modules/marked/bin/marked.js +2 -1
- package/packages/tallow-tui/node_modules/marked/lib/marked.d.ts +156 -125
- package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js +67 -2179
- package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js.map +3 -3
- package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js +67 -2201
- package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js.map +3 -3
- package/packages/tallow-tui/node_modules/marked/man/marked.1 +4 -2
- package/packages/tallow-tui/node_modules/marked/man/marked.1.md +2 -1
- package/packages/tallow-tui/node_modules/marked/package.json +26 -34
- package/skills/tallow-expert/SKILL.md +3 -5
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts +0 -32
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.js +0 -46
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts +0 -52
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js +0 -89
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts +0 -14
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js +0 -55
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-change-listener.test.ts +0 -121
- package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-ghost-text.test.ts +0 -112
- package/node_modules/@mariozechner/pi-tui/src/__tests__/mouse-events.test.ts +0 -134
- package/node_modules/@mariozechner/pi-tui/src/__tests__/settings-list.test.ts +0 -81
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-diff-regression.test.ts +0 -555
- package/node_modules/@mariozechner/pi-tui/src/border-styles.ts +0 -60
- package/node_modules/@mariozechner/pi-tui/src/components/bordered-box.ts +0 -113
- package/node_modules/@mariozechner/pi-tui/src/test-utils/capability-env.ts +0 -56
- package/packages/tallow-tui/node_modules/marked/lib/marked.cjs +0 -2211
- package/packages/tallow-tui/node_modules/marked/lib/marked.cjs.map +0 -7
- package/packages/tallow-tui/node_modules/marked/lib/marked.d.cts +0 -728
- package/packages/tallow-tui/node_modules/marked/marked.min.js +0 -69
|
@@ -40,8 +40,8 @@ export function isKittyProtocolActive() {
|
|
|
40
40
|
* Usage:
|
|
41
41
|
* - Key.escape, Key.enter, Key.tab, etc. for special keys
|
|
42
42
|
* - Key.backtick, Key.comma, Key.period, etc. for symbol keys
|
|
43
|
-
* - Key.ctrl("c"), Key.alt("x") for single
|
|
44
|
-
* - Key.ctrlShift("p"), Key.ctrlAlt("x") for combined modifiers
|
|
43
|
+
* - Key.ctrl("c"), Key.alt("x"), Key.super("k") for single modifiers
|
|
44
|
+
* - Key.ctrlShift("p"), Key.ctrlAlt("x"), Key.ctrlSuper("k") for combined modifiers
|
|
45
45
|
*/
|
|
46
46
|
export const Key = {
|
|
47
47
|
// Special keys
|
|
@@ -111,6 +111,7 @@ export const Key = {
|
|
|
111
111
|
ctrl: (key) => `ctrl+${key}`,
|
|
112
112
|
shift: (key) => `shift+${key}`,
|
|
113
113
|
alt: (key) => `alt+${key}`,
|
|
114
|
+
super: (key) => `super+${key}`,
|
|
114
115
|
// Combined modifiers
|
|
115
116
|
ctrlShift: (key) => `ctrl+shift+${key}`,
|
|
116
117
|
shiftCtrl: (key) => `shift+ctrl+${key}`,
|
|
@@ -118,8 +119,15 @@ export const Key = {
|
|
|
118
119
|
altCtrl: (key) => `alt+ctrl+${key}`,
|
|
119
120
|
shiftAlt: (key) => `shift+alt+${key}`,
|
|
120
121
|
altShift: (key) => `alt+shift+${key}`,
|
|
122
|
+
ctrlSuper: (key) => `ctrl+super+${key}`,
|
|
123
|
+
superCtrl: (key) => `super+ctrl+${key}`,
|
|
124
|
+
shiftSuper: (key) => `shift+super+${key}`,
|
|
125
|
+
superShift: (key) => `super+shift+${key}`,
|
|
126
|
+
altSuper: (key) => `alt+super+${key}`,
|
|
127
|
+
superAlt: (key) => `super+alt+${key}`,
|
|
121
128
|
// Triple modifiers
|
|
122
129
|
ctrlShiftAlt: (key) => `ctrl+shift+alt+${key}`,
|
|
130
|
+
ctrlShiftSuper: (key) => `ctrl+shift+super+${key}`,
|
|
123
131
|
};
|
|
124
132
|
// =============================================================================
|
|
125
133
|
// Constants
|
|
@@ -161,6 +169,7 @@ const MODIFIERS = {
|
|
|
161
169
|
shift: 1,
|
|
162
170
|
alt: 2,
|
|
163
171
|
ctrl: 4,
|
|
172
|
+
super: 8,
|
|
164
173
|
};
|
|
165
174
|
const LOCK_MASK = 64 + 128; // Caps Lock + Num Lock
|
|
166
175
|
const CODEPOINTS = {
|
|
@@ -185,6 +194,38 @@ const FUNCTIONAL_CODEPOINTS = {
|
|
|
185
194
|
home: -14,
|
|
186
195
|
end: -15,
|
|
187
196
|
};
|
|
197
|
+
const KITTY_FUNCTIONAL_KEY_EQUIVALENTS = new Map([
|
|
198
|
+
[57399, 48], // KP_0 -> 0
|
|
199
|
+
[57400, 49], // KP_1 -> 1
|
|
200
|
+
[57401, 50], // KP_2 -> 2
|
|
201
|
+
[57402, 51], // KP_3 -> 3
|
|
202
|
+
[57403, 52], // KP_4 -> 4
|
|
203
|
+
[57404, 53], // KP_5 -> 5
|
|
204
|
+
[57405, 54], // KP_6 -> 6
|
|
205
|
+
[57406, 55], // KP_7 -> 7
|
|
206
|
+
[57407, 56], // KP_8 -> 8
|
|
207
|
+
[57408, 57], // KP_9 -> 9
|
|
208
|
+
[57409, 46], // KP_DECIMAL -> .
|
|
209
|
+
[57410, 47], // KP_DIVIDE -> /
|
|
210
|
+
[57411, 42], // KP_MULTIPLY -> *
|
|
211
|
+
[57412, 45], // KP_SUBTRACT -> -
|
|
212
|
+
[57413, 43], // KP_ADD -> +
|
|
213
|
+
[57415, 61], // KP_EQUAL -> =
|
|
214
|
+
[57416, 44], // KP_SEPARATOR -> ,
|
|
215
|
+
[57417, ARROW_CODEPOINTS.left],
|
|
216
|
+
[57418, ARROW_CODEPOINTS.right],
|
|
217
|
+
[57419, ARROW_CODEPOINTS.up],
|
|
218
|
+
[57420, ARROW_CODEPOINTS.down],
|
|
219
|
+
[57421, FUNCTIONAL_CODEPOINTS.pageUp],
|
|
220
|
+
[57422, FUNCTIONAL_CODEPOINTS.pageDown],
|
|
221
|
+
[57423, FUNCTIONAL_CODEPOINTS.home],
|
|
222
|
+
[57424, FUNCTIONAL_CODEPOINTS.end],
|
|
223
|
+
[57425, FUNCTIONAL_CODEPOINTS.insert],
|
|
224
|
+
[57426, FUNCTIONAL_CODEPOINTS.delete],
|
|
225
|
+
]);
|
|
226
|
+
function normalizeKittyFunctionalCodepoint(codepoint) {
|
|
227
|
+
return KITTY_FUNCTIONAL_KEY_EQUIVALENTS.get(codepoint) ?? codepoint;
|
|
228
|
+
}
|
|
188
229
|
const LEGACY_KEY_SEQUENCES = {
|
|
189
230
|
up: ["\x1b[A", "\x1bOA"],
|
|
190
231
|
down: ["\x1b[B", "\x1bOB"],
|
|
@@ -306,15 +347,11 @@ const matchesLegacyModifierSequence = (data, key, modifier) => {
|
|
|
306
347
|
}
|
|
307
348
|
return false;
|
|
308
349
|
};
|
|
309
|
-
//
|
|
350
|
+
// Store the last parsed event type for isKeyRelease() to query
|
|
310
351
|
let _lastEventType = "press";
|
|
311
352
|
/**
|
|
312
|
-
* Check if the
|
|
313
|
-
* Performs fast pattern matching on raw terminal escape sequences.
|
|
353
|
+
* Check if the last parsed key event was a key release.
|
|
314
354
|
* Only meaningful when Kitty keyboard protocol with flag 2 is active.
|
|
315
|
-
*
|
|
316
|
-
* @param data - Raw terminal input string
|
|
317
|
-
* @returns true if the data contains a key release escape sequence
|
|
318
355
|
*/
|
|
319
356
|
export function isKeyRelease(data) {
|
|
320
357
|
// Don't treat bracketed paste content as key release, even if it contains
|
|
@@ -339,12 +376,8 @@ export function isKeyRelease(data) {
|
|
|
339
376
|
return false;
|
|
340
377
|
}
|
|
341
378
|
/**
|
|
342
|
-
* Check if the
|
|
343
|
-
* Performs fast pattern matching on raw terminal escape sequences.
|
|
379
|
+
* Check if the last parsed key event was a key repeat.
|
|
344
380
|
* Only meaningful when Kitty keyboard protocol with flag 2 is active.
|
|
345
|
-
*
|
|
346
|
-
* @param data - Raw terminal input string
|
|
347
|
-
* @returns true if the data contains a key repeat escape sequence
|
|
348
381
|
*/
|
|
349
382
|
export function isKeyRepeat(data) {
|
|
350
383
|
// Don't treat bracketed paste content as key repeat, even if it contains
|
|
@@ -444,8 +477,10 @@ function matchesKittySequence(data, expectedCodepoint, expectedModifier) {
|
|
|
444
477
|
// Check if modifiers match
|
|
445
478
|
if (actualMod !== expectedMod)
|
|
446
479
|
return false;
|
|
447
|
-
|
|
448
|
-
|
|
480
|
+
const normalizedCodepoint = normalizeKittyFunctionalCodepoint(parsed.codepoint);
|
|
481
|
+
const normalizedExpectedCodepoint = normalizeKittyFunctionalCodepoint(expectedCodepoint);
|
|
482
|
+
// Primary match: codepoint matches directly after normalizing functional keys
|
|
483
|
+
if (normalizedCodepoint === normalizedExpectedCodepoint)
|
|
449
484
|
return true;
|
|
450
485
|
// Alternate match: use base layout key for non-Latin keyboard layouts.
|
|
451
486
|
// This allows Ctrl+С (Cyrillic) to match Ctrl+c (Latin) when terminal reports
|
|
@@ -460,7 +495,7 @@ function matchesKittySequence(data, expectedCodepoint, expectedModifier) {
|
|
|
460
495
|
// (letter remapping) and Ctrl+/ could falsely match Ctrl+[ (symbol remapping)
|
|
461
496
|
// if the base layout key were always considered.
|
|
462
497
|
if (parsed.baseLayoutKey !== undefined && parsed.baseLayoutKey === expectedCodepoint) {
|
|
463
|
-
const cp =
|
|
498
|
+
const cp = normalizedCodepoint;
|
|
464
499
|
const isLatinLetter = cp >= 97 && cp <= 122; // a-z
|
|
465
500
|
const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(cp));
|
|
466
501
|
if (!isLatinLetter && !isKnownSymbol)
|
|
@@ -468,27 +503,25 @@ function matchesKittySequence(data, expectedCodepoint, expectedModifier) {
|
|
|
468
503
|
}
|
|
469
504
|
return false;
|
|
470
505
|
}
|
|
506
|
+
function parseModifyOtherKeysSequence(data) {
|
|
507
|
+
const match = data.match(/^\x1b\[27;(\d+);(\d+)~$/);
|
|
508
|
+
if (!match)
|
|
509
|
+
return null;
|
|
510
|
+
const modValue = parseInt(match[1], 10);
|
|
511
|
+
const codepoint = parseInt(match[2], 10);
|
|
512
|
+
return { codepoint, modifier: modValue - 1 };
|
|
513
|
+
}
|
|
471
514
|
/**
|
|
472
515
|
* Match xterm modifyOtherKeys format: CSI 27 ; modifiers ; keycode ~
|
|
473
516
|
* This is used by terminals when Kitty protocol is not enabled.
|
|
474
517
|
* Modifier values are 1-indexed: 2=shift, 3=alt, 5=ctrl, etc.
|
|
475
518
|
*/
|
|
476
519
|
function matchesModifyOtherKeys(data, expectedKeycode, expectedModifier) {
|
|
477
|
-
const
|
|
478
|
-
if (!
|
|
520
|
+
const parsed = parseModifyOtherKeysSequence(data);
|
|
521
|
+
if (!parsed)
|
|
479
522
|
return false;
|
|
480
|
-
|
|
481
|
-
const keycode = parseInt(match[2], 10);
|
|
482
|
-
// Convert from 1-indexed xterm format to our 0-indexed format
|
|
483
|
-
const actualMod = modValue - 1;
|
|
484
|
-
return keycode === expectedKeycode && actualMod === expectedModifier;
|
|
523
|
+
return parsed.codepoint === expectedKeycode && parsed.modifier === expectedModifier;
|
|
485
524
|
}
|
|
486
|
-
/**
|
|
487
|
-
* Detect Windows Terminal by session environment variable.
|
|
488
|
-
* Excludes SSH sessions where WT_SESSION may leak from the host.
|
|
489
|
-
*
|
|
490
|
-
* @returns true when running directly inside Windows Terminal
|
|
491
|
-
*/
|
|
492
525
|
function isWindowsTerminalSession() {
|
|
493
526
|
return (Boolean(process.env.WT_SESSION) &&
|
|
494
527
|
!process.env.SSH_CONNECTION &&
|
|
@@ -503,10 +536,6 @@ function isWindowsTerminalSession() {
|
|
|
503
536
|
*
|
|
504
537
|
* Prefer explicit Kitty / CSI-u / modifyOtherKeys sequences whenever they are
|
|
505
538
|
* available. Fall back to a Windows Terminal heuristic only for raw BS bytes.
|
|
506
|
-
*
|
|
507
|
-
* @param data - Raw terminal input byte
|
|
508
|
-
* @param expectedModifier - Modifier bitmask to match against
|
|
509
|
-
* @returns true if the data matches backspace with the given modifier
|
|
510
539
|
*/
|
|
511
540
|
function matchesRawBackspace(data, expectedModifier) {
|
|
512
541
|
if (data === "\x7f")
|
|
@@ -543,6 +572,30 @@ function rawCtrlChar(key) {
|
|
|
543
572
|
}
|
|
544
573
|
return null;
|
|
545
574
|
}
|
|
575
|
+
function isDigitKey(key) {
|
|
576
|
+
return key >= "0" && key <= "9";
|
|
577
|
+
}
|
|
578
|
+
function matchesPrintableModifyOtherKeys(data, expectedKeycode, expectedModifier) {
|
|
579
|
+
if (expectedModifier === 0)
|
|
580
|
+
return false;
|
|
581
|
+
return matchesModifyOtherKeys(data, expectedKeycode, expectedModifier);
|
|
582
|
+
}
|
|
583
|
+
function formatKeyNameWithModifiers(keyName, modifier) {
|
|
584
|
+
const mods = [];
|
|
585
|
+
const effectiveMod = modifier & ~LOCK_MASK;
|
|
586
|
+
const supportedModifierMask = MODIFIERS.shift | MODIFIERS.ctrl | MODIFIERS.alt | MODIFIERS.super;
|
|
587
|
+
if ((effectiveMod & ~supportedModifierMask) !== 0)
|
|
588
|
+
return undefined;
|
|
589
|
+
if (effectiveMod & MODIFIERS.shift)
|
|
590
|
+
mods.push("shift");
|
|
591
|
+
if (effectiveMod & MODIFIERS.ctrl)
|
|
592
|
+
mods.push("ctrl");
|
|
593
|
+
if (effectiveMod & MODIFIERS.alt)
|
|
594
|
+
mods.push("alt");
|
|
595
|
+
if (effectiveMod & MODIFIERS.super)
|
|
596
|
+
mods.push("super");
|
|
597
|
+
return mods.length > 0 ? `${mods.join("+")}+${keyName}` : keyName;
|
|
598
|
+
}
|
|
546
599
|
function parseKeyId(keyId) {
|
|
547
600
|
const parts = keyId.toLowerCase().split("+");
|
|
548
601
|
const key = parts[parts.length - 1];
|
|
@@ -553,6 +606,7 @@ function parseKeyId(keyId) {
|
|
|
553
606
|
ctrl: parts.includes("ctrl"),
|
|
554
607
|
shift: parts.includes("shift"),
|
|
555
608
|
alt: parts.includes("alt"),
|
|
609
|
+
super: parts.includes("super"),
|
|
556
610
|
};
|
|
557
611
|
}
|
|
558
612
|
/**
|
|
@@ -564,9 +618,10 @@ function parseKeyId(keyId) {
|
|
|
564
618
|
* - Ctrl combinations: "ctrl+c", "ctrl+z", etc.
|
|
565
619
|
* - Shift combinations: "shift+tab", "shift+enter"
|
|
566
620
|
* - Alt combinations: "alt+enter", "alt+backspace"
|
|
567
|
-
* -
|
|
621
|
+
* - Super combinations: "super+k", "super+enter"
|
|
622
|
+
* - Combined modifiers: "shift+ctrl+p", "ctrl+alt+x", "ctrl+super+k"
|
|
568
623
|
*
|
|
569
|
-
* Use the Key helper for autocomplete: Key.ctrl("c"), Key.escape, Key.ctrlShift("p")
|
|
624
|
+
* Use the Key helper for autocomplete: Key.ctrl("c"), Key.escape, Key.ctrlShift("p"), Key.super("k")
|
|
570
625
|
*
|
|
571
626
|
* @param data - Raw input data from terminal
|
|
572
627
|
* @param keyId - Key identifier (e.g., "ctrl+c", "escape", Key.ctrl("c"))
|
|
@@ -575,7 +630,7 @@ export function matchesKey(data, keyId) {
|
|
|
575
630
|
const parsed = parseKeyId(keyId);
|
|
576
631
|
if (!parsed)
|
|
577
632
|
return false;
|
|
578
|
-
const { key, ctrl, shift, alt } = parsed;
|
|
633
|
+
const { key, ctrl, shift, alt, super: superModifier } = parsed;
|
|
579
634
|
let modifier = 0;
|
|
580
635
|
if (shift)
|
|
581
636
|
modifier |= MODIFIERS.shift;
|
|
@@ -583,6 +638,8 @@ export function matchesKey(data, keyId) {
|
|
|
583
638
|
modifier |= MODIFIERS.alt;
|
|
584
639
|
if (ctrl)
|
|
585
640
|
modifier |= MODIFIERS.ctrl;
|
|
641
|
+
if (superModifier)
|
|
642
|
+
modifier |= MODIFIERS.super;
|
|
586
643
|
switch (key) {
|
|
587
644
|
case "escape":
|
|
588
645
|
case "esc":
|
|
@@ -593,10 +650,10 @@ export function matchesKey(data, keyId) {
|
|
|
593
650
|
matchesModifyOtherKeys(data, CODEPOINTS.escape, 0));
|
|
594
651
|
case "space":
|
|
595
652
|
if (!_kittyProtocolActive) {
|
|
596
|
-
if (
|
|
653
|
+
if (modifier === MODIFIERS.ctrl && data === "\x00") {
|
|
597
654
|
return true;
|
|
598
655
|
}
|
|
599
|
-
if (
|
|
656
|
+
if (modifier === MODIFIERS.alt && data === "\x1b ") {
|
|
600
657
|
return true;
|
|
601
658
|
}
|
|
602
659
|
}
|
|
@@ -608,8 +665,10 @@ export function matchesKey(data, keyId) {
|
|
|
608
665
|
return (matchesKittySequence(data, CODEPOINTS.space, modifier) ||
|
|
609
666
|
matchesModifyOtherKeys(data, CODEPOINTS.space, modifier));
|
|
610
667
|
case "tab":
|
|
611
|
-
if (
|
|
612
|
-
return data === "\x1b[Z" ||
|
|
668
|
+
if (modifier === MODIFIERS.shift) {
|
|
669
|
+
return (data === "\x1b[Z" ||
|
|
670
|
+
matchesKittySequence(data, CODEPOINTS.tab, MODIFIERS.shift) ||
|
|
671
|
+
matchesModifyOtherKeys(data, CODEPOINTS.tab, MODIFIERS.shift));
|
|
613
672
|
}
|
|
614
673
|
if (modifier === 0) {
|
|
615
674
|
return data === "\t" || matchesKittySequence(data, CODEPOINTS.tab, 0);
|
|
@@ -618,7 +677,7 @@ export function matchesKey(data, keyId) {
|
|
|
618
677
|
matchesModifyOtherKeys(data, CODEPOINTS.tab, modifier));
|
|
619
678
|
case "enter":
|
|
620
679
|
case "return":
|
|
621
|
-
if (
|
|
680
|
+
if (modifier === MODIFIERS.shift) {
|
|
622
681
|
// CSI u sequences (standard Kitty protocol)
|
|
623
682
|
if (matchesKittySequence(data, CODEPOINTS.enter, MODIFIERS.shift) ||
|
|
624
683
|
matchesKittySequence(data, CODEPOINTS.kpEnter, MODIFIERS.shift)) {
|
|
@@ -636,7 +695,7 @@ export function matchesKey(data, keyId) {
|
|
|
636
695
|
}
|
|
637
696
|
return false;
|
|
638
697
|
}
|
|
639
|
-
if (
|
|
698
|
+
if (modifier === MODIFIERS.alt) {
|
|
640
699
|
// CSI u sequences (standard Kitty protocol)
|
|
641
700
|
if (matchesKittySequence(data, CODEPOINTS.enter, MODIFIERS.alt) ||
|
|
642
701
|
matchesKittySequence(data, CODEPOINTS.kpEnter, MODIFIERS.alt)) {
|
|
@@ -664,14 +723,14 @@ export function matchesKey(data, keyId) {
|
|
|
664
723
|
matchesKittySequence(data, CODEPOINTS.kpEnter, modifier) ||
|
|
665
724
|
matchesModifyOtherKeys(data, CODEPOINTS.enter, modifier));
|
|
666
725
|
case "backspace":
|
|
667
|
-
if (
|
|
726
|
+
if (modifier === MODIFIERS.alt) {
|
|
668
727
|
if (data === "\x1b\x7f" || data === "\x1b\b") {
|
|
669
728
|
return true;
|
|
670
729
|
}
|
|
671
730
|
return (matchesKittySequence(data, CODEPOINTS.backspace, MODIFIERS.alt) ||
|
|
672
731
|
matchesModifyOtherKeys(data, CODEPOINTS.backspace, MODIFIERS.alt));
|
|
673
732
|
}
|
|
674
|
-
if (
|
|
733
|
+
if (modifier === MODIFIERS.ctrl) {
|
|
675
734
|
// Legacy raw 0x08 is ambiguous: it can be Ctrl+Backspace on Windows
|
|
676
735
|
// Terminal or plain Backspace on other terminals, while also
|
|
677
736
|
// overlapping with Ctrl+H.
|
|
@@ -747,7 +806,7 @@ export function matchesKey(data, keyId) {
|
|
|
747
806
|
}
|
|
748
807
|
return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageDown, modifier);
|
|
749
808
|
case "up":
|
|
750
|
-
if (
|
|
809
|
+
if (modifier === MODIFIERS.alt) {
|
|
751
810
|
return data === "\x1bp" || matchesKittySequence(data, ARROW_CODEPOINTS.up, MODIFIERS.alt);
|
|
752
811
|
}
|
|
753
812
|
if (modifier === 0) {
|
|
@@ -759,7 +818,7 @@ export function matchesKey(data, keyId) {
|
|
|
759
818
|
}
|
|
760
819
|
return matchesKittySequence(data, ARROW_CODEPOINTS.up, modifier);
|
|
761
820
|
case "down":
|
|
762
|
-
if (
|
|
821
|
+
if (modifier === MODIFIERS.alt) {
|
|
763
822
|
return data === "\x1bn" || matchesKittySequence(data, ARROW_CODEPOINTS.down, MODIFIERS.alt);
|
|
764
823
|
}
|
|
765
824
|
if (modifier === 0) {
|
|
@@ -771,13 +830,13 @@ export function matchesKey(data, keyId) {
|
|
|
771
830
|
}
|
|
772
831
|
return matchesKittySequence(data, ARROW_CODEPOINTS.down, modifier);
|
|
773
832
|
case "left":
|
|
774
|
-
if (
|
|
833
|
+
if (modifier === MODIFIERS.alt) {
|
|
775
834
|
return (data === "\x1b[1;3D" ||
|
|
776
835
|
(!_kittyProtocolActive && data === "\x1bB") ||
|
|
777
836
|
data === "\x1bb" ||
|
|
778
837
|
matchesKittySequence(data, ARROW_CODEPOINTS.left, MODIFIERS.alt));
|
|
779
838
|
}
|
|
780
|
-
if (
|
|
839
|
+
if (modifier === MODIFIERS.ctrl) {
|
|
781
840
|
return (data === "\x1b[1;5D" ||
|
|
782
841
|
matchesLegacyModifierSequence(data, "left", MODIFIERS.ctrl) ||
|
|
783
842
|
matchesKittySequence(data, ARROW_CODEPOINTS.left, MODIFIERS.ctrl));
|
|
@@ -791,13 +850,13 @@ export function matchesKey(data, keyId) {
|
|
|
791
850
|
}
|
|
792
851
|
return matchesKittySequence(data, ARROW_CODEPOINTS.left, modifier);
|
|
793
852
|
case "right":
|
|
794
|
-
if (
|
|
853
|
+
if (modifier === MODIFIERS.alt) {
|
|
795
854
|
return (data === "\x1b[1;3C" ||
|
|
796
855
|
(!_kittyProtocolActive && data === "\x1bF") ||
|
|
797
856
|
data === "\x1bf" ||
|
|
798
857
|
matchesKittySequence(data, ARROW_CODEPOINTS.right, MODIFIERS.alt));
|
|
799
858
|
}
|
|
800
|
-
if (
|
|
859
|
+
if (modifier === MODIFIERS.ctrl) {
|
|
801
860
|
return (data === "\x1b[1;5C" ||
|
|
802
861
|
matchesLegacyModifierSequence(data, "right", MODIFIERS.ctrl) ||
|
|
803
862
|
matchesKittySequence(data, ARROW_CODEPOINTS.right, MODIFIERS.ctrl));
|
|
@@ -829,40 +888,45 @@ export function matchesKey(data, keyId) {
|
|
|
829
888
|
return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES[functionKey]);
|
|
830
889
|
}
|
|
831
890
|
}
|
|
832
|
-
// Handle single letter keys
|
|
833
|
-
if (key.length === 1 && ((key >= "a" && key <= "z") || SYMBOL_KEYS.has(key))) {
|
|
891
|
+
// Handle single letter/digit keys and symbols
|
|
892
|
+
if (key.length === 1 && ((key >= "a" && key <= "z") || isDigitKey(key) || SYMBOL_KEYS.has(key))) {
|
|
834
893
|
const codepoint = key.charCodeAt(0);
|
|
835
894
|
const rawCtrl = rawCtrlChar(key);
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
895
|
+
const isLetter = key >= "a" && key <= "z";
|
|
896
|
+
const isDigit = isDigitKey(key);
|
|
897
|
+
if (modifier === MODIFIERS.ctrl + MODIFIERS.alt && !_kittyProtocolActive && rawCtrl) {
|
|
898
|
+
// Legacy: ctrl+alt+key is ESC followed by the control character.
|
|
899
|
+
// If that legacy form does not match, continue so CSI-u and
|
|
900
|
+
// modifyOtherKeys sequences from tmux can still be recognized.
|
|
901
|
+
if (data === `\x1b${rawCtrl}`)
|
|
902
|
+
return true;
|
|
839
903
|
}
|
|
840
|
-
if (
|
|
841
|
-
// Legacy: alt+letter is ESC followed by the
|
|
904
|
+
if (modifier === MODIFIERS.alt && !_kittyProtocolActive && (isLetter || isDigit)) {
|
|
905
|
+
// Legacy: alt+letter/digit is ESC followed by the key
|
|
842
906
|
if (data === `\x1b${key}`)
|
|
843
907
|
return true;
|
|
844
908
|
}
|
|
845
|
-
if (
|
|
909
|
+
if (modifier === MODIFIERS.ctrl) {
|
|
846
910
|
// Legacy: ctrl+key sends the control character
|
|
847
911
|
if (rawCtrl && data === rawCtrl)
|
|
848
912
|
return true;
|
|
849
913
|
return (matchesKittySequence(data, codepoint, MODIFIERS.ctrl) ||
|
|
850
|
-
|
|
914
|
+
matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.ctrl));
|
|
851
915
|
}
|
|
852
|
-
if (
|
|
916
|
+
if (modifier === MODIFIERS.shift + MODIFIERS.ctrl) {
|
|
853
917
|
return (matchesKittySequence(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl) ||
|
|
854
|
-
|
|
918
|
+
matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl));
|
|
855
919
|
}
|
|
856
|
-
if (
|
|
920
|
+
if (modifier === MODIFIERS.shift) {
|
|
857
921
|
// Legacy: shift+letter produces uppercase
|
|
858
|
-
if (data === key.toUpperCase())
|
|
922
|
+
if (isLetter && data === key.toUpperCase())
|
|
859
923
|
return true;
|
|
860
924
|
return (matchesKittySequence(data, codepoint, MODIFIERS.shift) ||
|
|
861
|
-
|
|
925
|
+
matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.shift));
|
|
862
926
|
}
|
|
863
927
|
if (modifier !== 0) {
|
|
864
928
|
return (matchesKittySequence(data, codepoint, modifier) ||
|
|
865
|
-
|
|
929
|
+
matchesPrintableModifyOtherKeys(data, codepoint, modifier));
|
|
866
930
|
}
|
|
867
931
|
// Check both raw char and Kitty sequence (needed for release events)
|
|
868
932
|
return data === key || matchesKittySequence(data, codepoint, 0);
|
|
@@ -875,64 +939,68 @@ export function matchesKey(data, keyId) {
|
|
|
875
939
|
* @param data - Raw input data from terminal
|
|
876
940
|
* @returns Key identifier string (e.g., "ctrl+c") or undefined
|
|
877
941
|
*/
|
|
942
|
+
function formatParsedKey(codepoint, modifier, baseLayoutKey) {
|
|
943
|
+
const normalizedCodepoint = normalizeKittyFunctionalCodepoint(codepoint);
|
|
944
|
+
// Use base layout key only when codepoint is not a recognized Latin
|
|
945
|
+
// letter (a-z), digit (0-9), or symbol (/, -, [, ;, etc.). For those,
|
|
946
|
+
// the codepoint is authoritative regardless of physical key position.
|
|
947
|
+
// This prevents remapped layouts (Dvorak, Colemak, xremap, etc.) from
|
|
948
|
+
// reporting the wrong key name based on the QWERTY physical position.
|
|
949
|
+
const isLatinLetter = normalizedCodepoint >= 97 && normalizedCodepoint <= 122; // a-z
|
|
950
|
+
const isDigit = normalizedCodepoint >= 48 && normalizedCodepoint <= 57; // 0-9
|
|
951
|
+
const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(normalizedCodepoint));
|
|
952
|
+
const effectiveCodepoint = isLatinLetter || isDigit || isKnownSymbol
|
|
953
|
+
? normalizedCodepoint
|
|
954
|
+
: (baseLayoutKey ?? normalizedCodepoint);
|
|
955
|
+
let keyName;
|
|
956
|
+
if (effectiveCodepoint === CODEPOINTS.escape)
|
|
957
|
+
keyName = "escape";
|
|
958
|
+
else if (effectiveCodepoint === CODEPOINTS.tab)
|
|
959
|
+
keyName = "tab";
|
|
960
|
+
else if (effectiveCodepoint === CODEPOINTS.enter || effectiveCodepoint === CODEPOINTS.kpEnter)
|
|
961
|
+
keyName = "enter";
|
|
962
|
+
else if (effectiveCodepoint === CODEPOINTS.space)
|
|
963
|
+
keyName = "space";
|
|
964
|
+
else if (effectiveCodepoint === CODEPOINTS.backspace)
|
|
965
|
+
keyName = "backspace";
|
|
966
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.delete)
|
|
967
|
+
keyName = "delete";
|
|
968
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.insert)
|
|
969
|
+
keyName = "insert";
|
|
970
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.home)
|
|
971
|
+
keyName = "home";
|
|
972
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.end)
|
|
973
|
+
keyName = "end";
|
|
974
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageUp)
|
|
975
|
+
keyName = "pageUp";
|
|
976
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageDown)
|
|
977
|
+
keyName = "pageDown";
|
|
978
|
+
else if (effectiveCodepoint === ARROW_CODEPOINTS.up)
|
|
979
|
+
keyName = "up";
|
|
980
|
+
else if (effectiveCodepoint === ARROW_CODEPOINTS.down)
|
|
981
|
+
keyName = "down";
|
|
982
|
+
else if (effectiveCodepoint === ARROW_CODEPOINTS.left)
|
|
983
|
+
keyName = "left";
|
|
984
|
+
else if (effectiveCodepoint === ARROW_CODEPOINTS.right)
|
|
985
|
+
keyName = "right";
|
|
986
|
+
else if (effectiveCodepoint >= 48 && effectiveCodepoint <= 57)
|
|
987
|
+
keyName = String.fromCharCode(effectiveCodepoint);
|
|
988
|
+
else if (effectiveCodepoint >= 97 && effectiveCodepoint <= 122)
|
|
989
|
+
keyName = String.fromCharCode(effectiveCodepoint);
|
|
990
|
+
else if (SYMBOL_KEYS.has(String.fromCharCode(effectiveCodepoint)))
|
|
991
|
+
keyName = String.fromCharCode(effectiveCodepoint);
|
|
992
|
+
if (!keyName)
|
|
993
|
+
return undefined;
|
|
994
|
+
return formatKeyNameWithModifiers(keyName, modifier);
|
|
995
|
+
}
|
|
878
996
|
export function parseKey(data) {
|
|
879
997
|
const kitty = parseKittySequence(data);
|
|
880
998
|
if (kitty) {
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
if (effectiveMod & MODIFIERS.ctrl)
|
|
887
|
-
mods.push("ctrl");
|
|
888
|
-
if (effectiveMod & MODIFIERS.alt)
|
|
889
|
-
mods.push("alt");
|
|
890
|
-
// Use base layout key only when codepoint is not a recognized Latin
|
|
891
|
-
// letter (a-z) or symbol (/, -, [, ;, etc.). For those, the codepoint
|
|
892
|
-
// is authoritative regardless of physical key position. This prevents
|
|
893
|
-
// remapped layouts (Dvorak, Colemak, xremap, etc.) from reporting the
|
|
894
|
-
// wrong key name based on the QWERTY physical position.
|
|
895
|
-
const isLatinLetter = codepoint >= 97 && codepoint <= 122; // a-z
|
|
896
|
-
const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(codepoint));
|
|
897
|
-
const effectiveCodepoint = isLatinLetter || isKnownSymbol ? codepoint : (baseLayoutKey ?? codepoint);
|
|
898
|
-
let keyName;
|
|
899
|
-
if (effectiveCodepoint === CODEPOINTS.escape)
|
|
900
|
-
keyName = "escape";
|
|
901
|
-
else if (effectiveCodepoint === CODEPOINTS.tab)
|
|
902
|
-
keyName = "tab";
|
|
903
|
-
else if (effectiveCodepoint === CODEPOINTS.enter || effectiveCodepoint === CODEPOINTS.kpEnter)
|
|
904
|
-
keyName = "enter";
|
|
905
|
-
else if (effectiveCodepoint === CODEPOINTS.space)
|
|
906
|
-
keyName = "space";
|
|
907
|
-
else if (effectiveCodepoint === CODEPOINTS.backspace)
|
|
908
|
-
keyName = "backspace";
|
|
909
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.delete)
|
|
910
|
-
keyName = "delete";
|
|
911
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.insert)
|
|
912
|
-
keyName = "insert";
|
|
913
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.home)
|
|
914
|
-
keyName = "home";
|
|
915
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.end)
|
|
916
|
-
keyName = "end";
|
|
917
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageUp)
|
|
918
|
-
keyName = "pageUp";
|
|
919
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageDown)
|
|
920
|
-
keyName = "pageDown";
|
|
921
|
-
else if (effectiveCodepoint === ARROW_CODEPOINTS.up)
|
|
922
|
-
keyName = "up";
|
|
923
|
-
else if (effectiveCodepoint === ARROW_CODEPOINTS.down)
|
|
924
|
-
keyName = "down";
|
|
925
|
-
else if (effectiveCodepoint === ARROW_CODEPOINTS.left)
|
|
926
|
-
keyName = "left";
|
|
927
|
-
else if (effectiveCodepoint === ARROW_CODEPOINTS.right)
|
|
928
|
-
keyName = "right";
|
|
929
|
-
else if (effectiveCodepoint >= 97 && effectiveCodepoint <= 122)
|
|
930
|
-
keyName = String.fromCharCode(effectiveCodepoint);
|
|
931
|
-
else if (SYMBOL_KEYS.has(String.fromCharCode(effectiveCodepoint)))
|
|
932
|
-
keyName = String.fromCharCode(effectiveCodepoint);
|
|
933
|
-
if (keyName) {
|
|
934
|
-
return mods.length > 0 ? `${mods.join("+")}+${keyName}` : keyName;
|
|
935
|
-
}
|
|
999
|
+
return formatParsedKey(kitty.codepoint, kitty.modifier, kitty.baseLayoutKey);
|
|
1000
|
+
}
|
|
1001
|
+
const modifyOtherKeys = parseModifyOtherKeysSequence(data);
|
|
1002
|
+
if (modifyOtherKeys) {
|
|
1003
|
+
return formatParsedKey(modifyOtherKeys.codepoint, modifyOtherKeys.modifier);
|
|
936
1004
|
}
|
|
937
1005
|
// Mode-aware legacy sequences
|
|
938
1006
|
// When Kitty protocol is active, ambiguous sequences are interpreted as custom terminal mappings:
|
|
@@ -991,8 +1059,8 @@ export function parseKey(data) {
|
|
|
991
1059
|
if (code >= 1 && code <= 26) {
|
|
992
1060
|
return `ctrl+alt+${String.fromCharCode(code + 96)}`;
|
|
993
1061
|
}
|
|
994
|
-
// Legacy alt+letter (ESC followed by
|
|
995
|
-
if (code >= 97 && code <= 122) {
|
|
1062
|
+
// Legacy alt+letter/digit (ESC followed by the key)
|
|
1063
|
+
if ((code >= 97 && code <= 122) || (code >= 48 && code <= 57)) {
|
|
996
1064
|
return `alt+${String.fromCharCode(code)}`;
|
|
997
1065
|
}
|
|
998
1066
|
}
|
|
@@ -1026,42 +1094,58 @@ export function parseKey(data) {
|
|
|
1026
1094
|
}
|
|
1027
1095
|
return undefined;
|
|
1028
1096
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1097
|
+
// =============================================================================
|
|
1098
|
+
// Kitty CSI-u Printable Decoding
|
|
1099
|
+
// =============================================================================
|
|
1100
|
+
const KITTY_CSI_U_REGEX = /^\x1b\[(\d+)(?::(\d*))?(?::(\d+))?(?:;(\d+))?(?::(\d+))?u$/;
|
|
1101
|
+
const KITTY_PRINTABLE_ALLOWED_MODIFIERS = MODIFIERS.shift | LOCK_MASK;
|
|
1031
1102
|
/**
|
|
1032
|
-
*
|
|
1103
|
+
* Decode a Kitty CSI-u sequence into a printable character, if applicable.
|
|
1033
1104
|
*
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
|
|
1037
|
-
export function parseMouseEvent(data) {
|
|
1038
|
-
const match = data.match(SGR_MOUSE_RE);
|
|
1039
|
-
if (!match)
|
|
1040
|
-
return null;
|
|
1041
|
-
const code = parseInt(match[1], 10);
|
|
1042
|
-
const x = parseInt(match[2], 10);
|
|
1043
|
-
const y = parseInt(match[3], 10);
|
|
1044
|
-
const isRelease = match[4] === "m";
|
|
1045
|
-
// Scroll wheel: codes 64 (up) and 65 (down)
|
|
1046
|
-
if (code === 64)
|
|
1047
|
-
return { type: "scroll-up", button: 0, x, y };
|
|
1048
|
-
if (code === 65)
|
|
1049
|
-
return { type: "scroll-down", button: 0, x, y };
|
|
1050
|
-
// Button number is in the low 2 bits
|
|
1051
|
-
const button = code & 0x03;
|
|
1052
|
-
// Bit 5 (32) = motion/drag
|
|
1053
|
-
if (code & 32)
|
|
1054
|
-
return { type: "drag", button, x, y };
|
|
1055
|
-
return { type: isRelease ? "release" : "press", button, x, y };
|
|
1056
|
-
}
|
|
1057
|
-
/**
|
|
1058
|
-
* Fast check: is this data an SGR mouse event?
|
|
1059
|
-
* Avoids regex for non-mouse input.
|
|
1105
|
+
* When Kitty keyboard protocol flag 1 (disambiguate) is active, terminals send
|
|
1106
|
+
* CSI-u sequences for all keys, including plain printable characters. This
|
|
1107
|
+
* function extracts the printable character from such sequences.
|
|
1060
1108
|
*
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1109
|
+
* Only accepts plain or Shift-modified keys. Rejects Ctrl, Alt, and unsupported
|
|
1110
|
+
* modifier combinations (those are handled by keybinding matching instead).
|
|
1111
|
+
* Prefers the shifted keycode when Shift is held and a shifted key is reported.
|
|
1112
|
+
*
|
|
1113
|
+
* @param data - Raw input data from terminal
|
|
1114
|
+
* @returns The printable character, or undefined if not a printable CSI-u sequence
|
|
1063
1115
|
*/
|
|
1064
|
-
export function
|
|
1065
|
-
|
|
1116
|
+
export function decodeKittyPrintable(data) {
|
|
1117
|
+
const match = data.match(KITTY_CSI_U_REGEX);
|
|
1118
|
+
if (!match)
|
|
1119
|
+
return undefined;
|
|
1120
|
+
// CSI-u groups: <codepoint>[:<shifted>[:<base>]];<mod>[:<event>]u
|
|
1121
|
+
const codepoint = Number.parseInt(match[1] ?? "", 10);
|
|
1122
|
+
if (!Number.isFinite(codepoint))
|
|
1123
|
+
return undefined;
|
|
1124
|
+
const shiftedKey = match[2] && match[2].length > 0 ? Number.parseInt(match[2], 10) : undefined;
|
|
1125
|
+
const modValue = match[4] ? Number.parseInt(match[4], 10) : 1;
|
|
1126
|
+
// Modifiers are 1-indexed in CSI-u; normalize to our bitmask.
|
|
1127
|
+
const modifier = Number.isFinite(modValue) ? modValue - 1 : 0;
|
|
1128
|
+
// Only accept printable CSI-u input for plain or Shift-modified text keys.
|
|
1129
|
+
// Reject unsupported modifier bits (e.g. Super/Meta) to avoid inserting
|
|
1130
|
+
// characters from modifier-only terminal events.
|
|
1131
|
+
if ((modifier & ~KITTY_PRINTABLE_ALLOWED_MODIFIERS) !== 0)
|
|
1132
|
+
return undefined;
|
|
1133
|
+
if (modifier & (MODIFIERS.alt | MODIFIERS.ctrl))
|
|
1134
|
+
return undefined;
|
|
1135
|
+
// Prefer the shifted keycode when Shift is held.
|
|
1136
|
+
let effectiveCodepoint = codepoint;
|
|
1137
|
+
if (modifier & MODIFIERS.shift && typeof shiftedKey === "number") {
|
|
1138
|
+
effectiveCodepoint = shiftedKey;
|
|
1139
|
+
}
|
|
1140
|
+
effectiveCodepoint = normalizeKittyFunctionalCodepoint(effectiveCodepoint);
|
|
1141
|
+
// Drop control characters or invalid codepoints.
|
|
1142
|
+
if (!Number.isFinite(effectiveCodepoint) || effectiveCodepoint < 32)
|
|
1143
|
+
return undefined;
|
|
1144
|
+
try {
|
|
1145
|
+
return String.fromCodePoint(effectiveCodepoint);
|
|
1146
|
+
}
|
|
1147
|
+
catch {
|
|
1148
|
+
return undefined;
|
|
1149
|
+
}
|
|
1066
1150
|
}
|
|
1067
1151
|
//# sourceMappingURL=keys.js.map
|