From 77a6e2be6d200fc102b26a64cfe0ddb7ea63f4b6 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 25 Feb 2025 02:40:37 -0500 Subject: [PATCH] File drag and drop --- src/core/webview/ClineProvider.ts | 3 +++ src/shared/ExtensionMessage.ts | 1 + .../src/components/chat/ChatTextArea.tsx | 23 ++++++++++++++++--- webview-ui/src/components/chat/ChatView.tsx | 5 ++-- .../src/context/ExtensionStateContext.tsx | 1 + 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index bb31be5dce..b9b378118f 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2386,6 +2386,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { const allowedCommands = vscode.workspace.getConfiguration("roo-cline").get("allowedCommands") || [] + const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) || "" + return { version: this.context.extension?.packageJSON?.version ?? "", apiConfiguration, @@ -2432,6 +2434,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { experiments: experiments ?? experimentDefault, mcpServers: this.mcpHub?.getAllServers() ?? [], maxOpenTabsContext: maxOpenTabsContext ?? 20, + cwd: cwd, } } diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index fe9fa39427..8f64a9ba05 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -129,6 +129,7 @@ export interface ExtensionState { customModes: ModeConfig[] toolRequirements?: Record // Map of tool names to their requirements (e.g. {"apply_diff": true} if diffEnabled) maxOpenTabsContext: number // Maximum number of VSCode open tabs to include in context (0-500) + cwd?: string // Current working directory } export interface ClineMessage { diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index d317efb96e..229a91d031 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -50,7 +50,7 @@ const ChatTextArea = forwardRef( }, ref, ) => { - const { filePaths, openedTabs, currentApiConfigName, listApiConfigMeta, customModes } = useExtensionState() + const { filePaths, openedTabs, currentApiConfigName, listApiConfigMeta, customModes, cwd } = useExtensionState() const [gitCommits, setGitCommits] = useState([]) const [showDropdown, setShowDropdown] = useState(false) @@ -589,18 +589,35 @@ const ChatTextArea = forwardRef( const files = Array.from(e.dataTransfer.files) const text = e.dataTransfer.getData("text") if (text) { - const newValue = inputValue.slice(0, cursorPosition) + text + inputValue.slice(cursorPosition) + let mentionText = text + const normalizedText = text.replace(/\\/g, "/") + const normalizedCwd = cwd ? cwd.replace(/\\/g, "/") : "" + + // Always use case-insensitive comparison for path matching + if (normalizedCwd) { + const lowerText = normalizedText.toLowerCase() + const lowerCwd = normalizedCwd.toLowerCase() + + if (lowerText.startsWith(lowerCwd)) { + mentionText = "@" + normalizedText.substring(normalizedCwd.length) + } + } + + const newValue = + inputValue.slice(0, cursorPosition) + mentionText + " " + inputValue.slice(cursorPosition) setInputValue(newValue) - const newCursorPosition = cursorPosition + text.length + const newCursorPosition = cursorPosition + mentionText.length + 1 setCursorPosition(newCursorPosition) setIntendedCursorPosition(newCursorPosition) return } + const acceptedTypes = ["png", "jpeg", "webp"] const imageFiles = files.filter((file) => { const [type, subtype] = file.type.split("/") return type === "image" && acceptedTypes.includes(subtype) }) + if (!shouldDisableImages && imageFiles.length > 0) { const imagePromises = imageFiles.map((file) => { return new Promise((resolve) => { diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index b9fc215a1c..98369cf095 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -880,9 +880,8 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie const placeholderText = useMemo(() => { const baseText = task ? "Type a message..." : "Type your task here..." const contextText = "(@ to add context, / to switch modes" - const imageText = shouldDisableImages ? "" : ", hold shift to drag in images" - const helpText = imageText ? `\n${contextText}${imageText})` : `\n${contextText})` - return baseText + helpText + const imageText = shouldDisableImages ? "hold shift to drag in files" : ", hold shift to drag in files/images" + return baseText + `\n${contextText}${imageText})` }, [task, shouldDisableImages]) const itemContent = useCallback( diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index 3dca8d5f51..e99877d8cb 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -118,6 +118,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode autoApprovalEnabled: false, customModes: [], maxOpenTabsContext: 20, + cwd: "", }) const [didHydrateState, setDidHydrateState] = useState(false)