@google/gemini-cli 0.13.0-nightly.20251030.42c79c64 → 0.13.0-nightly.20251101.caf2ca14
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.13.0-nightly.20251031.c89bc30d.tgz +0 -0
- package/dist/package.json +8 -10
- package/dist/src/commands/extensions/install.js +2 -2
- package/dist/src/commands/extensions/install.js.map +1 -1
- package/dist/src/commands/extensions/install.test.js +27 -16
- package/dist/src/commands/extensions/install.test.js.map +1 -1
- package/dist/src/commands/extensions/link.js +2 -2
- package/dist/src/commands/extensions/link.js.map +1 -1
- package/dist/src/commands/extensions/update.js +3 -2
- package/dist/src/commands/extensions/update.js.map +1 -1
- package/dist/src/commands/extensions/validate.d.ts +12 -0
- package/dist/src/commands/extensions/validate.js +83 -0
- package/dist/src/commands/extensions/validate.js.map +1 -0
- package/dist/src/commands/extensions/validate.test.d.ts +6 -0
- package/dist/src/commands/extensions/validate.test.js +93 -0
- package/dist/src/commands/extensions/validate.test.js.map +1 -0
- package/dist/src/commands/extensions.js +2 -0
- package/dist/src/commands/extensions.js.map +1 -1
- package/dist/src/config/config.js +2 -1
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +6 -10
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/extension-manager.js +8 -2
- package/dist/src/config/extension-manager.js.map +1 -1
- package/dist/src/config/extension.test.js +61 -1
- package/dist/src/config/extension.test.js.map +1 -1
- package/dist/src/config/extensions/update.d.ts +2 -2
- package/dist/src/config/extensions/update.js +28 -22
- package/dist/src/config/extensions/update.js.map +1 -1
- package/dist/src/config/settings.js +1 -1
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settings.test.js +13 -53
- package/dist/src/config/settings.test.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +26 -8
- package/dist/src/config/settingsSchema.js +25 -7
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/config/settingsSchema.test.js +2 -0
- package/dist/src/config/settingsSchema.test.js.map +1 -1
- package/dist/src/config/trustedFolders.d.ts +1 -1
- package/dist/src/config/trustedFolders.js +4 -2
- package/dist/src/config/trustedFolders.js.map +1 -1
- package/dist/src/gemini.d.ts +1 -1
- package/dist/src/gemini.js +8 -1
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +58 -28
- package/dist/src/gemini.test.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/test-utils/async.d.ts +9 -0
- package/dist/src/test-utils/async.js +29 -0
- package/dist/src/test-utils/async.js.map +1 -0
- package/dist/src/test-utils/render.d.ts +2 -1
- package/dist/src/test-utils/render.js +36 -2
- package/dist/src/test-utils/render.js.map +1 -1
- package/dist/src/test-utils/render.test.js +29 -4
- package/dist/src/test-utils/render.test.js.map +1 -1
- package/dist/src/ui/App.test.js +1 -1
- package/dist/src/ui/App.test.js.map +1 -1
- package/dist/src/ui/AppContainer.js +1 -1
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/AppContainer.test.js +205 -99
- package/dist/src/ui/AppContainer.test.js.map +1 -1
- package/dist/src/ui/auth/ApiAuthDialog.test.js +1 -1
- package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -1
- package/dist/src/ui/components/AnsiOutput.test.js +1 -1
- package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
- package/dist/src/ui/components/Composer.test.js +1 -1
- package/dist/src/ui/components/Composer.test.js.map +1 -1
- package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
- package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
- package/dist/src/ui/components/ContextSummaryDisplay.test.js +11 -6
- package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -1
- package/dist/src/ui/components/FolderTrustDialog.test.js +4 -3
- package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/Footer.js +3 -2
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Footer.test.js +59 -0
- package/dist/src/ui/components/Footer.test.js.map +1 -1
- package/dist/src/ui/components/Header.test.js +9 -5
- package/dist/src/ui/components/Header.test.js.map +1 -1
- package/dist/src/ui/components/Help.test.js +5 -3
- package/dist/src/ui/components/Help.test.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.test.js +139 -111
- package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
- package/dist/src/ui/components/LoadingIndicator.js +2 -2
- package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/src/ui/components/LoadingIndicator.test.js +28 -15
- package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.js +1 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js +2 -2
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +1 -1
- package/dist/src/ui/components/ModelDialog.js +1 -1
- package/dist/src/ui/components/ModelDialog.js.map +1 -1
- package/dist/src/ui/components/ModelDialog.test.js +21 -11
- package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
- package/dist/src/ui/components/ModelStatsDisplay.test.js +1 -1
- package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -1
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +11 -10
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/PrepareLabel.test.js +14 -8
- package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
- package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
- package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
- package/dist/src/ui/components/QueuedMessageDisplay.test.js +11 -6
- package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
- package/dist/src/ui/components/SessionSummaryDisplay.test.js +1 -1
- package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.test.js +438 -512
- package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.js +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.test.js +2 -2
- package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -1
- package/dist/src/ui/components/StatsDisplay.test.js +1 -1
- package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.js +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
- package/dist/src/ui/components/ThemeDialog.test.js +3 -2
- package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
- package/dist/src/ui/components/ToolStatsDisplay.test.js +1 -1
- package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -1
- package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
- package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
- package/dist/src/ui/components/messages/Todo.test.js +1 -1
- package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
- package/dist/src/ui/components/shared/BaseSelectionList.test.js +12 -11
- package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
- package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
- package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
- package/dist/src/ui/components/shared/TextInput.test.js +1 -1
- package/dist/src/ui/components/shared/TextInput.test.js.map +1 -1
- package/dist/src/ui/components/views/ChatList.test.js +7 -4
- package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
- package/dist/src/ui/components/views/ExtensionsList.js +1 -0
- package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
- package/dist/src/ui/components/views/ExtensionsList.test.js +13 -5
- package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
- package/dist/src/ui/components/views/McpStatus.test.js +23 -12
- package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.js +43 -45
- package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.test.js +136 -252
- package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
- package/dist/src/ui/contexts/SessionContext.test.js +9 -5
- package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js +1 -0
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.test.js +47 -34
- package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.test.js +141 -104
- package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/useAtCompletion.test.js +23 -21
- package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useCommandCompletion.test.js +16 -15
- package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.test.js +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
- package/dist/src/ui/hooks/useEditorSettings.test.js +1 -1
- package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.d.ts +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.js +9 -3
- package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +10 -9
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
- package/dist/src/ui/hooks/useFocus.test.js +1 -1
- package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
- package/dist/src/ui/hooks/useFolderTrust.test.js +7 -6
- package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.test.js +39 -38
- package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
- package/dist/src/ui/hooks/useGitBranchName.test.js +5 -4
- package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
- package/dist/src/ui/hooks/useIdeTrustListener.test.js +25 -11
- package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
- package/dist/src/ui/hooks/useKeypress.test.js +1 -1
- package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
- package/dist/src/ui/hooks/useLoadingIndicator.test.js +1 -1
- package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useMemoryMonitor.test.js +1 -1
- package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
- package/dist/src/ui/hooks/useMessageQueue.test.js +5 -4
- package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
- package/dist/src/ui/hooks/useModelCommand.test.js +7 -4
- package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.test.js +46 -16
- package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
- package/dist/src/ui/hooks/usePrivacySettings.test.js +11 -7
- package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
- package/dist/src/ui/hooks/usePromptCompletion.js +2 -2
- package/dist/src/ui/hooks/usePromptCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js +28 -14
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
- package/dist/src/ui/hooks/useSelectionList.test.js +116 -109
- package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
- package/dist/src/ui/hooks/useShellHistory.test.js +25 -17
- package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.js +16 -5
- package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.js +244 -111
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useTimer.test.js +1 -1
- package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +6 -2
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/hooks/vim.test.js +6 -21
- package/dist/src/ui/hooks/vim.test.js.map +1 -1
- package/dist/src/ui/state/extensions.d.ts +1 -0
- package/dist/src/ui/state/extensions.js +1 -0
- package/dist/src/ui/state/extensions.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -11
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { act } from 'react';
|
|
3
3
|
import { renderHook } from '../../test-utils/render.js';
|
|
4
|
+
import { waitFor } from '../../test-utils/async.js';
|
|
4
5
|
import { vi } from 'vitest';
|
|
5
6
|
import { KeypressProvider, useKeypressContext, DRAG_COMPLETION_TIMEOUT_MS, KITTY_SEQUENCE_TIMEOUT_MS,
|
|
6
7
|
// CSI_END_O,
|
|
@@ -32,6 +33,14 @@ class MockStdin extends EventEmitter {
|
|
|
32
33
|
this.emit('data', text);
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
// Helper function to setup keypress test with standard configuration
|
|
37
|
+
const setupKeypressTest = (kittyProtocolEnabled = true) => {
|
|
38
|
+
const keyHandler = vi.fn();
|
|
39
|
+
const wrapper = ({ children }) => (_jsx(KeypressProvider, { kittyProtocolEnabled: kittyProtocolEnabled, children: children }));
|
|
40
|
+
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
41
|
+
act(() => result.current.subscribe(keyHandler));
|
|
42
|
+
return { result, keyHandler };
|
|
43
|
+
};
|
|
35
44
|
describe('KeypressContext - Kitty Protocol', () => {
|
|
36
45
|
let stdin;
|
|
37
46
|
const mockSetRawMode = vi.fn();
|
|
@@ -45,100 +54,55 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|
|
45
54
|
});
|
|
46
55
|
});
|
|
47
56
|
describe('Enter key handling', () => {
|
|
48
|
-
it(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
name: 'return',
|
|
60
|
-
kittyProtocol: true,
|
|
61
|
-
ctrl: false,
|
|
62
|
-
meta: false,
|
|
63
|
-
shift: false,
|
|
64
|
-
}));
|
|
65
|
-
});
|
|
66
|
-
it('should recognize numpad enter key (keycode 57414) in kitty protocol', async () => {
|
|
67
|
-
const keyHandler = vi.fn();
|
|
68
|
-
const { result } = renderHook(() => useKeypressContext(), {
|
|
69
|
-
wrapper: ({ children }) => wrapper({ children, kittyProtocolEnabled: true }),
|
|
70
|
-
});
|
|
71
|
-
act(() => result.current.subscribe(keyHandler));
|
|
72
|
-
// Send kitty protocol sequence for numpad enter: ESC[57414u
|
|
73
|
-
act(() => {
|
|
74
|
-
stdin.write(`\x1b[57414u`);
|
|
75
|
-
});
|
|
76
|
-
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
77
|
-
name: 'return',
|
|
78
|
-
kittyProtocol: true,
|
|
79
|
-
ctrl: false,
|
|
80
|
-
meta: false,
|
|
81
|
-
shift: false,
|
|
82
|
-
}));
|
|
83
|
-
});
|
|
84
|
-
it('should handle numpad enter with modifiers', async () => {
|
|
85
|
-
const keyHandler = vi.fn();
|
|
86
|
-
const { result } = renderHook(() => useKeypressContext(), {
|
|
87
|
-
wrapper: ({ children }) => wrapper({ children, kittyProtocolEnabled: true }),
|
|
88
|
-
});
|
|
89
|
-
act(() => result.current.subscribe(keyHandler));
|
|
90
|
-
// Send kitty protocol sequence for numpad enter with Shift (modifier 2): ESC[57414;2u
|
|
57
|
+
it.each([
|
|
58
|
+
{
|
|
59
|
+
name: 'regular enter key (keycode 13)',
|
|
60
|
+
sequence: '\x1b[13u',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'numpad enter key (keycode 57414)',
|
|
64
|
+
sequence: '\x1b[57414u',
|
|
65
|
+
},
|
|
66
|
+
])('should recognize $name in kitty protocol', async ({ sequence }) => {
|
|
67
|
+
const { keyHandler } = setupKeypressTest(true);
|
|
91
68
|
act(() => {
|
|
92
|
-
stdin.write(
|
|
69
|
+
stdin.write(sequence);
|
|
93
70
|
});
|
|
94
71
|
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
95
72
|
name: 'return',
|
|
96
73
|
kittyProtocol: true,
|
|
97
74
|
ctrl: false,
|
|
98
75
|
meta: false,
|
|
99
|
-
shift: true,
|
|
100
|
-
}));
|
|
101
|
-
});
|
|
102
|
-
it('should handle numpad enter with Ctrl modifier', async () => {
|
|
103
|
-
const keyHandler = vi.fn();
|
|
104
|
-
const { result } = renderHook(() => useKeypressContext(), {
|
|
105
|
-
wrapper: ({ children }) => wrapper({ children, kittyProtocolEnabled: true }),
|
|
106
|
-
});
|
|
107
|
-
act(() => result.current.subscribe(keyHandler));
|
|
108
|
-
// Send kitty protocol sequence for numpad enter with Ctrl (modifier 5): ESC[57414;5u
|
|
109
|
-
act(() => stdin.write(`\x1b[57414;5u`));
|
|
110
|
-
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
111
|
-
name: 'return',
|
|
112
|
-
kittyProtocol: true,
|
|
113
|
-
ctrl: true,
|
|
114
|
-
meta: false,
|
|
115
76
|
shift: false,
|
|
116
77
|
}));
|
|
117
78
|
});
|
|
118
|
-
it(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
79
|
+
it.each([
|
|
80
|
+
{
|
|
81
|
+
modifier: 'Shift',
|
|
82
|
+
sequence: '\x1b[57414;2u',
|
|
83
|
+
expected: { ctrl: false, meta: false, shift: true },
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
modifier: 'Ctrl',
|
|
87
|
+
sequence: '\x1b[57414;5u',
|
|
88
|
+
expected: { ctrl: true, meta: false, shift: false },
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
modifier: 'Alt',
|
|
92
|
+
sequence: '\x1b[57414;3u',
|
|
93
|
+
expected: { ctrl: false, meta: true, shift: false },
|
|
94
|
+
},
|
|
95
|
+
])('should handle numpad enter with $modifier modifier', async ({ sequence, expected }) => {
|
|
96
|
+
const { keyHandler } = setupKeypressTest(true);
|
|
97
|
+
act(() => stdin.write(sequence));
|
|
128
98
|
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
129
99
|
name: 'return',
|
|
130
100
|
kittyProtocol: true,
|
|
131
|
-
|
|
132
|
-
meta: true,
|
|
133
|
-
shift: false,
|
|
101
|
+
...expected,
|
|
134
102
|
}));
|
|
135
103
|
});
|
|
136
104
|
it('should not process kitty sequences when kitty protocol is disabled', async () => {
|
|
137
|
-
const keyHandler =
|
|
138
|
-
const { result } = renderHook(() => useKeypressContext(), {
|
|
139
|
-
wrapper: ({ children }) => wrapper({ children, kittyProtocolEnabled: false }),
|
|
140
|
-
});
|
|
141
|
-
act(() => result.current.subscribe(keyHandler));
|
|
105
|
+
const { keyHandler } = setupKeypressTest(false);
|
|
142
106
|
// Send kitty protocol sequence for numpad enter
|
|
143
107
|
act(() => {
|
|
144
108
|
stdin.write(`\x1b[57414u`);
|
|
@@ -153,11 +117,7 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|
|
153
117
|
});
|
|
154
118
|
describe('Escape key handling', () => {
|
|
155
119
|
it('should recognize escape key (keycode 27) in kitty protocol', async () => {
|
|
156
|
-
const keyHandler =
|
|
157
|
-
const { result } = renderHook(() => useKeypressContext(), {
|
|
158
|
-
wrapper: ({ children }) => wrapper({ children, kittyProtocolEnabled: true }),
|
|
159
|
-
});
|
|
160
|
-
act(() => result.current.subscribe(keyHandler));
|
|
120
|
+
const { keyHandler } = setupKeypressTest(true);
|
|
161
121
|
// Send kitty protocol sequence for escape: ESC[27u
|
|
162
122
|
act(() => {
|
|
163
123
|
stdin.write('\x1b[27u');
|
|
@@ -169,132 +129,80 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|
|
169
129
|
});
|
|
170
130
|
});
|
|
171
131
|
describe('Tab and Backspace handling', () => {
|
|
172
|
-
it(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
name: '
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
const keyHandler = vi.fn();
|
|
201
|
-
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
202
|
-
act(() => result.current.subscribe(keyHandler));
|
|
203
|
-
act(() => {
|
|
204
|
-
stdin.write(`\x1b[127u`);
|
|
205
|
-
});
|
|
206
|
-
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
207
|
-
name: 'backspace',
|
|
208
|
-
kittyProtocol: true,
|
|
209
|
-
meta: false,
|
|
210
|
-
}));
|
|
211
|
-
});
|
|
212
|
-
it('should recognize Option+Backspace in kitty protocol', async () => {
|
|
213
|
-
const keyHandler = vi.fn();
|
|
214
|
-
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
215
|
-
act(() => result.current.subscribe(keyHandler));
|
|
216
|
-
// Modifier 3 is Alt/Option
|
|
217
|
-
act(() => {
|
|
218
|
-
stdin.write(`\x1b[127;3u`);
|
|
219
|
-
});
|
|
220
|
-
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
221
|
-
name: 'backspace',
|
|
222
|
-
kittyProtocol: true,
|
|
223
|
-
meta: true,
|
|
224
|
-
}));
|
|
225
|
-
});
|
|
226
|
-
it('should recognize Ctrl+Backspace in kitty protocol', async () => {
|
|
227
|
-
const keyHandler = vi.fn();
|
|
228
|
-
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
229
|
-
act(() => result.current.subscribe(keyHandler));
|
|
230
|
-
// Modifier 5 is Ctrl
|
|
132
|
+
it.each([
|
|
133
|
+
{
|
|
134
|
+
name: 'Tab key',
|
|
135
|
+
sequence: '\x1b[9u',
|
|
136
|
+
expected: { name: 'tab', shift: false },
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'Shift+Tab',
|
|
140
|
+
sequence: '\x1b[9;2u',
|
|
141
|
+
expected: { name: 'tab', shift: true },
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'Backspace',
|
|
145
|
+
sequence: '\x1b[127u',
|
|
146
|
+
expected: { name: 'backspace', meta: false },
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'Option+Backspace',
|
|
150
|
+
sequence: '\x1b[127;3u',
|
|
151
|
+
expected: { name: 'backspace', meta: true },
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'Ctrl+Backspace',
|
|
155
|
+
sequence: '\x1b[127;5u',
|
|
156
|
+
expected: { name: 'backspace', ctrl: true },
|
|
157
|
+
},
|
|
158
|
+
])('should recognize $name in kitty protocol', async ({ sequence, expected }) => {
|
|
159
|
+
const { keyHandler } = setupKeypressTest(true);
|
|
231
160
|
act(() => {
|
|
232
|
-
stdin.write(
|
|
161
|
+
stdin.write(sequence);
|
|
233
162
|
});
|
|
234
163
|
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
235
|
-
|
|
164
|
+
...expected,
|
|
236
165
|
kittyProtocol: true,
|
|
237
|
-
ctrl: true,
|
|
238
166
|
}));
|
|
239
167
|
});
|
|
240
168
|
});
|
|
241
169
|
describe('paste mode', () => {
|
|
242
|
-
it(
|
|
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
|
-
stdin.write(PASTE_START.slice(3));
|
|
274
|
-
stdin.write(pastedText);
|
|
275
|
-
stdin.write(PASTE_END);
|
|
276
|
-
});
|
|
277
|
-
await vi.waitFor(() => {
|
|
278
|
-
expect(keyHandler).toHaveBeenCalledTimes(1);
|
|
279
|
-
});
|
|
280
|
-
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
281
|
-
paste: true,
|
|
282
|
-
sequence: pastedText,
|
|
283
|
-
}));
|
|
284
|
-
});
|
|
285
|
-
it('should paste end code split over multiple writes', async () => {
|
|
170
|
+
it.each([
|
|
171
|
+
{
|
|
172
|
+
name: 'handle multiline paste as a single event',
|
|
173
|
+
pastedText: 'This \n is \n a \n multiline \n paste.',
|
|
174
|
+
writeSequence: (text) => {
|
|
175
|
+
stdin.write(PASTE_START);
|
|
176
|
+
stdin.write(text);
|
|
177
|
+
stdin.write(PASTE_END);
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: 'handle paste start code split over multiple writes',
|
|
182
|
+
pastedText: 'pasted content',
|
|
183
|
+
writeSequence: (text) => {
|
|
184
|
+
stdin.write(PASTE_START.slice(0, 3));
|
|
185
|
+
stdin.write(PASTE_START.slice(3));
|
|
186
|
+
stdin.write(text);
|
|
187
|
+
stdin.write(PASTE_END);
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: 'handle paste end code split over multiple writes',
|
|
192
|
+
pastedText: 'pasted content',
|
|
193
|
+
writeSequence: (text) => {
|
|
194
|
+
stdin.write(PASTE_START);
|
|
195
|
+
stdin.write(text);
|
|
196
|
+
stdin.write(PASTE_END.slice(0, 3));
|
|
197
|
+
stdin.write(PASTE_END.slice(3));
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
])('should $name', async ({ pastedText, writeSequence }) => {
|
|
286
201
|
const keyHandler = vi.fn();
|
|
287
|
-
const pastedText = 'pasted content';
|
|
288
202
|
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
289
203
|
act(() => result.current.subscribe(keyHandler));
|
|
290
|
-
act(() =>
|
|
291
|
-
|
|
292
|
-
stdin.write(pastedText);
|
|
293
|
-
// Split PASTE_END into two parts
|
|
294
|
-
stdin.write(PASTE_END.slice(0, 3));
|
|
295
|
-
stdin.write(PASTE_END.slice(3));
|
|
296
|
-
});
|
|
297
|
-
await vi.waitFor(() => {
|
|
204
|
+
act(() => writeSequence(pastedText));
|
|
205
|
+
await waitFor(() => {
|
|
298
206
|
expect(keyHandler).toHaveBeenCalledTimes(1);
|
|
299
207
|
});
|
|
300
208
|
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
@@ -390,6 +298,10 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|
|
390
298
|
{ sequence: `\x1b[1~`, expected: { name: 'home' } },
|
|
391
299
|
{ sequence: `\x1b[4~`, expected: { name: 'end' } },
|
|
392
300
|
{ sequence: `\x1b[2~`, expected: { name: 'insert' } },
|
|
301
|
+
{ sequence: `\x1b[11~`, expected: { name: 'f1' } },
|
|
302
|
+
{ sequence: `\x1b[17~`, expected: { name: 'f6' } },
|
|
303
|
+
{ sequence: `\x1b[23~`, expected: { name: 'f11' } },
|
|
304
|
+
{ sequence: `\x1b[24~`, expected: { name: 'f12' } },
|
|
393
305
|
// Reverse tabs
|
|
394
306
|
{ sequence: `\x1b[Z`, expected: { name: 'tab', shift: true } },
|
|
395
307
|
{ sequence: `\x1b[1;2Z`, expected: { name: 'tab', shift: true } },
|
|
@@ -429,26 +341,20 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|
|
429
341
|
});
|
|
430
342
|
describe('Double-tap and batching', () => {
|
|
431
343
|
it('should emit two delete events for double-tap CSI[3~', async () => {
|
|
432
|
-
const keyHandler =
|
|
433
|
-
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
434
|
-
act(() => result.current.subscribe(keyHandler));
|
|
344
|
+
const { keyHandler } = setupKeypressTest(true);
|
|
435
345
|
act(() => stdin.write(`\x1b[3~`));
|
|
436
346
|
act(() => stdin.write(`\x1b[3~`));
|
|
437
347
|
expect(keyHandler).toHaveBeenNthCalledWith(1, expect.objectContaining({ name: 'delete' }));
|
|
438
348
|
expect(keyHandler).toHaveBeenNthCalledWith(2, expect.objectContaining({ name: 'delete' }));
|
|
439
349
|
});
|
|
440
350
|
it('should parse two concatenated tilde-coded sequences in one chunk', async () => {
|
|
441
|
-
const keyHandler =
|
|
442
|
-
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
443
|
-
act(() => result.current.subscribe(keyHandler));
|
|
351
|
+
const { keyHandler } = setupKeypressTest(true);
|
|
444
352
|
act(() => stdin.write(`\x1b[3~\x1b[5~`));
|
|
445
353
|
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({ name: 'delete' }));
|
|
446
354
|
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({ name: 'pageup' }));
|
|
447
355
|
});
|
|
448
356
|
it('should ignore incomplete CSI then parse the next complete sequence', async () => {
|
|
449
|
-
const keyHandler =
|
|
450
|
-
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
451
|
-
act(() => result.current.subscribe(keyHandler));
|
|
357
|
+
const { keyHandler } = setupKeypressTest(true);
|
|
452
358
|
// Incomplete ESC sequence then a complete Delete
|
|
453
359
|
act(() => {
|
|
454
360
|
// Provide an incomplete ESC sequence chunk with a real ESC character
|
|
@@ -477,65 +383,45 @@ describe('Drag and Drop Handling', () => {
|
|
|
477
383
|
vi.useRealTimers();
|
|
478
384
|
});
|
|
479
385
|
describe('drag start by quotes', () => {
|
|
480
|
-
it(
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
act(() => stdin.write(SINGLE_QUOTE));
|
|
485
|
-
expect(keyHandler).not.toHaveBeenCalled();
|
|
486
|
-
});
|
|
487
|
-
it('should start collecting when double quote arrives and not broadcast immediately', async () => {
|
|
386
|
+
it.each([
|
|
387
|
+
{ name: 'single quote', quote: SINGLE_QUOTE },
|
|
388
|
+
{ name: 'double quote', quote: DOUBLE_QUOTE },
|
|
389
|
+
])('should start collecting when $name arrives and not broadcast immediately', async ({ quote }) => {
|
|
488
390
|
const keyHandler = vi.fn();
|
|
489
391
|
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
490
392
|
act(() => result.current.subscribe(keyHandler));
|
|
491
|
-
act(() => stdin.write(
|
|
393
|
+
act(() => stdin.write(quote));
|
|
492
394
|
expect(keyHandler).not.toHaveBeenCalled();
|
|
493
395
|
});
|
|
494
396
|
});
|
|
495
397
|
describe('drag collection and completion', () => {
|
|
496
|
-
it(
|
|
398
|
+
it.each([
|
|
399
|
+
{
|
|
400
|
+
name: 'collect single character inputs during drag mode',
|
|
401
|
+
characters: ['a'],
|
|
402
|
+
expectedText: 'a',
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
name: 'collect multiple characters and complete on timeout',
|
|
406
|
+
characters: ['p', 'a', 't', 'h'],
|
|
407
|
+
expectedText: 'path',
|
|
408
|
+
},
|
|
409
|
+
])('should $name', async ({ characters, expectedText }) => {
|
|
497
410
|
const keyHandler = vi.fn();
|
|
498
411
|
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
499
412
|
act(() => result.current.subscribe(keyHandler));
|
|
500
|
-
// Start by single quote
|
|
501
413
|
act(() => stdin.write(SINGLE_QUOTE));
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
// Character should not be immediately broadcast
|
|
505
|
-
expect(keyHandler).not.toHaveBeenCalled();
|
|
506
|
-
// Fast-forward to completion timeout
|
|
507
|
-
act(() => {
|
|
508
|
-
vi.advanceTimersByTime(DRAG_COMPLETION_TIMEOUT_MS + 10);
|
|
414
|
+
characters.forEach((char) => {
|
|
415
|
+
act(() => stdin.write(char));
|
|
509
416
|
});
|
|
510
|
-
// Should broadcast the collected path as paste (includes starting quote)
|
|
511
|
-
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
512
|
-
name: '',
|
|
513
|
-
paste: true,
|
|
514
|
-
sequence: `${SINGLE_QUOTE}a`,
|
|
515
|
-
}));
|
|
516
|
-
});
|
|
517
|
-
it('should collect multiple characters and complete on timeout', async () => {
|
|
518
|
-
const keyHandler = vi.fn();
|
|
519
|
-
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
520
|
-
act(() => result.current.subscribe(keyHandler));
|
|
521
|
-
// Start by single quote
|
|
522
|
-
act(() => stdin.write(SINGLE_QUOTE));
|
|
523
|
-
// Send multiple characters
|
|
524
|
-
act(() => stdin.write('p'));
|
|
525
|
-
act(() => stdin.write('a'));
|
|
526
|
-
act(() => stdin.write('t'));
|
|
527
|
-
act(() => stdin.write('h'));
|
|
528
|
-
// Characters should not be immediately broadcast
|
|
529
417
|
expect(keyHandler).not.toHaveBeenCalled();
|
|
530
|
-
// Fast-forward to completion timeout
|
|
531
418
|
act(() => {
|
|
532
419
|
vi.advanceTimersByTime(DRAG_COMPLETION_TIMEOUT_MS + 10);
|
|
533
420
|
});
|
|
534
|
-
// Should broadcast the collected path as paste (includes starting quote)
|
|
535
421
|
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
536
422
|
name: '',
|
|
537
423
|
paste: true,
|
|
538
|
-
sequence: `${SINGLE_QUOTE}
|
|
424
|
+
sequence: `${SINGLE_QUOTE}${expectedText}`,
|
|
539
425
|
}));
|
|
540
426
|
});
|
|
541
427
|
});
|
|
@@ -650,9 +536,7 @@ describe('Kitty Sequence Parsing', () => {
|
|
|
650
536
|
vi.useRealTimers();
|
|
651
537
|
});
|
|
652
538
|
it('should treat backslash as a regular keystroke', () => {
|
|
653
|
-
const keyHandler =
|
|
654
|
-
const { result } = renderHook(() => useKeypressContext(), { wrapper });
|
|
655
|
-
act(() => result.current.subscribe(keyHandler));
|
|
539
|
+
const { keyHandler } = setupKeypressTest(true);
|
|
656
540
|
act(() => stdin.write('\\'));
|
|
657
541
|
// Advance timers to trigger the backslash timeout
|
|
658
542
|
act(() => {
|
|
@@ -794,10 +678,10 @@ describe('Kitty Sequence Parsing', () => {
|
|
|
794
678
|
act(() => {
|
|
795
679
|
stdin.emit('data', Buffer.from(char));
|
|
796
680
|
});
|
|
797
|
-
await new Promise((resolve) =>
|
|
681
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
798
682
|
}
|
|
799
683
|
// Should parse once complete
|
|
800
|
-
await
|
|
684
|
+
await waitFor(() => {
|
|
801
685
|
expect(keyHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
802
686
|
name: 'escape',
|
|
803
687
|
kittyProtocol: true,
|