feat: update terminal theme without remounting the xterm instance

This commit is contained in:
Mohamed Boudra
2026-03-04 13:29:47 +07:00
parent 4f1783fc76
commit b21764fd40
3 changed files with 88 additions and 3 deletions
@@ -6,6 +6,9 @@ type StubTerminal = {
write: (text: string, callback?: () => void) => void;
reset: () => void;
focus: () => void;
refresh?: (start: number, end: number) => void;
options?: { theme?: unknown };
rows?: number;
};
function createRuntimeWithTerminal(): {
@@ -33,6 +36,9 @@ function createRuntimeWithTerminal(): {
terminal.resetCalls = resetCalls;
},
focus: () => {},
refresh: () => {},
options: { theme: undefined },
rows: 0,
resetCalls,
};
@@ -171,4 +177,23 @@ describe("terminal-emulator-runtime", () => {
expect(fitAndEmitResize).toHaveBeenNthCalledWith(1, false);
expect(fitAndEmitResize).toHaveBeenNthCalledWith(2, true);
});
it("updates terminal theme without remounting", () => {
const runtime = new TerminalEmulatorRuntime();
const refresh = vi.fn();
const terminal: StubTerminal = {
write: () => {},
reset: () => {},
focus: () => {},
refresh,
options: { theme: { background: "before" } },
rows: 12,
};
(runtime as unknown as { terminal: StubTerminal }).terminal = terminal;
runtime.setTheme({ theme: { background: "after" } as never });
expect(terminal.options?.theme).toEqual({ background: "after" });
expect(refresh).toHaveBeenCalledWith(0, 11);
});
});
@@ -464,6 +464,30 @@ export class TerminalEmulatorRuntime {
this.fitAndEmitResize?.(input?.force ?? false);
}
setTheme(input: { theme: ITheme }): void {
const terminal = this.terminal;
if (!terminal) {
return;
}
try {
terminal.options.theme = input.theme;
terminalDebugLog({
scope: "emulator-runtime",
event: "theme:update",
});
} catch {
// ignore
return;
}
try {
terminal.refresh(0, Math.max(0, terminal.rows - 1));
} catch {
// ignore
}
}
focus(): void {
this.terminal?.focus();
}