Procházet zdrojové kódy

Make mentions clickable

Saoud Rizwan před 1 rokem
rodič
revize
593b3d6b7c

+ 1 - 0
src/integrations/WorkspaceTracker.ts

@@ -28,6 +28,7 @@ class WorkspaceTracker {
 
 	private registerListeners() {
 		// Listen for file creation
+		// .bind(this) ensures the callback refers to class instance when using this, not necessary when using arrow function
 		this.disposables.push(vscode.workspace.onDidCreateFiles(this.onFilesCreated.bind(this)))
 
 		// Listen for file deletion

+ 4 - 0
src/providers/ClaudeDevProvider.ts

@@ -12,6 +12,7 @@ import axios from "axios"
 import { getTheme } from "../utils/getTheme"
 import { openFile, openImage } from "../utils/open-file"
 import WorkspaceTracker from "../integrations/WorkspaceTracker"
+import { openMention } from "../utils/context-mentions"
 
 /*
 https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
@@ -423,6 +424,9 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
 					case "openFile":
 						openFile(message.text!)
 						break
+					case "openMention":
+						openMention(message.text)
+						break
 					// Add more switch case statements here as more webview message commands
 					// are created within the webview context (i.e. inside media/main.js)
 				}

+ 1 - 0
src/shared/WebviewMessage.ts

@@ -19,6 +19,7 @@ export interface WebviewMessage {
 		| "requestOllamaModels"
 		| "openImage"
 		| "openFile"
+		| "openMention"
 	text?: string
 	askResponse?: ClaudeAskResponse
 	apiConfiguration?: ApiConfiguration

+ 9 - 0
src/shared/context-mentions.ts

@@ -0,0 +1,9 @@
+/*
+Mention regex
+- File and folder paths (starting with '/')
+- URLs (containing '://')
+- The 'problems' keyword
+- Word boundary after 'problems' to avoid partial matches
+*/
+export const mentionRegex = /@((?:\/|\w+:\/\/)[^\s]+|problems\b)/
+export const mentionRegexGlobal = new RegExp(mentionRegex.source, "g")

+ 28 - 0
src/utils/context-mentions.ts

@@ -0,0 +1,28 @@
+import * as vscode from "vscode"
+import * as path from "path"
+import { openFile } from "./open-file"
+
+export function openMention(mention?: string): void {
+	if (!mention) {
+		return
+	}
+
+	if (mention.startsWith("/")) {
+		const relPath = mention.slice(1)
+		const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0)
+		if (!cwd) {
+			return
+		}
+		const absPath = path.resolve(cwd, relPath)
+		if (mention.endsWith("/")) {
+			vscode.commands.executeCommand("revealInExplorer", vscode.Uri.file(absPath))
+			// vscode.commands.executeCommand("vscode.openFolder", , { forceNewWindow: false }) opens in new window
+		} else {
+			openFile(absPath)
+		}
+	} else if (mention === "problems") {
+		vscode.commands.executeCommand("workbench.actions.view.problems")
+	} else if (mention.startsWith("http")) {
+		vscode.env.openExternal(vscode.Uri.parse(mention))
+	}
+}

+ 2 - 3
webview-ui/src/components/ChatTextArea.tsx

@@ -4,15 +4,14 @@ import { useExtensionState } from "../context/ExtensionStateContext"
 import {
 	getContextMenuOptions,
 	insertMention,
-	mentionRegex,
-	mentionRegexGlobal,
 	removeMention,
 	shouldShowContextMenu,
 	ContextMenuOptionType,
-} from "../utils/mention-context"
+} from "../utils/context-mentions"
 import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
 import ContextMenu from "./ContextMenu"
 import Thumbnails from "./Thumbnails"
+import { mentionRegex, mentionRegexGlobal } from "../../../src/shared/context-mentions"
 
 interface ChatTextAreaProps {
 	inputValue: string

+ 5 - 4
webview-ui/src/components/ContextMenu.tsx

@@ -1,5 +1,5 @@
 import React, { useEffect, useMemo, useRef } from "react"
-import { ContextMenuOptionType, ContextMenuQueryItem, getContextMenuOptions } from "../utils/mention-context"
+import { ContextMenuOptionType, ContextMenuQueryItem, getContextMenuOptions } from "../utils/context-mentions"
 import { formatFilePathForTruncation } from "./CodeAccordian"
 
 interface ContextMenuProps {
@@ -109,14 +109,15 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
 				ref={menuRef}
 				style={{
 					backgroundColor: "var(--vscode-dropdown-background)",
-					border: "1px solid var(--vscode-dropdown-border)",
+					border: "1px solid var(--vscode-editorGroup-border)",
 					borderRadius: "3px",
+					boxShadow: "0 4px 10px rgba(0, 0, 0, 0.25)",
 					zIndex: 1000,
 					display: "flex",
 					flexDirection: "column",
-					boxShadow: "0 8px 16px rgba(0,0,0,0.24)",
 					maxHeight: "200px",
 					overflowY: "auto",
+					overflow: "hidden",
 				}}>
 				{/* Can't use virtuoso since it requires fixed height and menu height is dynamic based on # of items */}
 				{filteredOptions.map((option, index) => (
@@ -127,7 +128,7 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
 							padding: "8px 12px",
 							cursor: isOptionSelectable(option) ? "pointer" : "default",
 							color: "var(--vscode-dropdown-foreground)",
-							borderBottom: "1px solid var(--vscode-dropdown-border)",
+							borderBottom: "1px solid var(--vscode-editorGroup-border)",
 							display: "flex",
 							alignItems: "center",
 							justifyContent: "space-between",

+ 4 - 2
webview-ui/src/components/TaskHeader.tsx

@@ -3,9 +3,9 @@ import React, { memo, useEffect, useMemo, useRef, useState } from "react"
 import { useWindowSize } from "react-use"
 import { ClaudeMessage } from "../../../src/shared/ExtensionMessage"
 import { useExtensionState } from "../context/ExtensionStateContext"
-import { mentionRegexGlobal } from "../utils/mention-context"
 import { vscode } from "../utils/vscode"
 import Thumbnails from "./Thumbnails"
+import { mentionRegexGlobal } from "../../../src/shared/context-mentions"
 
 interface TaskHeaderProps {
 	task: ClaudeMessage
@@ -351,7 +351,9 @@ export const highlightMentions = (text?: string, withShadow = true) => {
 			return (
 				<span
 					key={index}
-					className={withShadow ? "mention-context-highlight-with-shadow" : "mention-context-highlight"}>
+					className={withShadow ? "mention-context-highlight-with-shadow" : "mention-context-highlight"}
+					style={{ cursor: "pointer" }}
+					onClick={() => vscode.postMessage({ type: "openMention", text: part })}>
 					@{part}
 				</span>
 			)

+ 1 - 9
webview-ui/src/utils/mention-context.ts → webview-ui/src/utils/context-mentions.ts

@@ -1,12 +1,4 @@
-/*
-Mention regex
-- File and folder paths (starting with '/')
-- URLs (containing '://')
-- The 'problems' keyword
-- Word boundary after 'problems' to avoid partial matches
-*/
-export const mentionRegex = /@((?:\/|\w+:\/\/)[^\s]+|problems\b)/
-export const mentionRegexGlobal = new RegExp(mentionRegex.source, "g")
+import { mentionRegex } from "../../../src/shared/context-mentions"
 
 export function insertMention(text: string, position: number, value: string): string {
 	const beforeCursor = text.slice(0, position)