mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
Codemode and write rows keep their last highlighting in a CodeHighlighter that checks theme and grammar changes itself. Markdown reuses the top-level blocks of its last render, held weakly, and assistant messages reuse their Markdown instances while streaming. Text.setText() keeps its wrapped lines for unchanged text. closes #10971
71 lines
2.9 KiB
TypeScript
71 lines
2.9 KiB
TypeScript
import type { TUI } from "@earendil-works/pi-tui";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { writeRenderers } from "../src/core/tools/renderers/write.ts";
|
|
import { codemodeRenderers } from "../src/extensions/codemode/renderer.ts";
|
|
import { ToolExecutionComponent } from "../src/modes/interactive/components/tool-execution.ts";
|
|
import { CodeHighlighter, highlightCode, initTheme } from "../src/modes/interactive/theme/theme.ts";
|
|
import * as syntaxHighlight from "../src/utils/syntax-highlight.ts";
|
|
|
|
const tui = { requestRender: () => {} } as unknown as TUI;
|
|
|
|
describe("CodeHighlighter", () => {
|
|
beforeEach(() => initTheme("dark"));
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it("reuses its last result until the code, the theme or the grammars change", async () => {
|
|
const code = 'const page = html`<div class="x">ok</div>`;';
|
|
const highlighter = new CodeHighlighter();
|
|
const first = highlighter.highlight(code, "javascript");
|
|
expect(highlighter.highlight(code, "javascript")).toBe(first);
|
|
expect(highlighter.highlight("const a = 1;", "javascript")).not.toBe(first);
|
|
|
|
initTheme("light");
|
|
expect(highlighter.highlight(code, "javascript")).toEqual(highlightCode(code, "javascript"));
|
|
const light = highlighter.highlight(code, "javascript");
|
|
await syntaxHighlight.loadAllHighlightLanguages();
|
|
expect(highlighter.highlight(code, "javascript")).not.toEqual(light);
|
|
});
|
|
|
|
it("codemode highlights the script once across progress, timer ticks, expanding and completion", () => {
|
|
vi.useFakeTimers();
|
|
const highlight = vi.spyOn(syntaxHighlight, "highlight");
|
|
const row = new ToolExecutionComponent(
|
|
"codemode",
|
|
"c",
|
|
{ code: "await tools.read({});" },
|
|
{},
|
|
codemodeRenderers,
|
|
tui,
|
|
"/",
|
|
);
|
|
row.setArgsComplete();
|
|
row.markExecutionStarted();
|
|
row.updateResult({ content: [], details: { calls: [] }, isError: false }, true);
|
|
vi.advanceTimersByTime(2_000);
|
|
row.setExpanded(true);
|
|
row.updateResult({ content: [{ type: "text", text: "done" }], details: { calls: [] }, isError: false }, false);
|
|
row.render(80);
|
|
expect(highlight).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("write highlights unchanged first lines and a complete file only once", () => {
|
|
const content = Array.from({ length: 60 }, (_, i) => `const v${i} = ${i};`).join("\n");
|
|
const row = new ToolExecutionComponent("write", "w", { path: "a.ts", content }, {}, writeRenderers, tui, "/");
|
|
row.updateArgs({ path: "a.ts", content: `${content} //` });
|
|
row.render(80);
|
|
const highlight = vi.spyOn(syntaxHighlight, "highlight");
|
|
// Only the changed last line is highlighted again.
|
|
row.updateArgs({ path: "a.ts", content: `${content} // more` });
|
|
row.render(80);
|
|
expect(highlight).toHaveBeenCalledTimes(1);
|
|
|
|
row.setArgsComplete();
|
|
row.setExpanded(true);
|
|
row.setExpanded(false);
|
|
row.render(80);
|
|
expect(highlight).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|