Skip to content

Commit dbd7839

Browse files
committed
Add headless support
This allows running ghostty-web in headless mode. This will enable off main-thread rendering using OffscreenCanvas.
1 parent 779b648 commit dbd7839

File tree

10 files changed

+1410
-814
lines changed

10 files changed

+1410
-814
lines changed

bench/versus.ts

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { Terminal as XTerm } from '@xterm/xterm';
1+
import { Terminal as XTermHeadless } from '@xterm/headless';
22
import { bench, group, run } from 'mitata';
3-
import { Ghostty, Terminal as GhosttyTerminal } from '../lib';
4-
import '../happydom';
3+
import { Ghostty } from '../lib/ghostty';
4+
import { Terminal as GhosttyHeadless } from '../lib/headless';
55

66
function generateColorText(lines: number): string {
77
const colors = [31, 32, 33, 34, 35, 36];
@@ -49,67 +49,69 @@ function generateCursorMovement(ops: number): string {
4949
return output;
5050
}
5151

52-
const withTerminals = async (fn: (term: GhosttyTerminal | XTerm) => Promise<void>) => {
53-
const ghostty = await Ghostty.load();
54-
bench('ghostty-web', async () => {
55-
const container = document.createElement('div');
56-
document.body.appendChild(container);
57-
const term = new GhosttyTerminal({ ghostty });
58-
await term.open(container);
52+
// Load Ghostty WASM once for all benchmarks
53+
const ghostty = await Ghostty.load();
54+
55+
const withTerminals = (fn: (term: GhosttyHeadless | XTermHeadless) => Promise<void>) => {
56+
bench('ghostty-web/headless', async () => {
57+
const term = new GhosttyHeadless({ ghostty });
5958
await fn(term);
60-
await term.dispose();
59+
term.dispose();
6160
});
62-
bench('xterm.js', async () => {
63-
const xterm = new XTerm();
64-
const container = document.createElement('div');
65-
document.body.appendChild(container);
66-
await xterm.open(container);
67-
await fn(xterm);
68-
await xterm.dispose();
61+
bench('@xterm/headless', async () => {
62+
const term = new XTermHeadless({
63+
allowProposedApi: true,
64+
});
65+
await fn(term);
66+
term.dispose();
6967
});
7068
};
7169

72-
const throughput = async (prefix: string, data: Record<string, Uint8Array | string>) => {
73-
await Promise.all(
74-
Object.entries(data).map(async ([name, data]) => {
75-
await group(`${prefix}: ${name}`, async () => {
76-
await withTerminals(async (term) => {
77-
await new Promise<void>((resolve) => {
78-
term.write(data, resolve);
79-
});
70+
const throughput = (prefix: string, data: Record<string, Uint8Array | string>) => {
71+
for (const [name, payload] of Object.entries(data)) {
72+
group(`${prefix}: ${name}`, () => {
73+
withTerminals(async (term) => {
74+
await new Promise<void>((resolve) => {
75+
term.write(payload, resolve);
8076
});
8177
});
82-
})
83-
);
78+
});
79+
}
8480
};
8581

86-
await throughput('raw bytes', {
82+
throughput('raw bytes', {
8783
'1KB': generateRawBytes(1024),
8884
'10KB': generateRawBytes(10 * 1024),
8985
'100KB': generateRawBytes(100 * 1024),
9086
'1MB': generateRawBytes(1024 * 1024),
9187
});
9288

93-
await throughput('color text', {
89+
throughput('color text', {
9490
'100 lines': generateColorText(100),
9591
'1000 lines': generateColorText(1000),
9692
'10000 lines': generateColorText(10000),
9793
});
9894

99-
await throughput('complex VT', {
95+
throughput('complex VT', {
10096
'100 lines': generateComplexVT(100),
10197
'1000 lines': generateComplexVT(1000),
10298
'10000 lines': generateComplexVT(10000),
10399
});
104100

105-
await throughput('cursor movement', {
101+
throughput('cursor movement', {
106102
'1000 operations': generateCursorMovement(1000),
107103
'10000 operations': generateCursorMovement(10000),
108104
'100000 operations': generateCursorMovement(100000),
109105
});
110106

111-
await group('read full viewport', async () => {
112-
await withTerminals(async (term) => {
107+
group('read full viewport', () => {
108+
withTerminals(async (term) => {
109+
// Write some content first
110+
await new Promise<void>((resolve) => {
111+
term.write(generateColorText(100), resolve);
112+
});
113+
114+
// Then read it back
113115
const lines = term.rows;
114116
for (let i = 0; i < lines; i++) {
115117
const line = term.buffer.active.getLine(i);

0 commit comments

Comments
 (0)