diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 7136b79bd..d28d8eed8 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed fenced `diff` code blocks and other highlight.js scopes to keep theme-aware syntax colors after the `cli-highlight` replacement ([#5092](https://github.com/earendil-works/pi/issues/5092)). + ## [0.76.0] - 2026-05-27 ### New Features diff --git a/packages/coding-agent/src/modes/interactive/theme/theme.ts b/packages/coding-agent/src/modes/interactive/theme/theme.ts index d9bcdf8c2..8bdf4816b 100644 --- a/packages/coding-agent/src/modes/interactive/theme/theme.ts +++ b/packages/coding-agent/src/modes/interactive/theme/theme.ts @@ -1042,17 +1042,27 @@ function buildCliHighlightTheme(t: Theme): CliHighlightTheme { built_in: (s: string) => t.fg("syntaxType", s), literal: (s: string) => t.fg("syntaxNumber", s), number: (s: string) => t.fg("syntaxNumber", s), + regexp: (s: string) => t.fg("syntaxString", s), string: (s: string) => t.fg("syntaxString", s), comment: (s: string) => t.fg("syntaxComment", s), + doctag: (s: string) => t.fg("syntaxComment", s), + meta: (s: string) => t.fg("muted", s), function: (s: string) => t.fg("syntaxFunction", s), title: (s: string) => t.fg("syntaxFunction", s), class: (s: string) => t.fg("syntaxType", s), type: (s: string) => t.fg("syntaxType", s), + tag: (s: string) => t.fg("syntaxPunctuation", s), + name: (s: string) => t.fg("syntaxKeyword", s), attr: (s: string) => t.fg("syntaxVariable", s), variable: (s: string) => t.fg("syntaxVariable", s), params: (s: string) => t.fg("syntaxVariable", s), operator: (s: string) => t.fg("syntaxOperator", s), punctuation: (s: string) => t.fg("syntaxPunctuation", s), + emphasis: (s: string) => t.italic(s), + strong: (s: string) => t.bold(s), + link: (s: string) => t.underline(s), + addition: (s: string) => t.fg("toolDiffAdded", s), + deletion: (s: string) => t.fg("toolDiffRemoved", s), }; } diff --git a/packages/coding-agent/test/syntax-highlight.test.ts b/packages/coding-agent/test/syntax-highlight.test.ts index 92d8aa391..6f311e494 100644 --- a/packages/coding-agent/test/syntax-highlight.test.ts +++ b/packages/coding-agent/test/syntax-highlight.test.ts @@ -1,4 +1,6 @@ -import { describe, expect, it } from "vitest"; +import { resetCapabilitiesCache, setCapabilities } from "@earendil-works/pi-tui"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { highlightCode, initTheme } from "../src/modes/interactive/theme/theme.ts"; import { highlight, renderHighlightedHtml, supportsLanguage } from "../src/utils/syntax-highlight.ts"; describe("syntax highlight renderer", () => { @@ -46,3 +48,29 @@ describe("syntax highlight renderer", () => { expect(rendered).toContain("[number:1]"); }); }); + +describe("theme syntax highlighting", () => { + beforeEach(() => { + setCapabilities({ images: null, trueColor: true, hyperlinks: false }); + initTheme("dark"); + }); + + afterEach(() => { + resetCapabilitiesCache(); + }); + + it("colors diff additions and deletions in fenced diff blocks", () => { + const lines = highlightCode("-old\n+new\n", "diff"); + + expect(lines[0]).toBe("\x1b[38;2;204;102;102m-old\x1b[39m"); + expect(lines[1]).toBe("\x1b[38;2;181;189;104m+new\x1b[39m"); + }); + + it("keeps cli-highlight default styled scopes mapped to theme styles", () => { + expect(highlightCode("const re = /foo+/gi;", "javascript")[0]).toContain( + "\x1b[38;2;206;145;120m/foo+/gi\x1b[39m", + ); + expect(highlightCode("@decorator", "python")[0]).toBe("\x1b[38;2;128;128;128m@decorator\x1b[39m"); + expect(highlightCode("
", "html")[0]).toContain("\x1b[38;2;86;156;214mdiv\x1b[39m"); + }); +});