diff --git a/src/extension.ts b/src/extension.ts index 2cf702f..eeb6569 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -234,6 +234,9 @@ class ClaudeChatProvider { case 'openFile': this._openFileInEditor(message.filePath); return; + case 'createImageFile': + this._createImageFile(message.imageData, message.imageType); + return; } }, null, @@ -1406,6 +1409,44 @@ class ClaudeChatProvider { } } + private async _createImageFile(imageData: string, imageType: string) { + try { + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; + if (!workspaceFolder) {return;} + + // Extract base64 data from data URL + const base64Data = imageData.split(',')[1]; + const buffer = Buffer.from(base64Data, 'base64'); + + // Get file extension from image type + const extension = imageType.split('/')[1] || 'png'; + + // Create unique filename with timestamp + const timestamp = Date.now(); + const imageFileName = `image_${timestamp}.${extension}`; + + // Create images folder in workspace .vscode directory + const imagesDir = vscode.Uri.joinPath(workspaceFolder.uri, '.vscode', 'claude-code-chat-images'); + await vscode.workspace.fs.createDirectory(imagesDir); + + // Create the image file + const imagePath = vscode.Uri.joinPath(imagesDir, imageFileName); + await vscode.workspace.fs.writeFile(imagePath, buffer); + + // Send the file path back to webview + this._panel?.webview.postMessage({ + type: 'imagePath', + data: { + filePath: imagePath.fsPath + } + }); + + } catch (error) { + console.error('Error creating image file:', error); + vscode.window.showErrorMessage('Failed to create image file'); + } + } + public dispose() { if (this._panel) { this._panel.dispose(); diff --git a/src/ui.ts b/src/ui.ts index e2ced68..6cdfe24 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1299,6 +1299,44 @@ const html = ` try { // Try to get clipboard data from the event first const clipboardData = e.clipboardData; + + // Check for images first + if (clipboardData && clipboardData.items) { + let hasImage = false; + for (let i = 0; i < clipboardData.items.length; i++) { + const item = clipboardData.items[i]; + if (item.type.startsWith('image/')) { + // Found an image, handle it + console.log('Image detected in clipboard:', item.type); + hasImage = true; + const blob = item.getAsFile(); + if (blob) { + console.log('Converting image blob to base64...'); + // Convert blob to base64 + const reader = new FileReader(); + reader.onload = function(event) { + const base64Data = event.target.result; + console.log('Sending image to extension for file creation'); + // Send to extension to create file + vscode.postMessage({ + type: 'createImageFile', + imageData: base64Data, + imageType: item.type + }); + }; + reader.readAsDataURL(blob); + } + break; // Process only the first image found + } + } + + // If we found an image, don't process any text + if (hasImage) { + return; + } + } + + // No image found, handle text let text = ''; if (clipboardData) { @@ -1771,6 +1809,35 @@ const html = ` } break; + case 'imagePath': + // Handle image file path response + if (message.data.filePath) { + // Get current cursor position and content + const cursorPosition = messageInput.selectionStart || messageInput.value.length; + const currentValue = messageInput.value || ''; + + // Insert the file path at the current cursor position + const textBefore = currentValue.substring(0, cursorPosition); + const textAfter = currentValue.substring(cursorPosition); + + // Add a space before the path if there's text before and it doesn't end with whitespace + const separator = (textBefore && !textBefore.endsWith(' ') && !textBefore.endsWith('\\n')) ? ' ' : ''; + + messageInput.value = textBefore + separator + message.data.filePath + textAfter; + + // Move cursor to end of inserted path + const newCursorPosition = cursorPosition + separator.length + message.data.filePath.length; + messageInput.setSelectionRange(newCursorPosition, newCursorPosition); + + // Focus back on textarea and adjust height + messageInput.focus(); + adjustTextareaHeight(); + + console.log('Inserted image path:', message.data.filePath); + console.log('Full textarea value:', messageInput.value); + } + break; + case 'updateTokens': console.log('Tokens updated in real-time:', message.data); // Update token totals in real-time