@google/gemini-cli 0.1.9-rc.1 → 0.1.10-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -8
- package/LICENSE +0 -202
- package/README.md +0 -142
- package/dist/.last_build +0 -0
- package/dist/google-gemini-cli-0.1.9-rc.1.tgz +0 -0
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -20
- package/dist/index.js.map +0 -1
- package/dist/package.json +0 -81
- package/dist/src/config/auth.d.ts +0 -6
- package/dist/src/config/auth.js +0 -32
- package/dist/src/config/auth.js.map +0 -1
- package/dist/src/config/config.d.ts +0 -14
- package/dist/src/config/config.js +0 -235
- package/dist/src/config/config.js.map +0 -1
- package/dist/src/config/extension.d.ts +0 -20
- package/dist/src/config/extension.js +0 -81
- package/dist/src/config/extension.js.map +0 -1
- package/dist/src/config/sandboxConfig.d.ts +0 -13
- package/dist/src/config/sandboxConfig.js +0 -75
- package/dist/src/config/sandboxConfig.js.map +0 -1
- package/dist/src/config/settings.d.ts +0 -70
- package/dist/src/config/settings.js +0 -165
- package/dist/src/config/settings.js.map +0 -1
- package/dist/src/gemini.d.ts +0 -6
- package/dist/src/gemini.js +0 -217
- package/dist/src/gemini.js.map +0 -1
- package/dist/src/gemini.test.d.ts +0 -6
- package/dist/src/gemini.test.js +0 -122
- package/dist/src/gemini.test.js.map +0 -1
- package/dist/src/generated/git-commit.d.ts +0 -6
- package/dist/src/generated/git-commit.js +0 -9
- package/dist/src/generated/git-commit.js.map +0 -1
- package/dist/src/nonInteractiveCli.d.ts +0 -7
- package/dist/src/nonInteractiveCli.js +0 -115
- package/dist/src/nonInteractiveCli.js.map +0 -1
- package/dist/src/ui/App.d.ts +0 -14
- package/dist/src/ui/App.js +0 -387
- package/dist/src/ui/App.js.map +0 -1
- package/dist/src/ui/App.test.d.ts +0 -6
- package/dist/src/ui/App.test.js +0 -299
- package/dist/src/ui/App.test.js.map +0 -1
- package/dist/src/ui/colors.d.ts +0 -7
- package/dist/src/ui/colors.js +0 -48
- package/dist/src/ui/colors.js.map +0 -1
- package/dist/src/ui/components/AboutBox.d.ts +0 -16
- package/dist/src/ui/components/AboutBox.js +0 -6
- package/dist/src/ui/components/AboutBox.js.map +0 -1
- package/dist/src/ui/components/AsciiArt.d.ts +0 -7
- package/dist/src/ui/components/AsciiArt.js +0 -26
- package/dist/src/ui/components/AsciiArt.js.map +0 -1
- package/dist/src/ui/components/AuthDialog.d.ts +0 -15
- package/dist/src/ui/components/AuthDialog.js +0 -47
- package/dist/src/ui/components/AuthDialog.js.map +0 -1
- package/dist/src/ui/components/AuthDialog.test.d.ts +0 -6
- package/dist/src/ui/components/AuthDialog.test.js +0 -69
- package/dist/src/ui/components/AuthDialog.test.js.map +0 -1
- package/dist/src/ui/components/AuthInProgress.d.ts +0 -11
- package/dist/src/ui/components/AuthInProgress.js +0 -27
- package/dist/src/ui/components/AuthInProgress.js.map +0 -1
- package/dist/src/ui/components/AutoAcceptIndicator.d.ts +0 -12
- package/dist/src/ui/components/AutoAcceptIndicator.js +0 -26
- package/dist/src/ui/components/AutoAcceptIndicator.js.map +0 -1
- package/dist/src/ui/components/ConsolePatcher.d.ts +0 -12
- package/dist/src/ui/components/ConsolePatcher.js +0 -40
- package/dist/src/ui/components/ConsolePatcher.js.map +0 -1
- package/dist/src/ui/components/ConsoleSummaryDisplay.d.ts +0 -11
- package/dist/src/ui/components/ConsoleSummaryDisplay.js +0 -11
- package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +0 -1
- package/dist/src/ui/components/ContextSummaryDisplay.d.ts +0 -15
- package/dist/src/ui/components/ContextSummaryDisplay.js +0 -41
- package/dist/src/ui/components/ContextSummaryDisplay.js.map +0 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.d.ts +0 -14
- package/dist/src/ui/components/DetailedMessagesDisplay.js +0 -34
- package/dist/src/ui/components/DetailedMessagesDisplay.js.map +0 -1
- package/dist/src/ui/components/EditorSettingsDialog.d.ts +0 -15
- package/dist/src/ui/components/EditorSettingsDialog.js +0 -73
- package/dist/src/ui/components/EditorSettingsDialog.js.map +0 -1
- package/dist/src/ui/components/Footer.d.ts +0 -20
- package/dist/src/ui/components/Footer.js +0 -13
- package/dist/src/ui/components/Footer.js.map +0 -1
- package/dist/src/ui/components/GeminiRespondingSpinner.d.ts +0 -17
- package/dist/src/ui/components/GeminiRespondingSpinner.js +0 -16
- package/dist/src/ui/components/GeminiRespondingSpinner.js.map +0 -1
- package/dist/src/ui/components/Header.d.ts +0 -12
- package/dist/src/ui/components/Header.js +0 -20
- package/dist/src/ui/components/Header.js.map +0 -1
- package/dist/src/ui/components/Help.d.ts +0 -12
- package/dist/src/ui/components/Help.js +0 -9
- package/dist/src/ui/components/Help.js.map +0 -1
- package/dist/src/ui/components/HistoryItemDisplay.d.ts +0 -18
- package/dist/src/ui/components/HistoryItemDisplay.js +0 -17
- package/dist/src/ui/components/HistoryItemDisplay.js.map +0 -1
- package/dist/src/ui/components/HistoryItemDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/HistoryItemDisplay.test.js +0 -81
- package/dist/src/ui/components/HistoryItemDisplay.test.js.map +0 -1
- package/dist/src/ui/components/InputPrompt.d.ts +0 -24
- package/dist/src/ui/components/InputPrompt.js +0 -331
- package/dist/src/ui/components/InputPrompt.js.map +0 -1
- package/dist/src/ui/components/InputPrompt.test.d.ts +0 -6
- package/dist/src/ui/components/InputPrompt.test.js +0 -154
- package/dist/src/ui/components/InputPrompt.test.js.map +0 -1
- package/dist/src/ui/components/LoadingIndicator.d.ts +0 -15
- package/dist/src/ui/components/LoadingIndicator.js +0 -19
- package/dist/src/ui/components/LoadingIndicator.js.map +0 -1
- package/dist/src/ui/components/LoadingIndicator.test.d.ts +0 -6
- package/dist/src/ui/components/LoadingIndicator.test.js +0 -141
- package/dist/src/ui/components/LoadingIndicator.test.js.map +0 -1
- package/dist/src/ui/components/MemoryUsageDisplay.d.ts +0 -7
- package/dist/src/ui/components/MemoryUsageDisplay.js +0 -27
- package/dist/src/ui/components/MemoryUsageDisplay.js.map +0 -1
- package/dist/src/ui/components/ModelStatsDisplay.d.ts +0 -7
- package/dist/src/ui/components/ModelStatsDisplay.js +0 -33
- package/dist/src/ui/components/ModelStatsDisplay.js.map +0 -1
- package/dist/src/ui/components/ModelStatsDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ModelStatsDisplay.test.js +0 -217
- package/dist/src/ui/components/ModelStatsDisplay.test.js.map +0 -1
- package/dist/src/ui/components/SessionSummaryDisplay.d.ts +0 -11
- package/dist/src/ui/components/SessionSummaryDisplay.js +0 -4
- package/dist/src/ui/components/SessionSummaryDisplay.js.map +0 -1
- package/dist/src/ui/components/SessionSummaryDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/SessionSummaryDisplay.test.js +0 -60
- package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +0 -1
- package/dist/src/ui/components/ShellModeIndicator.d.ts +0 -7
- package/dist/src/ui/components/ShellModeIndicator.js +0 -5
- package/dist/src/ui/components/ShellModeIndicator.js.map +0 -1
- package/dist/src/ui/components/ShowMoreLines.d.ts +0 -10
- package/dist/src/ui/components/ShowMoreLines.js +0 -24
- package/dist/src/ui/components/ShowMoreLines.js.map +0 -1
- package/dist/src/ui/components/StatsDisplay.d.ts +0 -12
- package/dist/src/ui/components/StatsDisplay.js +0 -42
- package/dist/src/ui/components/StatsDisplay.js.map +0 -1
- package/dist/src/ui/components/StatsDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/StatsDisplay.test.js +0 -275
- package/dist/src/ui/components/StatsDisplay.test.js.map +0 -1
- package/dist/src/ui/components/SuggestionsDisplay.d.ts +0 -21
- package/dist/src/ui/components/SuggestionsDisplay.js +0 -32
- package/dist/src/ui/components/SuggestionsDisplay.js.map +0 -1
- package/dist/src/ui/components/ThemeDialog.d.ts +0 -19
- package/dist/src/ui/components/ThemeDialog.js +0 -126
- package/dist/src/ui/components/ThemeDialog.js.map +0 -1
- package/dist/src/ui/components/Tips.d.ts +0 -12
- package/dist/src/ui/components/Tips.js +0 -8
- package/dist/src/ui/components/Tips.js.map +0 -1
- package/dist/src/ui/components/ToolStatsDisplay.d.ts +0 -7
- package/dist/src/ui/components/ToolStatsDisplay.js +0 -41
- package/dist/src/ui/components/ToolStatsDisplay.js.map +0 -1
- package/dist/src/ui/components/ToolStatsDisplay.test.d.ts +0 -6
- package/dist/src/ui/components/ToolStatsDisplay.test.js +0 -160
- package/dist/src/ui/components/ToolStatsDisplay.test.js.map +0 -1
- package/dist/src/ui/components/UpdateNotification.d.ts +0 -10
- package/dist/src/ui/components/UpdateNotification.js +0 -10
- package/dist/src/ui/components/UpdateNotification.js.map +0 -1
- package/dist/src/ui/components/messages/CompressionMessage.d.ts +0 -11
- package/dist/src/ui/components/messages/CompressionMessage.js +0 -16
- package/dist/src/ui/components/messages/CompressionMessage.js.map +0 -1
- package/dist/src/ui/components/messages/DiffRenderer.d.ts +0 -15
- package/dist/src/ui/components/messages/DiffRenderer.js +0 -212
- package/dist/src/ui/components/messages/DiffRenderer.js.map +0 -1
- package/dist/src/ui/components/messages/DiffRenderer.test.d.ts +0 -6
- package/dist/src/ui/components/messages/DiffRenderer.test.js +0 -239
- package/dist/src/ui/components/messages/DiffRenderer.test.js.map +0 -1
- package/dist/src/ui/components/messages/ErrorMessage.d.ts +0 -11
- package/dist/src/ui/components/messages/ErrorMessage.js +0 -9
- package/dist/src/ui/components/messages/ErrorMessage.js.map +0 -1
- package/dist/src/ui/components/messages/GeminiMessage.d.ts +0 -14
- package/dist/src/ui/components/messages/GeminiMessage.js +0 -10
- package/dist/src/ui/components/messages/GeminiMessage.js.map +0 -1
- package/dist/src/ui/components/messages/GeminiMessageContent.d.ts +0 -14
- package/dist/src/ui/components/messages/GeminiMessageContent.js +0 -15
- package/dist/src/ui/components/messages/GeminiMessageContent.js.map +0 -1
- package/dist/src/ui/components/messages/InfoMessage.d.ts +0 -11
- package/dist/src/ui/components/messages/InfoMessage.js +0 -9
- package/dist/src/ui/components/messages/InfoMessage.js.map +0 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.d.ts +0 -15
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +0 -111
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +0 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js +0 -37
- package/dist/src/ui/components/messages/ToolConfirmationMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +0 -18
- package/dist/src/ui/components/messages/ToolGroupMessage.js +0 -53
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +0 -1
- package/dist/src/ui/components/messages/ToolMessage.d.ts +0 -15
- package/dist/src/ui/components/messages/ToolMessage.js +0 -61
- package/dist/src/ui/components/messages/ToolMessage.js.map +0 -1
- package/dist/src/ui/components/messages/ToolMessage.test.d.ts +0 -6
- package/dist/src/ui/components/messages/ToolMessage.test.js +0 -116
- package/dist/src/ui/components/messages/ToolMessage.test.js.map +0 -1
- package/dist/src/ui/components/messages/UserMessage.d.ts +0 -11
- package/dist/src/ui/components/messages/UserMessage.js +0 -9
- package/dist/src/ui/components/messages/UserMessage.js.map +0 -1
- package/dist/src/ui/components/messages/UserShellMessage.d.ts +0 -11
- package/dist/src/ui/components/messages/UserShellMessage.js +0 -9
- package/dist/src/ui/components/messages/UserShellMessage.js.map +0 -1
- package/dist/src/ui/components/shared/MaxSizedBox.d.ts +0 -61
- package/dist/src/ui/components/shared/MaxSizedBox.js +0 -384
- package/dist/src/ui/components/shared/MaxSizedBox.js.map +0 -1
- package/dist/src/ui/components/shared/MaxSizedBox.test.d.ts +0 -6
- package/dist/src/ui/components/shared/MaxSizedBox.test.js +0 -134
- package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +0 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.d.ts +0 -41
- package/dist/src/ui/components/shared/RadioButtonSelect.js +0 -52
- package/dist/src/ui/components/shared/RadioButtonSelect.js.map +0 -1
- package/dist/src/ui/components/shared/text-buffer.d.ts +0 -128
- package/dist/src/ui/components/shared/text-buffer.js +0 -1122
- package/dist/src/ui/components/shared/text-buffer.js.map +0 -1
- package/dist/src/ui/constants.d.ts +0 -8
- package/dist/src/ui/constants.js +0 -12
- package/dist/src/ui/constants.js.map +0 -1
- package/dist/src/ui/contexts/OverflowContext.d.ts +0 -19
- package/dist/src/ui/contexts/OverflowContext.js +0 -43
- package/dist/src/ui/contexts/OverflowContext.js.map +0 -1
- package/dist/src/ui/contexts/SessionContext.d.ts +0 -33
- package/dist/src/ui/contexts/SessionContext.js +0 -49
- package/dist/src/ui/contexts/SessionContext.js.map +0 -1
- package/dist/src/ui/contexts/SessionContext.test.d.ts +0 -6
- package/dist/src/ui/contexts/SessionContext.test.js +0 -96
- package/dist/src/ui/contexts/SessionContext.test.js.map +0 -1
- package/dist/src/ui/contexts/StreamingContext.d.ts +0 -9
- package/dist/src/ui/contexts/StreamingContext.js +0 -15
- package/dist/src/ui/contexts/StreamingContext.js.map +0 -1
- package/dist/src/ui/editors/editorSettingsManager.d.ts +0 -19
- package/dist/src/ui/editors/editorSettingsManager.js +0 -54
- package/dist/src/ui/editors/editorSettingsManager.js.map +0 -1
- package/dist/src/ui/hooks/atCommandProcessor.d.ts +0 -31
- package/dist/src/ui/hooks/atCommandProcessor.js +0 -312
- package/dist/src/ui/hooks/atCommandProcessor.js.map +0 -1
- package/dist/src/ui/hooks/shellCommandProcessor.d.ts +0 -16
- package/dist/src/ui/hooks/shellCommandProcessor.js +0 -261
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +0 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +0 -31
- package/dist/src/ui/hooks/slashCommandProcessor.js +0 -965
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +0 -1
- package/dist/src/ui/hooks/useAuthCommand.d.ts +0 -14
- package/dist/src/ui/hooks/useAuthCommand.js +0 -54
- package/dist/src/ui/hooks/useAuthCommand.js.map +0 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.d.ts +0 -10
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js +0 -37
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +0 -1
- package/dist/src/ui/hooks/useBracketedPaste.d.ts +0 -12
- package/dist/src/ui/hooks/useBracketedPaste.js +0 -32
- package/dist/src/ui/hooks/useBracketedPaste.js.map +0 -1
- package/dist/src/ui/hooks/useCompletion.d.ts +0 -21
- package/dist/src/ui/hooks/useCompletion.js +0 -322
- package/dist/src/ui/hooks/useCompletion.js.map +0 -1
- package/dist/src/ui/hooks/useConsoleMessages.d.ts +0 -12
- package/dist/src/ui/hooks/useConsoleMessages.js +0 -60
- package/dist/src/ui/hooks/useConsoleMessages.js.map +0 -1
- package/dist/src/ui/hooks/useEditorSettings.d.ts +0 -16
- package/dist/src/ui/hooks/useEditorSettings.js +0 -43
- package/dist/src/ui/hooks/useEditorSettings.js.map +0 -1
- package/dist/src/ui/hooks/useGeminiStream.d.ts +0 -23
- package/dist/src/ui/hooks/useGeminiStream.js +0 -524
- package/dist/src/ui/hooks/useGeminiStream.js.map +0 -1
- package/dist/src/ui/hooks/useGeminiStream.test.d.ts +0 -6
- package/dist/src/ui/hooks/useGeminiStream.test.js +0 -775
- package/dist/src/ui/hooks/useGeminiStream.test.js.map +0 -1
- package/dist/src/ui/hooks/useGitBranchName.d.ts +0 -6
- package/dist/src/ui/hooks/useGitBranchName.js +0 -61
- package/dist/src/ui/hooks/useGitBranchName.js.map +0 -1
- package/dist/src/ui/hooks/useHistoryManager.d.ts +0 -22
- package/dist/src/ui/hooks/useHistoryManager.js +0 -72
- package/dist/src/ui/hooks/useHistoryManager.js.map +0 -1
- package/dist/src/ui/hooks/useInputHistory.d.ts +0 -19
- package/dist/src/ui/hooks/useInputHistory.js +0 -84
- package/dist/src/ui/hooks/useInputHistory.js.map +0 -1
- package/dist/src/ui/hooks/useKeypress.d.ts +0 -29
- package/dist/src/ui/hooks/useKeypress.js +0 -86
- package/dist/src/ui/hooks/useKeypress.js.map +0 -1
- package/dist/src/ui/hooks/useLoadingIndicator.d.ts +0 -10
- package/dist/src/ui/hooks/useLoadingIndicator.js +0 -44
- package/dist/src/ui/hooks/useLoadingIndicator.js.map +0 -1
- package/dist/src/ui/hooks/useLogger.d.ts +0 -10
- package/dist/src/ui/hooks/useLogger.js +0 -29
- package/dist/src/ui/hooks/useLogger.js.map +0 -1
- package/dist/src/ui/hooks/usePhraseCycler.d.ts +0 -14
- package/dist/src/ui/hooks/usePhraseCycler.js +0 -189
- package/dist/src/ui/hooks/usePhraseCycler.js.map +0 -1
- package/dist/src/ui/hooks/usePrivacySettings.d.ts +0 -16
- package/dist/src/ui/hooks/usePrivacySettings.js +0 -115
- package/dist/src/ui/hooks/usePrivacySettings.js.map +0 -1
- package/dist/src/ui/hooks/useReactToolScheduler.d.ts +0 -33
- package/dist/src/ui/hooks/useReactToolScheduler.js +0 -186
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +0 -1
- package/dist/src/ui/hooks/useRefreshMemoryCommand.d.ts +0 -6
- package/dist/src/ui/hooks/useRefreshMemoryCommand.js +0 -7
- package/dist/src/ui/hooks/useRefreshMemoryCommand.js.map +0 -1
- package/dist/src/ui/hooks/useShellHistory.d.ts +0 -11
- package/dist/src/ui/hooks/useShellHistory.js +0 -89
- package/dist/src/ui/hooks/useShellHistory.js.map +0 -1
- package/dist/src/ui/hooks/useShowMemoryCommand.d.ts +0 -9
- package/dist/src/ui/hooks/useShowMemoryCommand.js +0 -58
- package/dist/src/ui/hooks/useShowMemoryCommand.js.map +0 -1
- package/dist/src/ui/hooks/useStateAndRef.d.ts +0 -7
- package/dist/src/ui/hooks/useStateAndRef.js +0 -26
- package/dist/src/ui/hooks/useStateAndRef.js.map +0 -1
- package/dist/src/ui/hooks/useTerminalSize.d.ts +0 -9
- package/dist/src/ui/hooks/useTerminalSize.js +0 -27
- package/dist/src/ui/hooks/useTerminalSize.js.map +0 -1
- package/dist/src/ui/hooks/useThemeCommand.d.ts +0 -15
- package/dist/src/ui/hooks/useThemeCommand.js +0 -78
- package/dist/src/ui/hooks/useThemeCommand.js.map +0 -1
- package/dist/src/ui/hooks/useTimer.d.ts +0 -12
- package/dist/src/ui/hooks/useTimer.js +0 -58
- package/dist/src/ui/hooks/useTimer.js.map +0 -1
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.d.ts +0 -12
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.js +0 -40
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.js.map +0 -1
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.d.ts +0 -10
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js +0 -17
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js.map +0 -1
- package/dist/src/ui/privacy/GeminiPrivacyNotice.d.ts +0 -10
- package/dist/src/ui/privacy/GeminiPrivacyNotice.js +0 -17
- package/dist/src/ui/privacy/GeminiPrivacyNotice.js.map +0 -1
- package/dist/src/ui/privacy/PrivacyNotice.d.ts +0 -12
- package/dist/src/ui/privacy/PrivacyNotice.js +0 -25
- package/dist/src/ui/privacy/PrivacyNotice.js.map +0 -1
- package/dist/src/ui/themes/ansi-light.d.ts +0 -7
- package/dist/src/ui/themes/ansi-light.js +0 -139
- package/dist/src/ui/themes/ansi-light.js.map +0 -1
- package/dist/src/ui/themes/ansi.d.ts +0 -7
- package/dist/src/ui/themes/ansi.js +0 -149
- package/dist/src/ui/themes/ansi.js.map +0 -1
- package/dist/src/ui/themes/atom-one-dark.d.ts +0 -7
- package/dist/src/ui/themes/atom-one-dark.js +0 -136
- package/dist/src/ui/themes/atom-one-dark.js.map +0 -1
- package/dist/src/ui/themes/ayu-light.d.ts +0 -7
- package/dist/src/ui/themes/ayu-light.js +0 -128
- package/dist/src/ui/themes/ayu-light.js.map +0 -1
- package/dist/src/ui/themes/ayu.d.ts +0 -7
- package/dist/src/ui/themes/ayu.js +0 -102
- package/dist/src/ui/themes/ayu.js.map +0 -1
- package/dist/src/ui/themes/default-light.d.ts +0 -7
- package/dist/src/ui/themes/default-light.js +0 -100
- package/dist/src/ui/themes/default-light.js.map +0 -1
- package/dist/src/ui/themes/default.d.ts +0 -7
- package/dist/src/ui/themes/default.js +0 -143
- package/dist/src/ui/themes/default.js.map +0 -1
- package/dist/src/ui/themes/dracula.d.ts +0 -7
- package/dist/src/ui/themes/dracula.js +0 -113
- package/dist/src/ui/themes/dracula.js.map +0 -1
- package/dist/src/ui/themes/github-dark.d.ts +0 -7
- package/dist/src/ui/themes/github-dark.js +0 -136
- package/dist/src/ui/themes/github-dark.js.map +0 -1
- package/dist/src/ui/themes/github-light.d.ts +0 -7
- package/dist/src/ui/themes/github-light.js +0 -138
- package/dist/src/ui/themes/github-light.js.map +0 -1
- package/dist/src/ui/themes/googlecode.d.ts +0 -7
- package/dist/src/ui/themes/googlecode.js +0 -135
- package/dist/src/ui/themes/googlecode.js.map +0 -1
- package/dist/src/ui/themes/no-color.d.ts +0 -7
- package/dist/src/ui/themes/no-color.js +0 -84
- package/dist/src/ui/themes/no-color.js.map +0 -1
- package/dist/src/ui/themes/shades-of-purple.d.ts +0 -11
- package/dist/src/ui/themes/shades-of-purple.js +0 -302
- package/dist/src/ui/themes/shades-of-purple.js.map +0 -1
- package/dist/src/ui/themes/theme-manager.d.ts +0 -33
- package/dist/src/ui/themes/theme-manager.js +0 -109
- package/dist/src/ui/themes/theme-manager.js.map +0 -1
- package/dist/src/ui/themes/theme.d.ts +0 -67
- package/dist/src/ui/themes/theme.js +0 -304
- package/dist/src/ui/themes/theme.js.map +0 -1
- package/dist/src/ui/themes/xcode.d.ts +0 -7
- package/dist/src/ui/themes/xcode.js +0 -143
- package/dist/src/ui/themes/xcode.js.map +0 -1
- package/dist/src/ui/types.d.ts +0 -162
- package/dist/src/ui/types.js +0 -43
- package/dist/src/ui/types.js.map +0 -1
- package/dist/src/ui/utils/CodeColorizer.d.ts +0 -14
- package/dist/src/ui/utils/CodeColorizer.js +0 -97
- package/dist/src/ui/utils/CodeColorizer.js.map +0 -1
- package/dist/src/ui/utils/MarkdownDisplay.d.ts +0 -14
- package/dist/src/ui/utils/MarkdownDisplay.js +0 -276
- package/dist/src/ui/utils/MarkdownDisplay.js.map +0 -1
- package/dist/src/ui/utils/MarkdownDisplay.test.d.ts +0 -6
- package/dist/src/ui/utils/MarkdownDisplay.test.js +0 -176
- package/dist/src/ui/utils/MarkdownDisplay.test.js.map +0 -1
- package/dist/src/ui/utils/TableRenderer.d.ts +0 -17
- package/dist/src/ui/utils/TableRenderer.js +0 -66
- package/dist/src/ui/utils/TableRenderer.js.map +0 -1
- package/dist/src/ui/utils/commandUtils.d.ts +0 -22
- package/dist/src/ui/utils/commandUtils.js +0 -25
- package/dist/src/ui/utils/commandUtils.js.map +0 -1
- package/dist/src/ui/utils/computeStats.d.ts +0 -10
- package/dist/src/ui/utils/computeStats.js +0 -55
- package/dist/src/ui/utils/computeStats.js.map +0 -1
- package/dist/src/ui/utils/displayUtils.d.ts +0 -17
- package/dist/src/ui/utils/displayUtils.js +0 -24
- package/dist/src/ui/utils/displayUtils.js.map +0 -1
- package/dist/src/ui/utils/errorParsing.d.ts +0 -15
- package/dist/src/ui/utils/errorParsing.js +0 -79
- package/dist/src/ui/utils/errorParsing.js.map +0 -1
- package/dist/src/ui/utils/formatters.d.ts +0 -13
- package/dist/src/ui/utils/formatters.js +0 -56
- package/dist/src/ui/utils/formatters.js.map +0 -1
- package/dist/src/ui/utils/markdownUtilities.d.ts +0 -6
- package/dist/src/ui/utils/markdownUtilities.js +0 -110
- package/dist/src/ui/utils/markdownUtilities.js.map +0 -1
- package/dist/src/ui/utils/textUtils.d.ts +0 -22
- package/dist/src/ui/utils/textUtils.js +0 -58
- package/dist/src/ui/utils/textUtils.js.map +0 -1
- package/dist/src/ui/utils/updateCheck.d.ts +0 -6
- package/dist/src/ui/utils/updateCheck.js +0 -36
- package/dist/src/ui/utils/updateCheck.js.map +0 -1
- package/dist/src/utils/cleanup.d.ts +0 -6
- package/dist/src/utils/cleanup.js +0 -19
- package/dist/src/utils/cleanup.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/utils/readStdin.d.ts +0 -6
- package/dist/src/utils/readStdin.js +0 -34
- package/dist/src/utils/readStdin.js.map +0 -1
- package/dist/src/utils/sandbox-macos-permissive-closed.sb +0 -26
- package/dist/src/utils/sandbox-macos-permissive-open.sb +0 -19
- package/dist/src/utils/sandbox-macos-permissive-proxied.sb +0 -31
- package/dist/src/utils/sandbox-macos-restrictive-closed.sb +0 -87
- package/dist/src/utils/sandbox-macos-restrictive-open.sb +0 -90
- package/dist/src/utils/sandbox-macos-restrictive-proxied.sb +0 -92
- package/dist/src/utils/sandbox.d.ts +0 -7
- package/dist/src/utils/sandbox.js +0 -680
- package/dist/src/utils/sandbox.js.map +0 -1
- package/dist/src/utils/startupWarnings.d.ts +0 -6
- package/dist/src/utils/startupWarnings.js +0 -40
- package/dist/src/utils/startupWarnings.js.map +0 -1
- package/dist/src/utils/version.d.ts +0 -6
- package/dist/src/utils/version.js +0 -11
- package/dist/src/utils/version.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,1122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
import stripAnsi from 'strip-ansi';
|
|
7
|
-
import { spawnSync } from 'child_process';
|
|
8
|
-
import fs from 'fs';
|
|
9
|
-
import os from 'os';
|
|
10
|
-
import pathMod from 'path';
|
|
11
|
-
import { useState, useCallback, useEffect, useMemo } from 'react';
|
|
12
|
-
import stringWidth from 'string-width';
|
|
13
|
-
import { unescapePath } from '@google/gemini-cli-core';
|
|
14
|
-
import { toCodePoints, cpLen, cpSlice } from '../../utils/textUtils.js';
|
|
15
|
-
// Simple helper for word‑wise ops.
|
|
16
|
-
function isWordChar(ch) {
|
|
17
|
-
if (ch === undefined) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
return !/[\s,.;!?]/.test(ch);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Strip characters that can break terminal rendering.
|
|
24
|
-
*
|
|
25
|
-
* Strip ANSI escape codes and control characters except for line breaks.
|
|
26
|
-
* Control characters such as delete break terminal UI rendering.
|
|
27
|
-
*/
|
|
28
|
-
function stripUnsafeCharacters(str) {
|
|
29
|
-
const stripped = stripAnsi(str);
|
|
30
|
-
return toCodePoints(stripAnsi(stripped))
|
|
31
|
-
.filter((char) => {
|
|
32
|
-
if (char.length > 1)
|
|
33
|
-
return false;
|
|
34
|
-
const code = char.codePointAt(0);
|
|
35
|
-
if (code === undefined) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
const isUnsafe = code === 127 || (code <= 31 && code !== 13 && code !== 10);
|
|
39
|
-
return !isUnsafe;
|
|
40
|
-
})
|
|
41
|
-
.join('');
|
|
42
|
-
}
|
|
43
|
-
function clamp(v, min, max) {
|
|
44
|
-
return v < min ? min : v > max ? max : v;
|
|
45
|
-
}
|
|
46
|
-
/* -------------------------------------------------------------------------
|
|
47
|
-
* Debug helper – enable verbose logging by setting env var TEXTBUFFER_DEBUG=1
|
|
48
|
-
* ---------------------------------------------------------------------- */
|
|
49
|
-
// Enable verbose logging only when requested via env var.
|
|
50
|
-
const DEBUG = process.env['TEXTBUFFER_DEBUG'] === '1' ||
|
|
51
|
-
process.env['TEXTBUFFER_DEBUG'] === 'true';
|
|
52
|
-
function dbg(...args) {
|
|
53
|
-
if (DEBUG) {
|
|
54
|
-
console.log('[TextBuffer]', ...args);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
function calculateInitialCursorPosition(initialLines, offset) {
|
|
58
|
-
let remainingChars = offset;
|
|
59
|
-
let row = 0;
|
|
60
|
-
while (row < initialLines.length) {
|
|
61
|
-
const lineLength = cpLen(initialLines[row]);
|
|
62
|
-
// Add 1 for the newline character (except for the last line)
|
|
63
|
-
const totalCharsInLineAndNewline = lineLength + (row < initialLines.length - 1 ? 1 : 0);
|
|
64
|
-
if (remainingChars <= lineLength) {
|
|
65
|
-
// Cursor is on this line
|
|
66
|
-
return [row, remainingChars];
|
|
67
|
-
}
|
|
68
|
-
remainingChars -= totalCharsInLineAndNewline;
|
|
69
|
-
row++;
|
|
70
|
-
}
|
|
71
|
-
// Offset is beyond the text, place cursor at the end of the last line
|
|
72
|
-
if (initialLines.length > 0) {
|
|
73
|
-
const lastRow = initialLines.length - 1;
|
|
74
|
-
return [lastRow, cpLen(initialLines[lastRow])];
|
|
75
|
-
}
|
|
76
|
-
return [0, 0]; // Default for empty text
|
|
77
|
-
}
|
|
78
|
-
export function offsetToLogicalPos(text, offset) {
|
|
79
|
-
let row = 0;
|
|
80
|
-
let col = 0;
|
|
81
|
-
let currentOffset = 0;
|
|
82
|
-
if (offset === 0)
|
|
83
|
-
return [0, 0];
|
|
84
|
-
const lines = text.split('\n');
|
|
85
|
-
for (let i = 0; i < lines.length; i++) {
|
|
86
|
-
const line = lines[i];
|
|
87
|
-
const lineLength = cpLen(line);
|
|
88
|
-
const lineLengthWithNewline = lineLength + (i < lines.length - 1 ? 1 : 0);
|
|
89
|
-
if (offset <= currentOffset + lineLength) {
|
|
90
|
-
// Check against lineLength first
|
|
91
|
-
row = i;
|
|
92
|
-
col = offset - currentOffset;
|
|
93
|
-
return [row, col];
|
|
94
|
-
}
|
|
95
|
-
else if (offset <= currentOffset + lineLengthWithNewline) {
|
|
96
|
-
// Check if offset is the newline itself
|
|
97
|
-
row = i;
|
|
98
|
-
col = lineLength; // Position cursor at the end of the current line content
|
|
99
|
-
// If the offset IS the newline, and it's not the last line, advance to next line, col 0
|
|
100
|
-
if (offset === currentOffset + lineLengthWithNewline &&
|
|
101
|
-
i < lines.length - 1) {
|
|
102
|
-
return [i + 1, 0];
|
|
103
|
-
}
|
|
104
|
-
return [row, col]; // Otherwise, it's at the end of the current line content
|
|
105
|
-
}
|
|
106
|
-
currentOffset += lineLengthWithNewline;
|
|
107
|
-
}
|
|
108
|
-
// If offset is beyond the text length, place cursor at the end of the last line
|
|
109
|
-
// or [0,0] if text is empty
|
|
110
|
-
if (lines.length > 0) {
|
|
111
|
-
row = lines.length - 1;
|
|
112
|
-
col = cpLen(lines[row]);
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
row = 0;
|
|
116
|
-
col = 0;
|
|
117
|
-
}
|
|
118
|
-
return [row, col];
|
|
119
|
-
}
|
|
120
|
-
// Helper to calculate visual lines and map cursor positions
|
|
121
|
-
function calculateVisualLayout(logicalLines, logicalCursor, viewportWidth) {
|
|
122
|
-
const visualLines = [];
|
|
123
|
-
const logicalToVisualMap = [];
|
|
124
|
-
const visualToLogicalMap = [];
|
|
125
|
-
let currentVisualCursor = [0, 0];
|
|
126
|
-
logicalLines.forEach((logLine, logIndex) => {
|
|
127
|
-
logicalToVisualMap[logIndex] = [];
|
|
128
|
-
if (logLine.length === 0) {
|
|
129
|
-
// Handle empty logical line
|
|
130
|
-
logicalToVisualMap[logIndex].push([visualLines.length, 0]);
|
|
131
|
-
visualToLogicalMap.push([logIndex, 0]);
|
|
132
|
-
visualLines.push('');
|
|
133
|
-
if (logIndex === logicalCursor[0] && logicalCursor[1] === 0) {
|
|
134
|
-
currentVisualCursor = [visualLines.length - 1, 0];
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
// Non-empty logical line
|
|
139
|
-
let currentPosInLogLine = 0; // Tracks position within the current logical line (code point index)
|
|
140
|
-
const codePointsInLogLine = toCodePoints(logLine);
|
|
141
|
-
while (currentPosInLogLine < codePointsInLogLine.length) {
|
|
142
|
-
let currentChunk = '';
|
|
143
|
-
let currentChunkVisualWidth = 0;
|
|
144
|
-
let numCodePointsInChunk = 0;
|
|
145
|
-
let lastWordBreakPoint = -1; // Index in codePointsInLogLine for word break
|
|
146
|
-
let numCodePointsAtLastWordBreak = 0;
|
|
147
|
-
// Iterate through code points to build the current visual line (chunk)
|
|
148
|
-
for (let i = currentPosInLogLine; i < codePointsInLogLine.length; i++) {
|
|
149
|
-
const char = codePointsInLogLine[i];
|
|
150
|
-
const charVisualWidth = stringWidth(char);
|
|
151
|
-
if (currentChunkVisualWidth + charVisualWidth > viewportWidth) {
|
|
152
|
-
// Character would exceed viewport width
|
|
153
|
-
if (lastWordBreakPoint !== -1 &&
|
|
154
|
-
numCodePointsAtLastWordBreak > 0 &&
|
|
155
|
-
currentPosInLogLine + numCodePointsAtLastWordBreak < i) {
|
|
156
|
-
// We have a valid word break point to use, and it's not the start of the current segment
|
|
157
|
-
currentChunk = codePointsInLogLine
|
|
158
|
-
.slice(currentPosInLogLine, currentPosInLogLine + numCodePointsAtLastWordBreak)
|
|
159
|
-
.join('');
|
|
160
|
-
numCodePointsInChunk = numCodePointsAtLastWordBreak;
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
// No word break, or word break is at the start of this potential chunk, or word break leads to empty chunk.
|
|
164
|
-
// Hard break: take characters up to viewportWidth, or just the current char if it alone is too wide.
|
|
165
|
-
if (numCodePointsInChunk === 0 &&
|
|
166
|
-
charVisualWidth > viewportWidth) {
|
|
167
|
-
// Single character is wider than viewport, take it anyway
|
|
168
|
-
currentChunk = char;
|
|
169
|
-
numCodePointsInChunk = 1;
|
|
170
|
-
}
|
|
171
|
-
else if (numCodePointsInChunk === 0 &&
|
|
172
|
-
charVisualWidth <= viewportWidth) {
|
|
173
|
-
// This case should ideally be caught by the next iteration if the char fits.
|
|
174
|
-
// If it doesn't fit (because currentChunkVisualWidth was already > 0 from a previous char that filled the line),
|
|
175
|
-
// then numCodePointsInChunk would not be 0.
|
|
176
|
-
// This branch means the current char *itself* doesn't fit an empty line, which is handled by the above.
|
|
177
|
-
// If we are here, it means the loop should break and the current chunk (which is empty) is finalized.
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
break; // Break from inner loop to finalize this chunk
|
|
181
|
-
}
|
|
182
|
-
currentChunk += char;
|
|
183
|
-
currentChunkVisualWidth += charVisualWidth;
|
|
184
|
-
numCodePointsInChunk++;
|
|
185
|
-
// Check for word break opportunity (space)
|
|
186
|
-
if (char === ' ') {
|
|
187
|
-
lastWordBreakPoint = i; // Store code point index of the space
|
|
188
|
-
// Store the state *before* adding the space, if we decide to break here.
|
|
189
|
-
numCodePointsAtLastWordBreak = numCodePointsInChunk - 1; // Chars *before* the space
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// If the inner loop completed without breaking (i.e., remaining text fits)
|
|
193
|
-
// or if the loop broke but numCodePointsInChunk is still 0 (e.g. first char too wide for empty line)
|
|
194
|
-
if (numCodePointsInChunk === 0 &&
|
|
195
|
-
currentPosInLogLine < codePointsInLogLine.length) {
|
|
196
|
-
// This can happen if the very first character considered for a new visual line is wider than the viewport.
|
|
197
|
-
// In this case, we take that single character.
|
|
198
|
-
const firstChar = codePointsInLogLine[currentPosInLogLine];
|
|
199
|
-
currentChunk = firstChar;
|
|
200
|
-
numCodePointsInChunk = 1; // Ensure we advance
|
|
201
|
-
}
|
|
202
|
-
// If after everything, numCodePointsInChunk is still 0 but we haven't processed the whole logical line,
|
|
203
|
-
// it implies an issue, like viewportWidth being 0 or less. Avoid infinite loop.
|
|
204
|
-
if (numCodePointsInChunk === 0 &&
|
|
205
|
-
currentPosInLogLine < codePointsInLogLine.length) {
|
|
206
|
-
// Force advance by one character to prevent infinite loop if something went wrong
|
|
207
|
-
currentChunk = codePointsInLogLine[currentPosInLogLine];
|
|
208
|
-
numCodePointsInChunk = 1;
|
|
209
|
-
}
|
|
210
|
-
logicalToVisualMap[logIndex].push([
|
|
211
|
-
visualLines.length,
|
|
212
|
-
currentPosInLogLine,
|
|
213
|
-
]);
|
|
214
|
-
visualToLogicalMap.push([logIndex, currentPosInLogLine]);
|
|
215
|
-
visualLines.push(currentChunk);
|
|
216
|
-
// Cursor mapping logic
|
|
217
|
-
// Note: currentPosInLogLine here is the start of the currentChunk within the logical line.
|
|
218
|
-
if (logIndex === logicalCursor[0]) {
|
|
219
|
-
const cursorLogCol = logicalCursor[1]; // This is a code point index
|
|
220
|
-
if (cursorLogCol >= currentPosInLogLine &&
|
|
221
|
-
cursorLogCol < currentPosInLogLine + numCodePointsInChunk // Cursor is within this chunk
|
|
222
|
-
) {
|
|
223
|
-
currentVisualCursor = [
|
|
224
|
-
visualLines.length - 1,
|
|
225
|
-
cursorLogCol - currentPosInLogLine, // Visual col is also code point index within visual line
|
|
226
|
-
];
|
|
227
|
-
}
|
|
228
|
-
else if (cursorLogCol === currentPosInLogLine + numCodePointsInChunk &&
|
|
229
|
-
numCodePointsInChunk > 0) {
|
|
230
|
-
// Cursor is exactly at the end of this non-empty chunk
|
|
231
|
-
currentVisualCursor = [
|
|
232
|
-
visualLines.length - 1,
|
|
233
|
-
numCodePointsInChunk,
|
|
234
|
-
];
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
const logicalStartOfThisChunk = currentPosInLogLine;
|
|
238
|
-
currentPosInLogLine += numCodePointsInChunk;
|
|
239
|
-
// If the chunk processed did not consume the entire logical line,
|
|
240
|
-
// and the character immediately following the chunk is a space,
|
|
241
|
-
// advance past this space as it acted as a delimiter for word wrapping.
|
|
242
|
-
if (logicalStartOfThisChunk + numCodePointsInChunk <
|
|
243
|
-
codePointsInLogLine.length &&
|
|
244
|
-
currentPosInLogLine < codePointsInLogLine.length && // Redundant if previous is true, but safe
|
|
245
|
-
codePointsInLogLine[currentPosInLogLine] === ' ') {
|
|
246
|
-
currentPosInLogLine++;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
// After all chunks of a non-empty logical line are processed,
|
|
250
|
-
// if the cursor is at the very end of this logical line, update visual cursor.
|
|
251
|
-
if (logIndex === logicalCursor[0] &&
|
|
252
|
-
logicalCursor[1] === codePointsInLogLine.length // Cursor at end of logical line
|
|
253
|
-
) {
|
|
254
|
-
const lastVisualLineIdx = visualLines.length - 1;
|
|
255
|
-
if (lastVisualLineIdx >= 0 &&
|
|
256
|
-
visualLines[lastVisualLineIdx] !== undefined) {
|
|
257
|
-
currentVisualCursor = [
|
|
258
|
-
lastVisualLineIdx,
|
|
259
|
-
cpLen(visualLines[lastVisualLineIdx]), // Cursor at end of last visual line for this logical line
|
|
260
|
-
];
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
// If the entire logical text was empty, ensure there's one empty visual line.
|
|
266
|
-
if (logicalLines.length === 0 ||
|
|
267
|
-
(logicalLines.length === 1 && logicalLines[0] === '')) {
|
|
268
|
-
if (visualLines.length === 0) {
|
|
269
|
-
visualLines.push('');
|
|
270
|
-
if (!logicalToVisualMap[0])
|
|
271
|
-
logicalToVisualMap[0] = [];
|
|
272
|
-
logicalToVisualMap[0].push([0, 0]);
|
|
273
|
-
visualToLogicalMap.push([0, 0]);
|
|
274
|
-
}
|
|
275
|
-
currentVisualCursor = [0, 0];
|
|
276
|
-
}
|
|
277
|
-
// Handle cursor at the very end of the text (after all processing)
|
|
278
|
-
// This case might be covered by the loop end condition now, but kept for safety.
|
|
279
|
-
else if (logicalCursor[0] === logicalLines.length - 1 &&
|
|
280
|
-
logicalCursor[1] === cpLen(logicalLines[logicalLines.length - 1]) &&
|
|
281
|
-
visualLines.length > 0) {
|
|
282
|
-
const lastVisLineIdx = visualLines.length - 1;
|
|
283
|
-
currentVisualCursor = [lastVisLineIdx, cpLen(visualLines[lastVisLineIdx])];
|
|
284
|
-
}
|
|
285
|
-
return {
|
|
286
|
-
visualLines,
|
|
287
|
-
visualCursor: currentVisualCursor,
|
|
288
|
-
logicalToVisualMap,
|
|
289
|
-
visualToLogicalMap,
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
export function useTextBuffer({ initialText = '', initialCursorOffset = 0, viewport, stdin, setRawMode, onChange, isValidPath, }) {
|
|
293
|
-
const [lines, setLines] = useState(() => {
|
|
294
|
-
const l = initialText.split('\n');
|
|
295
|
-
return l.length === 0 ? [''] : l;
|
|
296
|
-
});
|
|
297
|
-
const [[initialCursorRow, initialCursorCol]] = useState(() => calculateInitialCursorPosition(lines, initialCursorOffset));
|
|
298
|
-
const [cursorRow, setCursorRow] = useState(initialCursorRow);
|
|
299
|
-
const [cursorCol, setCursorCol] = useState(initialCursorCol);
|
|
300
|
-
const [preferredCol, setPreferredCol] = useState(null); // Visual preferred col
|
|
301
|
-
const [undoStack, setUndoStack] = useState([]);
|
|
302
|
-
const [redoStack, setRedoStack] = useState([]);
|
|
303
|
-
const historyLimit = 100;
|
|
304
|
-
const [opQueue, setOpQueue] = useState([]);
|
|
305
|
-
const [clipboard, setClipboard] = useState(null);
|
|
306
|
-
const [selectionAnchor, setSelectionAnchor] = useState(null); // Logical selection
|
|
307
|
-
// Visual state
|
|
308
|
-
const [visualLines, setVisualLines] = useState(['']);
|
|
309
|
-
const [visualCursor, setVisualCursor] = useState([0, 0]);
|
|
310
|
-
const [visualScrollRow, setVisualScrollRow] = useState(0);
|
|
311
|
-
const [logicalToVisualMap, setLogicalToVisualMap] = useState([]);
|
|
312
|
-
const [visualToLogicalMap, setVisualToLogicalMap] = useState([]);
|
|
313
|
-
const currentLine = useCallback((r) => lines[r] ?? '', [lines]);
|
|
314
|
-
const currentLineLen = useCallback((r) => cpLen(currentLine(r)), [currentLine]);
|
|
315
|
-
// Recalculate visual layout whenever logical lines or viewport width changes
|
|
316
|
-
useEffect(() => {
|
|
317
|
-
const layout = calculateVisualLayout(lines, [cursorRow, cursorCol], viewport.width);
|
|
318
|
-
setVisualLines(layout.visualLines);
|
|
319
|
-
setVisualCursor(layout.visualCursor);
|
|
320
|
-
setLogicalToVisualMap(layout.logicalToVisualMap);
|
|
321
|
-
setVisualToLogicalMap(layout.visualToLogicalMap);
|
|
322
|
-
}, [lines, cursorRow, cursorCol, viewport.width]);
|
|
323
|
-
// Update visual scroll (vertical)
|
|
324
|
-
useEffect(() => {
|
|
325
|
-
const { height } = viewport;
|
|
326
|
-
let newVisualScrollRow = visualScrollRow;
|
|
327
|
-
if (visualCursor[0] < visualScrollRow) {
|
|
328
|
-
newVisualScrollRow = visualCursor[0];
|
|
329
|
-
}
|
|
330
|
-
else if (visualCursor[0] >= visualScrollRow + height) {
|
|
331
|
-
newVisualScrollRow = visualCursor[0] - height + 1;
|
|
332
|
-
}
|
|
333
|
-
if (newVisualScrollRow !== visualScrollRow) {
|
|
334
|
-
setVisualScrollRow(newVisualScrollRow);
|
|
335
|
-
}
|
|
336
|
-
}, [visualCursor, visualScrollRow, viewport]);
|
|
337
|
-
const pushUndo = useCallback(() => {
|
|
338
|
-
dbg('pushUndo', { cursor: [cursorRow, cursorCol], text: lines.join('\n') });
|
|
339
|
-
const snapshot = { lines: [...lines], cursorRow, cursorCol };
|
|
340
|
-
setUndoStack((prev) => {
|
|
341
|
-
const newStack = [...prev, snapshot];
|
|
342
|
-
if (newStack.length > historyLimit) {
|
|
343
|
-
newStack.shift();
|
|
344
|
-
}
|
|
345
|
-
return newStack;
|
|
346
|
-
});
|
|
347
|
-
setRedoStack([]);
|
|
348
|
-
}, [lines, cursorRow, cursorCol, historyLimit]);
|
|
349
|
-
const _restoreState = useCallback((state) => {
|
|
350
|
-
if (!state)
|
|
351
|
-
return false;
|
|
352
|
-
setLines(state.lines);
|
|
353
|
-
setCursorRow(state.cursorRow);
|
|
354
|
-
setCursorCol(state.cursorCol);
|
|
355
|
-
return true;
|
|
356
|
-
}, []);
|
|
357
|
-
const text = lines.join('\n');
|
|
358
|
-
useEffect(() => {
|
|
359
|
-
if (onChange) {
|
|
360
|
-
onChange(text);
|
|
361
|
-
}
|
|
362
|
-
}, [text, onChange]);
|
|
363
|
-
const undo = useCallback(() => {
|
|
364
|
-
const state = undoStack[undoStack.length - 1];
|
|
365
|
-
if (!state)
|
|
366
|
-
return false;
|
|
367
|
-
setUndoStack((prev) => prev.slice(0, -1));
|
|
368
|
-
const currentSnapshot = { lines: [...lines], cursorRow, cursorCol };
|
|
369
|
-
setRedoStack((prev) => [...prev, currentSnapshot]);
|
|
370
|
-
return _restoreState(state);
|
|
371
|
-
}, [undoStack, lines, cursorRow, cursorCol, _restoreState]);
|
|
372
|
-
const redo = useCallback(() => {
|
|
373
|
-
const state = redoStack[redoStack.length - 1];
|
|
374
|
-
if (!state)
|
|
375
|
-
return false;
|
|
376
|
-
setRedoStack((prev) => prev.slice(0, -1));
|
|
377
|
-
const currentSnapshot = { lines: [...lines], cursorRow, cursorCol };
|
|
378
|
-
setUndoStack((prev) => [...prev, currentSnapshot]);
|
|
379
|
-
return _restoreState(state);
|
|
380
|
-
}, [redoStack, lines, cursorRow, cursorCol, _restoreState]);
|
|
381
|
-
const applyOperations = useCallback((ops) => {
|
|
382
|
-
if (ops.length === 0)
|
|
383
|
-
return;
|
|
384
|
-
setOpQueue((prev) => [...prev, ...ops]);
|
|
385
|
-
}, []);
|
|
386
|
-
useEffect(() => {
|
|
387
|
-
if (opQueue.length === 0)
|
|
388
|
-
return;
|
|
389
|
-
const expandedOps = [];
|
|
390
|
-
for (const op of opQueue) {
|
|
391
|
-
if (op.type === 'insert') {
|
|
392
|
-
let currentText = '';
|
|
393
|
-
for (const char of toCodePoints(op.payload)) {
|
|
394
|
-
if (char.codePointAt(0) === 127) {
|
|
395
|
-
// \x7f
|
|
396
|
-
if (currentText.length > 0) {
|
|
397
|
-
expandedOps.push({ type: 'insert', payload: currentText });
|
|
398
|
-
currentText = '';
|
|
399
|
-
}
|
|
400
|
-
expandedOps.push({ type: 'backspace' });
|
|
401
|
-
}
|
|
402
|
-
else {
|
|
403
|
-
currentText += char;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if (currentText.length > 0) {
|
|
407
|
-
expandedOps.push({ type: 'insert', payload: currentText });
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
expandedOps.push(op);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
if (expandedOps.length === 0) {
|
|
415
|
-
setOpQueue([]); // Clear queue even if ops were no-ops
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
pushUndo(); // Snapshot before applying batch of updates
|
|
419
|
-
const newLines = [...lines];
|
|
420
|
-
let newCursorRow = cursorRow;
|
|
421
|
-
let newCursorCol = cursorCol;
|
|
422
|
-
const currentLine = (r) => newLines[r] ?? '';
|
|
423
|
-
for (const op of expandedOps) {
|
|
424
|
-
if (op.type === 'insert') {
|
|
425
|
-
const str = stripUnsafeCharacters(op.payload.replace(/\r\n/g, '\n').replace(/\r/g, '\n'));
|
|
426
|
-
const parts = str.split('\n');
|
|
427
|
-
const lineContent = currentLine(newCursorRow);
|
|
428
|
-
const before = cpSlice(lineContent, 0, newCursorCol);
|
|
429
|
-
const after = cpSlice(lineContent, newCursorCol);
|
|
430
|
-
if (parts.length > 1) {
|
|
431
|
-
newLines[newCursorRow] = before + parts[0];
|
|
432
|
-
const remainingParts = parts.slice(1);
|
|
433
|
-
const lastPartOriginal = remainingParts.pop() ?? '';
|
|
434
|
-
newLines.splice(newCursorRow + 1, 0, ...remainingParts);
|
|
435
|
-
newLines.splice(newCursorRow + parts.length - 1, 0, lastPartOriginal + after);
|
|
436
|
-
newCursorRow = newCursorRow + parts.length - 1;
|
|
437
|
-
newCursorCol = cpLen(lastPartOriginal);
|
|
438
|
-
}
|
|
439
|
-
else {
|
|
440
|
-
newLines[newCursorRow] = before + parts[0] + after;
|
|
441
|
-
newCursorCol = cpLen(before) + cpLen(parts[0]);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
else if (op.type === 'backspace') {
|
|
445
|
-
if (newCursorCol === 0 && newCursorRow === 0)
|
|
446
|
-
continue;
|
|
447
|
-
if (newCursorCol > 0) {
|
|
448
|
-
const lineContent = currentLine(newCursorRow);
|
|
449
|
-
newLines[newCursorRow] =
|
|
450
|
-
cpSlice(lineContent, 0, newCursorCol - 1) +
|
|
451
|
-
cpSlice(lineContent, newCursorCol);
|
|
452
|
-
newCursorCol--;
|
|
453
|
-
}
|
|
454
|
-
else if (newCursorRow > 0) {
|
|
455
|
-
const prevLineContent = currentLine(newCursorRow - 1);
|
|
456
|
-
const currentLineContentVal = currentLine(newCursorRow);
|
|
457
|
-
const newCol = cpLen(prevLineContent);
|
|
458
|
-
newLines[newCursorRow - 1] = prevLineContent + currentLineContentVal;
|
|
459
|
-
newLines.splice(newCursorRow, 1);
|
|
460
|
-
newCursorRow--;
|
|
461
|
-
newCursorCol = newCol;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
setLines(newLines);
|
|
466
|
-
setCursorRow(newCursorRow);
|
|
467
|
-
setCursorCol(newCursorCol);
|
|
468
|
-
setPreferredCol(null);
|
|
469
|
-
// Clear the queue after processing
|
|
470
|
-
setOpQueue((prev) => prev.slice(opQueue.length));
|
|
471
|
-
}, [opQueue, lines, cursorRow, cursorCol, pushUndo, setPreferredCol]);
|
|
472
|
-
const insert = useCallback((ch) => {
|
|
473
|
-
dbg('insert', { ch, beforeCursor: [cursorRow, cursorCol] });
|
|
474
|
-
ch = stripUnsafeCharacters(ch);
|
|
475
|
-
// Arbitrary threshold to avoid false positives on normal key presses
|
|
476
|
-
// while still detecting virtually all reasonable length file paths.
|
|
477
|
-
const minLengthToInferAsDragDrop = 3;
|
|
478
|
-
if (ch.length >= minLengthToInferAsDragDrop) {
|
|
479
|
-
// Possible drag and drop of a file path.
|
|
480
|
-
let potentialPath = ch;
|
|
481
|
-
if (potentialPath.length > 2 &&
|
|
482
|
-
potentialPath.startsWith("'") &&
|
|
483
|
-
potentialPath.endsWith("'")) {
|
|
484
|
-
potentialPath = ch.slice(1, -1);
|
|
485
|
-
}
|
|
486
|
-
potentialPath = potentialPath.trim();
|
|
487
|
-
// Be conservative and only add an @ if the path is valid.
|
|
488
|
-
if (isValidPath(unescapePath(potentialPath))) {
|
|
489
|
-
ch = `@${potentialPath}`;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
applyOperations([{ type: 'insert', payload: ch }]);
|
|
493
|
-
}, [applyOperations, cursorRow, cursorCol, isValidPath]);
|
|
494
|
-
const newline = useCallback(() => {
|
|
495
|
-
dbg('newline', { beforeCursor: [cursorRow, cursorCol] });
|
|
496
|
-
applyOperations([{ type: 'insert', payload: '\n' }]);
|
|
497
|
-
}, [applyOperations, cursorRow, cursorCol]);
|
|
498
|
-
const backspace = useCallback(() => {
|
|
499
|
-
dbg('backspace', { beforeCursor: [cursorRow, cursorCol] });
|
|
500
|
-
if (cursorCol === 0 && cursorRow === 0)
|
|
501
|
-
return;
|
|
502
|
-
applyOperations([{ type: 'backspace' }]);
|
|
503
|
-
}, [applyOperations, cursorRow, cursorCol]);
|
|
504
|
-
const del = useCallback(() => {
|
|
505
|
-
dbg('delete', { beforeCursor: [cursorRow, cursorCol] });
|
|
506
|
-
const lineContent = currentLine(cursorRow);
|
|
507
|
-
if (cursorCol < currentLineLen(cursorRow)) {
|
|
508
|
-
pushUndo();
|
|
509
|
-
setLines((prevLines) => {
|
|
510
|
-
const newLines = [...prevLines];
|
|
511
|
-
newLines[cursorRow] =
|
|
512
|
-
cpSlice(lineContent, 0, cursorCol) +
|
|
513
|
-
cpSlice(lineContent, cursorCol + 1);
|
|
514
|
-
return newLines;
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
else if (cursorRow < lines.length - 1) {
|
|
518
|
-
pushUndo();
|
|
519
|
-
const nextLineContent = currentLine(cursorRow + 1);
|
|
520
|
-
setLines((prevLines) => {
|
|
521
|
-
const newLines = [...prevLines];
|
|
522
|
-
newLines[cursorRow] = lineContent + nextLineContent;
|
|
523
|
-
newLines.splice(cursorRow + 1, 1);
|
|
524
|
-
return newLines;
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
// cursor position does not change for del
|
|
528
|
-
setPreferredCol(null);
|
|
529
|
-
}, [
|
|
530
|
-
pushUndo,
|
|
531
|
-
cursorRow,
|
|
532
|
-
cursorCol,
|
|
533
|
-
currentLine,
|
|
534
|
-
currentLineLen,
|
|
535
|
-
lines.length,
|
|
536
|
-
setPreferredCol,
|
|
537
|
-
]);
|
|
538
|
-
const setText = useCallback((newText) => {
|
|
539
|
-
dbg('setText', { text: newText });
|
|
540
|
-
pushUndo();
|
|
541
|
-
const newContentLines = newText.replace(/\r\n?/g, '\n').split('\n');
|
|
542
|
-
setLines(newContentLines.length === 0 ? [''] : newContentLines);
|
|
543
|
-
// Set logical cursor to the end of the new text
|
|
544
|
-
const lastNewLineIndex = newContentLines.length - 1;
|
|
545
|
-
setCursorRow(lastNewLineIndex);
|
|
546
|
-
setCursorCol(cpLen(newContentLines[lastNewLineIndex] ?? ''));
|
|
547
|
-
setPreferredCol(null);
|
|
548
|
-
}, [pushUndo, setPreferredCol]);
|
|
549
|
-
const replaceRange = useCallback((startRow, startCol, endRow, endCol, replacementText) => {
|
|
550
|
-
if (startRow > endRow ||
|
|
551
|
-
(startRow === endRow && startCol > endCol) ||
|
|
552
|
-
startRow < 0 ||
|
|
553
|
-
startCol < 0 ||
|
|
554
|
-
endRow >= lines.length ||
|
|
555
|
-
(endRow < lines.length && endCol > currentLineLen(endRow))) {
|
|
556
|
-
console.error('Invalid range provided to replaceRange', {
|
|
557
|
-
startRow,
|
|
558
|
-
startCol,
|
|
559
|
-
endRow,
|
|
560
|
-
endCol,
|
|
561
|
-
linesLength: lines.length,
|
|
562
|
-
endRowLineLength: currentLineLen(endRow),
|
|
563
|
-
});
|
|
564
|
-
return false;
|
|
565
|
-
}
|
|
566
|
-
dbg('replaceRange', {
|
|
567
|
-
start: [startRow, startCol],
|
|
568
|
-
end: [endRow, endCol],
|
|
569
|
-
text: replacementText,
|
|
570
|
-
});
|
|
571
|
-
pushUndo();
|
|
572
|
-
const sCol = clamp(startCol, 0, currentLineLen(startRow));
|
|
573
|
-
const eCol = clamp(endCol, 0, currentLineLen(endRow));
|
|
574
|
-
const prefix = cpSlice(currentLine(startRow), 0, sCol);
|
|
575
|
-
const suffix = cpSlice(currentLine(endRow), eCol);
|
|
576
|
-
const normalisedReplacement = replacementText
|
|
577
|
-
.replace(/\r\n/g, '\n')
|
|
578
|
-
.replace(/\r/g, '\n');
|
|
579
|
-
const replacementParts = normalisedReplacement.split('\n');
|
|
580
|
-
setLines((prevLines) => {
|
|
581
|
-
const newLines = [...prevLines];
|
|
582
|
-
// Remove lines between startRow and endRow (exclusive of startRow, inclusive of endRow if different)
|
|
583
|
-
if (startRow < endRow) {
|
|
584
|
-
newLines.splice(startRow + 1, endRow - startRow);
|
|
585
|
-
}
|
|
586
|
-
// Construct the new content for the startRow
|
|
587
|
-
newLines[startRow] = prefix + replacementParts[0];
|
|
588
|
-
// If replacementText has multiple lines, insert them
|
|
589
|
-
if (replacementParts.length > 1) {
|
|
590
|
-
const lastReplacementPart = replacementParts.pop() ?? ''; // parts are already split by \n
|
|
591
|
-
// Insert middle parts (if any)
|
|
592
|
-
if (replacementParts.length > 1) {
|
|
593
|
-
// parts[0] is already used
|
|
594
|
-
newLines.splice(startRow + 1, 0, ...replacementParts.slice(1));
|
|
595
|
-
}
|
|
596
|
-
// The line where the last part of the replacement will go
|
|
597
|
-
const targetRowForLastPart = startRow + (replacementParts.length - 1); // -1 because parts[0] is on startRow
|
|
598
|
-
// If the last part is not the first part (multi-line replacement)
|
|
599
|
-
if (targetRowForLastPart > startRow ||
|
|
600
|
-
(replacementParts.length === 1 && lastReplacementPart !== '')) {
|
|
601
|
-
// If the target row for the last part doesn't exist (because it's a new line created by replacement)
|
|
602
|
-
// ensure it's created before trying to append suffix.
|
|
603
|
-
// This case should be handled by splice if replacementParts.length > 1
|
|
604
|
-
// For single line replacement that becomes multi-line due to parts.length > 1 logic, this is tricky.
|
|
605
|
-
// Let's assume newLines[targetRowForLastPart] exists due to previous splice or it's newLines[startRow]
|
|
606
|
-
if (newLines[targetRowForLastPart] === undefined &&
|
|
607
|
-
targetRowForLastPart === startRow + 1 &&
|
|
608
|
-
replacementParts.length === 1) {
|
|
609
|
-
// This implies a single line replacement that became two lines.
|
|
610
|
-
// e.g. "abc" replace "b" with "B\nC" -> "aB", "C", "c"
|
|
611
|
-
// Here, lastReplacementPart is "C", targetRowForLastPart is startRow + 1
|
|
612
|
-
newLines.splice(targetRowForLastPart, 0, lastReplacementPart + suffix);
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
newLines[targetRowForLastPart] =
|
|
616
|
-
(newLines[targetRowForLastPart] || '') +
|
|
617
|
-
lastReplacementPart +
|
|
618
|
-
suffix;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
else {
|
|
622
|
-
// Single line in replacementParts, but it was the only part
|
|
623
|
-
newLines[startRow] += suffix;
|
|
624
|
-
}
|
|
625
|
-
setCursorRow(targetRowForLastPart);
|
|
626
|
-
setCursorCol(cpLen(newLines[targetRowForLastPart]) - cpLen(suffix));
|
|
627
|
-
}
|
|
628
|
-
else {
|
|
629
|
-
// Single line replacement (replacementParts has only one item)
|
|
630
|
-
newLines[startRow] += suffix;
|
|
631
|
-
setCursorRow(startRow);
|
|
632
|
-
setCursorCol(cpLen(prefix) + cpLen(replacementParts[0]));
|
|
633
|
-
}
|
|
634
|
-
return newLines;
|
|
635
|
-
});
|
|
636
|
-
setPreferredCol(null);
|
|
637
|
-
return true;
|
|
638
|
-
}, [pushUndo, lines, currentLine, currentLineLen, setPreferredCol]);
|
|
639
|
-
const deleteWordLeft = useCallback(() => {
|
|
640
|
-
dbg('deleteWordLeft', { beforeCursor: [cursorRow, cursorCol] });
|
|
641
|
-
if (cursorCol === 0 && cursorRow === 0)
|
|
642
|
-
return;
|
|
643
|
-
if (cursorCol === 0) {
|
|
644
|
-
backspace();
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
pushUndo();
|
|
648
|
-
const lineContent = currentLine(cursorRow);
|
|
649
|
-
const arr = toCodePoints(lineContent);
|
|
650
|
-
let start = cursorCol;
|
|
651
|
-
let onlySpaces = true;
|
|
652
|
-
for (let i = 0; i < start; i++) {
|
|
653
|
-
if (isWordChar(arr[i])) {
|
|
654
|
-
onlySpaces = false;
|
|
655
|
-
break;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
if (onlySpaces && start > 0) {
|
|
659
|
-
start--;
|
|
660
|
-
}
|
|
661
|
-
else {
|
|
662
|
-
while (start > 0 && !isWordChar(arr[start - 1]))
|
|
663
|
-
start--;
|
|
664
|
-
while (start > 0 && isWordChar(arr[start - 1]))
|
|
665
|
-
start--;
|
|
666
|
-
}
|
|
667
|
-
setLines((prevLines) => {
|
|
668
|
-
const newLines = [...prevLines];
|
|
669
|
-
newLines[cursorRow] =
|
|
670
|
-
cpSlice(lineContent, 0, start) + cpSlice(lineContent, cursorCol);
|
|
671
|
-
return newLines;
|
|
672
|
-
});
|
|
673
|
-
setCursorCol(start);
|
|
674
|
-
setPreferredCol(null);
|
|
675
|
-
}, [pushUndo, cursorRow, cursorCol, currentLine, backspace, setPreferredCol]);
|
|
676
|
-
const deleteWordRight = useCallback(() => {
|
|
677
|
-
dbg('deleteWordRight', { beforeCursor: [cursorRow, cursorCol] });
|
|
678
|
-
const lineContent = currentLine(cursorRow);
|
|
679
|
-
const arr = toCodePoints(lineContent);
|
|
680
|
-
if (cursorCol >= arr.length && cursorRow === lines.length - 1)
|
|
681
|
-
return;
|
|
682
|
-
if (cursorCol >= arr.length) {
|
|
683
|
-
del();
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
pushUndo();
|
|
687
|
-
let end = cursorCol;
|
|
688
|
-
while (end < arr.length && !isWordChar(arr[end]))
|
|
689
|
-
end++;
|
|
690
|
-
while (end < arr.length && isWordChar(arr[end]))
|
|
691
|
-
end++;
|
|
692
|
-
setLines((prevLines) => {
|
|
693
|
-
const newLines = [...prevLines];
|
|
694
|
-
newLines[cursorRow] =
|
|
695
|
-
cpSlice(lineContent, 0, cursorCol) + cpSlice(lineContent, end);
|
|
696
|
-
return newLines;
|
|
697
|
-
});
|
|
698
|
-
setPreferredCol(null);
|
|
699
|
-
}, [
|
|
700
|
-
pushUndo,
|
|
701
|
-
cursorRow,
|
|
702
|
-
cursorCol,
|
|
703
|
-
currentLine,
|
|
704
|
-
del,
|
|
705
|
-
lines.length,
|
|
706
|
-
setPreferredCol,
|
|
707
|
-
]);
|
|
708
|
-
const killLineRight = useCallback(() => {
|
|
709
|
-
const lineContent = currentLine(cursorRow);
|
|
710
|
-
if (cursorCol < currentLineLen(cursorRow)) {
|
|
711
|
-
// Cursor is before the end of the line's content, delete text to the right
|
|
712
|
-
pushUndo();
|
|
713
|
-
setLines((prevLines) => {
|
|
714
|
-
const newLines = [...prevLines];
|
|
715
|
-
newLines[cursorRow] = cpSlice(lineContent, 0, cursorCol);
|
|
716
|
-
return newLines;
|
|
717
|
-
});
|
|
718
|
-
// Cursor position and preferredCol do not change in this case
|
|
719
|
-
}
|
|
720
|
-
else if (cursorCol === currentLineLen(cursorRow) &&
|
|
721
|
-
cursorRow < lines.length - 1) {
|
|
722
|
-
// Cursor is at the end of the line's content (or line is empty),
|
|
723
|
-
// and it's not the last line. Delete the newline.
|
|
724
|
-
// `del()` handles pushUndo and setPreferredCol.
|
|
725
|
-
del();
|
|
726
|
-
}
|
|
727
|
-
// If cursor is at the end of the line and it's the last line, do nothing.
|
|
728
|
-
}, [
|
|
729
|
-
pushUndo,
|
|
730
|
-
cursorRow,
|
|
731
|
-
cursorCol,
|
|
732
|
-
currentLine,
|
|
733
|
-
currentLineLen,
|
|
734
|
-
lines.length,
|
|
735
|
-
del,
|
|
736
|
-
]);
|
|
737
|
-
const killLineLeft = useCallback(() => {
|
|
738
|
-
const lineContent = currentLine(cursorRow);
|
|
739
|
-
// Only act if the cursor is not at the beginning of the line
|
|
740
|
-
if (cursorCol > 0) {
|
|
741
|
-
pushUndo();
|
|
742
|
-
setLines((prevLines) => {
|
|
743
|
-
const newLines = [...prevLines];
|
|
744
|
-
newLines[cursorRow] = cpSlice(lineContent, cursorCol);
|
|
745
|
-
return newLines;
|
|
746
|
-
});
|
|
747
|
-
setCursorCol(0);
|
|
748
|
-
setPreferredCol(null);
|
|
749
|
-
}
|
|
750
|
-
}, [pushUndo, cursorRow, cursorCol, currentLine, setPreferredCol]);
|
|
751
|
-
const move = useCallback((dir) => {
|
|
752
|
-
let newVisualRow = visualCursor[0];
|
|
753
|
-
let newVisualCol = visualCursor[1];
|
|
754
|
-
let newPreferredCol = preferredCol;
|
|
755
|
-
const currentVisLineLen = cpLen(visualLines[newVisualRow] ?? '');
|
|
756
|
-
switch (dir) {
|
|
757
|
-
case 'left':
|
|
758
|
-
newPreferredCol = null;
|
|
759
|
-
if (newVisualCol > 0) {
|
|
760
|
-
newVisualCol--;
|
|
761
|
-
}
|
|
762
|
-
else if (newVisualRow > 0) {
|
|
763
|
-
newVisualRow--;
|
|
764
|
-
newVisualCol = cpLen(visualLines[newVisualRow] ?? '');
|
|
765
|
-
}
|
|
766
|
-
break;
|
|
767
|
-
case 'right':
|
|
768
|
-
newPreferredCol = null;
|
|
769
|
-
if (newVisualCol < currentVisLineLen) {
|
|
770
|
-
newVisualCol++;
|
|
771
|
-
}
|
|
772
|
-
else if (newVisualRow < visualLines.length - 1) {
|
|
773
|
-
newVisualRow++;
|
|
774
|
-
newVisualCol = 0;
|
|
775
|
-
}
|
|
776
|
-
break;
|
|
777
|
-
case 'up':
|
|
778
|
-
if (newVisualRow > 0) {
|
|
779
|
-
if (newPreferredCol === null)
|
|
780
|
-
newPreferredCol = newVisualCol;
|
|
781
|
-
newVisualRow--;
|
|
782
|
-
newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow] ?? ''));
|
|
783
|
-
}
|
|
784
|
-
break;
|
|
785
|
-
case 'down':
|
|
786
|
-
if (newVisualRow < visualLines.length - 1) {
|
|
787
|
-
if (newPreferredCol === null)
|
|
788
|
-
newPreferredCol = newVisualCol;
|
|
789
|
-
newVisualRow++;
|
|
790
|
-
newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow] ?? ''));
|
|
791
|
-
}
|
|
792
|
-
break;
|
|
793
|
-
case 'home':
|
|
794
|
-
newPreferredCol = null;
|
|
795
|
-
newVisualCol = 0;
|
|
796
|
-
break;
|
|
797
|
-
case 'end':
|
|
798
|
-
newPreferredCol = null;
|
|
799
|
-
newVisualCol = currentVisLineLen;
|
|
800
|
-
break;
|
|
801
|
-
// wordLeft and wordRight might need more sophisticated visual handling
|
|
802
|
-
// For now, they operate on the logical line derived from the visual cursor
|
|
803
|
-
case 'wordLeft': {
|
|
804
|
-
newPreferredCol = null;
|
|
805
|
-
if (visualToLogicalMap.length === 0 ||
|
|
806
|
-
logicalToVisualMap.length === 0)
|
|
807
|
-
break;
|
|
808
|
-
const [logRow, logColInitial] = visualToLogicalMap[newVisualRow] ?? [
|
|
809
|
-
0, 0,
|
|
810
|
-
];
|
|
811
|
-
const currentLogCol = logColInitial + newVisualCol;
|
|
812
|
-
const lineText = lines[logRow];
|
|
813
|
-
const sliceToCursor = cpSlice(lineText, 0, currentLogCol).replace(/[\s,.;!?]+$/, '');
|
|
814
|
-
let lastIdx = 0;
|
|
815
|
-
const regex = /[\s,.;!?]+/g;
|
|
816
|
-
let m;
|
|
817
|
-
while ((m = regex.exec(sliceToCursor)) != null)
|
|
818
|
-
lastIdx = m.index;
|
|
819
|
-
const newLogicalCol = lastIdx === 0 ? 0 : cpLen(sliceToCursor.slice(0, lastIdx)) + 1;
|
|
820
|
-
// Map newLogicalCol back to visual
|
|
821
|
-
const targetLogicalMapEntries = logicalToVisualMap[logRow];
|
|
822
|
-
if (!targetLogicalMapEntries)
|
|
823
|
-
break;
|
|
824
|
-
for (let i = targetLogicalMapEntries.length - 1; i >= 0; i--) {
|
|
825
|
-
const [visRow, logStartCol] = targetLogicalMapEntries[i];
|
|
826
|
-
if (newLogicalCol >= logStartCol) {
|
|
827
|
-
newVisualRow = visRow;
|
|
828
|
-
newVisualCol = newLogicalCol - logStartCol;
|
|
829
|
-
break;
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
break;
|
|
833
|
-
}
|
|
834
|
-
case 'wordRight': {
|
|
835
|
-
newPreferredCol = null;
|
|
836
|
-
if (visualToLogicalMap.length === 0 ||
|
|
837
|
-
logicalToVisualMap.length === 0)
|
|
838
|
-
break;
|
|
839
|
-
const [logRow, logColInitial] = visualToLogicalMap[newVisualRow] ?? [
|
|
840
|
-
0, 0,
|
|
841
|
-
];
|
|
842
|
-
const currentLogCol = logColInitial + newVisualCol;
|
|
843
|
-
const lineText = lines[logRow];
|
|
844
|
-
const regex = /[\s,.;!?]+/g;
|
|
845
|
-
let moved = false;
|
|
846
|
-
let m;
|
|
847
|
-
let newLogicalCol = currentLineLen(logRow); // Default to end of logical line
|
|
848
|
-
while ((m = regex.exec(lineText)) != null) {
|
|
849
|
-
const cpIdx = cpLen(lineText.slice(0, m.index));
|
|
850
|
-
if (cpIdx > currentLogCol) {
|
|
851
|
-
newLogicalCol = cpIdx;
|
|
852
|
-
moved = true;
|
|
853
|
-
break;
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
if (!moved && currentLogCol < currentLineLen(logRow)) {
|
|
857
|
-
// If no word break found after cursor, move to end
|
|
858
|
-
newLogicalCol = currentLineLen(logRow);
|
|
859
|
-
}
|
|
860
|
-
// Map newLogicalCol back to visual
|
|
861
|
-
const targetLogicalMapEntries = logicalToVisualMap[logRow];
|
|
862
|
-
if (!targetLogicalMapEntries)
|
|
863
|
-
break;
|
|
864
|
-
for (let i = 0; i < targetLogicalMapEntries.length; i++) {
|
|
865
|
-
const [visRow, logStartCol] = targetLogicalMapEntries[i];
|
|
866
|
-
const nextLogStartCol = i + 1 < targetLogicalMapEntries.length
|
|
867
|
-
? targetLogicalMapEntries[i + 1][1]
|
|
868
|
-
: Infinity;
|
|
869
|
-
if (newLogicalCol >= logStartCol &&
|
|
870
|
-
newLogicalCol < nextLogStartCol) {
|
|
871
|
-
newVisualRow = visRow;
|
|
872
|
-
newVisualCol = newLogicalCol - logStartCol;
|
|
873
|
-
break;
|
|
874
|
-
}
|
|
875
|
-
if (newLogicalCol === logStartCol &&
|
|
876
|
-
i === targetLogicalMapEntries.length - 1 &&
|
|
877
|
-
cpLen(visualLines[visRow] ?? '') === 0) {
|
|
878
|
-
// Special case: moving to an empty visual line at the end of a logical line
|
|
879
|
-
newVisualRow = visRow;
|
|
880
|
-
newVisualCol = 0;
|
|
881
|
-
break;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
break;
|
|
885
|
-
}
|
|
886
|
-
default:
|
|
887
|
-
break;
|
|
888
|
-
}
|
|
889
|
-
setVisualCursor([newVisualRow, newVisualCol]);
|
|
890
|
-
setPreferredCol(newPreferredCol);
|
|
891
|
-
// Update logical cursor based on new visual cursor
|
|
892
|
-
if (visualToLogicalMap[newVisualRow]) {
|
|
893
|
-
const [logRow, logStartCol] = visualToLogicalMap[newVisualRow];
|
|
894
|
-
setCursorRow(logRow);
|
|
895
|
-
setCursorCol(clamp(logStartCol + newVisualCol, 0, currentLineLen(logRow)));
|
|
896
|
-
}
|
|
897
|
-
dbg('move', {
|
|
898
|
-
dir,
|
|
899
|
-
visualBefore: visualCursor,
|
|
900
|
-
visualAfter: [newVisualRow, newVisualCol],
|
|
901
|
-
logicalAfter: [cursorRow, cursorCol],
|
|
902
|
-
});
|
|
903
|
-
}, [
|
|
904
|
-
visualCursor,
|
|
905
|
-
visualLines,
|
|
906
|
-
preferredCol,
|
|
907
|
-
lines,
|
|
908
|
-
currentLineLen,
|
|
909
|
-
visualToLogicalMap,
|
|
910
|
-
logicalToVisualMap,
|
|
911
|
-
cursorCol,
|
|
912
|
-
cursorRow,
|
|
913
|
-
]);
|
|
914
|
-
const openInExternalEditor = useCallback(async (opts = {}) => {
|
|
915
|
-
const editor = opts.editor ??
|
|
916
|
-
process.env['VISUAL'] ??
|
|
917
|
-
process.env['EDITOR'] ??
|
|
918
|
-
(process.platform === 'win32' ? 'notepad' : 'vi');
|
|
919
|
-
const tmpDir = fs.mkdtempSync(pathMod.join(os.tmpdir(), 'gemini-edit-'));
|
|
920
|
-
const filePath = pathMod.join(tmpDir, 'buffer.txt');
|
|
921
|
-
fs.writeFileSync(filePath, text, 'utf8');
|
|
922
|
-
pushUndo(); // Snapshot before external edit
|
|
923
|
-
const wasRaw = stdin?.isRaw ?? false;
|
|
924
|
-
try {
|
|
925
|
-
setRawMode?.(false);
|
|
926
|
-
const { status, error } = spawnSync(editor, [filePath], {
|
|
927
|
-
stdio: 'inherit',
|
|
928
|
-
});
|
|
929
|
-
if (error)
|
|
930
|
-
throw error;
|
|
931
|
-
if (typeof status === 'number' && status !== 0)
|
|
932
|
-
throw new Error(`External editor exited with status ${status}`);
|
|
933
|
-
let newText = fs.readFileSync(filePath, 'utf8');
|
|
934
|
-
newText = newText.replace(/\r\n?/g, '\n');
|
|
935
|
-
setText(newText);
|
|
936
|
-
}
|
|
937
|
-
catch (err) {
|
|
938
|
-
console.error('[useTextBuffer] external editor error', err);
|
|
939
|
-
// TODO(jacobr): potentially revert or handle error state.
|
|
940
|
-
}
|
|
941
|
-
finally {
|
|
942
|
-
if (wasRaw)
|
|
943
|
-
setRawMode?.(true);
|
|
944
|
-
try {
|
|
945
|
-
fs.unlinkSync(filePath);
|
|
946
|
-
}
|
|
947
|
-
catch {
|
|
948
|
-
/* ignore */
|
|
949
|
-
}
|
|
950
|
-
try {
|
|
951
|
-
fs.rmdirSync(tmpDir);
|
|
952
|
-
}
|
|
953
|
-
catch {
|
|
954
|
-
/* ignore */
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
}, [text, pushUndo, stdin, setRawMode, setText]);
|
|
958
|
-
const handleInput = useCallback((key) => {
|
|
959
|
-
const { sequence: input } = key;
|
|
960
|
-
dbg('handleInput', {
|
|
961
|
-
key,
|
|
962
|
-
cursor: [cursorRow, cursorCol],
|
|
963
|
-
visualCursor,
|
|
964
|
-
});
|
|
965
|
-
const beforeText = text;
|
|
966
|
-
const beforeLogicalCursor = [cursorRow, cursorCol];
|
|
967
|
-
const beforeVisualCursor = [...visualCursor];
|
|
968
|
-
if (key.name === 'escape')
|
|
969
|
-
return false;
|
|
970
|
-
if (key.name === 'return' ||
|
|
971
|
-
input === '\r' ||
|
|
972
|
-
input === '\n' ||
|
|
973
|
-
input === '\\\r' // VSCode terminal represents shift + enter this way
|
|
974
|
-
)
|
|
975
|
-
newline();
|
|
976
|
-
else if (key.name === 'left' && !key.meta && !key.ctrl)
|
|
977
|
-
move('left');
|
|
978
|
-
else if (key.ctrl && key.name === 'b')
|
|
979
|
-
move('left');
|
|
980
|
-
else if (key.name === 'right' && !key.meta && !key.ctrl)
|
|
981
|
-
move('right');
|
|
982
|
-
else if (key.ctrl && key.name === 'f')
|
|
983
|
-
move('right');
|
|
984
|
-
else if (key.name === 'up')
|
|
985
|
-
move('up');
|
|
986
|
-
else if (key.name === 'down')
|
|
987
|
-
move('down');
|
|
988
|
-
else if ((key.ctrl || key.meta) && key.name === 'left')
|
|
989
|
-
move('wordLeft');
|
|
990
|
-
else if (key.meta && key.name === 'b')
|
|
991
|
-
move('wordLeft');
|
|
992
|
-
else if ((key.ctrl || key.meta) && key.name === 'right')
|
|
993
|
-
move('wordRight');
|
|
994
|
-
else if (key.meta && key.name === 'f')
|
|
995
|
-
move('wordRight');
|
|
996
|
-
else if (key.name === 'home')
|
|
997
|
-
move('home');
|
|
998
|
-
else if (key.ctrl && key.name === 'a')
|
|
999
|
-
move('home');
|
|
1000
|
-
else if (key.name === 'end')
|
|
1001
|
-
move('end');
|
|
1002
|
-
else if (key.ctrl && key.name === 'e')
|
|
1003
|
-
move('end');
|
|
1004
|
-
else if (key.ctrl && key.name === 'w')
|
|
1005
|
-
deleteWordLeft();
|
|
1006
|
-
else if ((key.meta || key.ctrl) &&
|
|
1007
|
-
(key.name === 'backspace' || input === '\x7f'))
|
|
1008
|
-
deleteWordLeft();
|
|
1009
|
-
else if ((key.meta || key.ctrl) && key.name === 'delete')
|
|
1010
|
-
deleteWordRight();
|
|
1011
|
-
else if (key.name === 'backspace' ||
|
|
1012
|
-
input === '\x7f' ||
|
|
1013
|
-
(key.ctrl && key.name === 'h'))
|
|
1014
|
-
backspace();
|
|
1015
|
-
else if (key.name === 'delete' || (key.ctrl && key.name === 'd'))
|
|
1016
|
-
del();
|
|
1017
|
-
else if (input && !key.ctrl && !key.meta) {
|
|
1018
|
-
insert(input);
|
|
1019
|
-
}
|
|
1020
|
-
const textChanged = text !== beforeText;
|
|
1021
|
-
// After operations, visualCursor might not be immediately updated if the change
|
|
1022
|
-
// was to `lines`, `cursorRow`, or `cursorCol` which then triggers the useEffect.
|
|
1023
|
-
// So, for return value, we check logical cursor change.
|
|
1024
|
-
const cursorChanged = cursorRow !== beforeLogicalCursor[0] ||
|
|
1025
|
-
cursorCol !== beforeLogicalCursor[1] ||
|
|
1026
|
-
visualCursor[0] !== beforeVisualCursor[0] ||
|
|
1027
|
-
visualCursor[1] !== beforeVisualCursor[1];
|
|
1028
|
-
dbg('handleInput:after', {
|
|
1029
|
-
cursor: [cursorRow, cursorCol],
|
|
1030
|
-
visualCursor,
|
|
1031
|
-
text,
|
|
1032
|
-
});
|
|
1033
|
-
return textChanged || cursorChanged;
|
|
1034
|
-
}, [
|
|
1035
|
-
text,
|
|
1036
|
-
cursorRow,
|
|
1037
|
-
cursorCol,
|
|
1038
|
-
visualCursor,
|
|
1039
|
-
newline,
|
|
1040
|
-
move,
|
|
1041
|
-
deleteWordLeft,
|
|
1042
|
-
deleteWordRight,
|
|
1043
|
-
backspace,
|
|
1044
|
-
del,
|
|
1045
|
-
insert,
|
|
1046
|
-
]);
|
|
1047
|
-
const renderedVisualLines = useMemo(() => visualLines.slice(visualScrollRow, visualScrollRow + viewport.height), [visualLines, visualScrollRow, viewport.height]);
|
|
1048
|
-
const replaceRangeByOffset = useCallback((startOffset, endOffset, replacementText) => {
|
|
1049
|
-
dbg('replaceRangeByOffset', { startOffset, endOffset, replacementText });
|
|
1050
|
-
const [startRow, startCol] = offsetToLogicalPos(text, startOffset);
|
|
1051
|
-
const [endRow, endCol] = offsetToLogicalPos(text, endOffset);
|
|
1052
|
-
return replaceRange(startRow, startCol, endRow, endCol, replacementText);
|
|
1053
|
-
}, [text, replaceRange]);
|
|
1054
|
-
const moveToOffset = useCallback((offset) => {
|
|
1055
|
-
const [newRow, newCol] = offsetToLogicalPos(text, offset);
|
|
1056
|
-
setCursorRow(newRow);
|
|
1057
|
-
setCursorCol(newCol);
|
|
1058
|
-
setPreferredCol(null);
|
|
1059
|
-
dbg('moveToOffset', { offset, newCursor: [newRow, newCol] });
|
|
1060
|
-
}, [text, setPreferredCol]);
|
|
1061
|
-
const returnValue = {
|
|
1062
|
-
lines,
|
|
1063
|
-
text,
|
|
1064
|
-
cursor: [cursorRow, cursorCol],
|
|
1065
|
-
preferredCol,
|
|
1066
|
-
selectionAnchor,
|
|
1067
|
-
allVisualLines: visualLines,
|
|
1068
|
-
viewportVisualLines: renderedVisualLines,
|
|
1069
|
-
visualCursor,
|
|
1070
|
-
visualScrollRow,
|
|
1071
|
-
setText,
|
|
1072
|
-
insert,
|
|
1073
|
-
newline,
|
|
1074
|
-
backspace,
|
|
1075
|
-
del,
|
|
1076
|
-
move,
|
|
1077
|
-
undo,
|
|
1078
|
-
redo,
|
|
1079
|
-
replaceRange,
|
|
1080
|
-
replaceRangeByOffset,
|
|
1081
|
-
moveToOffset, // Added here
|
|
1082
|
-
deleteWordLeft,
|
|
1083
|
-
deleteWordRight,
|
|
1084
|
-
killLineRight,
|
|
1085
|
-
killLineLeft,
|
|
1086
|
-
handleInput,
|
|
1087
|
-
openInExternalEditor,
|
|
1088
|
-
applyOperations,
|
|
1089
|
-
copy: useCallback(() => {
|
|
1090
|
-
if (!selectionAnchor)
|
|
1091
|
-
return null;
|
|
1092
|
-
const [ar, ac] = selectionAnchor;
|
|
1093
|
-
const [br, bc] = [cursorRow, cursorCol];
|
|
1094
|
-
if (ar === br && ac === bc)
|
|
1095
|
-
return null;
|
|
1096
|
-
const topBefore = ar < br || (ar === br && ac < bc);
|
|
1097
|
-
const [sr, sc, er, ec] = topBefore ? [ar, ac, br, bc] : [br, bc, ar, ac];
|
|
1098
|
-
let selectedTextVal;
|
|
1099
|
-
if (sr === er) {
|
|
1100
|
-
selectedTextVal = cpSlice(currentLine(sr), sc, ec);
|
|
1101
|
-
}
|
|
1102
|
-
else {
|
|
1103
|
-
const parts = [cpSlice(currentLine(sr), sc)];
|
|
1104
|
-
for (let r = sr + 1; r < er; r++)
|
|
1105
|
-
parts.push(currentLine(r));
|
|
1106
|
-
parts.push(cpSlice(currentLine(er), 0, ec));
|
|
1107
|
-
selectedTextVal = parts.join('\n');
|
|
1108
|
-
}
|
|
1109
|
-
setClipboard(selectedTextVal);
|
|
1110
|
-
return selectedTextVal;
|
|
1111
|
-
}, [selectionAnchor, cursorRow, cursorCol, currentLine, setClipboard]),
|
|
1112
|
-
paste: useCallback(() => {
|
|
1113
|
-
if (clipboard === null)
|
|
1114
|
-
return false;
|
|
1115
|
-
applyOperations([{ type: 'insert', payload: clipboard }]);
|
|
1116
|
-
return true;
|
|
1117
|
-
}, [clipboard, applyOperations]),
|
|
1118
|
-
startSelection: useCallback(() => setSelectionAnchor([cursorRow, cursorCol]), [cursorRow, cursorCol, setSelectionAnchor]),
|
|
1119
|
-
};
|
|
1120
|
-
return returnValue;
|
|
1121
|
-
}
|
|
1122
|
-
//# sourceMappingURL=text-buffer.js.map
|