diff --git a/packages/cli/src/ui/utils/CodeColorizer.test.tsx b/packages/cli/src/ui/utils/CodeColorizer.test.tsx
index 2f231e1bb3..7fc120b58b 100644
--- a/packages/cli/src/ui/utils/CodeColorizer.test.tsx
+++ b/packages/cli/src/ui/utils/CodeColorizer.test.tsx
@@ -50,4 +50,36 @@ describe('colorizeCode', () => {
expect(lastFrame()).toMatch(/line 1\s*\n\s*\n\s*line 3/);
unmount();
});
+
+ it('does not let colors from ansi escape codes leak into colorized code', async () => {
+ const code = 'line 1\n\x1b[41mline 2 with red background\x1b[0m\nline 3';
+ const settings = new LoadedSettings(
+ { path: '', settings: {}, originalSettings: {} },
+ { path: '', settings: {}, originalSettings: {} },
+ {
+ path: '',
+ settings: { ui: { useAlternateBuffer: true, showLineNumbers: false } },
+ originalSettings: {
+ ui: { useAlternateBuffer: true, showLineNumbers: false },
+ },
+ },
+ { path: '', settings: {}, originalSettings: {} },
+ true,
+ [],
+ );
+
+ const result = colorizeCode({
+ code,
+ language: 'javascript',
+ maxWidth: 80,
+ settings,
+ hideLineNumbers: true,
+ });
+
+ const renderResult = renderWithProviders(<>{result}>);
+ await renderResult.waitUntilReady();
+
+ await expect(renderResult).toMatchSvgSnapshot();
+ renderResult.unmount();
+ });
});
diff --git a/packages/cli/src/ui/utils/CodeColorizer.tsx b/packages/cli/src/ui/utils/CodeColorizer.tsx
index 56e34eefa4..e5ce2562af 100644
--- a/packages/cli/src/ui/utils/CodeColorizer.tsx
+++ b/packages/cli/src/ui/utils/CodeColorizer.tsx
@@ -14,6 +14,7 @@ import type {
ElementContent,
RootContent,
} from 'hast';
+import stripAnsi from 'strip-ansi';
import { themeManager } from '../themes/theme-manager.js';
import type { Theme } from '../themes/theme.js';
import {
@@ -98,16 +99,17 @@ function highlightAndRenderLine(
theme: Theme,
): React.ReactNode {
try {
+ const strippedLine = stripAnsi(line);
const getHighlightedLine = () =>
!language || !lowlight.registered(language)
- ? lowlight.highlightAuto(line)
- : lowlight.highlight(language, line);
+ ? lowlight.highlightAuto(strippedLine)
+ : lowlight.highlight(language, strippedLine);
const renderedNode = renderHastNode(getHighlightedLine(), theme, undefined);
- return renderedNode !== null ? renderedNode : line;
+ return renderedNode !== null ? renderedNode : strippedLine;
} catch (_error) {
- return line;
+ return stripAnsi(line);
}
}
@@ -238,7 +240,7 @@ export function colorizeCode({
{`${index + 1}`}
)}
- {line}
+ {stripAnsi(line)}
));
diff --git a/packages/cli/src/ui/utils/__snapshots__/CodeColorizer-colorizeCode-does-not-let-colors-from-ansi-escape-codes-leak-into-colorized-code.snap.svg b/packages/cli/src/ui/utils/__snapshots__/CodeColorizer-colorizeCode-does-not-let-colors-from-ansi-escape-codes-leak-into-colorized-code.snap.svg
new file mode 100644
index 0000000000..04b774eb58
--- /dev/null
+++ b/packages/cli/src/ui/utils/__snapshots__/CodeColorizer-colorizeCode-does-not-let-colors-from-ansi-escape-codes-leak-into-colorized-code.snap.svg
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/packages/cli/src/ui/utils/__snapshots__/CodeColorizer.test.tsx.snap b/packages/cli/src/ui/utils/__snapshots__/CodeColorizer.test.tsx.snap
new file mode 100644
index 0000000000..c348c6ef50
--- /dev/null
+++ b/packages/cli/src/ui/utils/__snapshots__/CodeColorizer.test.tsx.snap
@@ -0,0 +1,7 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`colorizeCode > does not let colors from ansi escape codes leak into colorized code 1`] = `
+"line 1
+line 2 with red background
+line 3"
+`;