From ab44824e07832774b0a466536c0ca87e4f1482b1 Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Sat, 7 Jun 2025 14:48:56 -0700 Subject: Auto insert @ when dragging and dropping files. (#812) --- .../cli/src/ui/components/shared/text-buffer.ts | 35 +++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'packages/cli/src/ui/components/shared/text-buffer.ts') diff --git a/packages/cli/src/ui/components/shared/text-buffer.ts b/packages/cli/src/ui/components/shared/text-buffer.ts index 6ce1d13d..97ff1a1d 100644 --- a/packages/cli/src/ui/components/shared/text-buffer.ts +++ b/packages/cli/src/ui/components/shared/text-buffer.ts @@ -11,6 +11,7 @@ import os from 'os'; import pathMod from 'path'; import { useState, useCallback, useEffect, useMemo } from 'react'; import stringWidth from 'string-width'; +import { unescapePath } from '@gemini-code/core'; export type Direction = | 'left' @@ -85,6 +86,7 @@ interface UseTextBufferProps { stdin?: NodeJS.ReadStream | null; // For external editor setRawMode?: (mode: boolean) => void; // For external editor onChange?: (text: string) => void; // Callback for when text changes + isValidPath: (path: string) => boolean; } interface UndoHistoryEntry { @@ -392,6 +394,7 @@ export function useTextBuffer({ stdin, setRawMode, onChange, + isValidPath, }: UseTextBufferProps): TextBuffer { const [lines, setLines] = useState(() => { const l = initialText.split('\n'); @@ -561,6 +564,28 @@ export function useTextBuffer({ } dbg('insert', { ch, beforeCursor: [cursorRow, cursorCol] }); pushUndo(); + + // Arbitrary threshold to avoid false positives on normal key presses + // while still detecting virtually all reasonable length file paths. + const minLengthToInferAsDragDrop = 3; + if (ch.length >= minLengthToInferAsDragDrop) { + // Possible drag and drop of a file path. + let potentialPath = ch; + if ( + potentialPath.length > 2 && + potentialPath.startsWith("'") && + potentialPath.endsWith("'") + ) { + potentialPath = ch.slice(1, -1); + } + + potentialPath = potentialPath.trim(); + // Be conservative and only add an @ if the path is valid. + if (isValidPath(unescapePath(potentialPath))) { + ch = `@${potentialPath}`; + } + } + setLines((prevLines) => { const newLines = [...prevLines]; const lineContent = currentLine(cursorRow); @@ -573,7 +598,15 @@ export function useTextBuffer({ setCursorCol((prev) => prev + cpLen(ch)); // Use cpLen for character length setPreferredCol(null); }, - [pushUndo, cursorRow, cursorCol, currentLine, insertStr, setPreferredCol], + [ + pushUndo, + cursorRow, + cursorCol, + currentLine, + insertStr, + setPreferredCol, + isValidPath, + ], ); const newline = useCallback((): void => { -- cgit v1.2.3