summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/components/InputPrompt.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli/src/ui/components/InputPrompt.tsx')
-rw-r--r--packages/cli/src/ui/components/InputPrompt.tsx63
1 files changed, 62 insertions, 1 deletions
diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx
index 3771f5b9..371fb48d 100644
--- a/packages/cli/src/ui/components/InputPrompt.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.tsx
@@ -19,6 +19,12 @@ import { useKeypress, Key } from '../hooks/useKeypress.js';
import { isAtCommand, isSlashCommand } from '../utils/commandUtils.js';
import { CommandContext, SlashCommand } from '../commands/types.js';
import { Config } from '@google/gemini-cli-core';
+import {
+ clipboardHasImage,
+ saveClipboardImage,
+ cleanupOldClipboardImages,
+} from '../utils/clipboardUtils.js';
+import * as path from 'path';
export interface InputPromptProps {
buffer: TextBuffer;
@@ -52,7 +58,6 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
setShellModeActive,
}) => {
const [justNavigatedHistory, setJustNavigatedHistory] = useState(false);
-
const completion = useCompletion(
buffer.text,
config.getTargetDir(),
@@ -178,6 +183,54 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
[resetCompletionState, buffer, completionSuggestions, slashCommands],
);
+ // Handle clipboard image pasting with Ctrl+V
+ const handleClipboardImage = useCallback(async () => {
+ try {
+ if (await clipboardHasImage()) {
+ const imagePath = await saveClipboardImage(config.getTargetDir());
+ if (imagePath) {
+ // Clean up old images
+ cleanupOldClipboardImages(config.getTargetDir()).catch(() => {
+ // Ignore cleanup errors
+ });
+
+ // Get relative path from current directory
+ const relativePath = path.relative(config.getTargetDir(), imagePath);
+
+ // Insert @path reference at cursor position
+ const insertText = `@${relativePath}`;
+ const currentText = buffer.text;
+ const [row, col] = buffer.cursor;
+
+ // Calculate offset from row/col
+ let offset = 0;
+ for (let i = 0; i < row; i++) {
+ offset += buffer.lines[i].length + 1; // +1 for newline
+ }
+ offset += col;
+
+ // Add spaces around the path if needed
+ let textToInsert = insertText;
+ const charBefore = offset > 0 ? currentText[offset - 1] : '';
+ const charAfter =
+ offset < currentText.length ? currentText[offset] : '';
+
+ if (charBefore && charBefore !== ' ' && charBefore !== '\n') {
+ textToInsert = ' ' + textToInsert;
+ }
+ if (!charAfter || (charAfter !== ' ' && charAfter !== '\n')) {
+ textToInsert = textToInsert + ' ';
+ }
+
+ // Insert at cursor position
+ buffer.replaceRangeByOffset(offset, offset, textToInsert);
+ }
+ }
+ } catch (error) {
+ console.error('Error handling clipboard image:', error);
+ }
+ }, [buffer, config]);
+
const handleInput = useCallback(
(key: Key) => {
if (!focus) {
@@ -315,6 +368,12 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
return;
}
+ // Ctrl+V for clipboard image paste
+ if (key.ctrl && key.name === 'v') {
+ handleClipboardImage();
+ return;
+ }
+
// Fallback to the text buffer's default input handling for all other keys
buffer.handleInput(key);
},
@@ -329,6 +388,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
handleAutocomplete,
handleSubmitAndClear,
shellHistory,
+ handleClipboardImage,
],
);
@@ -372,6 +432,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
if (visualIdxInRenderedSet === cursorVisualRow) {
const relativeVisualColForHighlight = cursorVisualColAbsolute;
+
if (relativeVisualColForHighlight >= 0) {
if (relativeVisualColForHighlight < cpLen(display)) {
const charToHighlight =