perf(coding-agent): bound completed diff rendering

This commit is contained in:
Aleksandr Khaustov
2026-08-15 20:39:36 +04:00
parent ffd53ff92a
commit 006c5371ea
5 changed files with 171 additions and 25 deletions
@@ -255,6 +255,19 @@ describe("editToolRenderer", () => {
it("caches completed diff rendering across stable frame renders", async () => {
const uiTheme = await getUiTheme();
let renderDiffCalls = 0;
let statsColorCalls = 0;
const countingTheme = new Proxy(uiTheme, {
get(target, property) {
if (property === "fg") {
return (color: Parameters<themeModule.Theme["fg"]>[0], text: string): string => {
if (color === "toolDiffAdded" && text === "+1") statsColorCalls++;
return target.fg(color, text);
};
}
const value = Reflect.get(target, property, target) as unknown;
return typeof value === "function" ? value.bind(target) : value;
},
});
const options = {
expanded: false,
isPartial: false,
@@ -275,17 +288,19 @@ describe("editToolRenderer", () => {
},
},
options,
uiTheme,
countingTheme,
{ file_path: "src/example.ts" },
);
component.render(160);
component.render(120);
expect(renderDiffCalls).toBe(1);
expect(statsColorCalls).toBe(1);
options.expanded = true;
component.render(120);
expect(renderDiffCalls).toBe(2);
expect(statsColorCalls).toBe(1);
});
it("computes the hashline preview diff once a single-line edit finishes streaming", async () => {
@@ -420,6 +435,27 @@ describe("editToolRenderer", () => {
expect(lines.filter(line => line.includes("+2/-1"))).toHaveLength(1);
});
it("bounds a completed diff that contains one oversized change hunk", async () => {
const uiTheme = await getUiTheme();
const diff = Array.from({ length: 1_000 }, (_, i) => `+${i + 1}│line ${i}`).join("\n");
const component = editToolRenderer.renderResult(
{
content: [{ type: "text", text: "Updated demo.ts" }],
details: { diff, op: "update" },
},
{ expanded: false, isPartial: false, renderContext: { editMode: "hashline" } },
uiTheme,
{ file_path: "demo.ts" },
);
const lines = component.render(160).map(line => Bun.stripANSI(line));
const rendered = lines.join("\n");
expect(lines.filter(line => line.includes("│line "))).toHaveLength(40);
expect(rendered).toContain("+40│line 39");
expect(rendered).not.toContain("+41│line 40");
expect(rendered).toContain("960 more lines");
});
it("renders completed edit gutters without inherited frame padding", async () => {
const uiTheme = await getUiTheme();
const component = editToolRenderer.renderResult(
@@ -286,6 +286,75 @@ describe("truncateDiffByHunk", () => {
expect(idxOld).toBeLessThan(idxNew);
expect(idxNew).toBeLessThan(idxTrailing);
});
it("caps one oversized change hunk at the line budget", () => {
const diff = makeHunk("+", 0, 1_000).join("\n");
const head = truncateDiffByHunk(diff, 4, 32);
const tail = truncateDiffByHunk(diff, 4, 32, { fromTail: true });
expect(head.text.split("\n")).toHaveLength(32);
expect(head.text).toStartWith("+ new 0\n");
expect(head.text).toEndWith("+ new 31");
expect(head.hiddenLines).toBe(968);
expect(head.hiddenHunks).toBe(0);
expect(tail.text.split("\n")).toHaveLength(32);
expect(tail.text).toStartWith("+ new 968\n");
expect(tail.text).toEndWith("+ new 999");
expect(tail.hiddenLines).toBe(968);
expect(tail.hiddenHunks).toBe(0);
});
it("keeps an exact-size change hunk unchanged", () => {
const diff = makeHunk("-", 0, 32).join("\n");
expect(truncateDiffByHunk(diff, 4, 32)).toEqual({
text: diff,
hiddenHunks: 0,
hiddenLines: 0,
});
});
it("drops surrounding context when changes exactly fill the line budget", () => {
const diff = [" leading context", ...makeHunk("+", 0, 32), " trailing context"].join("\n");
for (const result of [truncateDiffByHunk(diff, 4, 32), truncateDiffByHunk(diff, 4, 32, { fromTail: true })]) {
expect(result.text.split("\n")).toHaveLength(32);
expect(result.text).not.toContain("context");
expect(result.hiddenLines).toBe(2);
expect(result.hiddenHunks).toBe(0);
}
});
it("does not exceed the line budget when context rounding spans multiple hunks", () => {
const diff = [
" leading context",
...makeHunk("+", 0, 15),
" middle context a",
" middle context b",
...makeHunk("-", 100, 15),
" trailing context",
].join("\n");
for (const result of [truncateDiffByHunk(diff, 4, 32), truncateDiffByHunk(diff, 4, 32, { fromTail: true })]) {
expect(result.text.split("\n")).toHaveLength(32);
expect(result.hiddenLines).toBe(2);
expect(result.hiddenHunks).toBe(0);
}
});
it("does not count a removed separator as a hidden hunk", () => {
const diff = [...makeHunk("+", 0, 16), " hunk separator", ...makeHunk("-", 100, 16)].join("\n");
for (const result of [truncateDiffByHunk(diff, 4, 32), truncateDiffByHunk(diff, 4, 32, { fromTail: true })]) {
expect(result.text.split("\n")).toHaveLength(32);
expect(result.hiddenLines).toBe(1);
expect(result.hiddenHunks).toBe(0);
}
});
it("reports every hunk excluded by the hunk limit", () => {
const diff = buildDiff(6, 1);
for (const result of [truncateDiffByHunk(diff, 2, 100), truncateDiffByHunk(diff, 2, 100, { fromTail: true })]) {
expect(result.hiddenHunks).toBe(4);
}
});
});
describe("formatErrorMessage (F4 sanitization)", () => {