Files
paseo/packages/app/src/utils/diff-highlight.test.ts
T
Mohamed BoudraandGitHub 38f0560f9b Syntax-highlight Edit, Write, and Read tool calls (#1218)
Highlighting reuses the existing code-block tokenizer and LRU cache, runs
lazily on expand, and falls back to plain text above a size cap so a large
Read can't stall the main thread. The diff highlighter reconstructs the old
and new file text by position rather than from @@ line ranges, so diffs that
arrive without real hunk headers still highlight.

Read content is normalized server-side: the cat -n line-number gutter some
providers emit is stripped so content is uniformly raw source, with the first
line number surfaced as offset for the client to rebuild the gutter.
2026-05-29 14:51:14 +08:00

54 lines
2.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { highlightDiffLines } from "./diff-highlight";
import { buildLineDiff, parseUnifiedDiff, type DiffLine } from "./tool-call-parsers";
function joinTokens(line: DiffLine): string {
return (line.tokens ?? []).map((token) => token.text).join("");
}
describe("highlightDiffLines", () => {
it("attaches tokens to add/remove/context lines for a supported language", () => {
const diff = buildLineDiff("const a = 1;\nconst b = 2;", "const a = 1;\nconst b = 3;");
const result = highlightDiffLines(diff, "/repo/src/index.ts");
const context = result.find((line) => line.type === "context");
const remove = result.find((line) => line.type === "remove");
const add = result.find((line) => line.type === "add");
expect(context?.tokens).toBeDefined();
expect(remove?.tokens).toBeDefined();
expect(add?.tokens).toBeDefined();
// Tokens reconstruct the code with the diff marker excluded.
expect(joinTokens(context as DiffLine)).toBe("const a = 1;");
expect(joinTokens(remove as DiffLine)).toBe("const b = 2;");
expect(joinTokens(add as DiffLine)).toBe("const b = 3;");
// A keyword token is recognised (proves real highlighting, not pass-through).
expect(add?.tokens?.some((token) => token.style === "keyword")).toBe(true);
});
it("highlights a Codex-style unified diff with bare @@ headers (no line ranges)", () => {
const unified = ["@@", "-const x = 1;", "+const x = 2;", " const y = 3;"].join("\n");
const result = highlightDiffLines(parseUnifiedDiff(unified), "/repo/a.ts");
const remove = result.find((line) => line.type === "remove");
const add = result.find((line) => line.type === "add");
const context = result.find((line) => line.type === "context");
expect(joinTokens(remove as DiffLine)).toBe("const x = 1;");
expect(joinTokens(add as DiffLine)).toBe("const x = 2;");
expect(joinTokens(context as DiffLine)).toBe("const y = 3;");
expect(result.find((line) => line.type === "header")?.tokens).toBeUndefined();
});
it("returns lines unchanged for an unsupported language", () => {
const diff = buildLineDiff("a", "b");
const result = highlightDiffLines(diff, "/repo/notes.unknownext");
expect(result).toBe(diff);
expect(result.every((line) => line.tokens === undefined)).toBe(true);
});
it("returns lines unchanged when there is no file path", () => {
const diff = buildLineDiff("a", "b");
expect(highlightDiffLines(diff, undefined)).toBe(diff);
});
});