wraithterm 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +313 -2
- package/css/xterm.css +285 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.js +707 -0
- package/dist/keycodes.d.ts +1 -0
- package/dist/keycodes.js +179 -0
- package/dist/protocol.d.ts +117 -0
- package/dist/protocol.js +1 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.js +19 -0
- package/dist/vite.d.ts +11 -0
- package/dist/vite.js +11 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +302 -0
- package/dist/xterm-api.d.ts +1956 -0
- package/dist/xterm-atlas.d.ts +39 -0
- package/dist/xterm-atlas.js +176 -0
- package/dist/xterm-internals.d.ts +120 -0
- package/dist/xterm-internals.js +19 -0
- package/dist/xterm-renderer.d.ts +77 -0
- package/dist/xterm-renderer.js +540 -0
- package/dist/xterm.d.ts +17 -0
- package/dist/xterm.js +35 -0
- package/docs/ARCHITECTURE.md +179 -0
- package/docs/COMPATIBILITY.md +66 -0
- package/docs/PERFORMANCE.md +122 -0
- package/docs/TOP_TIER.md +124 -0
- package/docs/XTERM_API.md +163 -0
- package/docs/compatibility/xterm-chrome.json +34 -0
- package/licenses/Ghostty-MIT.txt +21 -0
- package/licenses/JetBrainsMono-OFL.txt +93 -0
- package/licenses/NOTICE.md +93 -0
- package/licenses/Zig-MIT.txt +21 -0
- package/licenses/rust/arrayvec-0.7.8/LICENSE-APACHE +201 -0
- package/licenses/rust/arrayvec-0.7.8/LICENSE-MIT +25 -0
- package/licenses/rust/autocfg-1.5.1/LICENSE-APACHE +201 -0
- package/licenses/rust/autocfg-1.5.1/LICENSE-MIT +25 -0
- package/licenses/rust/bit-set-0.10.0/LICENSE-APACHE +201 -0
- package/licenses/rust/bit-set-0.10.0/LICENSE-MIT +25 -0
- package/licenses/rust/bit-vec-0.9.1/LICENSE-APACHE +201 -0
- package/licenses/rust/bit-vec-0.9.1/LICENSE-MIT +25 -0
- package/licenses/rust/bitflags-2.13.2/LICENSE-APACHE +201 -0
- package/licenses/rust/bitflags-2.13.2/LICENSE-MIT +25 -0
- package/licenses/rust/bumpalo-3.20.3/LICENSE-APACHE +201 -0
- package/licenses/rust/bumpalo-3.20.3/LICENSE-MIT +25 -0
- package/licenses/rust/bytemuck-1.25.2/LICENSE-APACHE +61 -0
- package/licenses/rust/bytemuck-1.25.2/LICENSE-MIT +9 -0
- package/licenses/rust/bytemuck-1.25.2/LICENSE-ZLIB +11 -0
- package/licenses/rust/bytemuck_derive-1.12.1/LICENSE-APACHE +61 -0
- package/licenses/rust/bytemuck_derive-1.12.1/LICENSE-MIT +9 -0
- package/licenses/rust/bytemuck_derive-1.12.1/LICENSE-ZLIB +11 -0
- package/licenses/rust/cfg-if-1.0.5/LICENSE-APACHE +201 -0
- package/licenses/rust/cfg-if-1.0.5/LICENSE-MIT +25 -0
- package/licenses/rust/cfg_aliases-0.2.2/LICENSE +9 -0
- package/licenses/rust/codespan-reporting-0.13.1/LICENSE +201 -0
- package/licenses/rust/crunchy-0.2.4/LICENSE +21 -0
- package/licenses/rust/document-features-0.2.12/LICENSE-APACHE +73 -0
- package/licenses/rust/document-features-0.2.12/LICENSE-MIT +19 -0
- package/licenses/rust/equivalent-1.0.2/LICENSE-APACHE +201 -0
- package/licenses/rust/equivalent-1.0.2/LICENSE-MIT +25 -0
- package/licenses/rust/foldhash-0.2.0/LICENSE +19 -0
- package/licenses/rust/font-types-0.12.6/LICENSE-APACHE +67 -0
- package/licenses/rust/font-types-0.12.6/LICENSE-MIT +25 -0
- package/licenses/rust/futures-core-0.3.34/LICENSE-APACHE +202 -0
- package/licenses/rust/futures-core-0.3.34/LICENSE-MIT +26 -0
- package/licenses/rust/futures-task-0.3.34/LICENSE-APACHE +202 -0
- package/licenses/rust/futures-task-0.3.34/LICENSE-MIT +26 -0
- package/licenses/rust/futures-util-0.3.34/LICENSE-APACHE +202 -0
- package/licenses/rust/futures-util-0.3.34/LICENSE-MIT +26 -0
- package/licenses/rust/half-2.7.1/LICENSE-APACHE +176 -0
- package/licenses/rust/half-2.7.1/LICENSE-MIT +19 -0
- package/licenses/rust/harfrust-0.13.3/LICENSE +22 -0
- package/licenses/rust/hashbrown-0.17.1/LICENSE-APACHE +201 -0
- package/licenses/rust/hashbrown-0.17.1/LICENSE-MIT +25 -0
- package/licenses/rust/indexmap-2.14.2/LICENSE-APACHE +201 -0
- package/licenses/rust/indexmap-2.14.2/LICENSE-MIT +25 -0
- package/licenses/rust/js-sys-0.3.106/LICENSE-APACHE +201 -0
- package/licenses/rust/js-sys-0.3.106/LICENSE-MIT +25 -0
- package/licenses/rust/libc-0.2.190/LICENSE-APACHE +176 -0
- package/licenses/rust/libc-0.2.190/LICENSE-MIT +25 -0
- package/licenses/rust/libloading-0.8.9/LICENSE +12 -0
- package/licenses/rust/libm-0.2.16/LICENSE.txt +258 -0
- package/licenses/rust/litrs-1.0.0/LICENSE-APACHE +176 -0
- package/licenses/rust/litrs-1.0.0/LICENSE-MIT +25 -0
- package/licenses/rust/lock_api-0.4.14/LICENSE-APACHE +201 -0
- package/licenses/rust/lock_api-0.4.14/LICENSE-MIT +25 -0
- package/licenses/rust/log-0.4.34/LICENSE-APACHE +201 -0
- package/licenses/rust/log-0.4.34/LICENSE-MIT +25 -0
- package/licenses/rust/naga-30.0.1/LICENSE.APACHE +176 -0
- package/licenses/rust/naga-30.0.1/LICENSE.MIT +21 -0
- package/licenses/rust/naga-types-30.0.1/LICENSE.APACHE +176 -0
- package/licenses/rust/naga-types-30.0.1/LICENSE.MIT +21 -0
- package/licenses/rust/num-traits-0.2.19/LICENSE-APACHE +201 -0
- package/licenses/rust/num-traits-0.2.19/LICENSE-MIT +25 -0
- package/licenses/rust/once_cell-1.21.4/LICENSE-APACHE +201 -0
- package/licenses/rust/once_cell-1.21.4/LICENSE-MIT +23 -0
- package/licenses/rust/parking_lot-0.12.5/LICENSE-APACHE +201 -0
- package/licenses/rust/parking_lot-0.12.5/LICENSE-MIT +25 -0
- package/licenses/rust/parking_lot_core-0.9.12/LICENSE-APACHE +201 -0
- package/licenses/rust/parking_lot_core-0.9.12/LICENSE-MIT +25 -0
- package/licenses/rust/pin-project-lite-0.2.17/LICENSE-APACHE +177 -0
- package/licenses/rust/pin-project-lite-0.2.17/LICENSE-MIT +23 -0
- package/licenses/rust/portable-atomic-1.15.0/LICENSE-APACHE +177 -0
- package/licenses/rust/portable-atomic-1.15.0/LICENSE-MIT +23 -0
- package/licenses/rust/portable-atomic-util-0.2.8/LICENSE-APACHE +177 -0
- package/licenses/rust/portable-atomic-util-0.2.8/LICENSE-MIT +23 -0
- package/licenses/rust/proc-macro2-1.0.107/LICENSE-APACHE +176 -0
- package/licenses/rust/proc-macro2-1.0.107/LICENSE-MIT +23 -0
- package/licenses/rust/quote-1.0.47/LICENSE-APACHE +176 -0
- package/licenses/rust/quote-1.0.47/LICENSE-MIT +23 -0
- package/licenses/rust/raw-window-handle-0.6.2/LICENSE-APACHE.md +177 -0
- package/licenses/rust/raw-window-handle-0.6.2/LICENSE-MIT.md +21 -0
- package/licenses/rust/raw-window-handle-0.6.2/LICENSE-ZLIB.md +11 -0
- package/licenses/rust/read-fonts-0.41.0/LICENSE-APACHE +67 -0
- package/licenses/rust/read-fonts-0.41.0/LICENSE-MIT +25 -0
- package/licenses/rust/read-fonts-0.43.3/LICENSE-APACHE +67 -0
- package/licenses/rust/read-fonts-0.43.3/LICENSE-MIT +25 -0
- package/licenses/rust/redox_syscall-0.5.18/LICENSE +22 -0
- package/licenses/rust/renderdoc-sys-1.1.0/LICENSE-APACHE +201 -0
- package/licenses/rust/renderdoc-sys-1.1.0/LICENSE-MIT +25 -0
- package/licenses/rust/rustc-hash-1.1.0/LICENSE-APACHE +201 -0
- package/licenses/rust/rustc-hash-1.1.0/LICENSE-MIT +23 -0
- package/licenses/rust/rustversion-1.0.23/LICENSE-APACHE +176 -0
- package/licenses/rust/rustversion-1.0.23/LICENSE-MIT +23 -0
- package/licenses/rust/scopeguard-1.2.0/LICENSE-APACHE +201 -0
- package/licenses/rust/scopeguard-1.2.0/LICENSE-MIT +25 -0
- package/licenses/rust/serde-1.0.229/LICENSE-APACHE +176 -0
- package/licenses/rust/serde-1.0.229/LICENSE-MIT +23 -0
- package/licenses/rust/serde_core-1.0.229/LICENSE-APACHE +176 -0
- package/licenses/rust/serde_core-1.0.229/LICENSE-MIT +23 -0
- package/licenses/rust/serde_derive-1.0.229/LICENSE-APACHE +176 -0
- package/licenses/rust/serde_derive-1.0.229/LICENSE-MIT +23 -0
- package/licenses/rust/skrifa-0.44.0/LICENSE-APACHE +67 -0
- package/licenses/rust/skrifa-0.44.0/LICENSE-MIT +25 -0
- package/licenses/rust/slab-0.4.12/LICENSE +25 -0
- package/licenses/rust/smallvec-1.16.2/LICENSE-APACHE +201 -0
- package/licenses/rust/smallvec-1.16.2/LICENSE-MIT +25 -0
- package/licenses/rust/static_assertions-1.1.0/LICENSE-APACHE +202 -0
- package/licenses/rust/static_assertions-1.1.0/LICENSE-MIT +21 -0
- package/licenses/rust/swash-0.2.10/LICENSE-APACHE +201 -0
- package/licenses/rust/swash-0.2.10/LICENSE-MIT +25 -0
- package/licenses/rust/syn-2.0.119/LICENSE-APACHE +176 -0
- package/licenses/rust/syn-2.0.119/LICENSE-MIT +23 -0
- package/licenses/rust/syn-3.0.6/LICENSE-APACHE +176 -0
- package/licenses/rust/syn-3.0.6/LICENSE-MIT +23 -0
- package/licenses/rust/termcolor-1.4.1/COPYING +3 -0
- package/licenses/rust/termcolor-1.4.1/LICENSE-MIT +21 -0
- package/licenses/rust/termcolor-1.4.1/UNLICENSE +24 -0
- package/licenses/rust/thiserror-2.0.21/LICENSE-APACHE +176 -0
- package/licenses/rust/thiserror-2.0.21/LICENSE-MIT +23 -0
- package/licenses/rust/thiserror-impl-2.0.21/LICENSE-APACHE +176 -0
- package/licenses/rust/thiserror-impl-2.0.21/LICENSE-MIT +23 -0
- package/licenses/rust/tokio-1.53.2/LICENSE +21 -0
- package/licenses/rust/unicode-ident-1.0.26/LICENSE-APACHE +176 -0
- package/licenses/rust/unicode-ident-1.0.26/LICENSE-MIT +23 -0
- package/licenses/rust/unicode-ident-1.0.26/LICENSE-UNICODE +39 -0
- package/licenses/rust/unicode-width-0.2.2/LICENSE-APACHE +201 -0
- package/licenses/rust/unicode-width-0.2.2/LICENSE-MIT +25 -0
- package/licenses/rust/wasm-bindgen-0.2.129/LICENSE-APACHE +201 -0
- package/licenses/rust/wasm-bindgen-0.2.129/LICENSE-MIT +25 -0
- package/licenses/rust/wasm-bindgen-futures-0.4.79/LICENSE-APACHE +201 -0
- package/licenses/rust/wasm-bindgen-futures-0.4.79/LICENSE-MIT +25 -0
- package/licenses/rust/wasm-bindgen-macro-0.2.129/LICENSE-APACHE +201 -0
- package/licenses/rust/wasm-bindgen-macro-0.2.129/LICENSE-MIT +25 -0
- package/licenses/rust/wasm-bindgen-macro-support-0.2.129/LICENSE-APACHE +201 -0
- package/licenses/rust/wasm-bindgen-macro-support-0.2.129/LICENSE-MIT +25 -0
- package/licenses/rust/wasm-bindgen-shared-0.2.129/LICENSE-APACHE +201 -0
- package/licenses/rust/wasm-bindgen-shared-0.2.129/LICENSE-MIT +25 -0
- package/licenses/rust/web-sys-0.3.106/LICENSE-APACHE +201 -0
- package/licenses/rust/web-sys-0.3.106/LICENSE-MIT +25 -0
- package/licenses/rust/wgpu-30.0.1/LICENSE.APACHE +176 -0
- package/licenses/rust/wgpu-30.0.1/LICENSE.MIT +21 -0
- package/licenses/rust/wgpu-core-30.0.1/LICENSE.APACHE +176 -0
- package/licenses/rust/wgpu-core-30.0.1/LICENSE.MIT +21 -0
- package/licenses/rust/wgpu-core-deps-windows-linux-android-30.0.1/LICENSE.APACHE +176 -0
- package/licenses/rust/wgpu-core-deps-windows-linux-android-30.0.1/LICENSE.MIT +21 -0
- package/licenses/rust/wgpu-hal-30.0.1/LICENSE.APACHE +176 -0
- package/licenses/rust/wgpu-hal-30.0.1/LICENSE.MIT +21 -0
- package/licenses/rust/wgpu-naga-bridge-30.0.1/LICENSE.APACHE +176 -0
- package/licenses/rust/wgpu-naga-bridge-30.0.1/LICENSE.MIT +21 -0
- package/licenses/rust/wgpu-types-30.0.1/LICENSE.APACHE +176 -0
- package/licenses/rust/wgpu-types-30.0.1/LICENSE.MIT +21 -0
- package/licenses/rust/winapi-util-0.1.11/COPYING +3 -0
- package/licenses/rust/winapi-util-0.1.11/LICENSE-MIT +21 -0
- package/licenses/rust/winapi-util-0.1.11/UNLICENSE +24 -0
- package/licenses/rust/windows-link-0.2.1/license-apache-2.0 +201 -0
- package/licenses/rust/windows-link-0.2.1/license-mit +21 -0
- package/licenses/rust/windows-sys-0.61.2/license-apache-2.0 +201 -0
- package/licenses/rust/windows-sys-0.61.2/license-mit +21 -0
- package/licenses/rust/yazi-0.2.1/LICENSE-APACHE +201 -0
- package/licenses/rust/yazi-0.2.1/LICENSE-MIT +19 -0
- package/licenses/rust/zeno-0.3.3/LICENSE-APACHE +201 -0
- package/licenses/rust/zeno-0.3.3/LICENSE-MIT +25 -0
- package/licenses/rust/zerocopy-0.8.62/LICENSE-APACHE +202 -0
- package/licenses/rust/zerocopy-0.8.62/LICENSE-BSD +24 -0
- package/licenses/rust/zerocopy-0.8.62/LICENSE-MIT +26 -0
- package/licenses/rust/zerocopy-derive-0.8.62/LICENSE-APACHE +202 -0
- package/licenses/rust/zerocopy-derive-0.8.62/LICENSE-BSD +24 -0
- package/licenses/rust/zerocopy-derive-0.8.62/LICENSE-MIT +26 -0
- package/licenses/xterm-MIT.txt +21 -0
- package/package.json +69 -4
- package/wasm/Ghostty-MIT.txt +21 -0
- package/wasm/JetBrainsMono-Regular.ttf +0 -0
- package/wasm/OFL.txt +93 -0
- package/wasm/optimization.json +6 -0
- package/wasm/wraith_engine.d.ts +176 -0
- package/wasm/wraith_engine.js +2057 -0
- package/wasm/wraith_engine_bg.wasm +0 -0
- package/wasm/wraith_engine_bg.wasm.d.ts +71 -0
package/dist/worker.js
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/// <reference lib="webworker" />
|
|
2
|
+
import init, { Engine } from '../wasm/wraith_engine.js';
|
|
3
|
+
import { percentile } from './types.js';
|
|
4
|
+
const scope = self;
|
|
5
|
+
let engine;
|
|
6
|
+
let cols = 80, rows = 24;
|
|
7
|
+
let scheduled = false, visible = true, busy = false, disposed = false;
|
|
8
|
+
let raf = 0, holdTimer;
|
|
9
|
+
let samples = [], frameTimes = [];
|
|
10
|
+
let cursor = '';
|
|
11
|
+
let mouseTracking = false;
|
|
12
|
+
let serial = Promise.resolve();
|
|
13
|
+
const encoder = new TextEncoder(), decoder = new TextDecoder();
|
|
14
|
+
function post(reply, transfers = []) {
|
|
15
|
+
scope.postMessage(reply, transfers);
|
|
16
|
+
}
|
|
17
|
+
function result(id, value) {
|
|
18
|
+
post({ type: 'result', id, value });
|
|
19
|
+
}
|
|
20
|
+
function releaseAbandonedHold() {
|
|
21
|
+
if (!engine || disposed)
|
|
22
|
+
return;
|
|
23
|
+
if (busy) {
|
|
24
|
+
holdTimer = setTimeout(releaseAbandonedHold, 16);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
engine.release_hold();
|
|
28
|
+
schedule();
|
|
29
|
+
}
|
|
30
|
+
function drain() {
|
|
31
|
+
for (const [kind, bytes] of engine.take_events()) {
|
|
32
|
+
if (kind === 0)
|
|
33
|
+
post({ type: 'data', bytes }, [bytes.buffer]);
|
|
34
|
+
if (kind === 1)
|
|
35
|
+
post({ type: 'title', title: decoder.decode(bytes) });
|
|
36
|
+
if (kind === 2)
|
|
37
|
+
post({ type: 'bell' });
|
|
38
|
+
if (kind === 3) {
|
|
39
|
+
clearTimeout(holdTimer);
|
|
40
|
+
if (bytes[0])
|
|
41
|
+
holdTimer = setTimeout(releaseAbandonedHold, 150);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const mouse = engine.mode(1000) || engine.mode(1002) || engine.mode(1003) || engine.mode(9);
|
|
45
|
+
if (mouse !== mouseTracking) {
|
|
46
|
+
mouseTracking = mouse;
|
|
47
|
+
post({ type: 'modes', mouse });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function draw(time, force = false) {
|
|
51
|
+
const start = performance.now();
|
|
52
|
+
if (engine.render(time, force)) {
|
|
53
|
+
samples.push(performance.now() - start);
|
|
54
|
+
frameTimes.push(time);
|
|
55
|
+
if (samples.length > 512)
|
|
56
|
+
samples.shift();
|
|
57
|
+
while (frameTimes.length && frameTimes[0] < time - 1000)
|
|
58
|
+
frameTimes.shift();
|
|
59
|
+
const x = engine.cursor_x, y = engine.cursor_y, next = `${x},${y}`;
|
|
60
|
+
if (next !== cursor) {
|
|
61
|
+
cursor = next;
|
|
62
|
+
post({ type: 'cursor', x, y });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (engine.needs_present)
|
|
66
|
+
schedule();
|
|
67
|
+
}
|
|
68
|
+
function schedule() {
|
|
69
|
+
if (!engine || scheduled || disposed || !visible || busy)
|
|
70
|
+
return;
|
|
71
|
+
scheduled = true;
|
|
72
|
+
raf = scope.requestAnimationFrame((time) => {
|
|
73
|
+
scheduled = false;
|
|
74
|
+
// An async GPU fence holds a Rust borrow across await. A previously queued
|
|
75
|
+
// animation callback must not enter the engine until that borrow ends.
|
|
76
|
+
if (busy || !engine || !visible || disposed)
|
|
77
|
+
return;
|
|
78
|
+
try {
|
|
79
|
+
draw(time);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
post({ type: 'error', error: String(error) });
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const blinkTimer = setInterval(() => schedule(), 250);
|
|
87
|
+
const statsTimer = setInterval(() => {
|
|
88
|
+
if (engine && !disposed && !busy)
|
|
89
|
+
post({
|
|
90
|
+
type: 'stats',
|
|
91
|
+
values: Array.from(engine.metrics()),
|
|
92
|
+
samples: [...samples],
|
|
93
|
+
fps: frameTimes.filter((t) => t > performance.now() - 1000).length,
|
|
94
|
+
adapter: engine.adapter,
|
|
95
|
+
});
|
|
96
|
+
}, 500);
|
|
97
|
+
function payload(workload, iteration) {
|
|
98
|
+
if (workload === 'sparse')
|
|
99
|
+
return encoder.encode(`\x1b[${(iteration % rows) + 1};1H\x1b[38;5;${(iteration % 216) + 16}mframe ${String(iteration).padStart(8, '0')}\x1b[0m`);
|
|
100
|
+
if (workload === 'scroll')
|
|
101
|
+
return encoder.encode(`\x1b[${rows};1H\r\n\x1b[38;5;${(iteration % 216) + 16}m${String(iteration).padStart(8, '0')} ${'stream '.repeat(Math.ceil(cols / 7)).slice(0, cols - 10)}\x1b[0m`);
|
|
102
|
+
let output = '\x1b[H';
|
|
103
|
+
for (let row = 0; row < rows; row++) {
|
|
104
|
+
output += `\x1b[${row + 1};1H\x1b[38;5;${((iteration + row) % 216) + 16}m`;
|
|
105
|
+
for (let col = 0; col < cols; col++)
|
|
106
|
+
output += String.fromCharCode(33 + ((col + row + iteration) % 94));
|
|
107
|
+
}
|
|
108
|
+
return encoder.encode(output + '\x1b[0m');
|
|
109
|
+
}
|
|
110
|
+
async function benchmark(options) {
|
|
111
|
+
const count = Math.max(32, Math.min(10000, Math.floor(options.frames ?? 512)));
|
|
112
|
+
const warmup = Math.max(0, Math.min(512, Math.floor(options.warmup ?? 64)));
|
|
113
|
+
const workload = options.workload ?? 'dense';
|
|
114
|
+
if (!['dense', 'sparse', 'scroll'].includes(workload))
|
|
115
|
+
throw new Error('Unknown benchmark workload');
|
|
116
|
+
if (engine.mode(1049))
|
|
117
|
+
throw new Error('Run benchmarks outside an active full-screen terminal application');
|
|
118
|
+
if (engine.mode(2026))
|
|
119
|
+
throw new Error('Wait for synchronized output to finish before benchmarking');
|
|
120
|
+
const cursorWasVisible = engine.mode(25);
|
|
121
|
+
busy = true;
|
|
122
|
+
clearTimeout(holdTimer);
|
|
123
|
+
if (scheduled) {
|
|
124
|
+
scope.cancelAnimationFrame(raf);
|
|
125
|
+
scheduled = false;
|
|
126
|
+
}
|
|
127
|
+
const durations = [];
|
|
128
|
+
let bytes = 0, completed = 0;
|
|
129
|
+
try {
|
|
130
|
+
engine.write(encoder.encode('\x1b[?1049h\x1b[?25l'));
|
|
131
|
+
// Generate inputs outside the timed region. The same 64-frame cycle is
|
|
132
|
+
// reproducible; timestamps measure parser + snapshot + encode + submit.
|
|
133
|
+
const inputs = Array.from({ length: 64 }, (_, i) => payload(workload, i));
|
|
134
|
+
for (let i = 0; i < warmup; i++) {
|
|
135
|
+
engine.write(inputs[i % 64]);
|
|
136
|
+
engine.render(performance.now(), true);
|
|
137
|
+
if ((i + 1) % 32 === 0)
|
|
138
|
+
await engine.fence();
|
|
139
|
+
}
|
|
140
|
+
await engine.fence();
|
|
141
|
+
const start = performance.now();
|
|
142
|
+
for (let i = 0; i < count; i++) {
|
|
143
|
+
const input = inputs[i % 64], before = performance.now();
|
|
144
|
+
engine.write(input);
|
|
145
|
+
const rendered = engine.render(performance.now(), true);
|
|
146
|
+
durations.push(performance.now() - before);
|
|
147
|
+
bytes += input.byteLength;
|
|
148
|
+
if (rendered)
|
|
149
|
+
completed++;
|
|
150
|
+
if ((i + 1) % 32 === 0)
|
|
151
|
+
await engine.fence();
|
|
152
|
+
}
|
|
153
|
+
await engine.fence();
|
|
154
|
+
const elapsedMs = performance.now() - start;
|
|
155
|
+
return {
|
|
156
|
+
workload,
|
|
157
|
+
frames: completed,
|
|
158
|
+
cols,
|
|
159
|
+
rows,
|
|
160
|
+
elapsedMs,
|
|
161
|
+
fencedFramesPerSecond: (completed * 1000) / elapsedMs,
|
|
162
|
+
cpuP50Ms: percentile(durations, 0.5),
|
|
163
|
+
cpuP95Ms: percentile(durations, 0.95),
|
|
164
|
+
cpuP99Ms: percentile(durations, 0.99),
|
|
165
|
+
inputMiBPerSecond: bytes / (1024 * 1024) / (elapsedMs / 1000),
|
|
166
|
+
adapter: engine.adapter,
|
|
167
|
+
userAgent: scope.navigator.userAgent,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
engine.write(encoder.encode('\x1b[?1049l' + (cursorWasVisible ? '\x1b[?25h' : '\x1b[?25l')));
|
|
172
|
+
busy = false;
|
|
173
|
+
drain();
|
|
174
|
+
schedule();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function handle(command) {
|
|
178
|
+
if (command.type === 'init') {
|
|
179
|
+
await init();
|
|
180
|
+
cols = command.cols;
|
|
181
|
+
rows = command.rows;
|
|
182
|
+
engine = await Engine.create(command.canvas, command.font, cols, rows, command.size, command.lineHeight, command.history);
|
|
183
|
+
for (const font of command.fonts)
|
|
184
|
+
engine.add_font(font);
|
|
185
|
+
engine.theme(command.theme[0], command.theme[1], command.theme[2]);
|
|
186
|
+
post({
|
|
187
|
+
type: 'ready',
|
|
188
|
+
width: engine.cell_width,
|
|
189
|
+
height: engine.cell_height,
|
|
190
|
+
adapter: engine.adapter,
|
|
191
|
+
});
|
|
192
|
+
schedule();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (!engine || disposed)
|
|
196
|
+
throw new Error('Wraith engine is not running');
|
|
197
|
+
switch (command.type) {
|
|
198
|
+
case 'write':
|
|
199
|
+
engine.write(command.bytes);
|
|
200
|
+
drain();
|
|
201
|
+
schedule();
|
|
202
|
+
post({ type: 'written', ids: command.ids });
|
|
203
|
+
break;
|
|
204
|
+
case 'resize':
|
|
205
|
+
engine.resize(command.cols, command.rows);
|
|
206
|
+
cols = command.cols;
|
|
207
|
+
rows = command.rows;
|
|
208
|
+
schedule();
|
|
209
|
+
result(command.id);
|
|
210
|
+
break;
|
|
211
|
+
case 'key':
|
|
212
|
+
engine.key(command.key, command.mods, command.action, command.text, command.unshifted);
|
|
213
|
+
drain();
|
|
214
|
+
break;
|
|
215
|
+
case 'mouse':
|
|
216
|
+
engine.mouse(command.action, command.button, command.mods, command.x, command.y, command.pressed);
|
|
217
|
+
drain();
|
|
218
|
+
break;
|
|
219
|
+
case 'scroll':
|
|
220
|
+
engine.scroll(command.delta);
|
|
221
|
+
schedule();
|
|
222
|
+
break;
|
|
223
|
+
case 'select':
|
|
224
|
+
engine.select(command.x1, command.y1, command.x2, command.y2);
|
|
225
|
+
schedule();
|
|
226
|
+
break;
|
|
227
|
+
case 'paste': {
|
|
228
|
+
// Sanitize terminal control characters and bracketed-paste terminators.
|
|
229
|
+
const text = command.text.replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, '');
|
|
230
|
+
const framed = engine.mode(2004) ? `\x1b[200~${text}\x1b[201~` : text.replace(/\r?\n/g, '\r');
|
|
231
|
+
const bytes = encoder.encode(framed);
|
|
232
|
+
post({ type: 'data', bytes }, [bytes.buffer]);
|
|
233
|
+
result(command.id);
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case 'focus':
|
|
237
|
+
if (engine.mode(1004)) {
|
|
238
|
+
const bytes = encoder.encode(command.focused ? '\x1b[I' : '\x1b[O');
|
|
239
|
+
post({ type: 'data', bytes }, [bytes.buffer]);
|
|
240
|
+
}
|
|
241
|
+
break;
|
|
242
|
+
case 'text':
|
|
243
|
+
result(command.id, engine.text(command.selected));
|
|
244
|
+
break;
|
|
245
|
+
case 'link':
|
|
246
|
+
result(command.id, engine.link(command.x, command.y));
|
|
247
|
+
break;
|
|
248
|
+
case 'theme':
|
|
249
|
+
engine.theme(command.colors[0], command.colors[1], command.colors[2]);
|
|
250
|
+
schedule();
|
|
251
|
+
break;
|
|
252
|
+
case 'flush':
|
|
253
|
+
busy = true;
|
|
254
|
+
if (scheduled) {
|
|
255
|
+
scope.cancelAnimationFrame(raf);
|
|
256
|
+
scheduled = false;
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
draw(performance.now(), true);
|
|
260
|
+
await engine.fence();
|
|
261
|
+
result(command.id);
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
busy = false;
|
|
265
|
+
schedule();
|
|
266
|
+
}
|
|
267
|
+
break;
|
|
268
|
+
case 'benchmark':
|
|
269
|
+
result(command.id, await benchmark(command.options));
|
|
270
|
+
break;
|
|
271
|
+
case 'visibility':
|
|
272
|
+
visible = command.visible;
|
|
273
|
+
if (visible)
|
|
274
|
+
schedule();
|
|
275
|
+
break;
|
|
276
|
+
case 'dispose':
|
|
277
|
+
disposed = true;
|
|
278
|
+
clearInterval(blinkTimer);
|
|
279
|
+
clearInterval(statsTimer);
|
|
280
|
+
clearTimeout(holdTimer);
|
|
281
|
+
if (scheduled)
|
|
282
|
+
scope.cancelAnimationFrame(raf);
|
|
283
|
+
engine.free();
|
|
284
|
+
engine = undefined;
|
|
285
|
+
result(command.id);
|
|
286
|
+
scope.close();
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
scope.onmessage = (event) => {
|
|
291
|
+
const command = event.data;
|
|
292
|
+
serial = serial
|
|
293
|
+
.then(() => handle(command))
|
|
294
|
+
.catch((error) => {
|
|
295
|
+
if (command.type === 'write')
|
|
296
|
+
post({ type: 'written', ids: command.ids, error: String(error) });
|
|
297
|
+
else if ('id' in command)
|
|
298
|
+
post({ type: 'result', id: command.id, error: String(error) });
|
|
299
|
+
else
|
|
300
|
+
post({ type: 'error', error: String(error) });
|
|
301
|
+
});
|
|
302
|
+
};
|