Make terminal scrollback configurable (#1021)
* Make terminal scrollback configurable * Fix terminal scrollback lint violation * Fix terminal runtime test environment split * Fix terminal scrollback updates --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
@@ -61,7 +61,11 @@ async function waitFor(input: { predicate: () => boolean; timeoutMs?: number }):
|
||||
}
|
||||
}
|
||||
|
||||
function createTerminalHost(input: { width: number; height: number }): MountedTerminal {
|
||||
function createTerminalHost(input: {
|
||||
width: number;
|
||||
height: number;
|
||||
scrollback?: number;
|
||||
}): MountedTerminal {
|
||||
const root = document.createElement("div");
|
||||
root.style.width = `${input.width}px`;
|
||||
root.style.height = `${input.height}px`;
|
||||
@@ -101,6 +105,7 @@ function createTerminalHost(input: { width: number; height: number }): MountedTe
|
||||
root,
|
||||
host,
|
||||
initialSnapshot: null,
|
||||
scrollback: input.scrollback ?? 10_000,
|
||||
theme: {
|
||||
background: "#0b0b0b",
|
||||
foreground: "#e6e6e6",
|
||||
@@ -163,6 +168,32 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("terminal emulator runtime in a real browser", () => {
|
||||
it("passes configured scrollback to xterm", async () => {
|
||||
await page.viewport(900, 600);
|
||||
createTerminalHost({ width: 720, height: 360, scrollback: 42_000 });
|
||||
|
||||
await waitFor({
|
||||
predicate: () => window.__paseoTerminal !== undefined,
|
||||
});
|
||||
|
||||
expect(window.__paseoTerminal?.options.scrollback).toBe(42_000);
|
||||
});
|
||||
|
||||
it("updates scrollback on the mounted xterm", async () => {
|
||||
await page.viewport(900, 600);
|
||||
const mounted = createTerminalHost({ width: 720, height: 360, scrollback: 10_000 });
|
||||
|
||||
await waitFor({
|
||||
predicate: () => window.__paseoTerminal !== undefined,
|
||||
});
|
||||
const terminal = window.__paseoTerminal;
|
||||
|
||||
mounted.runtime.setScrollback({ lines: 42_000 });
|
||||
|
||||
expect(window.__paseoTerminal).toBe(terminal);
|
||||
expect(window.__paseoTerminal?.options.scrollback).toBe(42_000);
|
||||
});
|
||||
|
||||
it("reports a larger PTY size when the terminal container grows", async () => {
|
||||
await page.viewport(900, 600);
|
||||
const mounted = createTerminalHost({ width: 360, height: 180 });
|
||||
|
||||
@@ -49,9 +49,29 @@ vi.mock("@xterm/addon-webgl", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const terminalConstructorOptions = vi.hoisted(() => ({
|
||||
values: [] as unknown[],
|
||||
}));
|
||||
|
||||
vi.mock("@xterm/xterm", () => ({
|
||||
Terminal: class Terminal {
|
||||
rows = 24;
|
||||
cols = 80;
|
||||
unicode = { activeVersion: "" };
|
||||
parser = {
|
||||
registerCsiHandler: () => undefined,
|
||||
};
|
||||
constructor(options: unknown) {
|
||||
terminalConstructorOptions.values.push(options);
|
||||
}
|
||||
loadAddon(): void {}
|
||||
open(): void {}
|
||||
onData(): { dispose: () => void } {
|
||||
return { dispose: () => undefined };
|
||||
}
|
||||
attachCustomKeyEventHandler(): void {}
|
||||
dispose(): void {}
|
||||
refresh(): void {}
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -63,7 +83,7 @@ interface StubTerminal {
|
||||
resize?: (cols: number, rows: number) => void;
|
||||
focus: () => void;
|
||||
refresh?: (start: number, end: number) => void;
|
||||
options?: { theme?: unknown };
|
||||
options?: { theme?: unknown; scrollback?: number };
|
||||
rows?: number;
|
||||
cols?: number;
|
||||
}
|
||||
@@ -118,6 +138,7 @@ describe("terminal-emulator-runtime", () => {
|
||||
(globalThis as { window?: { __paseoTerminal?: unknown } }).window = {
|
||||
__paseoTerminal: undefined,
|
||||
};
|
||||
terminalConstructorOptions.values = [];
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -317,6 +338,26 @@ describe("terminal-emulator-runtime", () => {
|
||||
expect(refresh).toHaveBeenCalledWith(0, 11);
|
||||
});
|
||||
|
||||
it("updates terminal scrollback without remounting", () => {
|
||||
const runtime = new TerminalEmulatorRuntime();
|
||||
const refresh = vi.fn();
|
||||
const terminal: StubTerminal = {
|
||||
write: () => {},
|
||||
reset: () => {},
|
||||
focus: () => {},
|
||||
refresh,
|
||||
options: { scrollback: 10_000 },
|
||||
rows: 12,
|
||||
cols: 40,
|
||||
};
|
||||
(runtime as unknown as { terminal: StubTerminal }).terminal = terminal;
|
||||
|
||||
runtime.setScrollback({ lines: 42_000 });
|
||||
|
||||
expect(terminal.options?.scrollback).toBe(42_000);
|
||||
expect(refresh).toHaveBeenCalledWith(0, 11);
|
||||
});
|
||||
|
||||
it("forces a refit when the page becomes visible again", () => {
|
||||
const runtime = new TerminalEmulatorRuntime();
|
||||
const fitAndEmitResize = vi.fn();
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface TerminalEmulatorRuntimeMountInput {
|
||||
root: HTMLDivElement;
|
||||
host: HTMLDivElement;
|
||||
initialSnapshot: TerminalState | null;
|
||||
scrollback: number;
|
||||
theme: ITheme;
|
||||
}
|
||||
|
||||
@@ -178,7 +179,7 @@ export class TerminalEmulatorRuntime {
|
||||
overviewRuler: {
|
||||
width: 8,
|
||||
},
|
||||
scrollback: 10_000,
|
||||
scrollback: input.scrollback,
|
||||
theme: withOverviewRulerBorderHidden(input.theme),
|
||||
});
|
||||
const fitAddon = new FitAddon();
|
||||
@@ -578,6 +579,22 @@ export class TerminalEmulatorRuntime {
|
||||
this.refreshVisibleRows();
|
||||
}
|
||||
|
||||
setScrollback(input: { lines: number }): void {
|
||||
const terminal = this.terminal;
|
||||
if (!terminal) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
terminal.options.scrollback = input.lines;
|
||||
} catch {
|
||||
// ignore
|
||||
return;
|
||||
}
|
||||
|
||||
this.refreshVisibleRows();
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this.terminal?.focus();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user