diff --git a/webview-ui/src/components/chat/BatchFilePermission.tsx b/webview-ui/src/components/chat/BatchFilePermission.tsx index 5bb5d754ccdd..c3bbc59118da 100644 --- a/webview-ui/src/components/chat/BatchFilePermission.tsx +++ b/webview-ui/src/components/chat/BatchFilePermission.tsx @@ -2,7 +2,8 @@ import { memo } from "react" import { ToolUseBlock, ToolUseBlockHeader } from "../common/ToolUseBlock" import { vscode } from "@src/utils/vscode" -import { removeLeadingNonAlphanumeric } from "@src/utils/removeLeadingNonAlphanumeric" +import { formatPathTooltip } from "@src/utils/formatPathTooltip" +import { PathTooltip } from "../ui/PathTooltip" interface FilePermissionItem { path: string @@ -35,10 +36,18 @@ export const BatchFilePermission = memo(({ files = [], onPermissionResponse, ts vscode.postMessage({ type: "openFile", text: file.content })}> {file.path?.startsWith(".") && .} - - {removeLeadingNonAlphanumeric(file.path ?? "") + "\u200E"} - {file.lineSnippet && ` ${file.lineSnippet}`} - + + + {formatPathTooltip( + file.path, + file.lineSnippet ? ` ${file.lineSnippet}` : undefined, + )} + +
diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index fd3d480014a6..4299240a549a 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -14,7 +14,7 @@ import { safeJsonParse } from "@roo/safeJsonParse" import { useExtensionState } from "@src/context/ExtensionStateContext" import { findMatchingResourceOrTemplate } from "@src/utils/mcp" import { vscode } from "@src/utils/vscode" -import { removeLeadingNonAlphanumeric } from "@src/utils/removeLeadingNonAlphanumeric" +import { formatPathTooltip } from "@src/utils/formatPathTooltip" import { getLanguageFromPath } from "@src/utils/getLanguageFromPath" import { ToolUseBlock, ToolUseBlockHeader } from "../common/ToolUseBlock" @@ -61,6 +61,7 @@ import { MessageCircle, } from "lucide-react" import { cn } from "@/lib/utils" +import { PathTooltip } from "../ui/PathTooltip" interface ChatRowProps { message: ClineMessage @@ -552,10 +553,11 @@ export const ChatRowContent = ({ className="group" onClick={() => vscode.postMessage({ type: "openFile", text: tool.content })}> {tool.path?.startsWith(".") && .} - - {removeLeadingNonAlphanumeric(tool.path ?? "") + "\u200E"} - {tool.reason} - + + + {formatPathTooltip(tool.path, tool.reason)} + +
- {header} + + {header} + ) : isFeedback ? (
@@ -56,9 +59,11 @@ const CodeAccordian = ({ ) : ( <> {path?.startsWith(".") && .} - - {removeLeadingNonAlphanumeric(path ?? "") + "\u200E"} - + + + {formatPathTooltip(path)} + + )}
diff --git a/webview-ui/src/components/ui/PathTooltip.tsx b/webview-ui/src/components/ui/PathTooltip.tsx new file mode 100644 index 000000000000..dc6e176d8e0a --- /dev/null +++ b/webview-ui/src/components/ui/PathTooltip.tsx @@ -0,0 +1,54 @@ +import { ReactNode } from "react" +import { StandardTooltip } from "./standard-tooltip" + +interface PathTooltipProps { + /** The file path or content to display in the tooltip */ + content: string + /** The element(s) that trigger the tooltip */ + children: ReactNode + /** The preferred side of the trigger to render the tooltip */ + side?: "top" | "right" | "bottom" | "left" + /** The preferred alignment against the trigger */ + align?: "start" | "center" | "end" + /** Distance in pixels from the trigger */ + sideOffset?: number + /** Whether the trigger should be rendered as a child */ + asChild?: boolean +} + +/** + * PathTooltip component specifically designed for displaying file paths with appropriate + * wrapping and responsive width behavior. Use this for truncated file paths that need + * tooltips to show the full path. + * + * Features: + * - Responsive max-width that adapts to panel size (max 300px on wide panels, 100vw on narrow) + * - Uses text-wrap instead of text-balance to minimize whitespace + * - Leverages existing break-words CSS for natural line breaking at path separators + * + * @example + * + * ...path.tsx + * + */ +export function PathTooltip({ + content, + children, + side = "top", + align = "start", + sideOffset = 4, + asChild = true, +}: PathTooltipProps) { + return ( + + {children} + + ) +} diff --git a/webview-ui/src/utils/formatPathTooltip.ts b/webview-ui/src/utils/formatPathTooltip.ts new file mode 100644 index 000000000000..cfe0b54a7fc6 --- /dev/null +++ b/webview-ui/src/utils/formatPathTooltip.ts @@ -0,0 +1,28 @@ +import { removeLeadingNonAlphanumeric } from "./removeLeadingNonAlphanumeric" + +/** + * Formats a file path for display in tooltips with consistent formatting. + * + * @param path - The file path to format + * @param additionalContent - Optional additional content to append (e.g., line snippets, reasons) + * @returns Formatted string ready for tooltip display + * + * @example + * formatPathTooltip("/src/components/MyComponent.tsx") + * // Returns: "src/components/MyComponent.tsx" + U+200E + * + * @example + * formatPathTooltip("/src/utils/helper.ts", ":42-45") + * // Returns: "src/utils/helper.ts:42-45" + U+200E + */ +export function formatPathTooltip(path?: string, additionalContent?: string): string { + if (!path) return "" + + const formattedPath = removeLeadingNonAlphanumeric(path) + "\u200E" + + if (additionalContent) { + return formattedPath + additionalContent + } + + return formattedPath +}