diff options
| author | Jayson Dasher <[email protected]> | 2025-07-12 00:06:49 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-12 04:06:49 +0000 |
| commit | c9e194ec6ae514cd35f1bdd8cebd6cc556a74208 (patch) | |
| tree | cb2414f7050ef972ba0549a888376d099e3d6bc8 /packages/cli/src/ui/components/InputPrompt.tsx | |
| parent | c4ea17692f4fac8df304993d2271704e79344968 (diff) | |
feat: Add clipboard image paste support for macOS (#1580)
Co-authored-by: Jacob Richman <[email protected]>
Co-authored-by: Scott Densmore <[email protected]>
Diffstat (limited to 'packages/cli/src/ui/components/InputPrompt.tsx')
| -rw-r--r-- | packages/cli/src/ui/components/InputPrompt.tsx | 63 |
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 = |
