feat: add file tabs and improve terminal rendering with WebGL

This commit is contained in:
Mohamed Boudra
2026-03-02 20:02:54 +07:00
parent 92b5f1e963
commit f418f3ab02
25 changed files with 1214 additions and 696 deletions
@@ -5,7 +5,7 @@ import { TerminalOutputPump } from "./terminal-output-pump";
describe("terminal-output-pump", () => {
it("batches selected-terminal chunk bursts into ordered flushes", () => {
vi.useFakeTimers();
const chunks: Array<{ sequence: number; text: string }> = [];
const chunks: Array<{ sequence: number; text: string; replay: boolean }> = [];
const pump = new TerminalOutputPump({
maxOutputChars: 100,
onSelectedOutputChunk: (chunk) => {
@@ -14,16 +14,16 @@ describe("terminal-output-pump", () => {
});
pump.setSelectedTerminal({ terminalId: "term-1" });
pump.append({ terminalId: "term-1", text: "a" });
pump.append({ terminalId: "term-1", text: "b" });
pump.append({ terminalId: "term-1", text: "c" });
pump.append({ terminalId: "term-1", text: "a", replay: false });
pump.append({ terminalId: "term-1", text: "b", replay: false });
pump.append({ terminalId: "term-1", text: "c", replay: false });
expect(chunks).toEqual([]);
vi.runOnlyPendingTimers();
expect(chunks).toEqual([
{ sequence: 1, text: "abc" },
{ sequence: 1, text: "abc", replay: false },
]);
vi.useRealTimers();
@@ -31,7 +31,7 @@ describe("terminal-output-pump", () => {
it("keeps per-terminal snapshots and switches selected stream deterministically", () => {
vi.useFakeTimers();
const chunks: Array<{ sequence: number; text: string }> = [];
const chunks: Array<{ sequence: number; text: string; replay: boolean }> = [];
const pump = new TerminalOutputPump({
maxOutputChars: 10,
onSelectedOutputChunk: (chunk) => {
@@ -40,21 +40,21 @@ describe("terminal-output-pump", () => {
});
pump.setSelectedTerminal({ terminalId: "term-1" });
pump.append({ terminalId: "term-1", text: "hello" });
pump.append({ terminalId: "term-1", text: "hello", replay: false });
vi.runOnlyPendingTimers();
expect(pump.readSnapshot({ terminalId: "term-1" })).toBe("hello");
pump.append({ terminalId: "term-2", text: "world" });
pump.append({ terminalId: "term-2", text: "world", replay: false });
vi.runOnlyPendingTimers();
expect(pump.readSnapshot({ terminalId: "term-2" })).toBe("world");
pump.setSelectedTerminal({ terminalId: "term-2" });
pump.append({ terminalId: "term-2", text: "!" });
pump.append({ terminalId: "term-2", text: "!", replay: false });
vi.runOnlyPendingTimers();
expect(chunks).toEqual([
{ sequence: 1, text: "hello" },
{ sequence: 2, text: "!" },
{ sequence: 1, text: "hello", replay: false },
{ sequence: 2, text: "!", replay: false },
]);
vi.useRealTimers();
@@ -62,7 +62,7 @@ describe("terminal-output-pump", () => {
it("resets selected output when clearing selected terminal", () => {
vi.useFakeTimers();
const chunks: Array<{ sequence: number; text: string }> = [];
const chunks: Array<{ sequence: number; text: string; replay: boolean }> = [];
const pump = new TerminalOutputPump({
maxOutputChars: 10,
onSelectedOutputChunk: (chunk) => {
@@ -71,15 +71,15 @@ describe("terminal-output-pump", () => {
});
pump.setSelectedTerminal({ terminalId: "term-1" });
pump.append({ terminalId: "term-1", text: "abc" });
pump.append({ terminalId: "term-1", text: "abc", replay: false });
vi.runOnlyPendingTimers();
pump.clearTerminal({ terminalId: "term-1" });
expect(pump.readSnapshot({ terminalId: "term-1" })).toBe("");
expect(chunks).toEqual([
{ sequence: 1, text: "abc" },
{ sequence: 2, text: "" },
{ sequence: 1, text: "abc", replay: false },
{ sequence: 2, text: "", replay: false },
]);
vi.useRealTimers();
@@ -91,8 +91,8 @@ describe("terminal-output-pump", () => {
onSelectedOutputChunk: () => {},
});
pump.append({ terminalId: "a", text: "one" });
pump.append({ terminalId: "b", text: "two" });
pump.append({ terminalId: "a", text: "one", replay: false });
pump.append({ terminalId: "b", text: "two", replay: false });
pump.prune({ terminalIds: ["b"] });
expect(pump.readSnapshot({ terminalId: "a" })).toBe("");