|
|
@@ -1,109 +1,59 @@
|
|
|
import { memo, useMemo } from "react"
|
|
|
-import { getLanguageFromPath } from "@src/utils/getLanguageFromPath"
|
|
|
-import CodeBlock, { CODE_BLOCK_BG_COLOR } from "./CodeBlock"
|
|
|
-import { ToolProgressStatus } from "@roo/shared/ExtensionMessage"
|
|
|
import { VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
|
|
|
|
|
|
+import { type ToolProgressStatus } from "@roo/shared/ExtensionMessage"
|
|
|
+import { getLanguageFromPath } from "@src/utils/getLanguageFromPath"
|
|
|
+import { removeLeadingNonAlphanumeric } from "@src/utils/removeLeadingNonAlphanumeric"
|
|
|
+
|
|
|
+import { ToolUseBlock, ToolUseBlockHeader } from "./ToolUseBlock"
|
|
|
+import CodeBlock from "./CodeBlock"
|
|
|
+
|
|
|
interface CodeAccordianProps {
|
|
|
+ path?: string
|
|
|
code?: string
|
|
|
- diff?: string
|
|
|
language?: string | undefined
|
|
|
- path?: string
|
|
|
- isFeedback?: boolean
|
|
|
- isConsoleLogs?: boolean
|
|
|
+ progressStatus?: ToolProgressStatus
|
|
|
+ isLoading?: boolean
|
|
|
isExpanded: boolean
|
|
|
+ isFeedback?: boolean
|
|
|
onToggleExpand: () => void
|
|
|
- isLoading?: boolean
|
|
|
- progressStatus?: ToolProgressStatus
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
-We need to remove certain leading characters from the path in order for our leading ellipses trick to work.
|
|
|
-However, we want to preserve all language characters (including CJK, Cyrillic, etc.) and only remove specific
|
|
|
-punctuation that might interfere with the ellipsis display.
|
|
|
-*/
|
|
|
-export const removeLeadingNonAlphanumeric = (path: string): string => {
|
|
|
- // Only remove specific punctuation characters that might interfere with ellipsis display
|
|
|
- // Keep all language characters (including CJK, Cyrillic, etc.) and numbers
|
|
|
- return path.replace(/^[/\\:*?"<>|]+/, "")
|
|
|
}
|
|
|
|
|
|
const CodeAccordian = ({
|
|
|
- code,
|
|
|
- diff,
|
|
|
- language,
|
|
|
path,
|
|
|
- isFeedback,
|
|
|
- isConsoleLogs,
|
|
|
+ code = "",
|
|
|
+ language,
|
|
|
+ progressStatus,
|
|
|
+ isLoading,
|
|
|
isExpanded,
|
|
|
+ isFeedback,
|
|
|
onToggleExpand,
|
|
|
- isLoading,
|
|
|
- progressStatus,
|
|
|
}: CodeAccordianProps) => {
|
|
|
- const inferredLanguage = useMemo(
|
|
|
- () => code && (language ?? (path ? getLanguageFromPath(path) : undefined)),
|
|
|
- [path, language, code],
|
|
|
- )
|
|
|
+ const inferredLanguage = useMemo(() => language ?? (path ? getLanguageFromPath(path) : undefined), [path, language])
|
|
|
+ const source = useMemo(() => code.trim(), [code])
|
|
|
+ const hasHeader = Boolean(path || isFeedback)
|
|
|
|
|
|
return (
|
|
|
- <div
|
|
|
- style={{
|
|
|
- borderRadius: 3,
|
|
|
- backgroundColor: CODE_BLOCK_BG_COLOR,
|
|
|
- overflow: "hidden", // This ensures the inner scrollable area doesn't overflow the rounded corners
|
|
|
- border: "1px solid var(--vscode-editorGroup-border)",
|
|
|
- }}>
|
|
|
- {(path || isFeedback || isConsoleLogs) && (
|
|
|
- <div
|
|
|
- style={{
|
|
|
- color: "var(--vscode-descriptionForeground)",
|
|
|
- display: "flex",
|
|
|
- alignItems: "center",
|
|
|
- padding: "9px 10px",
|
|
|
- cursor: isLoading ? "wait" : "pointer",
|
|
|
- opacity: isLoading ? 0.7 : 1,
|
|
|
- // pointerEvents: isLoading ? "none" : "auto",
|
|
|
- userSelect: "none",
|
|
|
- WebkitUserSelect: "none",
|
|
|
- MozUserSelect: "none",
|
|
|
- msUserSelect: "none",
|
|
|
- }}
|
|
|
- className={`${isLoading ? "animate-pulse" : ""}`}
|
|
|
- onClick={isLoading ? undefined : onToggleExpand}>
|
|
|
+ <ToolUseBlock>
|
|
|
+ {hasHeader && (
|
|
|
+ <ToolUseBlockHeader onClick={onToggleExpand}>
|
|
|
{isLoading && <VSCodeProgressRing className="size-3 mr-2" />}
|
|
|
- {isFeedback || isConsoleLogs ? (
|
|
|
- <div style={{ display: "flex", alignItems: "center" }}>
|
|
|
- <span
|
|
|
- className={`codicon codicon-${isFeedback ? "feedback" : "output"}`}
|
|
|
- style={{ marginRight: "6px" }}></span>
|
|
|
- <span
|
|
|
- style={{
|
|
|
- whiteSpace: "nowrap",
|
|
|
- overflow: "hidden",
|
|
|
- textOverflow: "ellipsis",
|
|
|
- marginRight: "8px",
|
|
|
- }}>
|
|
|
+ {isFeedback ? (
|
|
|
+ <div className="flex items-center">
|
|
|
+ <span className={`codicon codicon-${isFeedback ? "feedback" : "codicon-output"} mr-1.5`} />
|
|
|
+ <span className="whitespace-nowrap overflow-hidden text-ellipsis mr-2 rtl">
|
|
|
{isFeedback ? "User Edits" : "Console Logs"}
|
|
|
</span>
|
|
|
</div>
|
|
|
) : (
|
|
|
<>
|
|
|
{path?.startsWith(".") && <span>.</span>}
|
|
|
- <span
|
|
|
- style={{
|
|
|
- whiteSpace: "nowrap",
|
|
|
- overflow: "hidden",
|
|
|
- textOverflow: "ellipsis",
|
|
|
- marginRight: "8px",
|
|
|
- // trick to get ellipsis at beginning of string
|
|
|
- direction: "rtl",
|
|
|
- textAlign: "left",
|
|
|
- }}>
|
|
|
+ <span className="whitespace-nowrap overflow-hidden text-ellipsis text-left mr-2 rtl">
|
|
|
{removeLeadingNonAlphanumeric(path ?? "") + "\u200E"}
|
|
|
</span>
|
|
|
</>
|
|
|
)}
|
|
|
- <div style={{ flexGrow: 1 }}></div>
|
|
|
+ <div className="flex-grow-1" />
|
|
|
{progressStatus && progressStatus.text && (
|
|
|
<>
|
|
|
{progressStatus.icon && <span className={`codicon codicon-${progressStatus.icon} mr-1`} />}
|
|
|
@@ -113,24 +63,17 @@ const CodeAccordian = ({
|
|
|
</>
|
|
|
)}
|
|
|
<span className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span>
|
|
|
- </div>
|
|
|
+ </ToolUseBlockHeader>
|
|
|
)}
|
|
|
- {(!(path || isFeedback || isConsoleLogs) || isExpanded) && (
|
|
|
- <div
|
|
|
- style={{
|
|
|
- overflowX: "auto",
|
|
|
- overflowY: "hidden",
|
|
|
- maxWidth: "100%",
|
|
|
- }}>
|
|
|
- <CodeBlock
|
|
|
- source={(code ?? diff ?? "").trim()}
|
|
|
- language={diff !== undefined ? "diff" : inferredLanguage}
|
|
|
- />
|
|
|
+ {(!hasHeader || isExpanded) && (
|
|
|
+ <div className="overflow-x-auto overflow-y-hidden max-w-full">
|
|
|
+ <CodeBlock source={source} language={inferredLanguage} />
|
|
|
</div>
|
|
|
)}
|
|
|
- </div>
|
|
|
+ </ToolUseBlock>
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-// memo does shallow comparison of props, so if you need it to re-render when a nested object changes, you need to pass a custom comparison function
|
|
|
+// Memo does shallow comparison of props, so if you need it to re-render when a
|
|
|
+// nested object changes, you need to pass a custom comparison function.
|
|
|
export default memo(CodeAccordian)
|