@google/gemini-cli 0.11.0-preview.0 → 0.12.0-nightly.20251023.c4c0c0d1
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/google-gemini-cli-0.12.0-nightly.20251022.0542de95.tgz +0 -0
- package/dist/package.json +4 -3
- package/dist/src/commands/extensions/disable.js +13 -6
- package/dist/src/commands/extensions/disable.js.map +1 -1
- package/dist/src/commands/extensions/enable.js +13 -6
- package/dist/src/commands/extensions/enable.js.map +1 -1
- package/dist/src/commands/extensions/install.js +12 -2
- package/dist/src/commands/extensions/install.js.map +1 -1
- package/dist/src/commands/extensions/install.test.js +11 -3
- package/dist/src/commands/extensions/install.test.js.map +1 -1
- package/dist/src/commands/extensions/link.js +12 -2
- package/dist/src/commands/extensions/link.js.map +1 -1
- package/dist/src/commands/extensions/list.js +13 -4
- package/dist/src/commands/extensions/list.js.map +1 -1
- package/dist/src/commands/extensions/uninstall.js +12 -2
- package/dist/src/commands/extensions/uninstall.js.map +1 -1
- package/dist/src/commands/extensions/update.js +17 -13
- package/dist/src/commands/extensions/update.js.map +1 -1
- package/dist/src/commands/extensions.js +1 -0
- package/dist/src/commands/extensions.js.map +1 -1
- package/dist/src/commands/mcp/list.js +10 -3
- package/dist/src/commands/mcp/list.js.map +1 -1
- package/dist/src/commands/mcp/list.test.js +12 -6
- package/dist/src/commands/mcp/list.test.js.map +1 -1
- package/dist/src/config/config.js +12 -0
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +11 -0
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/extension-manager.d.ts +38 -0
- package/dist/src/config/extension-manager.js +412 -0
- package/dist/src/config/extension-manager.js.map +1 -0
- package/dist/src/config/extension.d.ts +4 -51
- package/dist/src/config/extension.js +1 -535
- package/dist/src/config/extension.js.map +1 -1
- package/dist/src/config/extension.test.js +316 -159
- package/dist/src/config/extension.test.js.map +1 -1
- package/dist/src/config/extensions/consent.d.ts +38 -0
- package/dist/src/config/extensions/consent.js +123 -0
- package/dist/src/config/extensions/consent.js.map +1 -0
- package/dist/src/config/extensions/extensionEnablement.js +1 -1
- package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
- package/dist/src/config/extensions/extensionSettings.d.ts +15 -0
- package/dist/src/config/extensions/extensionSettings.js +63 -0
- package/dist/src/config/extensions/extensionSettings.js.map +1 -0
- package/dist/src/config/extensions/extensionSettings.test.d.ts +6 -0
- package/dist/src/config/extensions/extensionSettings.test.js +137 -0
- package/dist/src/config/extensions/extensionSettings.test.js.map +1 -0
- package/dist/src/config/extensions/github.d.ts +2 -2
- package/dist/src/config/extensions/github.js +3 -8
- package/dist/src/config/extensions/github.js.map +1 -1
- package/dist/src/config/extensions/github.test.js +25 -7
- package/dist/src/config/extensions/github.test.js.map +1 -1
- package/dist/src/config/extensions/storage.d.ts +14 -0
- package/dist/src/config/extensions/storage.js +32 -0
- package/dist/src/config/extensions/storage.js.map +1 -0
- package/dist/src/config/extensions/update.d.ts +4 -4
- package/dist/src/config/extensions/update.js +11 -18
- package/dist/src/config/extensions/update.js.map +1 -1
- package/dist/src/config/extensions/update.test.js +32 -58
- package/dist/src/config/extensions/update.test.js.map +1 -1
- package/dist/src/config/extensions/variableSchema.d.ts +0 -6
- package/dist/src/config/extensions/variableSchema.js.map +1 -1
- package/dist/src/config/extensions/variables.d.ts +4 -0
- package/dist/src/config/extensions/variables.js +6 -0
- package/dist/src/config/extensions/variables.js.map +1 -1
- package/dist/src/config/settings.d.ts +2 -1
- package/dist/src/config/settings.js +4 -7
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settings.test.js +113 -14
- package/dist/src/config/settings.test.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +9 -0
- package/dist/src/config/settingsSchema.js +9 -0
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/gemini.js +22 -5
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/nonInteractiveCli.js +14 -1
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/nonInteractiveCli.test.js +84 -2
- package/dist/src/nonInteractiveCli.test.js.map +1 -1
- package/dist/src/test-utils/createExtension.d.ts +3 -1
- package/dist/src/test-utils/createExtension.js +3 -3
- package/dist/src/test-utils/createExtension.js.map +1 -1
- package/dist/src/ui/AppContainer.js +101 -47
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/AppContainer.test.js +138 -79
- package/dist/src/ui/AppContainer.test.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.js +19 -10
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.test.js +8 -0
- package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +5 -6
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.test.js +249 -393
- package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.test.js +0 -29
- package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
- package/dist/src/ui/components/views/ExtensionsList.d.ts +7 -1
- package/dist/src/ui/components/views/ExtensionsList.js +4 -10
- package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
- package/dist/src/ui/components/views/ExtensionsList.test.js +34 -21
- package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.js +328 -335
- package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js +10 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +30 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.d.ts +14 -4
- package/dist/src/ui/hooks/useExtensionUpdates.js +14 -17
- package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +23 -30
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
- package/dist/src/ui/hooks/useGitBranchName.js +4 -0
- package/dist/src/ui/hooks/useGitBranchName.js.map +1 -1
- package/dist/src/ui/hooks/useGitBranchName.test.js +19 -21
- package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js +22 -8
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.test.d.ts +6 -0
- package/dist/src/ui/hooks/useReactToolScheduler.test.js +65 -0
- package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -0
- package/dist/src/ui/hooks/useToolScheduler.test.js +30 -48
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/types.d.ts +2 -1
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/ui/utils/CodeColorizer.js +2 -1
- package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
- package/dist/src/utils/envVarResolver.d.ts +2 -2
- package/dist/src/utils/envVarResolver.js +10 -7
- package/dist/src/utils/envVarResolver.js.map +1 -1
- package/dist/src/zed-integration/schema.d.ts +4 -4
- package/dist/src/zed-integration/zedIntegration.js +3 -3
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -3
|
@@ -41,169 +41,186 @@ const ALT_KEY_CHARACTER_MAP = {
|
|
|
41
41
|
'\u00A5': 'y',
|
|
42
42
|
'\u03A9': 'z',
|
|
43
43
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Check if a buffer could potentially be a valid kitty sequence or its prefix.
|
|
46
|
+
*/
|
|
47
|
+
function couldBeKittySequence(buffer) {
|
|
48
|
+
// Kitty sequences always start with ESC[.
|
|
49
|
+
if (buffer.length === 0)
|
|
50
|
+
return true;
|
|
51
|
+
if (buffer === ESC || buffer === `${ESC}[`)
|
|
52
|
+
return true;
|
|
53
|
+
if (!buffer.startsWith(`${ESC}[`))
|
|
54
|
+
return false;
|
|
55
|
+
// Check for known kitty sequence patterns:
|
|
56
|
+
// 1. ESC[<digit> - could be CSI-u or tilde-coded
|
|
57
|
+
// 2. ESC[1;<digit> - parameterized functional
|
|
58
|
+
// 3. ESC[<letter> - legacy functional keys
|
|
59
|
+
// 4. ESC[Z - reverse tab
|
|
60
|
+
const afterCSI = buffer.slice(2);
|
|
61
|
+
// Check if it starts with a digit (could be CSI-u or parameterized)
|
|
62
|
+
if (/^\d/.test(afterCSI))
|
|
63
|
+
return true;
|
|
64
|
+
// Check for known single-letter sequences
|
|
65
|
+
if (/^[ABCDHFPQRSZ]/.test(afterCSI))
|
|
66
|
+
return true;
|
|
67
|
+
// Check for 1; pattern (parameterized sequences)
|
|
68
|
+
if (/^1;\d/.test(afterCSI))
|
|
69
|
+
return true;
|
|
70
|
+
// Anything else starting with ESC[ that doesn't match our patterns
|
|
71
|
+
// is likely not a kitty sequence we handle
|
|
72
|
+
return false;
|
|
51
73
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Parses a single complete kitty/parameterized/legacy sequence from the start
|
|
76
|
+
* of the buffer.
|
|
77
|
+
*
|
|
78
|
+
* This enables peel-and-continue parsing for batched input, allowing us to
|
|
79
|
+
* "peel off" one complete event when multiple sequences arrive in a single
|
|
80
|
+
* chunk, preventing buffer overflow and fragmentation.
|
|
81
|
+
*
|
|
82
|
+
* @param buffer - The input buffer string to parse.
|
|
83
|
+
* @returns The parsed Key and the number of characters consumed, or null if
|
|
84
|
+
* no complete sequence is found at the start of the buffer.
|
|
85
|
+
*/
|
|
86
|
+
function parseKittyPrefix(buffer) {
|
|
87
|
+
// In older terminals ESC [ Z was used as Cursor Backward Tabulation (CBT)
|
|
88
|
+
// In newer terminals the same functionality of key combination for moving
|
|
89
|
+
// backward through focusable elements is Shift+Tab, hence we will
|
|
90
|
+
// map ESC [ Z to Shift+Tab
|
|
91
|
+
// 0) Reverse Tab (legacy): ESC [ Z
|
|
92
|
+
// Treat as Shift+Tab for UI purposes.
|
|
93
|
+
// Regex parts:
|
|
94
|
+
// ^ - start of buffer
|
|
95
|
+
// ESC [ - CSI introducer
|
|
96
|
+
// Z - legacy reverse tab
|
|
97
|
+
const revTabLegacy = new RegExp(`^${ESC}\\[Z`);
|
|
98
|
+
let m = buffer.match(revTabLegacy);
|
|
99
|
+
if (m) {
|
|
100
|
+
return {
|
|
101
|
+
key: {
|
|
102
|
+
name: 'tab',
|
|
103
|
+
ctrl: false,
|
|
104
|
+
meta: false,
|
|
105
|
+
shift: true,
|
|
106
|
+
paste: false,
|
|
107
|
+
sequence: buffer.slice(0, m[0].length),
|
|
108
|
+
kittyProtocol: true,
|
|
109
|
+
},
|
|
110
|
+
length: m[0].length,
|
|
70
111
|
};
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
112
|
+
}
|
|
113
|
+
// 1) Reverse Tab (parameterized): ESC [ 1 ; <mods> Z
|
|
114
|
+
// Parameterized reverse Tab: ESC [ 1 ; <mods> Z
|
|
115
|
+
const revTabParam = new RegExp(`^${ESC}\\[1;(\\d+)Z`);
|
|
116
|
+
m = buffer.match(revTabParam);
|
|
117
|
+
if (m) {
|
|
118
|
+
let mods = parseInt(m[1], 10);
|
|
119
|
+
if (mods >= KITTY_MODIFIER_EVENT_TYPES_OFFSET) {
|
|
120
|
+
mods -= KITTY_MODIFIER_EVENT_TYPES_OFFSET;
|
|
74
121
|
}
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
122
|
+
const bits = mods - KITTY_MODIFIER_BASE;
|
|
123
|
+
const alt = (bits & MODIFIER_ALT_BIT) === MODIFIER_ALT_BIT;
|
|
124
|
+
const ctrl = (bits & MODIFIER_CTRL_BIT) === MODIFIER_CTRL_BIT;
|
|
125
|
+
return {
|
|
126
|
+
key: {
|
|
127
|
+
name: 'tab',
|
|
128
|
+
ctrl,
|
|
129
|
+
meta: alt,
|
|
130
|
+
// Reverse tab implies Shift behavior; force shift regardless of mods
|
|
131
|
+
shift: true,
|
|
132
|
+
paste: false,
|
|
133
|
+
sequence: buffer.slice(0, m[0].length),
|
|
134
|
+
kittyProtocol: true,
|
|
135
|
+
},
|
|
136
|
+
length: m[0].length,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// 2) Parameterized functional: ESC [ 1 ; <mods> (A|B|C|D|H|F|P|Q|R|S)
|
|
140
|
+
// 2) Parameterized functional: ESC [ 1 ; <mods> (A|B|C|D|H|F|P|Q|R|S)
|
|
141
|
+
// Arrows, Home/End, F1–F4 with modifiers encoded in <mods>.
|
|
142
|
+
const arrowPrefix = new RegExp(`^${ESC}\\[1;(\\d+)([ABCDHFPQSR])`);
|
|
143
|
+
m = buffer.match(arrowPrefix);
|
|
144
|
+
if (m) {
|
|
145
|
+
let mods = parseInt(m[1], 10);
|
|
146
|
+
if (mods >= KITTY_MODIFIER_EVENT_TYPES_OFFSET) {
|
|
147
|
+
mods -= KITTY_MODIFIER_EVENT_TYPES_OFFSET;
|
|
82
148
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// 1. ESC[<digit> - could be CSI-u or tilde-coded
|
|
100
|
-
// 2. ESC[1;<digit> - parameterized functional
|
|
101
|
-
// 3. ESC[<letter> - legacy functional keys
|
|
102
|
-
// 4. ESC[Z - reverse tab
|
|
103
|
-
const afterCSI = buffer.slice(2);
|
|
104
|
-
// Check if it starts with a digit (could be CSI-u or parameterized)
|
|
105
|
-
if (/^\d/.test(afterCSI))
|
|
106
|
-
return true;
|
|
107
|
-
// Check for known single-letter sequences
|
|
108
|
-
if (/^[ABCDHFPQRSZ]/.test(afterCSI))
|
|
109
|
-
return true;
|
|
110
|
-
// Check for 1; pattern (parameterized sequences)
|
|
111
|
-
if (/^1;\d/.test(afterCSI))
|
|
112
|
-
return true;
|
|
113
|
-
// Anything else starting with ESC[ that doesn't match our patterns
|
|
114
|
-
// is likely not a kitty sequence we handle
|
|
115
|
-
return false;
|
|
149
|
+
const bits = mods - KITTY_MODIFIER_BASE;
|
|
150
|
+
const shift = (bits & MODIFIER_SHIFT_BIT) === MODIFIER_SHIFT_BIT;
|
|
151
|
+
const alt = (bits & MODIFIER_ALT_BIT) === MODIFIER_ALT_BIT;
|
|
152
|
+
const ctrl = (bits & MODIFIER_CTRL_BIT) === MODIFIER_CTRL_BIT;
|
|
153
|
+
const sym = m[2];
|
|
154
|
+
const symbolToName = {
|
|
155
|
+
A: 'up',
|
|
156
|
+
B: 'down',
|
|
157
|
+
C: 'right',
|
|
158
|
+
D: 'left',
|
|
159
|
+
H: 'home',
|
|
160
|
+
F: 'end',
|
|
161
|
+
P: 'f1',
|
|
162
|
+
Q: 'f2',
|
|
163
|
+
R: 'f3',
|
|
164
|
+
S: 'f4',
|
|
116
165
|
};
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
// 2) Parameterized functional: ESC [ 1 ; <mods> (A|B|C|D|H|F|P|Q|R|S)
|
|
178
|
-
// 2) Parameterized functional: ESC [ 1 ; <mods> (A|B|C|D|H|F|P|Q|R|S)
|
|
179
|
-
// Arrows, Home/End, F1–F4 with modifiers encoded in <mods>.
|
|
180
|
-
const arrowPrefix = new RegExp(`^${ESC}\\[1;(\\d+)([ABCDHFPQSR])`);
|
|
181
|
-
m = buffer.match(arrowPrefix);
|
|
182
|
-
if (m) {
|
|
183
|
-
let mods = parseInt(m[1], 10);
|
|
184
|
-
if (mods >= KITTY_MODIFIER_EVENT_TYPES_OFFSET) {
|
|
185
|
-
mods -= KITTY_MODIFIER_EVENT_TYPES_OFFSET;
|
|
186
|
-
}
|
|
187
|
-
const bits = mods - KITTY_MODIFIER_BASE;
|
|
188
|
-
const shift = (bits & MODIFIER_SHIFT_BIT) === MODIFIER_SHIFT_BIT;
|
|
189
|
-
const alt = (bits & MODIFIER_ALT_BIT) === MODIFIER_ALT_BIT;
|
|
190
|
-
const ctrl = (bits & MODIFIER_CTRL_BIT) === MODIFIER_CTRL_BIT;
|
|
191
|
-
const sym = m[2];
|
|
192
|
-
const symbolToName = {
|
|
193
|
-
A: 'up',
|
|
194
|
-
B: 'down',
|
|
195
|
-
C: 'right',
|
|
196
|
-
D: 'left',
|
|
197
|
-
H: 'home',
|
|
198
|
-
F: 'end',
|
|
199
|
-
P: 'f1',
|
|
200
|
-
Q: 'f2',
|
|
201
|
-
R: 'f3',
|
|
202
|
-
S: 'f4',
|
|
203
|
-
};
|
|
204
|
-
const name = symbolToName[sym] || '';
|
|
205
|
-
if (!name)
|
|
206
|
-
return null;
|
|
166
|
+
const name = symbolToName[sym] || '';
|
|
167
|
+
if (!name)
|
|
168
|
+
return null;
|
|
169
|
+
return {
|
|
170
|
+
key: {
|
|
171
|
+
name,
|
|
172
|
+
ctrl,
|
|
173
|
+
meta: alt,
|
|
174
|
+
shift,
|
|
175
|
+
paste: false,
|
|
176
|
+
sequence: buffer.slice(0, m[0].length),
|
|
177
|
+
kittyProtocol: true,
|
|
178
|
+
},
|
|
179
|
+
length: m[0].length,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// 3) CSI-u form: ESC [ <code> ; <mods> (u|~)
|
|
183
|
+
// 3) CSI-u and tilde-coded functional keys: ESC [ <code> ; <mods> (u|~)
|
|
184
|
+
// 'u' terminator: Kitty CSI-u; '~' terminator: tilde-coded function keys.
|
|
185
|
+
const csiUPrefix = new RegExp(`^${ESC}\\[(\\d+)(;(\\d+))?([u~])`);
|
|
186
|
+
m = buffer.match(csiUPrefix);
|
|
187
|
+
if (m) {
|
|
188
|
+
const keyCode = parseInt(m[1], 10);
|
|
189
|
+
let modifiers = m[3] ? parseInt(m[3], 10) : KITTY_MODIFIER_BASE;
|
|
190
|
+
if (modifiers >= KITTY_MODIFIER_EVENT_TYPES_OFFSET) {
|
|
191
|
+
modifiers -= KITTY_MODIFIER_EVENT_TYPES_OFFSET;
|
|
192
|
+
}
|
|
193
|
+
const modifierBits = modifiers - KITTY_MODIFIER_BASE;
|
|
194
|
+
const shift = (modifierBits & MODIFIER_SHIFT_BIT) === MODIFIER_SHIFT_BIT;
|
|
195
|
+
const alt = (modifierBits & MODIFIER_ALT_BIT) === MODIFIER_ALT_BIT;
|
|
196
|
+
const ctrl = (modifierBits & MODIFIER_CTRL_BIT) === MODIFIER_CTRL_BIT;
|
|
197
|
+
const terminator = m[4];
|
|
198
|
+
// Tilde-coded functional keys (Delete, Insert, PageUp/Down, Home/End)
|
|
199
|
+
if (terminator === '~') {
|
|
200
|
+
let name = null;
|
|
201
|
+
switch (keyCode) {
|
|
202
|
+
case 1:
|
|
203
|
+
name = 'home';
|
|
204
|
+
break;
|
|
205
|
+
case 2:
|
|
206
|
+
name = 'insert';
|
|
207
|
+
break;
|
|
208
|
+
case 3:
|
|
209
|
+
name = 'delete';
|
|
210
|
+
break;
|
|
211
|
+
case 4:
|
|
212
|
+
name = 'end';
|
|
213
|
+
break;
|
|
214
|
+
case 5:
|
|
215
|
+
name = 'pageup';
|
|
216
|
+
break;
|
|
217
|
+
case 6:
|
|
218
|
+
name = 'pagedown';
|
|
219
|
+
break;
|
|
220
|
+
default:
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
if (name) {
|
|
207
224
|
return {
|
|
208
225
|
key: {
|
|
209
226
|
name,
|
|
@@ -217,136 +234,124 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
217
234
|
length: m[0].length,
|
|
218
235
|
};
|
|
219
236
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
ctrl,
|
|
289
|
-
meta: alt,
|
|
290
|
-
shift,
|
|
291
|
-
paste: false,
|
|
292
|
-
sequence: buffer.slice(0, m[0].length),
|
|
293
|
-
kittyProtocol: true,
|
|
294
|
-
},
|
|
295
|
-
length: m[0].length,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
// Ctrl+letters and Alt+letters
|
|
299
|
-
if ((ctrl || alt) &&
|
|
300
|
-
keyCode >= 'a'.charCodeAt(0) &&
|
|
301
|
-
keyCode <= 'z'.charCodeAt(0)) {
|
|
302
|
-
const letter = String.fromCharCode(keyCode);
|
|
303
|
-
return {
|
|
304
|
-
key: {
|
|
305
|
-
name: letter,
|
|
306
|
-
ctrl,
|
|
307
|
-
meta: alt,
|
|
308
|
-
shift,
|
|
309
|
-
paste: false,
|
|
310
|
-
sequence: buffer.slice(0, m[0].length),
|
|
311
|
-
kittyProtocol: true,
|
|
312
|
-
},
|
|
313
|
-
length: m[0].length,
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
// 4) Legacy function keys (no parameters): ESC [ (A|B|C|D|H|F)
|
|
318
|
-
// Arrows + Home/End without modifiers.
|
|
319
|
-
const legacyFuncKey = new RegExp(`^${ESC}\\[([ABCDHF])`);
|
|
320
|
-
m = buffer.match(legacyFuncKey);
|
|
321
|
-
if (m) {
|
|
322
|
-
const sym = m[1];
|
|
323
|
-
const nameMap = {
|
|
324
|
-
A: 'up',
|
|
325
|
-
B: 'down',
|
|
326
|
-
C: 'right',
|
|
327
|
-
D: 'left',
|
|
328
|
-
H: 'home',
|
|
329
|
-
F: 'end',
|
|
330
|
-
};
|
|
331
|
-
const name = nameMap[sym];
|
|
332
|
-
return {
|
|
333
|
-
key: {
|
|
334
|
-
name,
|
|
335
|
-
ctrl: false,
|
|
336
|
-
meta: false,
|
|
337
|
-
shift: false,
|
|
338
|
-
paste: false,
|
|
339
|
-
sequence: buffer.slice(0, m[0].length),
|
|
340
|
-
kittyProtocol: true,
|
|
341
|
-
},
|
|
342
|
-
length: m[0].length,
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
return null;
|
|
237
|
+
}
|
|
238
|
+
const kittyKeyCodeToName = {
|
|
239
|
+
[CHAR_CODE_ESC]: 'escape',
|
|
240
|
+
[KITTY_KEYCODE_TAB]: 'tab',
|
|
241
|
+
[KITTY_KEYCODE_BACKSPACE]: 'backspace',
|
|
242
|
+
[KITTY_KEYCODE_ENTER]: 'return',
|
|
243
|
+
[KITTY_KEYCODE_NUMPAD_ENTER]: 'return',
|
|
244
|
+
};
|
|
245
|
+
const name = kittyKeyCodeToName[keyCode];
|
|
246
|
+
if (name) {
|
|
247
|
+
return {
|
|
248
|
+
key: {
|
|
249
|
+
name,
|
|
250
|
+
ctrl,
|
|
251
|
+
meta: alt,
|
|
252
|
+
shift,
|
|
253
|
+
paste: false,
|
|
254
|
+
sequence: buffer.slice(0, m[0].length),
|
|
255
|
+
kittyProtocol: true,
|
|
256
|
+
},
|
|
257
|
+
length: m[0].length,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
// Ctrl+letters and Alt+letters
|
|
261
|
+
if ((ctrl || alt) &&
|
|
262
|
+
keyCode >= 'a'.charCodeAt(0) &&
|
|
263
|
+
keyCode <= 'z'.charCodeAt(0)) {
|
|
264
|
+
const letter = String.fromCharCode(keyCode);
|
|
265
|
+
return {
|
|
266
|
+
key: {
|
|
267
|
+
name: letter,
|
|
268
|
+
ctrl,
|
|
269
|
+
meta: alt,
|
|
270
|
+
shift,
|
|
271
|
+
paste: false,
|
|
272
|
+
sequence: buffer.slice(0, m[0].length),
|
|
273
|
+
kittyProtocol: true,
|
|
274
|
+
},
|
|
275
|
+
length: m[0].length,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// 4) Legacy function keys (no parameters): ESC [ (A|B|C|D|H|F)
|
|
280
|
+
// Arrows + Home/End without modifiers.
|
|
281
|
+
const legacyFuncKey = new RegExp(`^${ESC}\\[([ABCDHF])`);
|
|
282
|
+
m = buffer.match(legacyFuncKey);
|
|
283
|
+
if (m) {
|
|
284
|
+
const sym = m[1];
|
|
285
|
+
const nameMap = {
|
|
286
|
+
A: 'up',
|
|
287
|
+
B: 'down',
|
|
288
|
+
C: 'right',
|
|
289
|
+
D: 'left',
|
|
290
|
+
H: 'home',
|
|
291
|
+
F: 'end',
|
|
292
|
+
};
|
|
293
|
+
const name = nameMap[sym];
|
|
294
|
+
return {
|
|
295
|
+
key: {
|
|
296
|
+
name,
|
|
297
|
+
ctrl: false,
|
|
298
|
+
meta: false,
|
|
299
|
+
shift: false,
|
|
300
|
+
paste: false,
|
|
301
|
+
sequence: buffer.slice(0, m[0].length),
|
|
302
|
+
kittyProtocol: true,
|
|
303
|
+
},
|
|
304
|
+
length: m[0].length,
|
|
346
305
|
};
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
306
|
+
}
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
const KeypressContext = createContext(undefined);
|
|
310
|
+
export function useKeypressContext() {
|
|
311
|
+
const context = useContext(KeypressContext);
|
|
312
|
+
if (!context) {
|
|
313
|
+
throw new Error('useKeypressContext must be used within a KeypressProvider');
|
|
314
|
+
}
|
|
315
|
+
return context;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Determines if the passthrough stream workaround should be used.
|
|
319
|
+
* This is necessary for Node.js versions older than 20 or when the
|
|
320
|
+
* PASTE_WORKAROUND environment variable is set, to correctly handle
|
|
321
|
+
* paste events.
|
|
322
|
+
*/
|
|
323
|
+
function shouldUsePassthrough() {
|
|
324
|
+
const nodeMajorVersion = parseInt(process.versions.node.split('.')[0], 10);
|
|
325
|
+
return (nodeMajorVersion < 20 ||
|
|
326
|
+
process.env['PASTE_WORKAROUND'] === '1' ||
|
|
327
|
+
process.env['PASTE_WORKAROUND'] === 'true');
|
|
328
|
+
}
|
|
329
|
+
export function KeypressProvider({ children, kittyProtocolEnabled, config, debugKeystrokeLogging, }) {
|
|
330
|
+
const { stdin, setRawMode } = useStdin();
|
|
331
|
+
const subscribers = useRef(new Set()).current;
|
|
332
|
+
const subscribe = useCallback((handler) => subscribers.add(handler), [subscribers]);
|
|
333
|
+
const unsubscribe = useCallback((handler) => subscribers.delete(handler), [subscribers]);
|
|
334
|
+
const broadcast = useCallback((key) => subscribers.forEach((handler) => handler(key)), [subscribers]);
|
|
335
|
+
useEffect(() => {
|
|
336
|
+
const wasRaw = stdin.isRaw;
|
|
337
|
+
if (wasRaw === false) {
|
|
338
|
+
setRawMode(true);
|
|
339
|
+
}
|
|
340
|
+
const keypressStream = shouldUsePassthrough() ? new PassThrough() : null;
|
|
341
|
+
// If non-null that means we are in paste mode
|
|
342
|
+
let pasteBuffer = null;
|
|
343
|
+
// Used to turn "\" quickly followed by a "enter" into a shift enter
|
|
344
|
+
let backslashTimeout = null;
|
|
345
|
+
// Buffers incomplete Kitty sequences and timer to flush it
|
|
346
|
+
let kittySequenceBuffer = '';
|
|
347
|
+
let kittySequenceTimeout = null;
|
|
348
|
+
// Used to detect filename drag-and-drops.
|
|
349
|
+
let dragBuffer = '';
|
|
350
|
+
let draggingTimer = null;
|
|
351
|
+
const clearDraggingTimer = () => {
|
|
352
|
+
if (draggingTimer) {
|
|
353
|
+
clearTimeout(draggingTimer);
|
|
354
|
+
draggingTimer = null;
|
|
350
355
|
}
|
|
351
356
|
};
|
|
352
357
|
const flushKittyBufferOnInterrupt = (reason) => {
|
|
@@ -376,36 +381,36 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
376
381
|
}
|
|
377
382
|
if (key.name === 'paste-start') {
|
|
378
383
|
flushKittyBufferOnInterrupt('paste start');
|
|
379
|
-
|
|
384
|
+
pasteBuffer = Buffer.alloc(0);
|
|
380
385
|
return;
|
|
381
386
|
}
|
|
382
387
|
if (key.name === 'paste-end') {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
388
|
+
if (pasteBuffer !== null) {
|
|
389
|
+
broadcast({
|
|
390
|
+
name: '',
|
|
391
|
+
ctrl: false,
|
|
392
|
+
meta: false,
|
|
393
|
+
shift: false,
|
|
394
|
+
paste: true,
|
|
395
|
+
sequence: pasteBuffer.toString(),
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
pasteBuffer = null;
|
|
393
399
|
return;
|
|
394
400
|
}
|
|
395
|
-
if (
|
|
401
|
+
if (pasteBuffer !== null) {
|
|
396
402
|
pasteBuffer = Buffer.concat([pasteBuffer, Buffer.from(key.sequence)]);
|
|
397
403
|
return;
|
|
398
404
|
}
|
|
399
405
|
if (key.sequence === SINGLE_QUOTE ||
|
|
400
406
|
key.sequence === DOUBLE_QUOTE ||
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
dragBufferRef.current += key.sequence;
|
|
407
|
+
draggingTimer !== null) {
|
|
408
|
+
dragBuffer += key.sequence;
|
|
404
409
|
clearDraggingTimer();
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const seq =
|
|
408
|
-
|
|
410
|
+
draggingTimer = setTimeout(() => {
|
|
411
|
+
draggingTimer = null;
|
|
412
|
+
const seq = dragBuffer;
|
|
413
|
+
dragBuffer = '';
|
|
409
414
|
if (seq) {
|
|
410
415
|
broadcast({ ...key, name: '', paste: true, sequence: seq });
|
|
411
416
|
}
|
|
@@ -419,17 +424,14 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
419
424
|
ctrl: false,
|
|
420
425
|
meta: true,
|
|
421
426
|
shift: false,
|
|
422
|
-
paste:
|
|
427
|
+
paste: pasteBuffer !== null,
|
|
423
428
|
sequence: key.sequence,
|
|
424
429
|
});
|
|
425
430
|
return;
|
|
426
431
|
}
|
|
427
|
-
if (key.name === 'return' &&
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
backslashTimeout = null;
|
|
431
|
-
}
|
|
432
|
-
waitingForEnterAfterBackslash = false;
|
|
432
|
+
if (key.name === 'return' && backslashTimeout !== null) {
|
|
433
|
+
clearTimeout(backslashTimeout);
|
|
434
|
+
backslashTimeout = null;
|
|
433
435
|
broadcast({
|
|
434
436
|
...key,
|
|
435
437
|
shift: true,
|
|
@@ -439,20 +441,15 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
439
441
|
}
|
|
440
442
|
if (key.sequence === '\\' && !key.name) {
|
|
441
443
|
// Corrected escaping for backslash
|
|
442
|
-
waitingForEnterAfterBackslash = true;
|
|
443
444
|
backslashTimeout = setTimeout(() => {
|
|
444
|
-
waitingForEnterAfterBackslash = false;
|
|
445
445
|
backslashTimeout = null;
|
|
446
446
|
broadcast(key);
|
|
447
447
|
}, BACKSLASH_ENTER_DETECTION_WINDOW_MS);
|
|
448
448
|
return;
|
|
449
449
|
}
|
|
450
|
-
if (
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
backslashTimeout = null;
|
|
454
|
-
}
|
|
455
|
-
waitingForEnterAfterBackslash = false;
|
|
450
|
+
if (backslashTimeout !== null && key.name !== 'return') {
|
|
451
|
+
clearTimeout(backslashTimeout);
|
|
452
|
+
backslashTimeout = null;
|
|
456
453
|
broadcast({
|
|
457
454
|
name: '',
|
|
458
455
|
sequence: '\\',
|
|
@@ -614,7 +611,7 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
614
611
|
if (key.name === 'return' && key.sequence === `${ESC}\r`) {
|
|
615
612
|
key.meta = true;
|
|
616
613
|
}
|
|
617
|
-
broadcast({ ...key, paste:
|
|
614
|
+
broadcast({ ...key, paste: pasteBuffer !== null });
|
|
618
615
|
};
|
|
619
616
|
const handleRawKeypress = (data) => {
|
|
620
617
|
const pasteModePrefixBuffer = Buffer.from(PASTE_MODE_PREFIX);
|
|
@@ -660,7 +657,7 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
660
657
|
}
|
|
661
658
|
};
|
|
662
659
|
let rl;
|
|
663
|
-
if (
|
|
660
|
+
if (keypressStream !== null) {
|
|
664
661
|
rl = readline.createInterface({
|
|
665
662
|
input: keypressStream,
|
|
666
663
|
escapeCodeTimeout: 0,
|
|
@@ -675,7 +672,7 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
675
672
|
stdin.on('keypress', handleKeypress);
|
|
676
673
|
}
|
|
677
674
|
return () => {
|
|
678
|
-
if (
|
|
675
|
+
if (keypressStream !== null) {
|
|
679
676
|
keypressStream.removeListener('keypress', handleKeypress);
|
|
680
677
|
stdin.removeListener('data', handleRawKeypress);
|
|
681
678
|
}
|
|
@@ -708,7 +705,7 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
708
705
|
kittySequenceBuffer = '';
|
|
709
706
|
}
|
|
710
707
|
// Flush any pending paste data to avoid data loss on exit.
|
|
711
|
-
if (
|
|
708
|
+
if (pasteBuffer !== null) {
|
|
712
709
|
broadcast({
|
|
713
710
|
name: '',
|
|
714
711
|
ctrl: false,
|
|
@@ -717,23 +714,19 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
717
714
|
paste: true,
|
|
718
715
|
sequence: pasteBuffer.toString(),
|
|
719
716
|
});
|
|
720
|
-
pasteBuffer =
|
|
721
|
-
}
|
|
722
|
-
if (draggingTimerRef.current) {
|
|
723
|
-
clearTimeout(draggingTimerRef.current);
|
|
724
|
-
draggingTimerRef.current = null;
|
|
717
|
+
pasteBuffer = null;
|
|
725
718
|
}
|
|
726
|
-
|
|
719
|
+
clearDraggingTimer();
|
|
720
|
+
if (dragBuffer) {
|
|
727
721
|
broadcast({
|
|
728
722
|
name: '',
|
|
729
723
|
ctrl: false,
|
|
730
724
|
meta: false,
|
|
731
725
|
shift: false,
|
|
732
726
|
paste: true,
|
|
733
|
-
sequence:
|
|
727
|
+
sequence: dragBuffer,
|
|
734
728
|
});
|
|
735
|
-
|
|
736
|
-
dragBufferRef.current = '';
|
|
729
|
+
dragBuffer = '';
|
|
737
730
|
}
|
|
738
731
|
};
|
|
739
732
|
}, [
|
|
@@ -741,8 +734,8 @@ export function KeypressProvider({ children, kittyProtocolEnabled, config, debug
|
|
|
741
734
|
setRawMode,
|
|
742
735
|
kittyProtocolEnabled,
|
|
743
736
|
config,
|
|
744
|
-
subscribers,
|
|
745
737
|
debugKeystrokeLogging,
|
|
738
|
+
broadcast,
|
|
746
739
|
]);
|
|
747
740
|
return (_jsx(KeypressContext.Provider, { value: { subscribe, unsubscribe }, children: children }));
|
|
748
741
|
}
|