@machina.ai/cell-cli 1.11.0-rc1 → 1.13.0-rc1
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/package.json +12 -10
- package/dist/src/commands/extensions/disable.d.ts +1 -1
- package/dist/src/commands/extensions/disable.js +15 -7
- package/dist/src/commands/extensions/disable.js.map +1 -1
- package/dist/src/commands/extensions/enable.d.ts +1 -1
- package/dist/src/commands/extensions/enable.js +15 -7
- package/dist/src/commands/extensions/enable.js.map +1 -1
- package/dist/src/commands/extensions/install.js +14 -3
- package/dist/src/commands/extensions/install.js.map +1 -1
- package/dist/src/commands/extensions/install.test.js +39 -19
- package/dist/src/commands/extensions/install.test.js.map +1 -1
- package/dist/src/commands/extensions/link.js +14 -3
- 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 +13 -2
- package/dist/src/commands/extensions/uninstall.js.map +1 -1
- package/dist/src/commands/extensions/update.js +18 -13
- 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.js +93 -0
- package/dist/src/commands/extensions/validate.test.js.map +1 -0
- package/dist/src/commands/extensions.js +3 -0
- package/dist/src/commands/extensions.js.map +1 -1
- package/dist/src/commands/mcp/add.test.js +3 -0
- package/dist/src/commands/mcp/add.test.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 +37 -27
- package/dist/src/commands/mcp/list.test.js.map +1 -1
- package/dist/src/config/auth.js +0 -5
- package/dist/src/config/auth.js.map +1 -1
- package/dist/src/config/config.d.ts +6 -3
- package/dist/src/config/config.js +65 -80
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +235 -212
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/extension-manager.d.ts +63 -0
- package/dist/src/config/extension-manager.js +450 -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 +525 -201
- 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.d.ts +1 -1
- package/dist/src/config/extensions/extensionEnablement.js +4 -3
- package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
- package/dist/src/config/extensions/extensionEnablement.test.js +10 -10
- package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
- package/dist/src/config/extensions/extensionSettings.d.ts +15 -0
- package/dist/src/config/extensions/extensionSettings.js +113 -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 +254 -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 +5 -10
- package/dist/src/config/extensions/github.js.map +1 -1
- package/dist/src/config/extensions/github.test.js +153 -167
- package/dist/src/config/extensions/github.test.js.map +1 -1
- package/dist/src/config/extensions/github_fetch.d.ts +1 -1
- package/dist/src/config/extensions/github_fetch.js +13 -1
- package/dist/src/config/extensions/github_fetch.js.map +1 -1
- package/dist/src/config/extensions/github_fetch.test.d.ts +6 -0
- package/dist/src/config/extensions/github_fetch.test.js +169 -0
- package/dist/src/config/extensions/github_fetch.test.js.map +1 -0
- 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 +39 -39
- package/dist/src/config/extensions/update.js.map +1 -1
- package/dist/src/config/extensions/update.test.js +72 -74
- 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/keyBindings.d.ts +3 -0
- package/dist/src/config/keyBindings.js +30 -8
- package/dist/src/config/keyBindings.js.map +1 -1
- package/dist/src/config/keyBindings.test.js +17 -0
- package/dist/src/config/keyBindings.test.js.map +1 -1
- package/dist/src/config/policies/read-only.toml +56 -0
- package/dist/src/config/policies/write.toml +63 -0
- package/dist/src/config/policies/yolo.toml +31 -0
- package/dist/src/config/policy-engine.integration.test.js +41 -38
- package/dist/src/config/policy-engine.integration.test.js.map +1 -1
- package/dist/src/config/policy.d.ts +2 -2
- package/dist/src/config/policy.js +10 -148
- package/dist/src/config/policy.js.map +1 -1
- package/dist/src/config/sandboxConfig.d.ts +1 -1
- package/dist/src/config/sandboxConfig.js +6 -3
- package/dist/src/config/sandboxConfig.js.map +1 -1
- package/dist/src/config/settings.d.ts +2 -1
- package/dist/src/config/settings.js +58 -18
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settings.test.js +128 -69
- package/dist/src/config/settings.test.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +170 -28
- package/dist/src/config/settingsSchema.js +418 -27
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/config/settingsSchema.test.js +42 -1
- 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/core/initializer.js +2 -1
- package/dist/src/core/initializer.js.map +1 -1
- package/dist/src/gemini.d.ts +1 -1
- package/dist/src/gemini.js +46 -16
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +88 -30
- 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/nonInteractiveCli.d.ts +9 -1
- package/dist/src/nonInteractiveCli.js +114 -7
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/nonInteractiveCli.test.js +355 -112
- package/dist/src/nonInteractiveCli.test.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.js +4 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.test.js +22 -0
- package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
- package/dist/src/services/FeedbackService.js +2 -2
- package/dist/src/services/FeedbackService.js.map +1 -1
- package/dist/src/services/McpPromptLoader.js +2 -2
- package/dist/src/services/McpPromptLoader.js.map +1 -1
- package/dist/src/services/McpPromptLoader.test.js +4 -2
- package/dist/src/services/McpPromptLoader.test.js.map +1 -1
- 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/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/test-utils/render.d.ts +16 -2
- package/dist/src/test-utils/render.js +66 -4
- package/dist/src/test-utils/render.js.map +1 -1
- package/dist/src/test-utils/render.test.d.ts +6 -0
- package/dist/src/test-utils/render.test.js +79 -0
- package/dist/src/test-utils/render.test.js.map +1 -0
- 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 +181 -65
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/AppContainer.test.js +505 -147
- package/dist/src/ui/AppContainer.test.js.map +1 -1
- package/dist/src/ui/IdeIntegrationNudge.js +1 -1
- package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
- package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
- package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
- package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
- package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
- package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
- package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
- package/dist/src/ui/auth/AuthDialog.js +7 -3
- package/dist/src/ui/auth/AuthDialog.js.map +1 -1
- package/dist/src/ui/auth/useAuth.d.ts +2 -0
- package/dist/src/ui/auth/useAuth.js +31 -2
- package/dist/src/ui/auth/useAuth.js.map +1 -1
- package/dist/src/ui/colors.js +3 -0
- package/dist/src/ui/colors.js.map +1 -1
- package/dist/src/ui/commands/directoryCommand.js +1 -1
- package/dist/src/ui/commands/directoryCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.js +64 -11
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.test.js +72 -1
- package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +14 -14
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.test.js +4 -0
- package/dist/src/ui/commands/mcpCommand.test.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.js +1 -1
- package/dist/src/ui/commands/memoryCommand.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.test.js +3 -1
- package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
- package/dist/src/ui/commands/policiesCommand.d.ts +7 -0
- package/dist/src/ui/commands/policiesCommand.js +59 -0
- package/dist/src/ui/commands/policiesCommand.js.map +1 -0
- package/dist/src/ui/commands/policiesCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/policiesCommand.test.js +83 -0
- package/dist/src/ui/commands/policiesCommand.test.js.map +1 -0
- 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/AsciiArt.d.ts +3 -3
- package/dist/src/ui/components/AsciiArt.js +3 -3
- package/dist/src/ui/components/Composer.js +1 -1
- package/dist/src/ui/components/Composer.js.map +1 -1
- package/dist/src/ui/components/Composer.test.js +5 -2
- package/dist/src/ui/components/Composer.test.js.map +1 -1
- package/dist/src/ui/components/ConfigInitDisplay.js +4 -6
- package/dist/src/ui/components/ConfigInitDisplay.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/ConsoleSummaryDisplay.js +1 -1
- package/dist/src/ui/components/ConsoleSummaryDisplay.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/DetailedMessagesDisplay.js +1 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
- package/dist/src/ui/components/DialogManager.js +4 -0
- package/dist/src/ui/components/DialogManager.js.map +1 -1
- package/dist/src/ui/components/FolderTrustDialog.test.js +2 -1
- package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/Footer.js +4 -3
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Footer.test.js +83 -0
- package/dist/src/ui/components/Footer.test.js.map +1 -1
- package/dist/src/ui/components/Header.test.js +13 -5
- package/dist/src/ui/components/Header.test.js.map +1 -1
- package/dist/src/ui/components/Help.test.js +5 -4
- package/dist/src/ui/components/Help.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 +27 -8
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.test.js +776 -727
- 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/MainContent.js +15 -4
- package/dist/src/ui/components/MainContent.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 +23 -13
- 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/Notifications.js +38 -5
- package/dist/src/ui/components/Notifications.js.map +1 -1
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +2 -2
- 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.js +32 -25
- package/dist/src/ui/components/SettingsDialog.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.test.js +428 -532
- 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 +2 -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/InfoMessage.js +1 -1
- package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
- package/dist/src/ui/components/messages/Todo.js +27 -5
- package/dist/src/ui/components/messages/Todo.js.map +1 -1
- package/dist/src/ui/components/messages/Todo.test.js +20 -8
- package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.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/messages/WarningMessage.js +2 -2
- package/dist/src/ui/components/messages/WarningMessage.js.map +1 -1
- package/dist/src/ui/components/shared/BaseSelectionList.test.js +1 -1
- 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.d.ts +15 -0
- package/dist/src/ui/components/shared/TextInput.js +38 -0
- package/dist/src/ui/components/shared/TextInput.js.map +1 -0
- package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
- package/dist/src/ui/components/shared/TextInput.test.js +242 -0
- package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
- package/dist/src/ui/components/shared/text-buffer.d.ts +9 -2
- package/dist/src/ui/components/shared/text-buffer.js +51 -13
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.test.js +385 -202
- package/dist/src/ui/components/shared/text-buffer.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.d.ts +7 -1
- package/dist/src/ui/components/views/ExtensionsList.js +9 -11
- package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
- package/dist/src/ui/components/views/ExtensionsList.test.js +43 -22
- 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.d.ts +3 -2
- package/dist/src/ui/contexts/KeypressContext.js +610 -540
- package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.test.js +438 -718
- package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
- package/dist/src/ui/contexts/MouseContext.d.ts +21 -0
- package/dist/src/ui/contexts/MouseContext.js +89 -0
- package/dist/src/ui/contexts/MouseContext.js.map +1 -0
- package/dist/src/ui/contexts/MouseContext.test.d.ts +6 -0
- package/dist/src/ui/contexts/MouseContext.test.js +164 -0
- package/dist/src/ui/contexts/MouseContext.test.js.map +1 -0
- package/dist/src/ui/contexts/SessionContext.test.js +35 -17
- package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
- package/dist/src/ui/contexts/UIActionsContext.d.ts +2 -0
- package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
- package/dist/src/ui/contexts/UIStateContext.d.ts +2 -0
- package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.js +31 -9
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.test.js +64 -35
- package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.test.js +193 -165
- package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/useAtCompletion.test.js +16 -5
- package/dist/src/ui/hooks/useAtCompletion.test.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 +32 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useCommandCompletion.test.js +66 -64
- package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.test.js +26 -9
- package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
- package/dist/src/ui/hooks/useEditorSettings.test.js +40 -34
- package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.d.ts +14 -5
- package/dist/src/ui/hooks/useExtensionUpdates.js +18 -13
- package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +49 -44
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
- package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -5
- package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
- package/dist/src/ui/hooks/useFocus.test.js +25 -9
- package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
- package/dist/src/ui/hooks/useFolderTrust.test.js +46 -22
- package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +56 -19
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.test.js +260 -411
- package/dist/src/ui/hooks/useGeminiStream.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 +46 -34
- package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
- package/dist/src/ui/hooks/useHistoryManager.test.js +2 -1
- package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
- package/dist/src/ui/hooks/useIdeTrustListener.test.js +40 -9
- package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
- package/dist/src/ui/hooks/useInputHistory.test.js +2 -1
- package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
- package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -1
- package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
- package/dist/src/ui/hooks/useKeypress.test.js +103 -114
- package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
- package/dist/src/ui/hooks/useLoadingIndicator.test.js +24 -6
- package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useMemoryMonitor.test.js +10 -5
- package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
- package/dist/src/ui/hooks/useMessageQueue.test.js +62 -45
- package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
- package/dist/src/ui/hooks/useModelCommand.test.js +21 -11
- package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
- package/dist/src/ui/hooks/useMouse.d.ts +17 -0
- package/dist/src/ui/hooks/useMouse.js +27 -0
- package/dist/src/ui/hooks/useMouse.js.map +1 -0
- package/dist/src/ui/hooks/useMouse.test.d.ts +6 -0
- package/dist/src/ui/hooks/useMouse.test.js +57 -0
- package/dist/src/ui/hooks/useMouse.test.js.map +1 -0
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -2
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.js +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.test.js +109 -106
- package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
- package/dist/src/ui/hooks/usePrivacySettings.test.js +26 -6
- 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.js +13 -14
- package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js +55 -48
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.d.ts +8 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js +59 -34
- 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/useReverseSearchCompletion.test.js +2 -2
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useSelectionList.js +5 -4
- package/dist/src/ui/hooks/useSelectionList.js.map +1 -1
- package/dist/src/ui/hooks/useSelectionList.test.js +272 -183
- package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
- package/dist/src/ui/hooks/useShellHistory.test.js +52 -20
- package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.js +18 -7
- package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.js +275 -137
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useTimer.test.js +43 -14
- package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +226 -242
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/hooks/vim.test.js +235 -355
- package/dist/src/ui/hooks/vim.test.js.map +1 -1
- package/dist/src/ui/keyMatchers.test.js +30 -3
- package/dist/src/ui/keyMatchers.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/src/ui/themes/ansi-light.js +1 -0
- package/dist/src/ui/themes/ansi-light.js.map +1 -1
- package/dist/src/ui/themes/ansi.js +1 -0
- package/dist/src/ui/themes/ansi.js.map +1 -1
- package/dist/src/ui/themes/atom-one-dark.js +2 -0
- package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
- package/dist/src/ui/themes/ayu-light.js +2 -0
- package/dist/src/ui/themes/ayu-light.js.map +1 -1
- package/dist/src/ui/themes/ayu.js +2 -0
- package/dist/src/ui/themes/ayu.js.map +1 -1
- package/dist/src/ui/themes/color-utils.d.ts +1 -0
- package/dist/src/ui/themes/color-utils.js +6 -0
- package/dist/src/ui/themes/color-utils.js.map +1 -1
- package/dist/src/ui/themes/color-utils.test.js +13 -1
- package/dist/src/ui/themes/color-utils.test.js.map +1 -1
- package/dist/src/ui/themes/dracula.js +2 -0
- package/dist/src/ui/themes/dracula.js.map +1 -1
- package/dist/src/ui/themes/github-dark.js +2 -0
- package/dist/src/ui/themes/github-dark.js.map +1 -1
- package/dist/src/ui/themes/github-light.js +2 -0
- package/dist/src/ui/themes/github-light.js.map +1 -1
- package/dist/src/ui/themes/googlecode.js +2 -0
- package/dist/src/ui/themes/googlecode.js.map +1 -1
- package/dist/src/ui/themes/no-color.js +3 -0
- package/dist/src/ui/themes/no-color.js.map +1 -1
- package/dist/src/ui/themes/semantic-tokens.d.ts +2 -0
- package/dist/src/ui/themes/semantic-tokens.js +6 -0
- package/dist/src/ui/themes/semantic-tokens.js.map +1 -1
- package/dist/src/ui/themes/shades-of-purple.js +2 -0
- package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
- package/dist/src/ui/themes/theme.d.ts +3 -0
- package/dist/src/ui/themes/theme.js +14 -3
- package/dist/src/ui/themes/theme.js.map +1 -1
- package/dist/src/ui/themes/theme.test.js +67 -1
- package/dist/src/ui/themes/theme.test.js.map +1 -1
- package/dist/src/ui/themes/xcode.js +2 -0
- package/dist/src/ui/themes/xcode.js.map +1 -1
- package/dist/src/ui/types.d.ts +3 -1
- package/dist/src/ui/types.js +2 -0
- 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/ui/utils/InlineMarkdownRenderer.d.ts +1 -0
- package/dist/src/ui/utils/InlineMarkdownRenderer.js +11 -10
- package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.js +11 -9
- package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
- package/dist/src/ui/utils/clipboardUtils.js +2 -2
- package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
- package/dist/src/ui/utils/input.d.ts +17 -0
- package/dist/src/ui/utils/input.js +51 -0
- package/dist/src/ui/utils/input.js.map +1 -0
- package/dist/src/ui/utils/input.test.d.ts +6 -0
- package/dist/src/ui/utils/input.test.js +44 -0
- package/dist/src/ui/utils/input.test.js.map +1 -0
- package/dist/src/ui/utils/kittyProtocolDetector.js +13 -4
- package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
- package/dist/src/ui/utils/mouse.d.ts +31 -0
- package/dist/src/ui/utils/mouse.js +164 -0
- package/dist/src/ui/utils/mouse.js.map +1 -0
- package/dist/src/ui/utils/mouse.test.d.ts +6 -0
- package/dist/src/ui/utils/mouse.test.js +131 -0
- package/dist/src/ui/utils/mouse.test.js.map +1 -0
- package/dist/src/ui/utils/textOutput.d.ts +25 -0
- package/dist/src/ui/utils/textOutput.js +49 -0
- package/dist/src/ui/utils/textOutput.js.map +1 -0
- package/dist/src/ui/utils/textOutput.test.d.ts +6 -0
- package/dist/src/ui/utils/textOutput.test.js +79 -0
- package/dist/src/ui/utils/textOutput.test.js.map +1 -0
- package/dist/src/ui/utils/updateCheck.d.ts +7 -1
- package/dist/src/ui/utils/updateCheck.js +33 -29
- package/dist/src/ui/utils/updateCheck.js.map +1 -1
- package/dist/src/ui/utils/updateCheck.test.js +24 -50
- package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
- package/dist/src/utils/commentJson.js +2 -2
- package/dist/src/utils/commentJson.js.map +1 -1
- package/dist/src/utils/commentJson.test.js +7 -6
- package/dist/src/utils/commentJson.test.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/utils/events.d.ts +11 -2
- package/dist/src/utils/events.js +1 -0
- package/dist/src/utils/events.js.map +1 -1
- package/dist/src/utils/handleAutoUpdate.js +9 -3
- package/dist/src/utils/handleAutoUpdate.js.map +1 -1
- package/dist/src/utils/sandbox.js +16 -18
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/utils/version.js +6 -2
- package/dist/src/utils/version.js.map +1 -1
- package/dist/src/zed-integration/acp.js +2 -1
- package/dist/src/zed-integration/acp.js.map +1 -1
- package/dist/src/zed-integration/schema.d.ts +4 -4
- package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
- package/dist/src/zed-integration/zedIntegration.js +12 -19
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -14
- package/dist/src/config/policy.test.js +0 -360
- package/dist/src/config/policy.test.js.map +0 -1
- package/dist/src/utils/package.d.ts +0 -12
- package/dist/src/utils/package.js +0 -24
- package/dist/src/utils/package.js.map +0 -1
- /package/dist/src/{config/policy.test.d.ts → commands/extensions/validate.test.d.ts} +0 -0
|
@@ -5,7 +5,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
5
5
|
* SPDX-License-Identifier: Apache-2.0
|
|
6
6
|
*/
|
|
7
7
|
import { renderWithProviders } from '../../test-utils/render.js';
|
|
8
|
-
import { waitFor
|
|
8
|
+
import { waitFor } from '../../test-utils/async.js';
|
|
9
|
+
import { act } from 'react';
|
|
9
10
|
import { InputPrompt } from './InputPrompt.js';
|
|
10
11
|
import { ApprovalMode } from '@google/gemini-cli-core';
|
|
11
12
|
import * as path from 'node:path';
|
|
@@ -112,6 +113,7 @@ describe('InputPrompt', () => {
|
|
|
112
113
|
moveToOffset: vi.fn((offset) => {
|
|
113
114
|
mockBuffer.cursor = [0, offset];
|
|
114
115
|
}),
|
|
116
|
+
moveToVisualPosition: vi.fn(),
|
|
115
117
|
killLineRight: vi.fn(),
|
|
116
118
|
killLineLeft: vi.fn(),
|
|
117
119
|
openInExternalEditor: vi.fn(),
|
|
@@ -207,63 +209,68 @@ describe('InputPrompt', () => {
|
|
|
207
209
|
streamingState: StreamingState.Idle,
|
|
208
210
|
};
|
|
209
211
|
});
|
|
210
|
-
const wait = (ms = 50) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
211
212
|
it('should call shellHistory.getPreviousCommand on up arrow in shell mode', async () => {
|
|
212
213
|
props.shellModeActive = true;
|
|
213
214
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
214
|
-
await
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
expect(mockShellHistory.getPreviousCommand).toHaveBeenCalled();
|
|
215
|
+
await act(async () => {
|
|
216
|
+
stdin.write('\u001B[A');
|
|
217
|
+
});
|
|
218
|
+
await waitFor(() => expect(mockShellHistory.getPreviousCommand).toHaveBeenCalled());
|
|
218
219
|
unmount();
|
|
219
220
|
});
|
|
220
221
|
it('should call shellHistory.getNextCommand on down arrow in shell mode', async () => {
|
|
221
222
|
props.shellModeActive = true;
|
|
222
223
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
223
|
-
await
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
await act(async () => {
|
|
225
|
+
stdin.write('\u001B[B');
|
|
226
|
+
await waitFor(() => expect(mockShellHistory.getNextCommand).toHaveBeenCalled());
|
|
227
|
+
});
|
|
227
228
|
unmount();
|
|
228
229
|
});
|
|
229
230
|
it('should set the buffer text when a shell history command is retrieved', async () => {
|
|
230
231
|
props.shellModeActive = true;
|
|
231
232
|
vi.mocked(mockShellHistory.getPreviousCommand).mockReturnValue('previous command');
|
|
232
233
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
233
|
-
await
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
await act(async () => {
|
|
235
|
+
stdin.write('\u001B[A');
|
|
236
|
+
});
|
|
237
|
+
await waitFor(() => {
|
|
238
|
+
expect(mockShellHistory.getPreviousCommand).toHaveBeenCalled();
|
|
239
|
+
expect(props.buffer.setText).toHaveBeenCalledWith('previous command');
|
|
240
|
+
});
|
|
238
241
|
unmount();
|
|
239
242
|
});
|
|
240
243
|
it('should call shellHistory.addCommandToHistory on submit in shell mode', async () => {
|
|
241
244
|
props.shellModeActive = true;
|
|
242
245
|
props.buffer.setText('ls -l');
|
|
243
246
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
244
|
-
await
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
await act(async () => {
|
|
248
|
+
stdin.write('\r');
|
|
249
|
+
});
|
|
250
|
+
await waitFor(() => {
|
|
251
|
+
expect(mockShellHistory.addCommandToHistory).toHaveBeenCalledWith('ls -l');
|
|
252
|
+
expect(props.onSubmit).toHaveBeenCalledWith('ls -l');
|
|
253
|
+
});
|
|
249
254
|
unmount();
|
|
250
255
|
});
|
|
251
256
|
it('should NOT call shell history methods when not in shell mode', async () => {
|
|
252
257
|
props.buffer.setText('some text');
|
|
253
258
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
254
|
-
await
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
await
|
|
259
|
-
|
|
260
|
-
|
|
259
|
+
await act(async () => {
|
|
260
|
+
stdin.write('\u001B[A'); // Up arrow
|
|
261
|
+
});
|
|
262
|
+
await waitFor(() => expect(mockInputHistory.navigateUp).toHaveBeenCalled());
|
|
263
|
+
await act(async () => {
|
|
264
|
+
stdin.write('\u001B[B'); // Down arrow
|
|
265
|
+
});
|
|
266
|
+
await waitFor(() => expect(mockInputHistory.navigateDown).toHaveBeenCalled());
|
|
267
|
+
await act(async () => {
|
|
268
|
+
stdin.write('\r'); // Enter
|
|
269
|
+
});
|
|
270
|
+
await waitFor(() => expect(props.onSubmit).toHaveBeenCalledWith('some text'));
|
|
261
271
|
expect(mockShellHistory.getPreviousCommand).not.toHaveBeenCalled();
|
|
262
272
|
expect(mockShellHistory.getNextCommand).not.toHaveBeenCalled();
|
|
263
273
|
expect(mockShellHistory.addCommandToHistory).not.toHaveBeenCalled();
|
|
264
|
-
expect(mockInputHistory.navigateUp).toHaveBeenCalled();
|
|
265
|
-
expect(mockInputHistory.navigateDown).toHaveBeenCalled();
|
|
266
|
-
expect(props.onSubmit).toHaveBeenCalledWith('some text');
|
|
267
274
|
unmount();
|
|
268
275
|
});
|
|
269
276
|
it('should call completion.navigateUp for both up arrow and Ctrl+P when suggestions are showing', async () => {
|
|
@@ -277,13 +284,15 @@ describe('InputPrompt', () => {
|
|
|
277
284
|
});
|
|
278
285
|
props.buffer.setText('/mem');
|
|
279
286
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
280
|
-
await wait();
|
|
281
287
|
// Test up arrow
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
await
|
|
286
|
-
|
|
288
|
+
await act(async () => {
|
|
289
|
+
stdin.write('\u001B[A'); // Up arrow
|
|
290
|
+
});
|
|
291
|
+
await waitFor(() => expect(mockCommandCompletion.navigateUp).toHaveBeenCalledTimes(1));
|
|
292
|
+
await act(async () => {
|
|
293
|
+
stdin.write('\u0010'); // Ctrl+P
|
|
294
|
+
});
|
|
295
|
+
await waitFor(() => expect(mockCommandCompletion.navigateUp).toHaveBeenCalledTimes(2));
|
|
287
296
|
expect(mockCommandCompletion.navigateDown).not.toHaveBeenCalled();
|
|
288
297
|
unmount();
|
|
289
298
|
});
|
|
@@ -298,13 +307,15 @@ describe('InputPrompt', () => {
|
|
|
298
307
|
});
|
|
299
308
|
props.buffer.setText('/mem');
|
|
300
309
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
301
|
-
await wait();
|
|
302
310
|
// Test down arrow
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
await
|
|
307
|
-
|
|
311
|
+
await act(async () => {
|
|
312
|
+
stdin.write('\u001B[B'); // Down arrow
|
|
313
|
+
});
|
|
314
|
+
await waitFor(() => expect(mockCommandCompletion.navigateDown).toHaveBeenCalledTimes(1));
|
|
315
|
+
await act(async () => {
|
|
316
|
+
stdin.write('\u000E'); // Ctrl+N
|
|
317
|
+
});
|
|
318
|
+
await waitFor(() => expect(mockCommandCompletion.navigateDown).toHaveBeenCalledTimes(2));
|
|
308
319
|
expect(mockCommandCompletion.navigateUp).not.toHaveBeenCalled();
|
|
309
320
|
unmount();
|
|
310
321
|
});
|
|
@@ -315,17 +326,24 @@ describe('InputPrompt', () => {
|
|
|
315
326
|
});
|
|
316
327
|
props.buffer.setText('some text');
|
|
317
328
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
318
|
-
await
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
await
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
await
|
|
327
|
-
|
|
328
|
-
|
|
329
|
+
await act(async () => {
|
|
330
|
+
stdin.write('\u001B[A'); // Up arrow
|
|
331
|
+
});
|
|
332
|
+
await waitFor(() => expect(mockInputHistory.navigateUp).toHaveBeenCalled());
|
|
333
|
+
await act(async () => {
|
|
334
|
+
stdin.write('\u001B[B'); // Down arrow
|
|
335
|
+
});
|
|
336
|
+
await waitFor(() => expect(mockInputHistory.navigateDown).toHaveBeenCalled());
|
|
337
|
+
await act(async () => {
|
|
338
|
+
stdin.write('\u0010'); // Ctrl+P
|
|
339
|
+
});
|
|
340
|
+
await act(async () => {
|
|
341
|
+
stdin.write('\u000E'); // Ctrl+N
|
|
342
|
+
});
|
|
343
|
+
await waitFor(() => {
|
|
344
|
+
expect(mockCommandCompletion.navigateUp).not.toHaveBeenCalled();
|
|
345
|
+
expect(mockCommandCompletion.navigateDown).not.toHaveBeenCalled();
|
|
346
|
+
});
|
|
329
347
|
unmount();
|
|
330
348
|
});
|
|
331
349
|
describe('clipboard image paste', () => {
|
|
@@ -338,23 +356,27 @@ describe('InputPrompt', () => {
|
|
|
338
356
|
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(true);
|
|
339
357
|
vi.mocked(clipboardUtils.saveClipboardImage).mockResolvedValue('/test/.cell-cli-clipboard/clipboard-123.png');
|
|
340
358
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
341
|
-
await wait();
|
|
342
359
|
// Send Ctrl+V
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
360
|
+
await act(async () => {
|
|
361
|
+
stdin.write('\x16'); // Ctrl+V
|
|
362
|
+
});
|
|
363
|
+
await waitFor(() => {
|
|
364
|
+
expect(clipboardUtils.clipboardHasImage).toHaveBeenCalled();
|
|
365
|
+
expect(clipboardUtils.saveClipboardImage).toHaveBeenCalledWith(props.config.getTargetDir());
|
|
366
|
+
expect(clipboardUtils.cleanupOldClipboardImages).toHaveBeenCalledWith(props.config.getTargetDir());
|
|
367
|
+
expect(mockBuffer.replaceRangeByOffset).toHaveBeenCalled();
|
|
368
|
+
});
|
|
349
369
|
unmount();
|
|
350
370
|
});
|
|
351
371
|
it('should not insert anything when clipboard has no image', async () => {
|
|
352
372
|
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
|
|
353
373
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
354
|
-
await
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
374
|
+
await act(async () => {
|
|
375
|
+
stdin.write('\x16'); // Ctrl+V
|
|
376
|
+
});
|
|
377
|
+
await waitFor(() => {
|
|
378
|
+
expect(clipboardUtils.clipboardHasImage).toHaveBeenCalled();
|
|
379
|
+
});
|
|
358
380
|
expect(clipboardUtils.saveClipboardImage).not.toHaveBeenCalled();
|
|
359
381
|
expect(mockBuffer.setText).not.toHaveBeenCalled();
|
|
360
382
|
unmount();
|
|
@@ -363,10 +385,12 @@ describe('InputPrompt', () => {
|
|
|
363
385
|
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(true);
|
|
364
386
|
vi.mocked(clipboardUtils.saveClipboardImage).mockResolvedValue(null);
|
|
365
387
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
366
|
-
await
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
388
|
+
await act(async () => {
|
|
389
|
+
stdin.write('\x16'); // Ctrl+V
|
|
390
|
+
});
|
|
391
|
+
await waitFor(() => {
|
|
392
|
+
expect(clipboardUtils.saveClipboardImage).toHaveBeenCalled();
|
|
393
|
+
});
|
|
370
394
|
expect(mockBuffer.setText).not.toHaveBeenCalled();
|
|
371
395
|
unmount();
|
|
372
396
|
});
|
|
@@ -380,11 +404,13 @@ describe('InputPrompt', () => {
|
|
|
380
404
|
mockBuffer.lines = ['Hello world'];
|
|
381
405
|
mockBuffer.replaceRangeByOffset = vi.fn();
|
|
382
406
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
383
|
-
await
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
407
|
+
await act(async () => {
|
|
408
|
+
stdin.write('\x16'); // Ctrl+V
|
|
409
|
+
});
|
|
410
|
+
await waitFor(() => {
|
|
411
|
+
// Should insert at cursor position with spaces
|
|
412
|
+
expect(mockBuffer.replaceRangeByOffset).toHaveBeenCalled();
|
|
413
|
+
});
|
|
388
414
|
// Get the actual call to see what path was used
|
|
389
415
|
const actualCall = vi.mocked(mockBuffer.replaceRangeByOffset).mock
|
|
390
416
|
.calls[0];
|
|
@@ -399,10 +425,12 @@ describe('InputPrompt', () => {
|
|
|
399
425
|
.mockImplementation(() => { });
|
|
400
426
|
vi.mocked(clipboardUtils.clipboardHasImage).mockRejectedValue(new Error('Clipboard error'));
|
|
401
427
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
402
|
-
await
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
428
|
+
await act(async () => {
|
|
429
|
+
stdin.write('\x16'); // Ctrl+V
|
|
430
|
+
});
|
|
431
|
+
await waitFor(() => {
|
|
432
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Error handling clipboard image:', expect.any(Error));
|
|
433
|
+
});
|
|
406
434
|
expect(mockBuffer.setText).not.toHaveBeenCalled();
|
|
407
435
|
consoleErrorSpy.mockRestore();
|
|
408
436
|
unmount();
|
|
@@ -418,10 +446,10 @@ describe('InputPrompt', () => {
|
|
|
418
446
|
});
|
|
419
447
|
props.buffer.setText('/mem');
|
|
420
448
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
421
|
-
await
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
449
|
+
await act(async () => {
|
|
450
|
+
stdin.write('\t'); // Press Tab
|
|
451
|
+
});
|
|
452
|
+
await waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
425
453
|
unmount();
|
|
426
454
|
});
|
|
427
455
|
it('should append a sub-command when the parent command is already complete', async () => {
|
|
@@ -437,10 +465,10 @@ describe('InputPrompt', () => {
|
|
|
437
465
|
});
|
|
438
466
|
props.buffer.setText('/memory ');
|
|
439
467
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
440
|
-
await
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(1);
|
|
468
|
+
await act(async () => {
|
|
469
|
+
stdin.write('\t'); // Press Tab
|
|
470
|
+
});
|
|
471
|
+
await waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(1));
|
|
444
472
|
unmount();
|
|
445
473
|
});
|
|
446
474
|
it('should handle the "backspace" edge case correctly', async () => {
|
|
@@ -457,11 +485,12 @@ describe('InputPrompt', () => {
|
|
|
457
485
|
// The user has backspaced, so the query is now just '/memory'
|
|
458
486
|
props.buffer.setText('/memory');
|
|
459
487
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
460
|
-
await
|
|
461
|
-
|
|
462
|
-
|
|
488
|
+
await act(async () => {
|
|
489
|
+
stdin.write('\t'); // Press Tab
|
|
490
|
+
});
|
|
491
|
+
await waitFor(() =>
|
|
463
492
|
// It should NOT become '/show'. It should correctly become '/memory show'.
|
|
464
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
493
|
+
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
465
494
|
unmount();
|
|
466
495
|
});
|
|
467
496
|
it('should complete a partial argument for a command', async () => {
|
|
@@ -474,10 +503,10 @@ describe('InputPrompt', () => {
|
|
|
474
503
|
});
|
|
475
504
|
props.buffer.setText('/chat resume fi-');
|
|
476
505
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
477
|
-
await
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
506
|
+
await act(async () => {
|
|
507
|
+
stdin.write('\t'); // Press Tab
|
|
508
|
+
});
|
|
509
|
+
await waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
481
510
|
unmount();
|
|
482
511
|
});
|
|
483
512
|
it('should autocomplete on Enter when suggestions are active, without submitting', async () => {
|
|
@@ -489,11 +518,13 @@ describe('InputPrompt', () => {
|
|
|
489
518
|
});
|
|
490
519
|
props.buffer.setText('/mem');
|
|
491
520
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
492
|
-
await
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
521
|
+
await act(async () => {
|
|
522
|
+
stdin.write('\r');
|
|
523
|
+
});
|
|
524
|
+
await waitFor(() => {
|
|
525
|
+
// The app should autocomplete the text, NOT submit.
|
|
526
|
+
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
527
|
+
});
|
|
497
528
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
498
529
|
unmount();
|
|
499
530
|
});
|
|
@@ -514,19 +545,21 @@ describe('InputPrompt', () => {
|
|
|
514
545
|
});
|
|
515
546
|
props.buffer.setText('/?');
|
|
516
547
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
517
|
-
await
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
548
|
+
await act(async () => {
|
|
549
|
+
stdin.write('\t'); // Press Tab for autocomplete
|
|
550
|
+
});
|
|
551
|
+
await waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
521
552
|
unmount();
|
|
522
553
|
});
|
|
523
554
|
it('should not submit on Enter when the buffer is empty or only contains whitespace', async () => {
|
|
524
555
|
props.buffer.setText(' '); // Set buffer to whitespace
|
|
525
556
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
526
|
-
await
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
557
|
+
await act(async () => {
|
|
558
|
+
stdin.write('\r'); // Press Enter
|
|
559
|
+
});
|
|
560
|
+
await waitFor(() => {
|
|
561
|
+
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
562
|
+
});
|
|
530
563
|
unmount();
|
|
531
564
|
});
|
|
532
565
|
it('should submit directly on Enter when isPerfectMatch is true', async () => {
|
|
@@ -537,10 +570,10 @@ describe('InputPrompt', () => {
|
|
|
537
570
|
});
|
|
538
571
|
props.buffer.setText('/clear');
|
|
539
572
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
540
|
-
await
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
expect(props.onSubmit).toHaveBeenCalledWith('/clear');
|
|
573
|
+
await act(async () => {
|
|
574
|
+
stdin.write('\r');
|
|
575
|
+
});
|
|
576
|
+
await waitFor(() => expect(props.onSubmit).toHaveBeenCalledWith('/clear'));
|
|
544
577
|
unmount();
|
|
545
578
|
});
|
|
546
579
|
it('should submit directly on Enter when a complete leaf command is typed', async () => {
|
|
@@ -551,10 +584,10 @@ describe('InputPrompt', () => {
|
|
|
551
584
|
});
|
|
552
585
|
props.buffer.setText('/clear');
|
|
553
586
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
554
|
-
await
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
expect(props.onSubmit).toHaveBeenCalledWith('/clear');
|
|
587
|
+
await act(async () => {
|
|
588
|
+
stdin.write('\r');
|
|
589
|
+
});
|
|
590
|
+
await waitFor(() => expect(props.onSubmit).toHaveBeenCalledWith('/clear'));
|
|
558
591
|
unmount();
|
|
559
592
|
});
|
|
560
593
|
it('should autocomplete an @-path on Enter without submitting', async () => {
|
|
@@ -566,10 +599,10 @@ describe('InputPrompt', () => {
|
|
|
566
599
|
});
|
|
567
600
|
props.buffer.setText('@src/components/');
|
|
568
601
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
569
|
-
await
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
602
|
+
await act(async () => {
|
|
603
|
+
stdin.write('\r');
|
|
604
|
+
});
|
|
605
|
+
await waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
573
606
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
574
607
|
unmount();
|
|
575
608
|
});
|
|
@@ -579,243 +612,137 @@ describe('InputPrompt', () => {
|
|
|
579
612
|
mockBuffer.cursor = [0, 11];
|
|
580
613
|
mockBuffer.lines = ['first line\\'];
|
|
581
614
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
582
|
-
await
|
|
583
|
-
|
|
584
|
-
|
|
615
|
+
await act(async () => {
|
|
616
|
+
stdin.write('\r');
|
|
617
|
+
});
|
|
618
|
+
await waitFor(() => {
|
|
619
|
+
expect(props.buffer.backspace).toHaveBeenCalled();
|
|
620
|
+
expect(props.buffer.newline).toHaveBeenCalled();
|
|
621
|
+
});
|
|
585
622
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
586
|
-
expect(props.buffer.backspace).toHaveBeenCalled();
|
|
587
|
-
expect(props.buffer.newline).toHaveBeenCalled();
|
|
588
623
|
unmount();
|
|
589
624
|
});
|
|
590
625
|
it('should clear the buffer on Ctrl+C if it has text', async () => {
|
|
591
|
-
|
|
626
|
+
await act(async () => {
|
|
627
|
+
props.buffer.setText('some text to clear');
|
|
628
|
+
});
|
|
592
629
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
593
|
-
await
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
630
|
+
await act(async () => {
|
|
631
|
+
stdin.write('\x03'); // Ctrl+C character
|
|
632
|
+
});
|
|
633
|
+
await waitFor(() => {
|
|
634
|
+
expect(props.buffer.setText).toHaveBeenCalledWith('');
|
|
635
|
+
expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled();
|
|
636
|
+
});
|
|
598
637
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
599
638
|
unmount();
|
|
600
639
|
});
|
|
601
640
|
it('should NOT clear the buffer on Ctrl+C if it is empty', async () => {
|
|
602
641
|
props.buffer.text = '';
|
|
603
642
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
604
|
-
await
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
643
|
+
await act(async () => {
|
|
644
|
+
stdin.write('\x03'); // Ctrl+C character
|
|
645
|
+
});
|
|
646
|
+
await waitFor(() => {
|
|
647
|
+
expect(props.buffer.setText).not.toHaveBeenCalled();
|
|
648
|
+
});
|
|
608
649
|
unmount();
|
|
609
650
|
});
|
|
610
651
|
describe('cursor-based completion trigger', () => {
|
|
611
|
-
it(
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
617
|
-
...mockCommandCompletion,
|
|
652
|
+
it.each([
|
|
653
|
+
{
|
|
654
|
+
name: 'should trigger completion when cursor is after @ without spaces',
|
|
655
|
+
text: '@src/components',
|
|
656
|
+
cursor: [0, 15],
|
|
618
657
|
showSuggestions: true,
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
expect(mockedUseCommandCompletion).toHaveBeenCalledWith(mockBuffer, ['/test/project/src'], path.join('test', 'project', 'src'), mockSlashCommands, mockCommandContext, false, false, expect.any(Object));
|
|
625
|
-
unmount();
|
|
626
|
-
});
|
|
627
|
-
it('should trigger completion when cursor is after / without spaces', async () => {
|
|
628
|
-
mockBuffer.text = '/memory';
|
|
629
|
-
mockBuffer.lines = ['/memory'];
|
|
630
|
-
mockBuffer.cursor = [0, 7];
|
|
631
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
632
|
-
...mockCommandCompletion,
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
name: 'should trigger completion when cursor is after / without spaces',
|
|
661
|
+
text: '/memory',
|
|
662
|
+
cursor: [0, 7],
|
|
633
663
|
showSuggestions: true,
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
unmount();
|
|
640
|
-
});
|
|
641
|
-
it('should NOT trigger completion when cursor is after space following @', async () => {
|
|
642
|
-
mockBuffer.text = '@src/file.ts hello';
|
|
643
|
-
mockBuffer.lines = ['@src/file.ts hello'];
|
|
644
|
-
mockBuffer.cursor = [0, 18];
|
|
645
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
646
|
-
...mockCommandCompletion,
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
name: 'should NOT trigger completion when cursor is after space following @',
|
|
667
|
+
text: '@src/file.ts hello',
|
|
668
|
+
cursor: [0, 18],
|
|
647
669
|
showSuggestions: false,
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
unmount();
|
|
654
|
-
});
|
|
655
|
-
it('should NOT trigger completion when cursor is after space following /', async () => {
|
|
656
|
-
mockBuffer.text = '/memory add';
|
|
657
|
-
mockBuffer.lines = ['/memory add'];
|
|
658
|
-
mockBuffer.cursor = [0, 11];
|
|
659
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
660
|
-
...mockCommandCompletion,
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
name: 'should NOT trigger completion when cursor is after space following /',
|
|
673
|
+
text: '/memory add',
|
|
674
|
+
cursor: [0, 11],
|
|
661
675
|
showSuggestions: false,
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
unmount();
|
|
668
|
-
});
|
|
669
|
-
it('should NOT trigger completion when cursor is not after @ or /', async () => {
|
|
670
|
-
mockBuffer.text = 'hello world';
|
|
671
|
-
mockBuffer.lines = ['hello world'];
|
|
672
|
-
mockBuffer.cursor = [0, 5];
|
|
673
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
674
|
-
...mockCommandCompletion,
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
name: 'should NOT trigger completion when cursor is not after @ or /',
|
|
679
|
+
text: 'hello world',
|
|
680
|
+
cursor: [0, 5],
|
|
675
681
|
showSuggestions: false,
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
unmount();
|
|
682
|
-
});
|
|
683
|
-
it('should handle multiline text correctly', async () => {
|
|
684
|
-
mockBuffer.text = 'first line\n/memory';
|
|
685
|
-
mockBuffer.lines = ['first line', '/memory'];
|
|
686
|
-
mockBuffer.cursor = [1, 7];
|
|
687
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
688
|
-
...mockCommandCompletion,
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
name: 'should handle multiline text correctly',
|
|
685
|
+
text: 'first line\n/memory',
|
|
686
|
+
cursor: [1, 7],
|
|
689
687
|
showSuggestions: false,
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
expect(mockedUseCommandCompletion).toHaveBeenCalledWith(mockBuffer, ['/test/project/src'], path.join('test', 'project', 'src'), mockSlashCommands, mockCommandContext, false, false, expect.any(Object));
|
|
696
|
-
unmount();
|
|
697
|
-
});
|
|
698
|
-
it('should handle single line slash command correctly', async () => {
|
|
699
|
-
mockBuffer.text = '/memory';
|
|
700
|
-
mockBuffer.lines = ['/memory'];
|
|
701
|
-
mockBuffer.cursor = [0, 7];
|
|
702
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
703
|
-
...mockCommandCompletion,
|
|
704
|
-
showSuggestions: true,
|
|
705
|
-
suggestions: [{ label: 'show', value: 'show' }],
|
|
706
|
-
});
|
|
707
|
-
const { unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
708
|
-
await wait();
|
|
709
|
-
expect(mockedUseCommandCompletion).toHaveBeenCalledWith(mockBuffer, ['/test/project/src'], path.join('test', 'project', 'src'), mockSlashCommands, mockCommandContext, false, false, expect.any(Object));
|
|
710
|
-
unmount();
|
|
711
|
-
});
|
|
712
|
-
it('should handle Unicode characters (emojis) correctly in paths', async () => {
|
|
713
|
-
// Test with emoji in path after @
|
|
714
|
-
mockBuffer.text = '@src/file👍.txt';
|
|
715
|
-
mockBuffer.lines = ['@src/file👍.txt'];
|
|
716
|
-
mockBuffer.cursor = [0, 14]; // After the emoji character
|
|
717
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
718
|
-
...mockCommandCompletion,
|
|
688
|
+
},
|
|
689
|
+
{
|
|
690
|
+
name: 'should handle Unicode characters (emojis) correctly in paths',
|
|
691
|
+
text: '@src/file👍.txt',
|
|
692
|
+
cursor: [0, 14],
|
|
719
693
|
showSuggestions: true,
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
unmount();
|
|
726
|
-
});
|
|
727
|
-
it('should handle Unicode characters with spaces after them', async () => {
|
|
728
|
-
// Test with emoji followed by space - should NOT trigger completion
|
|
729
|
-
mockBuffer.text = '@src/file👍.txt hello';
|
|
730
|
-
mockBuffer.lines = ['@src/file👍.txt hello'];
|
|
731
|
-
mockBuffer.cursor = [0, 20]; // After the space
|
|
732
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
733
|
-
...mockCommandCompletion,
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
name: 'should handle Unicode characters with spaces after them',
|
|
697
|
+
text: '@src/file👍.txt hello',
|
|
698
|
+
cursor: [0, 20],
|
|
734
699
|
showSuggestions: false,
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
unmount();
|
|
741
|
-
});
|
|
742
|
-
it('should handle escaped spaces in paths correctly', async () => {
|
|
743
|
-
// Test with escaped space in path - should trigger completion
|
|
744
|
-
mockBuffer.text = '@src/my\\ file.txt';
|
|
745
|
-
mockBuffer.lines = ['@src/my\\ file.txt'];
|
|
746
|
-
mockBuffer.cursor = [0, 16]; // After the escaped space and filename
|
|
747
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
748
|
-
...mockCommandCompletion,
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
name: 'should handle escaped spaces in paths correctly',
|
|
703
|
+
text: '@src/my\\ file.txt',
|
|
704
|
+
cursor: [0, 16],
|
|
749
705
|
showSuggestions: true,
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
unmount();
|
|
756
|
-
});
|
|
757
|
-
it('should NOT trigger completion after unescaped space following escaped space', async () => {
|
|
758
|
-
// Test: @path/my\ file.txt hello (unescaped space after escaped space)
|
|
759
|
-
mockBuffer.text = '@path/my\\ file.txt hello';
|
|
760
|
-
mockBuffer.lines = ['@path/my\\ file.txt hello'];
|
|
761
|
-
mockBuffer.cursor = [0, 24]; // After "hello"
|
|
762
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
763
|
-
...mockCommandCompletion,
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
name: 'should NOT trigger completion after unescaped space following escaped space',
|
|
709
|
+
text: '@path/my\\ file.txt hello',
|
|
710
|
+
cursor: [0, 24],
|
|
764
711
|
showSuggestions: false,
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
unmount();
|
|
771
|
-
});
|
|
772
|
-
it('should handle multiple escaped spaces in paths', async () => {
|
|
773
|
-
// Test with multiple escaped spaces
|
|
774
|
-
mockBuffer.text = '@docs/my\\ long\\ file\\ name.md';
|
|
775
|
-
mockBuffer.lines = ['@docs/my\\ long\\ file\\ name.md'];
|
|
776
|
-
mockBuffer.cursor = [0, 29]; // At the end
|
|
777
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
778
|
-
...mockCommandCompletion,
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
name: 'should handle multiple escaped spaces in paths',
|
|
715
|
+
text: '@docs/my\\ long\\ file\\ name.md',
|
|
716
|
+
cursor: [0, 29],
|
|
779
717
|
showSuggestions: true,
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
await wait();
|
|
786
|
-
expect(mockedUseCommandCompletion).toHaveBeenCalledWith(mockBuffer, ['/test/project/src'], path.join('test', 'project', 'src'), mockSlashCommands, mockCommandContext, false, false, expect.any(Object));
|
|
787
|
-
unmount();
|
|
788
|
-
});
|
|
789
|
-
it('should handle escaped spaces in slash commands', async () => {
|
|
790
|
-
// Test escaped spaces with slash commands (though less common)
|
|
791
|
-
mockBuffer.text = '/memory\\ test';
|
|
792
|
-
mockBuffer.lines = ['/memory\\ test'];
|
|
793
|
-
mockBuffer.cursor = [0, 13]; // At the end
|
|
794
|
-
mockedUseCommandCompletion.mockReturnValue({
|
|
795
|
-
...mockCommandCompletion,
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
name: 'should handle escaped spaces in slash commands',
|
|
721
|
+
text: '/memory\\ test',
|
|
722
|
+
cursor: [0, 13],
|
|
796
723
|
showSuggestions: true,
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
mockBuffer.
|
|
807
|
-
mockBuffer.
|
|
808
|
-
mockBuffer.cursor = [0, 25]; // After the escaped space and emoji
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
name: 'should handle Unicode characters with escaped spaces',
|
|
727
|
+
text: `@${path.join('files', 'emoji\\ 👍\\ test.txt')}`,
|
|
728
|
+
cursor: [0, 25],
|
|
729
|
+
showSuggestions: true,
|
|
730
|
+
},
|
|
731
|
+
])('$name', async ({ text, cursor, showSuggestions }) => {
|
|
732
|
+
mockBuffer.text = text;
|
|
733
|
+
mockBuffer.lines = text.split('\n');
|
|
734
|
+
mockBuffer.cursor = cursor;
|
|
809
735
|
mockedUseCommandCompletion.mockReturnValue({
|
|
810
736
|
...mockCommandCompletion,
|
|
811
|
-
showSuggestions
|
|
812
|
-
suggestions:
|
|
813
|
-
{ label: '
|
|
814
|
-
|
|
737
|
+
showSuggestions,
|
|
738
|
+
suggestions: showSuggestions
|
|
739
|
+
? [{ label: 'suggestion', value: 'suggestion' }]
|
|
740
|
+
: [],
|
|
815
741
|
});
|
|
816
742
|
const { unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
817
|
-
await
|
|
818
|
-
|
|
743
|
+
await waitFor(() => {
|
|
744
|
+
expect(mockedUseCommandCompletion).toHaveBeenCalledWith(mockBuffer, ['/test/project/src'], path.join('test', 'project', 'src'), mockSlashCommands, mockCommandContext, false, false, expect.any(Object));
|
|
745
|
+
});
|
|
819
746
|
unmount();
|
|
820
747
|
});
|
|
821
748
|
});
|
|
@@ -823,32 +750,38 @@ describe('InputPrompt', () => {
|
|
|
823
750
|
it('should not call buffer.handleInput when vim mode is enabled and vim handles the input', async () => {
|
|
824
751
|
props.vimHandleInput = vi.fn().mockReturnValue(true); // Mock that vim handled it.
|
|
825
752
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
826
|
-
await
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
753
|
+
await act(async () => {
|
|
754
|
+
stdin.write('i');
|
|
755
|
+
});
|
|
756
|
+
await waitFor(() => {
|
|
757
|
+
expect(props.vimHandleInput).toHaveBeenCalled();
|
|
758
|
+
});
|
|
830
759
|
expect(mockBuffer.handleInput).not.toHaveBeenCalled();
|
|
831
760
|
unmount();
|
|
832
761
|
});
|
|
833
762
|
it('should call buffer.handleInput when vim mode is enabled but vim does not handle the input', async () => {
|
|
834
763
|
props.vimHandleInput = vi.fn().mockReturnValue(false); // Mock that vim did NOT handle it.
|
|
835
764
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
836
|
-
await
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
765
|
+
await act(async () => {
|
|
766
|
+
stdin.write('i');
|
|
767
|
+
});
|
|
768
|
+
await waitFor(() => {
|
|
769
|
+
expect(props.vimHandleInput).toHaveBeenCalled();
|
|
770
|
+
expect(mockBuffer.handleInput).toHaveBeenCalled();
|
|
771
|
+
});
|
|
841
772
|
unmount();
|
|
842
773
|
});
|
|
843
774
|
it('should call handleInput when vim mode is disabled', async () => {
|
|
844
775
|
// Mock vimHandleInput to return false (vim didn't handle the input)
|
|
845
776
|
props.vimHandleInput = vi.fn().mockReturnValue(false);
|
|
846
777
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
847
|
-
await
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
778
|
+
await act(async () => {
|
|
779
|
+
stdin.write('i');
|
|
780
|
+
});
|
|
781
|
+
await waitFor(() => {
|
|
782
|
+
expect(props.vimHandleInput).toHaveBeenCalled();
|
|
783
|
+
expect(mockBuffer.handleInput).toHaveBeenCalled();
|
|
784
|
+
});
|
|
852
785
|
unmount();
|
|
853
786
|
});
|
|
854
787
|
});
|
|
@@ -856,185 +789,158 @@ describe('InputPrompt', () => {
|
|
|
856
789
|
it('should handle bracketed paste when not focused', async () => {
|
|
857
790
|
props.focus = false;
|
|
858
791
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
859
|
-
await
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
792
|
+
await act(async () => {
|
|
793
|
+
stdin.write('\x1B[200~pasted text\x1B[201~');
|
|
794
|
+
});
|
|
795
|
+
await waitFor(() => {
|
|
796
|
+
expect(mockBuffer.handleInput).toHaveBeenCalledWith(expect.objectContaining({
|
|
797
|
+
paste: true,
|
|
798
|
+
sequence: 'pasted text',
|
|
799
|
+
}));
|
|
800
|
+
});
|
|
866
801
|
unmount();
|
|
867
802
|
});
|
|
868
803
|
it('should ignore regular keypresses when not focused', async () => {
|
|
869
804
|
props.focus = false;
|
|
870
805
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
871
|
-
await
|
|
872
|
-
|
|
873
|
-
|
|
806
|
+
await act(async () => {
|
|
807
|
+
stdin.write('a');
|
|
808
|
+
});
|
|
809
|
+
await waitFor(() => { });
|
|
874
810
|
expect(mockBuffer.handleInput).not.toHaveBeenCalled();
|
|
875
811
|
unmount();
|
|
876
812
|
});
|
|
877
813
|
});
|
|
878
814
|
describe('Highlighting and Cursor Display', () => {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
mockBuffer.viewportVisualLines = [text];
|
|
942
|
-
mockBuffer.visualCursor = [0, 8]; // cursor after '👍' (length is 6 + 2 for emoji)
|
|
943
|
-
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
944
|
-
await wait();
|
|
945
|
-
const frame = stdout.lastFrame();
|
|
946
|
-
expect(frame).toContain(`hello 👍${chalk.inverse(' ')}`);
|
|
947
|
-
unmount();
|
|
948
|
-
});
|
|
949
|
-
it('should display cursor on an empty line', async () => {
|
|
950
|
-
mockBuffer.text = '';
|
|
951
|
-
mockBuffer.lines = [''];
|
|
952
|
-
mockBuffer.viewportVisualLines = [''];
|
|
953
|
-
mockBuffer.visualCursor = [0, 0];
|
|
954
|
-
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
955
|
-
await wait();
|
|
956
|
-
const frame = stdout.lastFrame();
|
|
957
|
-
expect(frame).toContain(chalk.inverse(' '));
|
|
958
|
-
unmount();
|
|
959
|
-
});
|
|
960
|
-
it('should display cursor on a space between words', async () => {
|
|
961
|
-
mockBuffer.text = 'hello world';
|
|
962
|
-
mockBuffer.lines = ['hello world'];
|
|
963
|
-
mockBuffer.viewportVisualLines = ['hello world'];
|
|
964
|
-
mockBuffer.visualCursor = [0, 5]; // cursor on the space
|
|
965
|
-
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
966
|
-
await wait();
|
|
967
|
-
const frame = stdout.lastFrame();
|
|
968
|
-
expect(frame).toContain(`hello${chalk.inverse(' ')}world`);
|
|
969
|
-
unmount();
|
|
970
|
-
});
|
|
971
|
-
it('should display cursor in the middle of a line in a multiline block', async () => {
|
|
972
|
-
const text = 'first line\nsecond line\nthird line';
|
|
973
|
-
mockBuffer.text = text;
|
|
974
|
-
mockBuffer.lines = text.split('\n');
|
|
975
|
-
mockBuffer.viewportVisualLines = text.split('\n');
|
|
976
|
-
mockBuffer.visualCursor = [1, 3]; // cursor on 'o' in 'second'
|
|
977
|
-
mockBuffer.visualToLogicalMap = [
|
|
978
|
-
[0, 0],
|
|
979
|
-
[1, 0],
|
|
980
|
-
[2, 0],
|
|
981
|
-
];
|
|
982
|
-
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
983
|
-
await wait();
|
|
984
|
-
const frame = stdout.lastFrame();
|
|
985
|
-
expect(frame).toContain(`sec${chalk.inverse('o')}nd line`);
|
|
986
|
-
unmount();
|
|
987
|
-
});
|
|
988
|
-
it('should display cursor at the beginning of a line in a multiline block', async () => {
|
|
989
|
-
const text = 'first line\nsecond line';
|
|
990
|
-
mockBuffer.text = text;
|
|
991
|
-
mockBuffer.lines = text.split('\n');
|
|
992
|
-
mockBuffer.viewportVisualLines = text.split('\n');
|
|
993
|
-
mockBuffer.visualCursor = [1, 0]; // cursor on 's' in 'second'
|
|
994
|
-
mockBuffer.visualToLogicalMap = [
|
|
995
|
-
[0, 0],
|
|
996
|
-
[1, 0],
|
|
997
|
-
];
|
|
998
|
-
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
999
|
-
await wait();
|
|
1000
|
-
const frame = stdout.lastFrame();
|
|
1001
|
-
expect(frame).toContain(`${chalk.inverse('s')}econd line`);
|
|
1002
|
-
unmount();
|
|
1003
|
-
});
|
|
1004
|
-
it('should display cursor at the end of a line in a multiline block', async () => {
|
|
1005
|
-
const text = 'first line\nsecond line';
|
|
1006
|
-
mockBuffer.text = text;
|
|
1007
|
-
mockBuffer.lines = text.split('\n');
|
|
1008
|
-
mockBuffer.viewportVisualLines = text.split('\n');
|
|
1009
|
-
mockBuffer.visualCursor = [0, 10]; // cursor after 'first line'
|
|
1010
|
-
mockBuffer.visualToLogicalMap = [
|
|
1011
|
-
[0, 0],
|
|
1012
|
-
[1, 0],
|
|
1013
|
-
];
|
|
1014
|
-
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1015
|
-
await wait();
|
|
1016
|
-
const frame = stdout.lastFrame();
|
|
1017
|
-
expect(frame).toContain(`first line${chalk.inverse(' ')}`);
|
|
1018
|
-
unmount();
|
|
815
|
+
describe('single-line scenarios', () => {
|
|
816
|
+
it.each([
|
|
817
|
+
{
|
|
818
|
+
name: 'mid-word',
|
|
819
|
+
text: 'hello world',
|
|
820
|
+
visualCursor: [0, 3],
|
|
821
|
+
expected: `hel${chalk.inverse('l')}o world`,
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
name: 'at the beginning of the line',
|
|
825
|
+
text: 'hello',
|
|
826
|
+
visualCursor: [0, 0],
|
|
827
|
+
expected: `${chalk.inverse('h')}ello`,
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
name: 'at the end of the line',
|
|
831
|
+
text: 'hello',
|
|
832
|
+
visualCursor: [0, 5],
|
|
833
|
+
expected: `hello${chalk.inverse(' ')}`,
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
name: 'on a highlighted token',
|
|
837
|
+
text: 'run @path/to/file',
|
|
838
|
+
visualCursor: [0, 9],
|
|
839
|
+
expected: `@path/${chalk.inverse('t')}o/file`,
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
name: 'for multi-byte unicode characters',
|
|
843
|
+
text: 'hello 👍 world',
|
|
844
|
+
visualCursor: [0, 6],
|
|
845
|
+
expected: `hello ${chalk.inverse('👍')} world`,
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
name: 'at the end of a line with unicode characters',
|
|
849
|
+
text: 'hello 👍',
|
|
850
|
+
visualCursor: [0, 8],
|
|
851
|
+
expected: `hello 👍${chalk.inverse(' ')}`,
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
name: 'on an empty line',
|
|
855
|
+
text: '',
|
|
856
|
+
visualCursor: [0, 0],
|
|
857
|
+
expected: chalk.inverse(' '),
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
name: 'on a space between words',
|
|
861
|
+
text: 'hello world',
|
|
862
|
+
visualCursor: [0, 5],
|
|
863
|
+
expected: `hello${chalk.inverse(' ')}world`,
|
|
864
|
+
},
|
|
865
|
+
])('should display cursor correctly $name', async ({ text, visualCursor, expected }) => {
|
|
866
|
+
mockBuffer.text = text;
|
|
867
|
+
mockBuffer.lines = [text];
|
|
868
|
+
mockBuffer.viewportVisualLines = [text];
|
|
869
|
+
mockBuffer.visualCursor = visualCursor;
|
|
870
|
+
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
871
|
+
await waitFor(() => {
|
|
872
|
+
const frame = stdout.lastFrame();
|
|
873
|
+
expect(frame).toContain(expected);
|
|
874
|
+
});
|
|
875
|
+
unmount();
|
|
876
|
+
});
|
|
1019
877
|
});
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
878
|
+
describe('multi-line scenarios', () => {
|
|
879
|
+
it.each([
|
|
880
|
+
{
|
|
881
|
+
name: 'in the middle of a line',
|
|
882
|
+
text: 'first line\nsecond line\nthird line',
|
|
883
|
+
visualCursor: [1, 3],
|
|
884
|
+
visualToLogicalMap: [
|
|
885
|
+
[0, 0],
|
|
886
|
+
[1, 0],
|
|
887
|
+
[2, 0],
|
|
888
|
+
],
|
|
889
|
+
expected: `sec${chalk.inverse('o')}nd line`,
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
name: 'at the beginning of a line',
|
|
893
|
+
text: 'first line\nsecond line',
|
|
894
|
+
visualCursor: [1, 0],
|
|
895
|
+
visualToLogicalMap: [
|
|
896
|
+
[0, 0],
|
|
897
|
+
[1, 0],
|
|
898
|
+
],
|
|
899
|
+
expected: `${chalk.inverse('s')}econd line`,
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
name: 'at the end of a line',
|
|
903
|
+
text: 'first line\nsecond line',
|
|
904
|
+
visualCursor: [0, 10],
|
|
905
|
+
visualToLogicalMap: [
|
|
906
|
+
[0, 0],
|
|
907
|
+
[1, 0],
|
|
908
|
+
],
|
|
909
|
+
expected: `first line${chalk.inverse(' ')}`,
|
|
910
|
+
},
|
|
911
|
+
])('should display cursor correctly $name in a multiline block', async ({ text, visualCursor, expected, visualToLogicalMap }) => {
|
|
912
|
+
mockBuffer.text = text;
|
|
913
|
+
mockBuffer.lines = text.split('\n');
|
|
914
|
+
mockBuffer.viewportVisualLines = text.split('\n');
|
|
915
|
+
mockBuffer.visualCursor = visualCursor;
|
|
916
|
+
mockBuffer.visualToLogicalMap = visualToLogicalMap;
|
|
917
|
+
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
918
|
+
await waitFor(() => {
|
|
919
|
+
const frame = stdout.lastFrame();
|
|
920
|
+
expect(frame).toContain(expected);
|
|
921
|
+
});
|
|
922
|
+
unmount();
|
|
923
|
+
});
|
|
924
|
+
it('should display cursor on a blank line in a multiline block', async () => {
|
|
925
|
+
const text = 'first line\n\nthird line';
|
|
926
|
+
mockBuffer.text = text;
|
|
927
|
+
mockBuffer.lines = text.split('\n');
|
|
928
|
+
mockBuffer.viewportVisualLines = text.split('\n');
|
|
929
|
+
mockBuffer.visualCursor = [1, 0]; // cursor on the blank line
|
|
930
|
+
mockBuffer.visualToLogicalMap = [
|
|
931
|
+
[0, 0],
|
|
932
|
+
[1, 0],
|
|
933
|
+
[2, 0],
|
|
934
|
+
];
|
|
935
|
+
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
936
|
+
await waitFor(() => {
|
|
937
|
+
const frame = stdout.lastFrame();
|
|
938
|
+
const lines = frame.split('\n');
|
|
939
|
+
// The line with the cursor should just be an inverted space inside the box border
|
|
940
|
+
expect(lines.find((l) => l.includes(chalk.inverse(' ')))).not.toBeUndefined();
|
|
941
|
+
});
|
|
942
|
+
unmount();
|
|
943
|
+
});
|
|
1038
944
|
});
|
|
1039
945
|
});
|
|
1040
946
|
describe('multiline rendering', () => {
|
|
@@ -1052,15 +958,16 @@ describe('InputPrompt', () => {
|
|
|
1052
958
|
[2, 0], // 'world' is logical line 2, col 0
|
|
1053
959
|
];
|
|
1054
960
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1055
|
-
await
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
961
|
+
await waitFor(() => {
|
|
962
|
+
const frame = stdout.lastFrame();
|
|
963
|
+
// Check that all lines, including the empty one, are rendered.
|
|
964
|
+
// This implicitly tests that the Box wrapper provides height for the empty line.
|
|
965
|
+
expect(frame).toContain('hello');
|
|
966
|
+
expect(frame).toContain(`world${chalk.inverse(' ')}`);
|
|
967
|
+
const outputLines = frame.split('\n');
|
|
968
|
+
// The number of lines should be 2 for the border plus 3 for the content.
|
|
969
|
+
expect(outputLines.length).toBe(5);
|
|
970
|
+
});
|
|
1064
971
|
unmount();
|
|
1065
972
|
});
|
|
1066
973
|
});
|
|
@@ -1080,16 +987,18 @@ describe('InputPrompt', () => {
|
|
|
1080
987
|
},
|
|
1081
988
|
])('should handle multiline paste $description', async ({ pastedText }) => {
|
|
1082
989
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1083
|
-
await wait();
|
|
1084
990
|
// Simulate a bracketed paste event from the terminal
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
991
|
+
await act(async () => {
|
|
992
|
+
stdin.write(`\x1b[200~${pastedText}\x1b[201~`);
|
|
993
|
+
});
|
|
994
|
+
await waitFor(() => {
|
|
995
|
+
// Verify that the buffer's handleInput was called once with the full text
|
|
996
|
+
expect(props.buffer.handleInput).toHaveBeenCalledTimes(1);
|
|
997
|
+
expect(props.buffer.handleInput).toHaveBeenCalledWith(expect.objectContaining({
|
|
998
|
+
paste: true,
|
|
999
|
+
sequence: pastedText,
|
|
1000
|
+
}));
|
|
1001
|
+
});
|
|
1093
1002
|
unmount();
|
|
1094
1003
|
});
|
|
1095
1004
|
});
|
|
@@ -1109,13 +1018,20 @@ describe('InputPrompt', () => {
|
|
|
1109
1018
|
// isTerminalPasteTrusted will be false due to beforeEach setup.
|
|
1110
1019
|
props.buffer.text = 'some command';
|
|
1111
1020
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1112
|
-
await
|
|
1021
|
+
await act(async () => {
|
|
1022
|
+
await vi.runAllTimersAsync();
|
|
1023
|
+
});
|
|
1113
1024
|
// Simulate a paste operation (this should set the paste protection)
|
|
1114
|
-
|
|
1115
|
-
|
|
1025
|
+
await act(async () => {
|
|
1026
|
+
stdin.write(`\x1b[200~pasted content\x1b[201~`);
|
|
1027
|
+
});
|
|
1116
1028
|
// Simulate an Enter key press immediately after paste
|
|
1117
|
-
|
|
1118
|
-
|
|
1029
|
+
await act(async () => {
|
|
1030
|
+
stdin.write('\r');
|
|
1031
|
+
});
|
|
1032
|
+
await act(async () => {
|
|
1033
|
+
await vi.runAllTimersAsync();
|
|
1034
|
+
});
|
|
1119
1035
|
// Verify that onSubmit was NOT called due to recent paste protection
|
|
1120
1036
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
1121
1037
|
// It should call newline() instead
|
|
@@ -1126,19 +1042,27 @@ describe('InputPrompt', () => {
|
|
|
1126
1042
|
// isTerminalPasteTrusted will be false due to beforeEach setup.
|
|
1127
1043
|
props.buffer.text = 'pasted text';
|
|
1128
1044
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1129
|
-
await
|
|
1045
|
+
await act(async () => {
|
|
1046
|
+
await vi.runAllTimersAsync();
|
|
1047
|
+
});
|
|
1130
1048
|
// Simulate a paste operation (this sets the protection)
|
|
1131
|
-
act(() => {
|
|
1049
|
+
await act(async () => {
|
|
1132
1050
|
stdin.write('\x1b[200~pasted text\x1b[201~');
|
|
1133
1051
|
});
|
|
1134
|
-
await
|
|
1052
|
+
await act(async () => {
|
|
1053
|
+
await vi.runAllTimersAsync();
|
|
1054
|
+
});
|
|
1135
1055
|
// Advance timers past the protection timeout
|
|
1136
1056
|
await act(async () => {
|
|
1137
1057
|
await vi.advanceTimersByTimeAsync(50);
|
|
1138
1058
|
});
|
|
1139
1059
|
// Now Enter should work normally
|
|
1140
|
-
|
|
1141
|
-
|
|
1060
|
+
await act(async () => {
|
|
1061
|
+
stdin.write('\r');
|
|
1062
|
+
});
|
|
1063
|
+
await act(async () => {
|
|
1064
|
+
await vi.runAllTimersAsync();
|
|
1065
|
+
});
|
|
1142
1066
|
expect(props.onSubmit).toHaveBeenCalledWith('pasted text');
|
|
1143
1067
|
expect(props.buffer.newline).not.toHaveBeenCalled();
|
|
1144
1068
|
unmount();
|
|
@@ -1156,13 +1080,23 @@ describe('InputPrompt', () => {
|
|
|
1156
1080
|
setup();
|
|
1157
1081
|
props.buffer.text = 'pasted command';
|
|
1158
1082
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: true });
|
|
1159
|
-
await
|
|
1083
|
+
await act(async () => {
|
|
1084
|
+
await vi.runAllTimersAsync();
|
|
1085
|
+
});
|
|
1160
1086
|
// Simulate a paste operation
|
|
1161
|
-
|
|
1162
|
-
|
|
1087
|
+
await act(async () => {
|
|
1088
|
+
stdin.write('\x1b[200~some pasted stuff\x1b[201~');
|
|
1089
|
+
});
|
|
1090
|
+
await act(async () => {
|
|
1091
|
+
await vi.runAllTimersAsync();
|
|
1092
|
+
});
|
|
1163
1093
|
// Simulate an Enter key press immediately after paste
|
|
1164
|
-
|
|
1165
|
-
|
|
1094
|
+
await act(async () => {
|
|
1095
|
+
stdin.write('\r');
|
|
1096
|
+
});
|
|
1097
|
+
await act(async () => {
|
|
1098
|
+
await vi.runAllTimersAsync();
|
|
1099
|
+
});
|
|
1166
1100
|
// Verify that onSubmit was called
|
|
1167
1101
|
expect(props.onSubmit).toHaveBeenCalledWith('pasted command');
|
|
1168
1102
|
unmount();
|
|
@@ -1171,10 +1105,16 @@ describe('InputPrompt', () => {
|
|
|
1171
1105
|
// Set up buffer with text before rendering to ensure submission works
|
|
1172
1106
|
props.buffer.text = 'normal command';
|
|
1173
1107
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1174
|
-
await
|
|
1108
|
+
await act(async () => {
|
|
1109
|
+
await vi.runAllTimersAsync();
|
|
1110
|
+
});
|
|
1175
1111
|
// Press Enter without any recent paste
|
|
1176
|
-
|
|
1177
|
-
|
|
1112
|
+
await act(async () => {
|
|
1113
|
+
stdin.write('\r');
|
|
1114
|
+
});
|
|
1115
|
+
await act(async () => {
|
|
1116
|
+
await vi.runAllTimersAsync();
|
|
1117
|
+
});
|
|
1178
1118
|
// Verify that onSubmit was called normally
|
|
1179
1119
|
expect(props.onSubmit).toHaveBeenCalledWith('normal command');
|
|
1180
1120
|
unmount();
|
|
@@ -1186,13 +1126,19 @@ describe('InputPrompt', () => {
|
|
|
1186
1126
|
props.onEscapePromptChange = onEscapePromptChange;
|
|
1187
1127
|
props.buffer.setText('text to clear');
|
|
1188
1128
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1189
|
-
await
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1129
|
+
await act(async () => {
|
|
1130
|
+
stdin.write('\x1B');
|
|
1131
|
+
await waitFor(() => {
|
|
1132
|
+
expect(onEscapePromptChange).toHaveBeenCalledWith(false);
|
|
1133
|
+
});
|
|
1134
|
+
});
|
|
1135
|
+
await act(async () => {
|
|
1136
|
+
stdin.write('\x1B');
|
|
1137
|
+
await waitFor(() => {
|
|
1138
|
+
expect(props.buffer.setText).toHaveBeenCalledWith('');
|
|
1139
|
+
expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled();
|
|
1140
|
+
});
|
|
1141
|
+
});
|
|
1196
1142
|
unmount();
|
|
1197
1143
|
});
|
|
1198
1144
|
it('should reset escape state on any non-ESC key', async () => {
|
|
@@ -1200,23 +1146,27 @@ describe('InputPrompt', () => {
|
|
|
1200
1146
|
props.onEscapePromptChange = onEscapePromptChange;
|
|
1201
1147
|
props.buffer.setText('some text');
|
|
1202
1148
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1149
|
+
await act(async () => {
|
|
1150
|
+
stdin.write('\x1B');
|
|
1151
|
+
await waitFor(() => {
|
|
1152
|
+
expect(onEscapePromptChange).toHaveBeenCalledWith(false);
|
|
1153
|
+
});
|
|
1206
1154
|
});
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1155
|
+
await act(async () => {
|
|
1156
|
+
stdin.write('a');
|
|
1157
|
+
await waitFor(() => {
|
|
1158
|
+
expect(onEscapePromptChange).toHaveBeenCalledWith(false);
|
|
1159
|
+
});
|
|
1210
1160
|
});
|
|
1211
1161
|
unmount();
|
|
1212
1162
|
});
|
|
1213
1163
|
it('should handle ESC in shell mode by disabling shell mode', async () => {
|
|
1214
1164
|
props.shellModeActive = true;
|
|
1215
1165
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1216
|
-
await
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1166
|
+
await act(async () => {
|
|
1167
|
+
stdin.write('\x1B');
|
|
1168
|
+
await waitFor(() => expect(props.setShellModeActive).toHaveBeenCalledWith(false));
|
|
1169
|
+
});
|
|
1220
1170
|
unmount();
|
|
1221
1171
|
});
|
|
1222
1172
|
it('should handle ESC when completion suggestions are showing', async () => {
|
|
@@ -1226,10 +1176,10 @@ describe('InputPrompt', () => {
|
|
|
1226
1176
|
suggestions: [{ label: 'suggestion', value: 'suggestion' }],
|
|
1227
1177
|
});
|
|
1228
1178
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1229
|
-
await
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled();
|
|
1179
|
+
await act(async () => {
|
|
1180
|
+
stdin.write('\x1B');
|
|
1181
|
+
});
|
|
1182
|
+
await waitFor(() => expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled());
|
|
1233
1183
|
unmount();
|
|
1234
1184
|
});
|
|
1235
1185
|
it('should not call onEscapePromptChange when not provided', async () => {
|
|
@@ -1237,21 +1187,28 @@ describe('InputPrompt', () => {
|
|
|
1237
1187
|
props.onEscapePromptChange = undefined;
|
|
1238
1188
|
props.buffer.setText('some text');
|
|
1239
1189
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1240
|
-
await
|
|
1241
|
-
|
|
1242
|
-
|
|
1190
|
+
await act(async () => {
|
|
1191
|
+
await vi.runAllTimersAsync();
|
|
1192
|
+
});
|
|
1193
|
+
await act(async () => {
|
|
1194
|
+
stdin.write('\x1B');
|
|
1195
|
+
});
|
|
1196
|
+
await act(async () => {
|
|
1197
|
+
await vi.runAllTimersAsync();
|
|
1198
|
+
});
|
|
1243
1199
|
vi.useRealTimers();
|
|
1244
1200
|
unmount();
|
|
1245
1201
|
});
|
|
1246
1202
|
it('should not interfere with existing keyboard shortcuts', async () => {
|
|
1247
1203
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1248
|
-
await
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
expect(props.onClearScreen).toHaveBeenCalled();
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1204
|
+
await act(async () => {
|
|
1205
|
+
stdin.write('\x0C');
|
|
1206
|
+
});
|
|
1207
|
+
await waitFor(() => expect(props.onClearScreen).toHaveBeenCalled());
|
|
1208
|
+
await act(async () => {
|
|
1209
|
+
stdin.write('\x01');
|
|
1210
|
+
});
|
|
1211
|
+
await waitFor(() => expect(props.buffer.move).toHaveBeenCalledWith('home'));
|
|
1255
1212
|
unmount();
|
|
1256
1213
|
});
|
|
1257
1214
|
});
|
|
@@ -1279,9 +1236,8 @@ describe('InputPrompt', () => {
|
|
|
1279
1236
|
activeSuggestionIndex: 0,
|
|
1280
1237
|
});
|
|
1281
1238
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1282
|
-
await wait();
|
|
1283
1239
|
// Trigger reverse search with Ctrl+R
|
|
1284
|
-
act(() => {
|
|
1240
|
+
await act(async () => {
|
|
1285
1241
|
stdin.write('\x12');
|
|
1286
1242
|
});
|
|
1287
1243
|
await waitFor(() => {
|
|
@@ -1293,17 +1249,29 @@ describe('InputPrompt', () => {
|
|
|
1293
1249
|
});
|
|
1294
1250
|
unmount();
|
|
1295
1251
|
});
|
|
1296
|
-
it(
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1252
|
+
it.each([
|
|
1253
|
+
{ name: 'standard', kittyProtocolEnabled: false, escapeSequence: '\x1B' },
|
|
1254
|
+
{
|
|
1255
|
+
name: 'kitty',
|
|
1256
|
+
kittyProtocolEnabled: true,
|
|
1257
|
+
escapeSequence: '\u001b[27u',
|
|
1258
|
+
},
|
|
1259
|
+
])('resets reverse search state on Escape ($name)', async ({ kittyProtocolEnabled, escapeSequence }) => {
|
|
1260
|
+
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled });
|
|
1261
|
+
await act(async () => {
|
|
1262
|
+
stdin.write('\x12');
|
|
1263
|
+
});
|
|
1264
|
+
// Wait for reverse search to be active
|
|
1265
|
+
await waitFor(() => {
|
|
1266
|
+
expect(stdout.lastFrame()).toContain('(r:)');
|
|
1267
|
+
});
|
|
1268
|
+
await act(async () => {
|
|
1269
|
+
stdin.write(escapeSequence);
|
|
1270
|
+
});
|
|
1303
1271
|
await waitFor(() => {
|
|
1304
1272
|
expect(stdout.lastFrame()).not.toContain('(r:)');
|
|
1273
|
+
expect(stdout.lastFrame()).not.toContain('echo hello');
|
|
1305
1274
|
});
|
|
1306
|
-
expect(stdout.lastFrame()).not.toContain('echo hello');
|
|
1307
1275
|
unmount();
|
|
1308
1276
|
});
|
|
1309
1277
|
it('completes the highlighted entry on Tab and exits reverse-search', async () => {
|
|
@@ -1326,7 +1294,7 @@ describe('InputPrompt', () => {
|
|
|
1326
1294
|
}));
|
|
1327
1295
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1328
1296
|
// Enter reverse search mode with Ctrl+R
|
|
1329
|
-
act(() => {
|
|
1297
|
+
await act(async () => {
|
|
1330
1298
|
stdin.write('\x12');
|
|
1331
1299
|
});
|
|
1332
1300
|
// Verify reverse search is active
|
|
@@ -1334,12 +1302,13 @@ describe('InputPrompt', () => {
|
|
|
1334
1302
|
expect(stdout.lastFrame()).toContain('(r:)');
|
|
1335
1303
|
});
|
|
1336
1304
|
// Press Tab to complete the highlighted entry
|
|
1337
|
-
act(() => {
|
|
1305
|
+
await act(async () => {
|
|
1338
1306
|
stdin.write('\t');
|
|
1339
1307
|
});
|
|
1340
|
-
await
|
|
1341
|
-
|
|
1342
|
-
|
|
1308
|
+
await waitFor(() => {
|
|
1309
|
+
expect(mockHandleAutocomplete).toHaveBeenCalledWith(0);
|
|
1310
|
+
expect(props.buffer.setText).toHaveBeenCalledWith('echo hello');
|
|
1311
|
+
});
|
|
1343
1312
|
unmount();
|
|
1344
1313
|
}, 15000);
|
|
1345
1314
|
it('submits the highlighted entry on Enter and exits reverse-search', async () => {
|
|
@@ -1355,13 +1324,13 @@ describe('InputPrompt', () => {
|
|
|
1355
1324
|
activeSuggestionIndex: 0,
|
|
1356
1325
|
});
|
|
1357
1326
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1358
|
-
act(() => {
|
|
1327
|
+
await act(async () => {
|
|
1359
1328
|
stdin.write('\x12');
|
|
1360
1329
|
});
|
|
1361
1330
|
await waitFor(() => {
|
|
1362
1331
|
expect(stdout.lastFrame()).toContain('(r:)');
|
|
1363
1332
|
});
|
|
1364
|
-
act(() => {
|
|
1333
|
+
await act(async () => {
|
|
1365
1334
|
stdin.write('\r');
|
|
1366
1335
|
});
|
|
1367
1336
|
await waitFor(() => {
|
|
@@ -1384,16 +1353,15 @@ describe('InputPrompt', () => {
|
|
|
1384
1353
|
showSuggestions: reverseSearchActiveFromInputPrompt,
|
|
1385
1354
|
}));
|
|
1386
1355
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1387
|
-
await wait();
|
|
1388
1356
|
// reverse search with Ctrl+R
|
|
1389
|
-
act(() => {
|
|
1357
|
+
await act(async () => {
|
|
1390
1358
|
stdin.write('\x12');
|
|
1391
1359
|
});
|
|
1392
1360
|
await waitFor(() => {
|
|
1393
1361
|
expect(stdout.lastFrame()).toContain('(r:)');
|
|
1394
1362
|
});
|
|
1395
1363
|
// Press kitty escape key
|
|
1396
|
-
act(() => {
|
|
1364
|
+
await act(async () => {
|
|
1397
1365
|
stdin.write('\u001b[27u');
|
|
1398
1366
|
});
|
|
1399
1367
|
await waitFor(() => {
|
|
@@ -1410,10 +1378,12 @@ describe('InputPrompt', () => {
|
|
|
1410
1378
|
props.buffer.cursor = [1, 2];
|
|
1411
1379
|
props.buffer.lines = ['line 1', 'line 2', 'line 3'];
|
|
1412
1380
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1413
|
-
await
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1381
|
+
await act(async () => {
|
|
1382
|
+
stdin.write('\x05'); // Ctrl+E
|
|
1383
|
+
});
|
|
1384
|
+
await waitFor(() => {
|
|
1385
|
+
expect(props.buffer.move).toHaveBeenCalledWith('end');
|
|
1386
|
+
});
|
|
1417
1387
|
expect(props.buffer.moveToOffset).not.toHaveBeenCalled();
|
|
1418
1388
|
unmount();
|
|
1419
1389
|
});
|
|
@@ -1422,10 +1392,12 @@ describe('InputPrompt', () => {
|
|
|
1422
1392
|
props.buffer.cursor = [0, 5];
|
|
1423
1393
|
props.buffer.lines = ['single line text'];
|
|
1424
1394
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1425
|
-
await
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1395
|
+
await act(async () => {
|
|
1396
|
+
stdin.write('\x05'); // Ctrl+E
|
|
1397
|
+
});
|
|
1398
|
+
await waitFor(() => {
|
|
1399
|
+
expect(props.buffer.move).toHaveBeenCalledWith('end');
|
|
1400
|
+
});
|
|
1429
1401
|
expect(props.buffer.moveToOffset).not.toHaveBeenCalled();
|
|
1430
1402
|
unmount();
|
|
1431
1403
|
});
|
|
@@ -1445,18 +1417,18 @@ describe('InputPrompt', () => {
|
|
|
1445
1417
|
activeSuggestionIndex: isActive ? 0 : -1,
|
|
1446
1418
|
}));
|
|
1447
1419
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1448
|
-
await
|
|
1449
|
-
act(() => {
|
|
1420
|
+
await act(async () => {
|
|
1450
1421
|
stdin.write('\x12'); // Ctrl+R
|
|
1451
1422
|
});
|
|
1452
|
-
await
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1423
|
+
await waitFor(() => {
|
|
1424
|
+
const frame = stdout.lastFrame() ?? '';
|
|
1425
|
+
expect(frame).toContain('(r:)');
|
|
1426
|
+
expect(frame).toContain('git commit');
|
|
1427
|
+
expect(frame).toContain('git push');
|
|
1428
|
+
});
|
|
1457
1429
|
unmount();
|
|
1458
1430
|
});
|
|
1459
|
-
it
|
|
1431
|
+
it('expands and collapses long suggestion via Right/Left arrows', async () => {
|
|
1460
1432
|
props.shellModeActive = false;
|
|
1461
1433
|
const longValue = 'l'.repeat(200);
|
|
1462
1434
|
vi.mocked(useReverseSearchCompletion).mockReturnValue({
|
|
@@ -1468,18 +1440,26 @@ describe('InputPrompt', () => {
|
|
|
1468
1440
|
isLoadingSuggestions: false,
|
|
1469
1441
|
});
|
|
1470
1442
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1471
|
-
await
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
await
|
|
1481
|
-
|
|
1482
|
-
|
|
1443
|
+
await act(async () => {
|
|
1444
|
+
stdin.write('\x12');
|
|
1445
|
+
});
|
|
1446
|
+
await waitFor(() => {
|
|
1447
|
+
expect(clean(stdout.lastFrame())).toContain('→');
|
|
1448
|
+
});
|
|
1449
|
+
await act(async () => {
|
|
1450
|
+
stdin.write('\u001B[C');
|
|
1451
|
+
});
|
|
1452
|
+
await waitFor(() => {
|
|
1453
|
+
expect(clean(stdout.lastFrame())).toContain('←');
|
|
1454
|
+
});
|
|
1455
|
+
expect(stdout.lastFrame()).toMatchSnapshot('command-search-render-expanded-match');
|
|
1456
|
+
await act(async () => {
|
|
1457
|
+
stdin.write('\u001B[D');
|
|
1458
|
+
});
|
|
1459
|
+
await waitFor(() => {
|
|
1460
|
+
expect(clean(stdout.lastFrame())).toContain('→');
|
|
1461
|
+
});
|
|
1462
|
+
expect(stdout.lastFrame()).toMatchSnapshot('command-search-render-collapsed-match');
|
|
1483
1463
|
unmount();
|
|
1484
1464
|
});
|
|
1485
1465
|
it('renders match window and expanded view (snapshots)', async () => {
|
|
@@ -1496,13 +1476,18 @@ describe('InputPrompt', () => {
|
|
|
1496
1476
|
isLoadingSuggestions: false,
|
|
1497
1477
|
});
|
|
1498
1478
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1499
|
-
await
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1479
|
+
await act(async () => {
|
|
1480
|
+
stdin.write('\x12');
|
|
1481
|
+
});
|
|
1482
|
+
await waitFor(() => {
|
|
1483
|
+
expect(stdout.lastFrame()).toMatchSnapshot('command-search-render-collapsed-match');
|
|
1484
|
+
});
|
|
1485
|
+
await act(async () => {
|
|
1486
|
+
stdin.write('\u001B[C');
|
|
1487
|
+
});
|
|
1488
|
+
await waitFor(() => {
|
|
1489
|
+
expect(stdout.lastFrame()).toMatchSnapshot('command-search-render-expanded-match');
|
|
1490
|
+
});
|
|
1506
1491
|
unmount();
|
|
1507
1492
|
});
|
|
1508
1493
|
it('does not show expand/collapse indicator for short suggestions', async () => {
|
|
@@ -1517,12 +1502,72 @@ describe('InputPrompt', () => {
|
|
|
1517
1502
|
isLoadingSuggestions: false,
|
|
1518
1503
|
});
|
|
1519
1504
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1520
|
-
await
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1505
|
+
await act(async () => {
|
|
1506
|
+
stdin.write('\x12');
|
|
1507
|
+
});
|
|
1508
|
+
await waitFor(() => {
|
|
1509
|
+
const frame = clean(stdout.lastFrame());
|
|
1510
|
+
// Ensure it rendered the search mode
|
|
1511
|
+
expect(frame).toContain('(r:)');
|
|
1512
|
+
expect(frame).not.toContain('→');
|
|
1513
|
+
expect(frame).not.toContain('←');
|
|
1514
|
+
});
|
|
1515
|
+
unmount();
|
|
1516
|
+
});
|
|
1517
|
+
});
|
|
1518
|
+
describe('mouse interaction', () => {
|
|
1519
|
+
it.each([
|
|
1520
|
+
{
|
|
1521
|
+
name: 'first line, first char',
|
|
1522
|
+
relX: 0,
|
|
1523
|
+
relY: 0,
|
|
1524
|
+
mouseCol: 5,
|
|
1525
|
+
mouseRow: 2,
|
|
1526
|
+
},
|
|
1527
|
+
{
|
|
1528
|
+
name: 'first line, middle char',
|
|
1529
|
+
relX: 6,
|
|
1530
|
+
relY: 0,
|
|
1531
|
+
mouseCol: 11,
|
|
1532
|
+
mouseRow: 2,
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
name: 'second line, first char',
|
|
1536
|
+
relX: 0,
|
|
1537
|
+
relY: 1,
|
|
1538
|
+
mouseCol: 5,
|
|
1539
|
+
mouseRow: 3,
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
name: 'second line, end char',
|
|
1543
|
+
relX: 5,
|
|
1544
|
+
relY: 1,
|
|
1545
|
+
mouseCol: 10,
|
|
1546
|
+
mouseRow: 3,
|
|
1547
|
+
},
|
|
1548
|
+
])('should move cursor on mouse click - $name', async ({ relX, relY, mouseCol, mouseRow }) => {
|
|
1549
|
+
props.buffer.text = 'hello world\nsecond line';
|
|
1550
|
+
props.buffer.lines = ['hello world', 'second line'];
|
|
1551
|
+
props.buffer.viewportVisualLines = ['hello world', 'second line'];
|
|
1552
|
+
props.buffer.visualToLogicalMap = [
|
|
1553
|
+
[0, 0],
|
|
1554
|
+
[1, 0],
|
|
1555
|
+
];
|
|
1556
|
+
props.buffer.visualCursor = [0, 11];
|
|
1557
|
+
props.buffer.visualScrollRow = 0;
|
|
1558
|
+
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { mouseEventsEnabled: true });
|
|
1559
|
+
// Wait for initial render
|
|
1560
|
+
await waitFor(() => {
|
|
1561
|
+
expect(stdout.lastFrame()).toContain('hello world');
|
|
1562
|
+
});
|
|
1563
|
+
// Simulate left mouse press at calculated coordinates.
|
|
1564
|
+
// Assumes inner box is at x=4, y=1 based on border(1)+padding(1)+prompt(2) and border-top(1).
|
|
1565
|
+
await act(async () => {
|
|
1566
|
+
stdin.write(`\x1b[<0;${mouseCol};${mouseRow}M`);
|
|
1567
|
+
});
|
|
1568
|
+
await waitFor(() => {
|
|
1569
|
+
expect(props.buffer.moveToVisualPosition).toHaveBeenCalledWith(relY, relX);
|
|
1570
|
+
});
|
|
1526
1571
|
unmount();
|
|
1527
1572
|
});
|
|
1528
1573
|
});
|
|
@@ -1532,12 +1577,12 @@ describe('InputPrompt', () => {
|
|
|
1532
1577
|
props.popAllMessages = mockPopAllMessages;
|
|
1533
1578
|
props.buffer.text = '';
|
|
1534
1579
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1535
|
-
await
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1580
|
+
await act(async () => {
|
|
1581
|
+
stdin.write('\u001B[A');
|
|
1582
|
+
});
|
|
1583
|
+
await waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1539
1584
|
const callback = mockPopAllMessages.mock.calls[0][0];
|
|
1540
|
-
act(() => {
|
|
1585
|
+
await act(async () => {
|
|
1541
1586
|
callback('Message 1\n\nMessage 2\n\nMessage 3');
|
|
1542
1587
|
});
|
|
1543
1588
|
expect(props.buffer.setText).toHaveBeenCalledWith('Message 1\n\nMessage 2\n\nMessage 3');
|
|
@@ -1548,11 +1593,11 @@ describe('InputPrompt', () => {
|
|
|
1548
1593
|
props.popAllMessages = mockPopAllMessages;
|
|
1549
1594
|
props.buffer.text = 'some text';
|
|
1550
1595
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1551
|
-
await
|
|
1552
|
-
|
|
1553
|
-
|
|
1596
|
+
await act(async () => {
|
|
1597
|
+
stdin.write('\u001B[A');
|
|
1598
|
+
});
|
|
1599
|
+
await waitFor(() => expect(mockInputHistory.navigateUp).toHaveBeenCalled());
|
|
1554
1600
|
expect(mockPopAllMessages).not.toHaveBeenCalled();
|
|
1555
|
-
expect(mockInputHistory.navigateUp).toHaveBeenCalled();
|
|
1556
1601
|
unmount();
|
|
1557
1602
|
});
|
|
1558
1603
|
it('should handle undefined messages from popAllMessages', async () => {
|
|
@@ -1560,12 +1605,12 @@ describe('InputPrompt', () => {
|
|
|
1560
1605
|
props.popAllMessages = mockPopAllMessages;
|
|
1561
1606
|
props.buffer.text = '';
|
|
1562
1607
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1563
|
-
await
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1608
|
+
await act(async () => {
|
|
1609
|
+
stdin.write('\u001B[A');
|
|
1610
|
+
});
|
|
1611
|
+
await waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1567
1612
|
const callback = mockPopAllMessages.mock.calls[0][0];
|
|
1568
|
-
act(() => {
|
|
1613
|
+
await act(async () => {
|
|
1569
1614
|
callback(undefined);
|
|
1570
1615
|
});
|
|
1571
1616
|
expect(props.buffer.setText).not.toHaveBeenCalled();
|
|
@@ -1580,10 +1625,10 @@ describe('InputPrompt', () => {
|
|
|
1580
1625
|
props.buffer.visualCursor = [0, 0];
|
|
1581
1626
|
props.buffer.visualScrollRow = 0;
|
|
1582
1627
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1583
|
-
await
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1628
|
+
await act(async () => {
|
|
1629
|
+
stdin.write('\u001B[A');
|
|
1630
|
+
});
|
|
1631
|
+
await waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1587
1632
|
unmount();
|
|
1588
1633
|
});
|
|
1589
1634
|
it('should handle single queued message', async () => {
|
|
@@ -1591,11 +1636,12 @@ describe('InputPrompt', () => {
|
|
|
1591
1636
|
props.popAllMessages = mockPopAllMessages;
|
|
1592
1637
|
props.buffer.text = '';
|
|
1593
1638
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1594
|
-
await
|
|
1595
|
-
|
|
1596
|
-
|
|
1639
|
+
await act(async () => {
|
|
1640
|
+
stdin.write('\u001B[A');
|
|
1641
|
+
});
|
|
1642
|
+
await waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1597
1643
|
const callback = mockPopAllMessages.mock.calls[0][0];
|
|
1598
|
-
act(() => {
|
|
1644
|
+
await act(async () => {
|
|
1599
1645
|
callback('Single message');
|
|
1600
1646
|
});
|
|
1601
1647
|
expect(props.buffer.setText).toHaveBeenCalledWith('Single message');
|
|
@@ -1606,20 +1652,20 @@ describe('InputPrompt', () => {
|
|
|
1606
1652
|
props.popAllMessages = mockPopAllMessages;
|
|
1607
1653
|
props.buffer.text = ' '; // Whitespace only
|
|
1608
1654
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1609
|
-
await
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1655
|
+
await act(async () => {
|
|
1656
|
+
stdin.write('\u001B[A');
|
|
1657
|
+
});
|
|
1658
|
+
await waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1613
1659
|
unmount();
|
|
1614
1660
|
});
|
|
1615
1661
|
it('should not call popAllMessages if it is not provided', async () => {
|
|
1616
1662
|
props.popAllMessages = undefined;
|
|
1617
1663
|
props.buffer.text = '';
|
|
1618
1664
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1619
|
-
await
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
expect(mockInputHistory.navigateUp).toHaveBeenCalled();
|
|
1665
|
+
await act(async () => {
|
|
1666
|
+
stdin.write('\u001B[A');
|
|
1667
|
+
});
|
|
1668
|
+
await waitFor(() => expect(mockInputHistory.navigateUp).toHaveBeenCalled());
|
|
1623
1669
|
unmount();
|
|
1624
1670
|
});
|
|
1625
1671
|
it('should navigate input history on fresh start when no queued messages exist', async () => {
|
|
@@ -1627,12 +1673,12 @@ describe('InputPrompt', () => {
|
|
|
1627
1673
|
props.popAllMessages = mockPopAllMessages;
|
|
1628
1674
|
props.buffer.text = '';
|
|
1629
1675
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1630
|
-
await
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1676
|
+
await act(async () => {
|
|
1677
|
+
stdin.write('\u001B[A');
|
|
1678
|
+
});
|
|
1679
|
+
await waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1634
1680
|
const callback = mockPopAllMessages.mock.calls[0][0];
|
|
1635
|
-
act(() => {
|
|
1681
|
+
await act(async () => {
|
|
1636
1682
|
callback(undefined);
|
|
1637
1683
|
});
|
|
1638
1684
|
expect(mockInputHistory.navigateUp).toHaveBeenCalled();
|
|
@@ -1644,33 +1690,31 @@ describe('InputPrompt', () => {
|
|
|
1644
1690
|
it('should render correctly in shell mode', async () => {
|
|
1645
1691
|
props.shellModeActive = true;
|
|
1646
1692
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1647
|
-
await
|
|
1648
|
-
expect(stdout.lastFrame()).toMatchSnapshot();
|
|
1693
|
+
await waitFor(() => expect(stdout.lastFrame()).toMatchSnapshot());
|
|
1649
1694
|
unmount();
|
|
1650
1695
|
});
|
|
1651
1696
|
it('should render correctly when accepting edits', async () => {
|
|
1652
1697
|
props.approvalMode = ApprovalMode.AUTO_EDIT;
|
|
1653
1698
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1654
|
-
await
|
|
1655
|
-
expect(stdout.lastFrame()).toMatchSnapshot();
|
|
1699
|
+
await waitFor(() => expect(stdout.lastFrame()).toMatchSnapshot());
|
|
1656
1700
|
unmount();
|
|
1657
1701
|
});
|
|
1658
1702
|
it('should render correctly in yolo mode', async () => {
|
|
1659
1703
|
props.approvalMode = ApprovalMode.YOLO;
|
|
1660
1704
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1661
|
-
await
|
|
1662
|
-
expect(stdout.lastFrame()).toMatchSnapshot();
|
|
1705
|
+
await waitFor(() => expect(stdout.lastFrame()).toMatchSnapshot());
|
|
1663
1706
|
unmount();
|
|
1664
1707
|
});
|
|
1665
1708
|
it('should not show inverted cursor when shell is focused', async () => {
|
|
1666
1709
|
props.isEmbeddedShellFocused = true;
|
|
1667
1710
|
props.focus = false;
|
|
1668
1711
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1669
|
-
await
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1712
|
+
await waitFor(() => {
|
|
1713
|
+
expect(stdout.lastFrame()).not.toContain(`{chalk.inverse(' ')}`);
|
|
1714
|
+
// This snapshot is good to make sure there was an input prompt but does
|
|
1715
|
+
// not show the inverted cursor because snapshots do not show colors.
|
|
1716
|
+
expect(stdout.lastFrame()).toMatchSnapshot();
|
|
1717
|
+
});
|
|
1674
1718
|
unmount();
|
|
1675
1719
|
});
|
|
1676
1720
|
});
|
|
@@ -1678,54 +1722,59 @@ describe('InputPrompt', () => {
|
|
|
1678
1722
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), {
|
|
1679
1723
|
shellFocus: false,
|
|
1680
1724
|
});
|
|
1681
|
-
await
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
expect(mockBuffer.handleInput).toHaveBeenCalled();
|
|
1685
|
-
unmount();
|
|
1686
|
-
});
|
|
1687
|
-
it('should prevent slash commands from being queued while streaming', async () => {
|
|
1688
|
-
props.onSubmit = vi.fn();
|
|
1689
|
-
props.buffer.text = '/help';
|
|
1690
|
-
props.setQueueErrorMessage = vi.fn();
|
|
1691
|
-
props.streamingState = StreamingState.Responding;
|
|
1692
|
-
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1693
|
-
await wait();
|
|
1694
|
-
stdin.write('/help');
|
|
1695
|
-
stdin.write('\r');
|
|
1696
|
-
await wait();
|
|
1697
|
-
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
1698
|
-
expect(props.setQueueErrorMessage).toHaveBeenCalledWith('Slash commands cannot be queued');
|
|
1699
|
-
unmount();
|
|
1700
|
-
});
|
|
1701
|
-
it('should prevent shell commands from being queued while streaming', async () => {
|
|
1702
|
-
props.onSubmit = vi.fn();
|
|
1703
|
-
props.buffer.text = 'ls';
|
|
1704
|
-
props.setQueueErrorMessage = vi.fn();
|
|
1705
|
-
props.streamingState = StreamingState.Responding;
|
|
1706
|
-
props.shellModeActive = true;
|
|
1707
|
-
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1708
|
-
await wait();
|
|
1709
|
-
stdin.write('ls');
|
|
1710
|
-
stdin.write('\r');
|
|
1711
|
-
await wait();
|
|
1712
|
-
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
1713
|
-
expect(props.setQueueErrorMessage).toHaveBeenCalledWith('Shell commands cannot be queued');
|
|
1725
|
+
await act(async () => {
|
|
1726
|
+
stdin.write('a');
|
|
1727
|
+
});
|
|
1728
|
+
await waitFor(() => expect(mockBuffer.handleInput).toHaveBeenCalled());
|
|
1714
1729
|
unmount();
|
|
1715
1730
|
});
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1731
|
+
describe('command queuing while streaming', () => {
|
|
1732
|
+
beforeEach(() => {
|
|
1733
|
+
props.streamingState = StreamingState.Responding;
|
|
1734
|
+
props.setQueueErrorMessage = vi.fn();
|
|
1735
|
+
props.onSubmit = vi.fn();
|
|
1736
|
+
});
|
|
1737
|
+
it.each([
|
|
1738
|
+
{
|
|
1739
|
+
name: 'should prevent slash commands',
|
|
1740
|
+
bufferText: '/help',
|
|
1741
|
+
shellMode: false,
|
|
1742
|
+
shouldSubmit: false,
|
|
1743
|
+
errorMessage: 'Slash commands cannot be queued',
|
|
1744
|
+
},
|
|
1745
|
+
{
|
|
1746
|
+
name: 'should prevent shell commands',
|
|
1747
|
+
bufferText: 'ls',
|
|
1748
|
+
shellMode: true,
|
|
1749
|
+
shouldSubmit: false,
|
|
1750
|
+
errorMessage: 'Shell commands cannot be queued',
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
name: 'should allow regular messages',
|
|
1754
|
+
bufferText: 'regular message',
|
|
1755
|
+
shellMode: false,
|
|
1756
|
+
shouldSubmit: true,
|
|
1757
|
+
errorMessage: null,
|
|
1758
|
+
},
|
|
1759
|
+
])('$name', async ({ bufferText, shellMode, shouldSubmit, errorMessage }) => {
|
|
1760
|
+
props.buffer.text = bufferText;
|
|
1761
|
+
props.shellModeActive = shellMode;
|
|
1762
|
+
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1763
|
+
await act(async () => {
|
|
1764
|
+
stdin.write('\r');
|
|
1765
|
+
});
|
|
1766
|
+
await waitFor(() => {
|
|
1767
|
+
if (shouldSubmit) {
|
|
1768
|
+
expect(props.onSubmit).toHaveBeenCalledWith(bufferText);
|
|
1769
|
+
expect(props.setQueueErrorMessage).not.toHaveBeenCalled();
|
|
1770
|
+
}
|
|
1771
|
+
else {
|
|
1772
|
+
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
1773
|
+
expect(props.setQueueErrorMessage).toHaveBeenCalledWith(errorMessage);
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
unmount();
|
|
1777
|
+
});
|
|
1729
1778
|
});
|
|
1730
1779
|
});
|
|
1731
1780
|
function clean(str) {
|