@google/gemini-cli 0.5.0-preview.1 → 0.7.0-nightly.20250912.68035591
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/LICENSE +2 -2
- package/README.md +12 -2
- package/dist/google-gemini-cli-0.6.0-nightly.tgz +0 -0
- package/dist/package.json +2 -2
- package/dist/src/commands/extensions/install.d.ts +1 -0
- package/dist/src/commands/extensions/install.js +7 -0
- package/dist/src/commands/extensions/install.js.map +1 -1
- package/dist/src/config/config.d.ts +1 -0
- package/dist/src/config/config.js +8 -0
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/extension.d.ts +12 -0
- package/dist/src/config/extension.js +90 -6
- package/dist/src/config/extension.js.map +1 -1
- package/dist/src/config/keyBindings.d.ts +2 -1
- package/dist/src/config/keyBindings.js +2 -0
- package/dist/src/config/keyBindings.js.map +1 -1
- package/dist/src/config/settings.js +2 -0
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +58 -1
- package/dist/src/config/settingsSchema.js +55 -1
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/config/trustedFolders.js +2 -2
- package/dist/src/config/trustedFolders.js.map +1 -1
- package/dist/src/config/trustedFolders.test.js +12 -18
- package/dist/src/config/trustedFolders.test.js.map +1 -1
- package/dist/src/core/initializer.js +6 -1
- package/dist/src/core/initializer.js.map +1 -1
- package/dist/src/gemini.js +1 -2
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +1 -0
- 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/generated/git-commit.js.map +1 -1
- package/dist/src/nonInteractiveCli.js +23 -9
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/services/prompt-processors/shellProcessor.js +8 -1
- package/dist/src/services/prompt-processors/shellProcessor.js.map +1 -1
- package/dist/src/ui/AppContainer.js +50 -21
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/IdeIntegrationNudge.js +2 -1
- package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
- package/dist/src/ui/auth/AuthDialog.js +2 -2
- package/dist/src/ui/auth/AuthDialog.js.map +1 -1
- package/dist/src/ui/auth/AuthInProgress.js +2 -2
- package/dist/src/ui/auth/AuthInProgress.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.js +2 -2
- package/dist/src/ui/commands/chatCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.js +79 -15
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
- package/dist/src/ui/commands/ideCommand.js +2 -2
- package/dist/src/ui/commands/ideCommand.js.map +1 -1
- package/dist/src/ui/components/AboutBox.js +2 -2
- package/dist/src/ui/components/AboutBox.js.map +1 -1
- package/dist/src/ui/components/AnsiOutput.d.ts +13 -0
- package/dist/src/ui/components/AnsiOutput.js +12 -0
- package/dist/src/ui/components/AnsiOutput.js.map +1 -0
- package/dist/src/ui/components/AnsiOutput.test.d.ts +6 -0
- package/dist/src/ui/components/AnsiOutput.test.js +97 -0
- package/dist/src/ui/components/AnsiOutput.test.js.map +1 -0
- package/dist/src/ui/components/AutoAcceptIndicator.js +4 -4
- package/dist/src/ui/components/AutoAcceptIndicator.js.map +1 -1
- package/dist/src/ui/components/Composer.js +5 -5
- package/dist/src/ui/components/Composer.js.map +1 -1
- package/dist/src/ui/components/ConfigInitDisplay.js +2 -1
- package/dist/src/ui/components/ConfigInitDisplay.js.map +1 -1
- package/dist/src/ui/components/ConsoleSummaryDisplay.js +2 -2
- package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
- package/dist/src/ui/components/ContextSummaryDisplay.js +3 -3
- package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
- package/dist/src/ui/components/ContextUsageDisplay.js +2 -2
- package/dist/src/ui/components/ContextUsageDisplay.js.map +1 -1
- package/dist/src/ui/components/DebugProfiler.js +2 -2
- package/dist/src/ui/components/DebugProfiler.js.map +1 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.js +7 -7
- package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
- package/dist/src/ui/components/DialogManager.js +8 -4
- package/dist/src/ui/components/DialogManager.js.map +1 -1
- package/dist/src/ui/components/EditorSettingsDialog.js +5 -5
- package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
- package/dist/src/ui/components/FolderTrustDialog.js +4 -3
- package/dist/src/ui/components/FolderTrustDialog.js.map +1 -1
- package/dist/src/ui/components/FolderTrustDialog.test.js +6 -1
- package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/Footer.js +1 -1
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/GeminiRespondingSpinner.js +3 -2
- package/dist/src/ui/components/GeminiRespondingSpinner.js.map +1 -1
- package/dist/src/ui/components/Header.js +2 -2
- package/dist/src/ui/components/Header.js.map +1 -1
- package/dist/src/ui/components/Help.js +5 -5
- package/dist/src/ui/components/Help.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.d.ts +2 -0
- 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.d.ts +3 -0
- package/dist/src/ui/components/InputPrompt.js +21 -4
- package/dist/src/ui/components/InputPrompt.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/LoopDetectionConfirmation.d.ts +13 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.js +35 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.test.d.ts +6 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js +25 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +1 -0
- package/dist/src/ui/components/MainContent.js +1 -1
- package/dist/src/ui/components/MainContent.js.map +1 -1
- package/dist/src/ui/components/MemoryUsageDisplay.js +6 -4
- package/dist/src/ui/components/MemoryUsageDisplay.js.map +1 -1
- package/dist/src/ui/components/ModelStatsDisplay.js +7 -7
- package/dist/src/ui/components/ModelStatsDisplay.js.map +1 -1
- package/dist/src/ui/components/Notifications.js +2 -2
- package/dist/src/ui/components/Notifications.js.map +1 -1
- package/dist/src/ui/components/PrepareLabel.js +2 -2
- package/dist/src/ui/components/PrepareLabel.js.map +1 -1
- package/dist/src/ui/components/ProQuotaDialog.js +2 -2
- package/dist/src/ui/components/ProQuotaDialog.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.js +7 -7
- package/dist/src/ui/components/SettingsDialog.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.js +2 -2
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
- package/dist/src/ui/components/ShellInputPrompt.d.ts +11 -0
- package/dist/src/ui/components/ShellInputPrompt.js +36 -0
- package/dist/src/ui/components/ShellInputPrompt.js.map +1 -0
- package/dist/src/ui/components/ShellModeIndicator.js +2 -2
- package/dist/src/ui/components/ShellModeIndicator.js.map +1 -1
- package/dist/src/ui/components/ShowMoreLines.js +2 -2
- package/dist/src/ui/components/ShowMoreLines.js.map +1 -1
- package/dist/src/ui/components/StatsDisplay.js +6 -6
- package/dist/src/ui/components/StatsDisplay.js.map +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.js +8 -8
- package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
- package/dist/src/ui/components/ThemeDialog.js +4 -4
- package/dist/src/ui/components/ThemeDialog.js.map +1 -1
- package/dist/src/ui/components/Tips.js +2 -2
- package/dist/src/ui/components/Tips.js.map +1 -1
- package/dist/src/ui/components/ToolStatsDisplay.js +4 -4
- package/dist/src/ui/components/ToolStatsDisplay.js.map +1 -1
- package/dist/src/ui/components/UpdateNotification.js +2 -2
- package/dist/src/ui/components/UpdateNotification.js.map +1 -1
- package/dist/src/ui/components/WorkspaceMigrationDialog.js +4 -4
- package/dist/src/ui/components/WorkspaceMigrationDialog.js.map +1 -1
- package/dist/src/ui/components/messages/CompressionMessage.d.ts +1 -2
- package/dist/src/ui/components/messages/CompressionMessage.js +37 -8
- package/dist/src/ui/components/messages/CompressionMessage.js.map +1 -1
- package/dist/src/ui/components/messages/CompressionMessage.test.d.ts +6 -0
- package/dist/src/ui/components/messages/CompressionMessage.test.js +160 -0
- package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -0
- package/dist/src/ui/components/messages/DiffRenderer.d.ts +2 -1
- package/dist/src/ui/components/messages/DiffRenderer.js +14 -22
- package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
- package/dist/src/ui/components/messages/ErrorMessage.js +2 -2
- package/dist/src/ui/components/messages/ErrorMessage.js.map +1 -1
- package/dist/src/ui/components/messages/GeminiMessage.js +2 -2
- package/dist/src/ui/components/messages/GeminiMessage.js.map +1 -1
- package/dist/src/ui/components/messages/InfoMessage.js +2 -2
- package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +31 -19
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +3 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.js +10 -6
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolMessage.d.ts +4 -0
- package/dist/src/ui/components/messages/ToolMessage.js +17 -10
- package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolMessage.test.js +33 -1
- package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -1
- package/dist/src/ui/components/messages/UserMessage.js +3 -3
- package/dist/src/ui/components/messages/UserMessage.js.map +1 -1
- package/dist/src/ui/components/messages/UserShellMessage.js +2 -2
- package/dist/src/ui/components/messages/UserShellMessage.js.map +1 -1
- package/dist/src/ui/components/shared/MaxSizedBox.js +2 -2
- package/dist/src/ui/components/shared/MaxSizedBox.js.map +1 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.js +12 -12
- package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.d.ts +19 -2
- package/dist/src/ui/components/shared/text-buffer.js +176 -132
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/contexts/UIStateContext.d.ts +4 -1
- package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
- package/dist/src/ui/hooks/keyToAnsi.d.ts +15 -0
- package/dist/src/ui/hooks/keyToAnsi.js +67 -0
- package/dist/src/ui/hooks/keyToAnsi.js.map +1 -0
- package/dist/src/ui/hooks/shellCommandProcessor.d.ts +2 -1
- package/dist/src/ui/hooks/shellCommandProcessor.js +58 -15
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.test.js +196 -17
- package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.js +2 -2
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.d.ts +7 -1
- package/dist/src/ui/hooks/useGeminiStream.js +43 -9
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useIdeTrustListener.js +2 -2
- package/dist/src/ui/hooks/useIdeTrustListener.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js +0 -2
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.d.ts +3 -2
- package/dist/src/ui/hooks/useReactToolScheduler.js +21 -17
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +5 -4
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/keyMatchers.test.js +6 -0
- package/dist/src/ui/keyMatchers.test.js.map +1 -1
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.js +5 -5
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.js.map +1 -1
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js +2 -2
- package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js.map +1 -1
- package/dist/src/ui/privacy/GeminiPrivacyNotice.js +2 -2
- package/dist/src/ui/privacy/GeminiPrivacyNotice.js.map +1 -1
- package/dist/src/ui/themes/theme.js +17 -17
- package/dist/src/ui/themes/theme.js.map +1 -1
- package/dist/src/ui/types.d.ts +6 -0
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/ui/utils/CodeColorizer.js +3 -2
- package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
- package/dist/src/ui/utils/InlineMarkdownRenderer.js +7 -7
- package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.js +10 -10
- package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
- package/dist/src/ui/utils/TableRenderer.js +4 -4
- package/dist/src/ui/utils/TableRenderer.js.map +1 -1
- package/dist/src/ui/utils/displayUtils.js +4 -4
- package/dist/src/ui/utils/displayUtils.js.map +1 -1
- package/dist/src/ui/utils/textUtils.d.ts +9 -0
- package/dist/src/ui/utils/textUtils.js +52 -3
- package/dist/src/ui/utils/textUtils.js.map +1 -1
- package/dist/src/utils/errors.d.ts +21 -0
- package/dist/src/utils/errors.js +93 -0
- package/dist/src/utils/errors.js.map +1 -1
- package/dist/src/utils/errors.test.d.ts +6 -0
- package/dist/src/utils/errors.test.js +303 -0
- package/dist/src/utils/errors.test.js.map +1 -0
- package/dist/src/utils/sandbox.js +2 -0
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/utils/settingsUtils.test.js +37 -2
- package/dist/src/utils/settingsUtils.test.js.map +1 -1
- package/dist/src/zed-integration/zedIntegration.js +10 -7
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/google-gemini-cli-0.5.0-preview.tgz +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState, useRef } from 'react';
|
|
3
3
|
import { Text, Box } from 'ink';
|
|
4
|
-
import {
|
|
4
|
+
import { theme } from '../../semantic-colors.js';
|
|
5
5
|
import { useKeypress } from '../../hooks/useKeypress.js';
|
|
6
6
|
/**
|
|
7
7
|
* A custom component that displays a list of items with radio buttons,
|
|
@@ -90,27 +90,27 @@ export function RadioButtonSelect({ items, initialIndex = 0, onSelect, onHighlig
|
|
|
90
90
|
}
|
|
91
91
|
}, { isActive: !!(isFocused && items.length > 0) });
|
|
92
92
|
const visibleItems = items.slice(scrollOffset, scrollOffset + maxItemsToShow);
|
|
93
|
-
return (_jsxs(Box, { flexDirection: "column", children: [showScrollArrows && (_jsx(Text, { color: scrollOffset > 0 ?
|
|
93
|
+
return (_jsxs(Box, { flexDirection: "column", children: [showScrollArrows && (_jsx(Text, { color: scrollOffset > 0 ? theme.text.primary : theme.text.secondary, children: "\u25B2" })), visibleItems.map((item, index) => {
|
|
94
94
|
const itemIndex = scrollOffset + index;
|
|
95
95
|
const isSelected = activeIndex === itemIndex;
|
|
96
|
-
let textColor =
|
|
97
|
-
let numberColor =
|
|
96
|
+
let textColor = theme.text.primary;
|
|
97
|
+
let numberColor = theme.text.primary;
|
|
98
98
|
if (isSelected) {
|
|
99
|
-
textColor =
|
|
100
|
-
numberColor =
|
|
99
|
+
textColor = theme.status.success;
|
|
100
|
+
numberColor = theme.status.success;
|
|
101
101
|
}
|
|
102
102
|
else if (item.disabled) {
|
|
103
|
-
textColor =
|
|
104
|
-
numberColor =
|
|
103
|
+
textColor = theme.text.secondary;
|
|
104
|
+
numberColor = theme.text.secondary;
|
|
105
105
|
}
|
|
106
106
|
if (!showNumbers) {
|
|
107
|
-
numberColor =
|
|
107
|
+
numberColor = theme.text.secondary;
|
|
108
108
|
}
|
|
109
109
|
const numberColumnWidth = String(items.length).length;
|
|
110
110
|
const itemNumberText = `${String(itemIndex + 1).padStart(numberColumnWidth)}.`;
|
|
111
|
-
return (_jsxs(Box, { alignItems: "center", children: [_jsx(Box, { minWidth: 2, flexShrink: 0, children: _jsx(Text, { color: isSelected ?
|
|
111
|
+
return (_jsxs(Box, { alignItems: "center", children: [_jsx(Box, { minWidth: 2, flexShrink: 0, children: _jsx(Text, { color: isSelected ? theme.status.success : theme.text.primary, "aria-hidden": true, children: isSelected ? '●' : ' ' }) }), _jsx(Box, { marginRight: 1, flexShrink: 0, minWidth: itemNumberText.length, "aria-state": { checked: isSelected }, children: _jsx(Text, { color: numberColor, children: itemNumberText }) }), item.themeNameDisplay && item.themeTypeDisplay ? (_jsxs(Text, { color: textColor, wrap: "truncate", children: [item.themeNameDisplay, ' ', _jsx(Text, { color: theme.text.secondary, children: item.themeTypeDisplay })] })) : (_jsx(Text, { color: textColor, wrap: "truncate", children: item.label }))] }, item.label));
|
|
112
112
|
}), showScrollArrows && (_jsx(Text, { color: scrollOffset + maxItemsToShow < items.length
|
|
113
|
-
?
|
|
114
|
-
:
|
|
113
|
+
? theme.text.primary
|
|
114
|
+
: theme.text.secondary, children: "\u25BC" }))] }));
|
|
115
115
|
}
|
|
116
116
|
//# sourceMappingURL=RadioButtonSelect.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioButtonSelect.js","sourceRoot":"","sources":["../../../../../src/ui/components/shared/RadioButtonSelect.tsx"],"names":[],"mappings":";AAOA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"RadioButtonSelect.js","sourceRoot":"","sources":["../../../../../src/ui/components/shared/RadioButtonSelect.tsx"],"names":[],"mappings":"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"}
|
|
@@ -57,6 +57,11 @@ export declare function offsetToLogicalPos(text: string, offset: number): [numbe
|
|
|
57
57
|
* Inverse operation of offsetToLogicalPos
|
|
58
58
|
*/
|
|
59
59
|
export declare function logicalPosToOffset(lines: string[], row: number, col: number): number;
|
|
60
|
+
export interface VisualLayout {
|
|
61
|
+
visualLines: string[];
|
|
62
|
+
logicalToVisualMap: Array<Array<[number, number]>>;
|
|
63
|
+
visualToLogicalMap: Array<[number, number]>;
|
|
64
|
+
}
|
|
60
65
|
export interface TextBufferState {
|
|
61
66
|
lines: string[];
|
|
62
67
|
cursorRow: number;
|
|
@@ -67,6 +72,8 @@ export interface TextBufferState {
|
|
|
67
72
|
clipboard: string | null;
|
|
68
73
|
selectionAnchor: [number, number] | null;
|
|
69
74
|
viewportWidth: number;
|
|
75
|
+
viewportHeight: number;
|
|
76
|
+
visualLayout: VisualLayout;
|
|
70
77
|
}
|
|
71
78
|
export declare const pushUndo: (currentState: TextBufferState) => TextBufferState;
|
|
72
79
|
export type TextBufferAction = {
|
|
@@ -83,6 +90,13 @@ export type TextBufferAction = {
|
|
|
83
90
|
payload: {
|
|
84
91
|
dir: Direction;
|
|
85
92
|
};
|
|
93
|
+
} | {
|
|
94
|
+
type: 'set_cursor';
|
|
95
|
+
payload: {
|
|
96
|
+
cursorRow: number;
|
|
97
|
+
cursorCol: number;
|
|
98
|
+
preferredCol: number | null;
|
|
99
|
+
};
|
|
86
100
|
} | {
|
|
87
101
|
type: 'delete';
|
|
88
102
|
} | {
|
|
@@ -114,8 +128,11 @@ export type TextBufferAction = {
|
|
|
114
128
|
} | {
|
|
115
129
|
type: 'create_undo_snapshot';
|
|
116
130
|
} | {
|
|
117
|
-
type: '
|
|
118
|
-
payload:
|
|
131
|
+
type: 'set_viewport';
|
|
132
|
+
payload: {
|
|
133
|
+
width: number;
|
|
134
|
+
height: number;
|
|
135
|
+
};
|
|
119
136
|
} | {
|
|
120
137
|
type: 'vim_delete_word_forward';
|
|
121
138
|
payload: {
|
|
@@ -8,9 +8,8 @@ import fs from 'node:fs';
|
|
|
8
8
|
import os from 'node:os';
|
|
9
9
|
import pathMod from 'node:path';
|
|
10
10
|
import { useState, useCallback, useEffect, useMemo, useReducer } from 'react';
|
|
11
|
-
import stringWidth from 'string-width';
|
|
12
11
|
import { unescapePath } from '@google/gemini-cli-core';
|
|
13
|
-
import { toCodePoints, cpLen, cpSlice, stripUnsafeCharacters, } from '../../utils/textUtils.js';
|
|
12
|
+
import { toCodePoints, cpLen, cpSlice, stripUnsafeCharacters, getCachedStringWidth, } from '../../utils/textUtils.js';
|
|
14
13
|
import { handleVimAction } from './vim-buffer-actions.js';
|
|
15
14
|
// Simple helper for word‑wise ops.
|
|
16
15
|
function isWordChar(ch) {
|
|
@@ -455,12 +454,12 @@ export function logicalPosToOffset(lines, row, col) {
|
|
|
455
454
|
}
|
|
456
455
|
return offset;
|
|
457
456
|
}
|
|
458
|
-
//
|
|
459
|
-
|
|
457
|
+
// Calculates the visual wrapping of lines and the mapping between logical and visual coordinates.
|
|
458
|
+
// This is an expensive operation and should be memoized.
|
|
459
|
+
function calculateLayout(logicalLines, viewportWidth) {
|
|
460
460
|
const visualLines = [];
|
|
461
461
|
const logicalToVisualMap = [];
|
|
462
462
|
const visualToLogicalMap = [];
|
|
463
|
-
let currentVisualCursor = [0, 0];
|
|
464
463
|
logicalLines.forEach((logLine, logIndex) => {
|
|
465
464
|
logicalToVisualMap[logIndex] = [];
|
|
466
465
|
if (logLine.length === 0) {
|
|
@@ -468,9 +467,6 @@ function calculateVisualLayout(logicalLines, logicalCursor, viewportWidth) {
|
|
|
468
467
|
logicalToVisualMap[logIndex].push([visualLines.length, 0]);
|
|
469
468
|
visualToLogicalMap.push([logIndex, 0]);
|
|
470
469
|
visualLines.push('');
|
|
471
|
-
if (logIndex === logicalCursor[0] && logicalCursor[1] === 0) {
|
|
472
|
-
currentVisualCursor = [visualLines.length - 1, 0];
|
|
473
|
-
}
|
|
474
470
|
}
|
|
475
471
|
else {
|
|
476
472
|
// Non-empty logical line
|
|
@@ -485,7 +481,7 @@ function calculateVisualLayout(logicalLines, logicalCursor, viewportWidth) {
|
|
|
485
481
|
// Iterate through code points to build the current visual line (chunk)
|
|
486
482
|
for (let i = currentPosInLogLine; i < codePointsInLogLine.length; i++) {
|
|
487
483
|
const char = codePointsInLogLine[i];
|
|
488
|
-
const charVisualWidth =
|
|
484
|
+
const charVisualWidth = getCachedStringWidth(char);
|
|
489
485
|
if (currentChunkVisualWidth + charVisualWidth > viewportWidth) {
|
|
490
486
|
// Character would exceed viewport width
|
|
491
487
|
if (lastWordBreakPoint !== -1 &&
|
|
@@ -551,27 +547,6 @@ function calculateVisualLayout(logicalLines, logicalCursor, viewportWidth) {
|
|
|
551
547
|
]);
|
|
552
548
|
visualToLogicalMap.push([logIndex, currentPosInLogLine]);
|
|
553
549
|
visualLines.push(currentChunk);
|
|
554
|
-
// Cursor mapping logic
|
|
555
|
-
// Note: currentPosInLogLine here is the start of the currentChunk within the logical line.
|
|
556
|
-
if (logIndex === logicalCursor[0]) {
|
|
557
|
-
const cursorLogCol = logicalCursor[1]; // This is a code point index
|
|
558
|
-
if (cursorLogCol >= currentPosInLogLine &&
|
|
559
|
-
cursorLogCol < currentPosInLogLine + numCodePointsInChunk // Cursor is within this chunk
|
|
560
|
-
) {
|
|
561
|
-
currentVisualCursor = [
|
|
562
|
-
visualLines.length - 1,
|
|
563
|
-
cursorLogCol - currentPosInLogLine, // Visual col is also code point index within visual line
|
|
564
|
-
];
|
|
565
|
-
}
|
|
566
|
-
else if (cursorLogCol === currentPosInLogLine + numCodePointsInChunk &&
|
|
567
|
-
numCodePointsInChunk > 0) {
|
|
568
|
-
// Cursor is exactly at the end of this non-empty chunk
|
|
569
|
-
currentVisualCursor = [
|
|
570
|
-
visualLines.length - 1,
|
|
571
|
-
numCodePointsInChunk,
|
|
572
|
-
];
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
550
|
const logicalStartOfThisChunk = currentPosInLogLine;
|
|
576
551
|
currentPosInLogLine += numCodePointsInChunk;
|
|
577
552
|
// If the chunk processed did not consume the entire logical line,
|
|
@@ -584,20 +559,6 @@ function calculateVisualLayout(logicalLines, logicalCursor, viewportWidth) {
|
|
|
584
559
|
currentPosInLogLine++;
|
|
585
560
|
}
|
|
586
561
|
}
|
|
587
|
-
// After all chunks of a non-empty logical line are processed,
|
|
588
|
-
// if the cursor is at the very end of this logical line, update visual cursor.
|
|
589
|
-
if (logIndex === logicalCursor[0] &&
|
|
590
|
-
logicalCursor[1] === codePointsInLogLine.length // Cursor at end of logical line
|
|
591
|
-
) {
|
|
592
|
-
const lastVisualLineIdx = visualLines.length - 1;
|
|
593
|
-
if (lastVisualLineIdx >= 0 &&
|
|
594
|
-
visualLines[lastVisualLineIdx] !== undefined) {
|
|
595
|
-
currentVisualCursor = [
|
|
596
|
-
lastVisualLineIdx,
|
|
597
|
-
cpLen(visualLines[lastVisualLineIdx]), // Cursor at end of last visual line for this logical line
|
|
598
|
-
];
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
562
|
}
|
|
602
563
|
});
|
|
603
564
|
// If the entire logical text was empty, ensure there's one empty visual line.
|
|
@@ -610,23 +571,46 @@ function calculateVisualLayout(logicalLines, logicalCursor, viewportWidth) {
|
|
|
610
571
|
logicalToVisualMap[0].push([0, 0]);
|
|
611
572
|
visualToLogicalMap.push([0, 0]);
|
|
612
573
|
}
|
|
613
|
-
currentVisualCursor = [0, 0];
|
|
614
|
-
}
|
|
615
|
-
// Handle cursor at the very end of the text (after all processing)
|
|
616
|
-
// This case might be covered by the loop end condition now, but kept for safety.
|
|
617
|
-
else if (logicalCursor[0] === logicalLines.length - 1 &&
|
|
618
|
-
logicalCursor[1] === cpLen(logicalLines[logicalLines.length - 1]) &&
|
|
619
|
-
visualLines.length > 0) {
|
|
620
|
-
const lastVisLineIdx = visualLines.length - 1;
|
|
621
|
-
currentVisualCursor = [lastVisLineIdx, cpLen(visualLines[lastVisLineIdx])];
|
|
622
574
|
}
|
|
623
575
|
return {
|
|
624
576
|
visualLines,
|
|
625
|
-
visualCursor: currentVisualCursor,
|
|
626
577
|
logicalToVisualMap,
|
|
627
578
|
visualToLogicalMap,
|
|
628
579
|
};
|
|
629
580
|
}
|
|
581
|
+
// Calculates the visual cursor position based on a pre-calculated layout.
|
|
582
|
+
// This is a lightweight operation.
|
|
583
|
+
function calculateVisualCursorFromLayout(layout, logicalCursor) {
|
|
584
|
+
const { logicalToVisualMap, visualLines } = layout;
|
|
585
|
+
const [logicalRow, logicalCol] = logicalCursor;
|
|
586
|
+
const segmentsForLogicalLine = logicalToVisualMap[logicalRow];
|
|
587
|
+
if (!segmentsForLogicalLine || segmentsForLogicalLine.length === 0) {
|
|
588
|
+
// This can happen for an empty document.
|
|
589
|
+
return [0, 0];
|
|
590
|
+
}
|
|
591
|
+
// Find the segment where the logical column fits.
|
|
592
|
+
// The segments are sorted by startColInLogical.
|
|
593
|
+
let targetSegmentIndex = segmentsForLogicalLine.findIndex(([, startColInLogical], index) => {
|
|
594
|
+
const nextStartColInLogical = index + 1 < segmentsForLogicalLine.length
|
|
595
|
+
? segmentsForLogicalLine[index + 1][1]
|
|
596
|
+
: Infinity;
|
|
597
|
+
return (logicalCol >= startColInLogical && logicalCol < nextStartColInLogical);
|
|
598
|
+
});
|
|
599
|
+
// If not found, it means the cursor is at the end of the logical line.
|
|
600
|
+
if (targetSegmentIndex === -1) {
|
|
601
|
+
if (logicalCol === 0) {
|
|
602
|
+
targetSegmentIndex = 0;
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
targetSegmentIndex = segmentsForLogicalLine.length - 1;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const [visualRow, startColInLogical] = segmentsForLogicalLine[targetSegmentIndex];
|
|
609
|
+
const visualCol = logicalCol - startColInLogical;
|
|
610
|
+
// The visual column should not exceed the length of the visual line.
|
|
611
|
+
const clampedVisualCol = Math.min(visualCol, cpLen(visualLines[visualRow] ?? ''));
|
|
612
|
+
return [visualRow, clampedVisualCol];
|
|
613
|
+
}
|
|
630
614
|
const historyLimit = 100;
|
|
631
615
|
export const pushUndo = (currentState) => {
|
|
632
616
|
const snapshot = {
|
|
@@ -640,7 +624,7 @@ export const pushUndo = (currentState) => {
|
|
|
640
624
|
}
|
|
641
625
|
return { ...currentState, undoStack: newStack, redoStack: [] };
|
|
642
626
|
};
|
|
643
|
-
|
|
627
|
+
function textBufferReducerLogic(state, action) {
|
|
644
628
|
const pushUndoLocal = pushUndo;
|
|
645
629
|
const currentLine = (r) => state.lines[r] ?? '';
|
|
646
630
|
const currentLineLen = (r) => cpLen(currentLine(r));
|
|
@@ -727,68 +711,101 @@ export function textBufferReducer(state, action) {
|
|
|
727
711
|
preferredCol: null,
|
|
728
712
|
};
|
|
729
713
|
}
|
|
730
|
-
case '
|
|
731
|
-
|
|
714
|
+
case 'set_viewport': {
|
|
715
|
+
const { width, height } = action.payload;
|
|
716
|
+
if (width === state.viewportWidth && height === state.viewportHeight) {
|
|
732
717
|
return state;
|
|
733
718
|
}
|
|
734
|
-
return {
|
|
719
|
+
return {
|
|
720
|
+
...state,
|
|
721
|
+
viewportWidth: width,
|
|
722
|
+
viewportHeight: height,
|
|
723
|
+
};
|
|
735
724
|
}
|
|
736
725
|
case 'move': {
|
|
737
726
|
const { dir } = action.payload;
|
|
738
|
-
const {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
727
|
+
const { cursorRow, cursorCol, lines, visualLayout, preferredCol } = state;
|
|
728
|
+
// Visual movements
|
|
729
|
+
if (dir === 'left' ||
|
|
730
|
+
dir === 'right' ||
|
|
731
|
+
dir === 'up' ||
|
|
732
|
+
dir === 'down' ||
|
|
733
|
+
dir === 'home' ||
|
|
734
|
+
dir === 'end') {
|
|
735
|
+
const visualCursor = calculateVisualCursorFromLayout(visualLayout, [
|
|
736
|
+
cursorRow,
|
|
737
|
+
cursorCol,
|
|
738
|
+
]);
|
|
739
|
+
const { visualLines, visualToLogicalMap } = visualLayout;
|
|
740
|
+
let newVisualRow = visualCursor[0];
|
|
741
|
+
let newVisualCol = visualCursor[1];
|
|
742
|
+
let newPreferredCol = preferredCol;
|
|
743
|
+
const currentVisLineLen = cpLen(visualLines[newVisualRow] ?? '');
|
|
744
|
+
switch (dir) {
|
|
745
|
+
case 'left':
|
|
746
|
+
newPreferredCol = null;
|
|
747
|
+
if (newVisualCol > 0) {
|
|
748
|
+
newVisualCol--;
|
|
749
|
+
}
|
|
750
|
+
else if (newVisualRow > 0) {
|
|
751
|
+
newVisualRow--;
|
|
752
|
+
newVisualCol = cpLen(visualLines[newVisualRow] ?? '');
|
|
753
|
+
}
|
|
754
|
+
break;
|
|
755
|
+
case 'right':
|
|
756
|
+
newPreferredCol = null;
|
|
757
|
+
if (newVisualCol < currentVisLineLen) {
|
|
758
|
+
newVisualCol++;
|
|
759
|
+
}
|
|
760
|
+
else if (newVisualRow < visualLines.length - 1) {
|
|
761
|
+
newVisualRow++;
|
|
762
|
+
newVisualCol = 0;
|
|
763
|
+
}
|
|
764
|
+
break;
|
|
765
|
+
case 'up':
|
|
766
|
+
if (newVisualRow > 0) {
|
|
767
|
+
if (newPreferredCol === null)
|
|
768
|
+
newPreferredCol = newVisualCol;
|
|
769
|
+
newVisualRow--;
|
|
770
|
+
newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow] ?? ''));
|
|
771
|
+
}
|
|
772
|
+
break;
|
|
773
|
+
case 'down':
|
|
774
|
+
if (newVisualRow < visualLines.length - 1) {
|
|
775
|
+
if (newPreferredCol === null)
|
|
776
|
+
newPreferredCol = newVisualCol;
|
|
777
|
+
newVisualRow++;
|
|
778
|
+
newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow] ?? ''));
|
|
779
|
+
}
|
|
780
|
+
break;
|
|
781
|
+
case 'home':
|
|
782
|
+
newPreferredCol = null;
|
|
763
783
|
newVisualCol = 0;
|
|
784
|
+
break;
|
|
785
|
+
case 'end':
|
|
786
|
+
newPreferredCol = null;
|
|
787
|
+
newVisualCol = currentVisLineLen;
|
|
788
|
+
break;
|
|
789
|
+
default: {
|
|
790
|
+
const exhaustiveCheck = dir;
|
|
791
|
+
console.error(`Unknown visual movement direction: ${exhaustiveCheck}`);
|
|
792
|
+
return state;
|
|
764
793
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow] ?? ''));
|
|
780
|
-
}
|
|
781
|
-
break;
|
|
782
|
-
case 'home':
|
|
783
|
-
newPreferredCol = null;
|
|
784
|
-
newVisualCol = 0;
|
|
785
|
-
break;
|
|
786
|
-
case 'end':
|
|
787
|
-
newPreferredCol = null;
|
|
788
|
-
newVisualCol = currentVisLineLen;
|
|
789
|
-
break;
|
|
794
|
+
}
|
|
795
|
+
if (visualToLogicalMap[newVisualRow]) {
|
|
796
|
+
const [logRow, logStartCol] = visualToLogicalMap[newVisualRow];
|
|
797
|
+
return {
|
|
798
|
+
...state,
|
|
799
|
+
cursorRow: logRow,
|
|
800
|
+
cursorCol: clamp(logStartCol + newVisualCol, 0, cpLen(lines[logRow] ?? '')),
|
|
801
|
+
preferredCol: newPreferredCol,
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
return state;
|
|
805
|
+
}
|
|
806
|
+
// Logical movements
|
|
807
|
+
switch (dir) {
|
|
790
808
|
case 'wordLeft': {
|
|
791
|
-
const { cursorRow, cursorCol, lines } = state;
|
|
792
809
|
if (cursorCol === 0 && cursorRow === 0)
|
|
793
810
|
return state;
|
|
794
811
|
let newCursorRow = cursorRow;
|
|
@@ -827,7 +844,6 @@ export function textBufferReducer(state, action) {
|
|
|
827
844
|
};
|
|
828
845
|
}
|
|
829
846
|
case 'wordRight': {
|
|
830
|
-
const { cursorRow, cursorCol, lines } = state;
|
|
831
847
|
if (cursorRow === lines.length - 1 &&
|
|
832
848
|
cursorCol === cpLen(lines[cursorRow] ?? '')) {
|
|
833
849
|
return state;
|
|
@@ -856,18 +872,14 @@ export function textBufferReducer(state, action) {
|
|
|
856
872
|
};
|
|
857
873
|
}
|
|
858
874
|
default:
|
|
859
|
-
|
|
875
|
+
return state;
|
|
860
876
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
preferredCol: newPreferredCol,
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
return state;
|
|
877
|
+
}
|
|
878
|
+
case 'set_cursor': {
|
|
879
|
+
return {
|
|
880
|
+
...state,
|
|
881
|
+
...action.payload,
|
|
882
|
+
};
|
|
871
883
|
}
|
|
872
884
|
case 'delete': {
|
|
873
885
|
const { cursorRow, cursorCol, lines } = state;
|
|
@@ -878,7 +890,11 @@ export function textBufferReducer(state, action) {
|
|
|
878
890
|
newLines[cursorRow] =
|
|
879
891
|
cpSlice(lineContent, 0, cursorCol) +
|
|
880
892
|
cpSlice(lineContent, cursorCol + 1);
|
|
881
|
-
return {
|
|
893
|
+
return {
|
|
894
|
+
...nextState,
|
|
895
|
+
lines: newLines,
|
|
896
|
+
preferredCol: null,
|
|
897
|
+
};
|
|
882
898
|
}
|
|
883
899
|
else if (cursorRow < lines.length - 1) {
|
|
884
900
|
const nextState = pushUndoLocal(state);
|
|
@@ -886,7 +902,11 @@ export function textBufferReducer(state, action) {
|
|
|
886
902
|
const newLines = [...nextState.lines];
|
|
887
903
|
newLines[cursorRow] = lineContent + nextLineContent;
|
|
888
904
|
newLines.splice(cursorRow + 1, 1);
|
|
889
|
-
return {
|
|
905
|
+
return {
|
|
906
|
+
...nextState,
|
|
907
|
+
lines: newLines,
|
|
908
|
+
preferredCol: null,
|
|
909
|
+
};
|
|
890
910
|
}
|
|
891
911
|
return state;
|
|
892
912
|
}
|
|
@@ -958,7 +978,10 @@ export function textBufferReducer(state, action) {
|
|
|
958
978
|
const nextState = pushUndoLocal(state);
|
|
959
979
|
const newLines = [...nextState.lines];
|
|
960
980
|
newLines[cursorRow] = cpSlice(lineContent, 0, cursorCol);
|
|
961
|
-
return {
|
|
981
|
+
return {
|
|
982
|
+
...nextState,
|
|
983
|
+
lines: newLines,
|
|
984
|
+
};
|
|
962
985
|
}
|
|
963
986
|
else if (cursorRow < lines.length - 1) {
|
|
964
987
|
// Act as a delete
|
|
@@ -967,7 +990,11 @@ export function textBufferReducer(state, action) {
|
|
|
967
990
|
const newLines = [...nextState.lines];
|
|
968
991
|
newLines[cursorRow] = lineContent + nextLineContent;
|
|
969
992
|
newLines.splice(cursorRow + 1, 1);
|
|
970
|
-
return {
|
|
993
|
+
return {
|
|
994
|
+
...nextState,
|
|
995
|
+
lines: newLines,
|
|
996
|
+
preferredCol: null,
|
|
997
|
+
};
|
|
971
998
|
}
|
|
972
999
|
return state;
|
|
973
1000
|
}
|
|
@@ -1078,11 +1105,23 @@ export function textBufferReducer(state, action) {
|
|
|
1078
1105
|
}
|
|
1079
1106
|
}
|
|
1080
1107
|
}
|
|
1108
|
+
export function textBufferReducer(state, action) {
|
|
1109
|
+
const newState = textBufferReducerLogic(state, action);
|
|
1110
|
+
if (newState.lines !== state.lines ||
|
|
1111
|
+
newState.viewportWidth !== state.viewportWidth) {
|
|
1112
|
+
return {
|
|
1113
|
+
...newState,
|
|
1114
|
+
visualLayout: calculateLayout(newState.lines, newState.viewportWidth),
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
return newState;
|
|
1118
|
+
}
|
|
1081
1119
|
// --- End of reducer logic ---
|
|
1082
1120
|
export function useTextBuffer({ initialText = '', initialCursorOffset = 0, viewport, stdin, setRawMode, onChange, isValidPath, shellModeActive = false, }) {
|
|
1083
1121
|
const initialState = useMemo(() => {
|
|
1084
1122
|
const lines = initialText.split('\n');
|
|
1085
1123
|
const [initialCursorRow, initialCursorCol] = calculateInitialCursorPosition(lines.length === 0 ? [''] : lines, initialCursorOffset);
|
|
1124
|
+
const visualLayout = calculateLayout(lines.length === 0 ? [''] : lines, viewport.width);
|
|
1086
1125
|
return {
|
|
1087
1126
|
lines: lines.length === 0 ? [''] : lines,
|
|
1088
1127
|
cursorRow: initialCursorRow,
|
|
@@ -1093,13 +1132,15 @@ export function useTextBuffer({ initialText = '', initialCursorOffset = 0, viewp
|
|
|
1093
1132
|
clipboard: null,
|
|
1094
1133
|
selectionAnchor: null,
|
|
1095
1134
|
viewportWidth: viewport.width,
|
|
1135
|
+
viewportHeight: viewport.height,
|
|
1136
|
+
visualLayout,
|
|
1096
1137
|
};
|
|
1097
|
-
}, [initialText, initialCursorOffset, viewport.width]);
|
|
1138
|
+
}, [initialText, initialCursorOffset, viewport.width, viewport.height]);
|
|
1098
1139
|
const [state, dispatch] = useReducer(textBufferReducer, initialState);
|
|
1099
|
-
const { lines, cursorRow, cursorCol, preferredCol, selectionAnchor } = state;
|
|
1140
|
+
const { lines, cursorRow, cursorCol, preferredCol, selectionAnchor, visualLayout, } = state;
|
|
1100
1141
|
const text = useMemo(() => lines.join('\n'), [lines]);
|
|
1101
|
-
const
|
|
1102
|
-
const { visualLines
|
|
1142
|
+
const visualCursor = useMemo(() => calculateVisualCursorFromLayout(visualLayout, [cursorRow, cursorCol]), [visualLayout, cursorRow, cursorCol]);
|
|
1143
|
+
const { visualLines } = visualLayout;
|
|
1103
1144
|
const [visualScrollRow, setVisualScrollRow] = useState(0);
|
|
1104
1145
|
useEffect(() => {
|
|
1105
1146
|
if (onChange) {
|
|
@@ -1107,8 +1148,11 @@ export function useTextBuffer({ initialText = '', initialCursorOffset = 0, viewp
|
|
|
1107
1148
|
}
|
|
1108
1149
|
}, [text, onChange]);
|
|
1109
1150
|
useEffect(() => {
|
|
1110
|
-
dispatch({
|
|
1111
|
-
|
|
1151
|
+
dispatch({
|
|
1152
|
+
type: 'set_viewport',
|
|
1153
|
+
payload: { width: viewport.width, height: viewport.height },
|
|
1154
|
+
});
|
|
1155
|
+
}, [viewport.width, viewport.height]);
|
|
1112
1156
|
// Update visual scroll (vertical)
|
|
1113
1157
|
useEffect(() => {
|
|
1114
1158
|
const { height } = viewport;
|
|
@@ -1170,7 +1214,7 @@ export function useTextBuffer({ initialText = '', initialCursorOffset = 0, viewp
|
|
|
1170
1214
|
}, []);
|
|
1171
1215
|
const move = useCallback((dir) => {
|
|
1172
1216
|
dispatch({ type: 'move', payload: { dir } });
|
|
1173
|
-
}, []);
|
|
1217
|
+
}, [dispatch]);
|
|
1174
1218
|
const undo = useCallback(() => {
|
|
1175
1219
|
dispatch({ type: 'undo' });
|
|
1176
1220
|
}, []);
|