Skip to content

Commit 60270d1

Browse files
authored
Revert "feat: syntax highlighting terminal output with Shiki" (#3023)
Revert "feat: syntax highlighting terminal output with Shiki (#3021)" This reverts commit 8b072ad.
1 parent 81e01a9 commit 60270d1

File tree

3 files changed

+66
-64
lines changed

3 files changed

+66
-64
lines changed
Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,55 @@
1-
import { forwardRef, useState } from "react"
2-
import { useTranslation } from "react-i18next"
1+
import { HTMLAttributes, forwardRef, useMemo, useState } from "react"
2+
import { Virtuoso } from "react-virtuoso"
3+
import { ChevronDown } from "lucide-react"
34

45
import { useExtensionState } from "@src/context/ExtensionStateContext"
5-
import { BaseTerminal } from "../../../../src/integrations/terminal/BaseTerminal"
6-
import CodeBlock, { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock"
6+
import { cn } from "@src/lib/utils"
77

88
interface CommandExecutionProps {
99
command: string
1010
output: string
1111
}
1212

1313
export const CommandExecution = forwardRef<HTMLDivElement, CommandExecutionProps>(({ command, output }, ref) => {
14-
const { t } = useTranslation()
15-
const { terminalShellIntegrationDisabled = false, terminalOutputLineLimit = 500 } = useExtensionState()
14+
const { terminalShellIntegrationDisabled = false } = useExtensionState()
15+
16+
// If we aren't opening the VSCode terminal for this command then we default
17+
// to expanding the command execution output.
1618
const [isExpanded, setIsExpanded] = useState(terminalShellIntegrationDisabled)
17-
const compressedOutput = BaseTerminal.compressTerminalOutput(output, terminalOutputLineLimit)
1819

19-
const onToggleExpand = () => {
20-
setIsExpanded(!isExpanded)
21-
}
20+
const lines = useMemo(() => output.split("\n"), [output])
2221

2322
return (
24-
<>
23+
<div ref={ref} className="w-full p-2 rounded-xs bg-vscode-editor-background">
2524
<div
26-
ref={ref}
27-
style={{
28-
borderRadius: 3,
29-
border: "1px solid var(--vscode-editorGroup-border)",
30-
overflow: "hidden",
31-
backgroundColor: CODE_BLOCK_BG_COLOR,
32-
}}>
33-
<CodeBlock source={command} language="shell" />
34-
{output.length > 0 && (
35-
<div style={{ width: "100%" }}>
36-
<div
37-
onClick={onToggleExpand}
38-
style={{
39-
display: "flex",
40-
alignItems: "center",
41-
gap: "4px",
42-
width: "100%",
43-
justifyContent: "flex-start",
44-
cursor: "pointer",
45-
padding: `2px 8px ${isExpanded ? 0 : 8}px 8px`,
46-
}}>
47-
<span className={`codicon codicon-chevron-${isExpanded ? "down" : "right"}`}></span>
48-
<span style={{ fontSize: "0.8em" }}>{t("chat:commandOutput")}</span>
49-
</div>
50-
{isExpanded && <CodeBlock source={compressedOutput} language="log" />}
51-
</div>
52-
)}
25+
className={cn("flex flex-row justify-between cursor-pointer active:opacity-75", {
26+
"opacity-50": isExpanded,
27+
})}
28+
onClick={() => setIsExpanded(!isExpanded)}>
29+
<Line>{command}</Line>
30+
<ChevronDown className={cn("size-4 transition-transform duration-300", { "rotate-180": isExpanded })} />
31+
</div>
32+
<div className={cn("h-[200px]", { hidden: !isExpanded })}>
33+
<Virtuoso
34+
className="h-full mt-2"
35+
totalCount={lines.length}
36+
itemContent={(i) => <Line>{lines[i]}</Line>}
37+
followOutput="auto"
38+
/>
5339
</div>
54-
</>
40+
</div>
5541
)
5642
})
5743

44+
type LineProps = HTMLAttributes<HTMLDivElement>
45+
46+
const Line = ({ className, ...props }: LineProps) => {
47+
return (
48+
<div
49+
className={cn("font-mono text-vscode-editor-foreground whitespace-pre-wrap break-words", className)}
50+
{...props}
51+
/>
52+
)
53+
}
54+
5855
CommandExecution.displayName = "CommandExecution"
Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
// npx jest src/components/chat/__tests__/CommandExecution.test.tsx
22

33
import React from "react"
4-
import { render, screen, fireEvent } from "@testing-library/react"
4+
import { render, screen } from "@testing-library/react"
55

66
import { ExtensionStateContextProvider } from "@src/context/ExtensionStateContext"
77

88
import { CommandExecution } from "../CommandExecution"
99

10-
jest.mock("../../../components/common/CodeBlock")
11-
1210
jest.mock("@src/lib/utils", () => ({
1311
cn: (...inputs: any[]) => inputs.filter(Boolean).join(" "),
1412
}))
1513

14+
jest.mock("lucide-react", () => ({
15+
ChevronDown: () => <div data-testid="chevron-down">ChevronDown</div>,
16+
}))
17+
18+
jest.mock("react-virtuoso", () => ({
19+
Virtuoso: React.forwardRef(({ totalCount, itemContent }: any, ref: any) => (
20+
<div ref={ref} data-testid="virtuoso-container">
21+
{Array.from({ length: totalCount }).map((_, index) => (
22+
<div key={index} data-testid={`virtuoso-item-${index}`}>
23+
{itemContent(index)}
24+
</div>
25+
))}
26+
</div>
27+
)),
28+
VirtuosoHandle: jest.fn(),
29+
}))
30+
1631
describe("CommandExecution", () => {
1732
const renderComponent = (command: string, output: string) => {
1833
return render(
@@ -25,34 +40,24 @@ describe("CommandExecution", () => {
2540
it("renders command output with virtualized list", () => {
2641
const testOutput = "Line 1\nLine 2\nLine 3"
2742
renderComponent("ls", testOutput)
28-
const codeBlock = screen.getByTestId("mock-code-block")
29-
expect(codeBlock).toHaveTextContent("ls")
30-
31-
fireEvent.click(screen.getByText("commandOutput"))
32-
const outputBlock = screen.getAllByTestId("mock-code-block")[1]
33-
34-
expect(outputBlock).toHaveTextContent("Line 1")
35-
expect(outputBlock).toHaveTextContent("Line 2")
36-
expect(outputBlock).toHaveTextContent("Line 3")
43+
expect(screen.getByTestId("virtuoso-container")).toBeInTheDocument()
44+
expect(screen.getByText("Line 1")).toBeInTheDocument()
45+
expect(screen.getByText("Line 2")).toBeInTheDocument()
46+
expect(screen.getByText("Line 3")).toBeInTheDocument()
3747
})
3848

3949
it("handles empty output", () => {
4050
renderComponent("ls", "")
41-
const codeBlock = screen.getByTestId("mock-code-block")
42-
expect(codeBlock).toHaveTextContent("ls")
43-
expect(screen.queryByText("commandOutput")).not.toBeInTheDocument()
44-
expect(screen.queryAllByTestId("mock-code-block")).toHaveLength(1)
51+
expect(screen.getByTestId("virtuoso-container")).toBeInTheDocument()
52+
expect(screen.getByTestId("virtuoso-item-0")).toBeInTheDocument()
53+
expect(screen.queryByTestId("virtuoso-item-1")).not.toBeInTheDocument()
4554
})
4655

4756
it("handles large output", () => {
4857
const largeOutput = Array.from({ length: 1000 }, (_, i) => `Line ${i + 1}`).join("\n")
4958
renderComponent("ls", largeOutput)
50-
const codeBlock = screen.getByTestId("mock-code-block")
51-
expect(codeBlock).toHaveTextContent("ls")
52-
53-
fireEvent.click(screen.getByText("commandOutput"))
54-
const outputBlock = screen.getAllByTestId("mock-code-block")[1]
55-
expect(outputBlock).toHaveTextContent("Line 1")
56-
expect(outputBlock).toHaveTextContent("Line 1000")
59+
expect(screen.getByTestId("virtuoso-container")).toBeInTheDocument()
60+
expect(screen.getByText("Line 1")).toBeInTheDocument()
61+
expect(screen.getByText("Line 1000")).toBeInTheDocument()
5762
})
5863
})
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import * as React from "react"
22

33
interface CodeBlockProps {
4-
source?: string
4+
children?: React.ReactNode
55
language?: string
66
}
77

8-
const CodeBlock: React.FC<CodeBlockProps> = ({ source = "" }) => <div data-testid="mock-code-block">{source}</div>
8+
const CodeBlock: React.FC<CodeBlockProps> = () => <div data-testid="mock-code-block">Mocked Code Block</div>
99

1010
export default CodeBlock

0 commit comments

Comments
 (0)