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
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import init, { Compositor } from '../wasm/wraith_engine.js';
|
|
2
|
+
import { BrowserAtlas, AtlasFull } from './xterm-atlas.js';
|
|
3
|
+
import { internals, CELL_HAS_EXTENDED, CELL_IS_COMBINED, CELL_CODEPOINT_MASK, packedRow, } from './xterm-internals.js';
|
|
4
|
+
/** u32 words per packed GPU cell: fg, bg, underline, flags, glyph. */
|
|
5
|
+
export const CELL_WORDS = 5;
|
|
6
|
+
const rgb = (value) => ((value & 255) << 16) | (value & 0xff00) | ((value >>> 16) & 255);
|
|
7
|
+
const rgba = (value) => rgb(value >>> 8);
|
|
8
|
+
function wordColor(word, foreground, colors, brighten) {
|
|
9
|
+
const mode = word & 0x3000000;
|
|
10
|
+
if (mode === 0x3000000)
|
|
11
|
+
return rgb(word);
|
|
12
|
+
if (mode) {
|
|
13
|
+
const index = word & 255;
|
|
14
|
+
return rgba(colors.ansi[index + (brighten && index < 8 ? 8 : 0)].rgba);
|
|
15
|
+
}
|
|
16
|
+
return rgba((foreground ? colors.foreground : colors.background).rgba);
|
|
17
|
+
}
|
|
18
|
+
function resolveColor(data, foreground, bright, colors, boldBright) {
|
|
19
|
+
const color = foreground ? data.getFgColor() : data.getBgColor();
|
|
20
|
+
if (foreground ? data.isFgRGB() : data.isBgRGB())
|
|
21
|
+
return rgb(color);
|
|
22
|
+
if (foreground ? data.isFgPalette() : data.isBgPalette()) {
|
|
23
|
+
const index = color + (bright && data.isBold() && boldBright && color < 8 ? 8 : 0);
|
|
24
|
+
return rgba(colors.ansi[index].rgba);
|
|
25
|
+
}
|
|
26
|
+
return rgba((foreground ? colors.foreground : colors.background).rgba);
|
|
27
|
+
}
|
|
28
|
+
function sameRow(words, rows, offset, count) {
|
|
29
|
+
for (let i = 0; i < count; i++)
|
|
30
|
+
if (words[i] !== rows[offset + i])
|
|
31
|
+
return false;
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
let initialization;
|
|
35
|
+
/** Renderer replacement only: xterm keeps input, parser, scrollback and addons.
|
|
36
|
+
* A retained DOM renderer provides metrics and loss/feature fallback. */
|
|
37
|
+
export class XtermRenderer {
|
|
38
|
+
terminal;
|
|
39
|
+
core;
|
|
40
|
+
fallback;
|
|
41
|
+
state = 'initializing';
|
|
42
|
+
reason;
|
|
43
|
+
gpu;
|
|
44
|
+
memory;
|
|
45
|
+
atlas;
|
|
46
|
+
canvas;
|
|
47
|
+
rows;
|
|
48
|
+
subscriptions = [];
|
|
49
|
+
geometry = '';
|
|
50
|
+
font = '';
|
|
51
|
+
full = true;
|
|
52
|
+
staging = new Uint32Array(0);
|
|
53
|
+
/** Raw xterm words (3 per cell) that produced each staged row. Staging
|
|
54
|
+
* mirrors the GPU cell buffer, so a row whose words recur needs no packing:
|
|
55
|
+
* in place it is skipped, after scrolling it is copied within staging. */
|
|
56
|
+
rowWords = new Uint32Array(0);
|
|
57
|
+
/** 1 while staging row y is exactly the packing of rowWords row y. */
|
|
58
|
+
rowCached = new Uint8Array(0);
|
|
59
|
+
/** Frame stamp of the last write to each staging row this frame. */
|
|
60
|
+
rowStamp = new Uint32Array(0);
|
|
61
|
+
stamp = 0;
|
|
62
|
+
shift = 1;
|
|
63
|
+
lastViewportY = 0;
|
|
64
|
+
cell;
|
|
65
|
+
view = new Float32Array(4);
|
|
66
|
+
frame = new Uint32Array(8);
|
|
67
|
+
disposed = false;
|
|
68
|
+
fatal = false;
|
|
69
|
+
hovering = false;
|
|
70
|
+
blink = true;
|
|
71
|
+
timer;
|
|
72
|
+
selectedStart;
|
|
73
|
+
selectedEnd;
|
|
74
|
+
columnSelection = false;
|
|
75
|
+
ready;
|
|
76
|
+
get active() {
|
|
77
|
+
return this.core._renderService._renderer.value === this;
|
|
78
|
+
}
|
|
79
|
+
get dimensions() {
|
|
80
|
+
return this.fallback.dimensions;
|
|
81
|
+
}
|
|
82
|
+
get onRequestRedraw() {
|
|
83
|
+
return this.fallback.onRequestRedraw;
|
|
84
|
+
}
|
|
85
|
+
constructor(terminal, core, fallback) {
|
|
86
|
+
this.terminal = terminal;
|
|
87
|
+
this.core = core;
|
|
88
|
+
this.fallback = fallback;
|
|
89
|
+
const document = terminal.element.ownerDocument;
|
|
90
|
+
this.cell = terminal.buffer.active.getNullCell();
|
|
91
|
+
this.rows = core.screenElement.querySelector('.xterm-rows');
|
|
92
|
+
this.canvas = document.createElement('canvas');
|
|
93
|
+
this.canvas.className = 'wraith-xterm-webgpu';
|
|
94
|
+
this.canvas.setAttribute('aria-hidden', 'true');
|
|
95
|
+
Object.assign(this.canvas.style, {
|
|
96
|
+
position: 'absolute',
|
|
97
|
+
left: '0',
|
|
98
|
+
top: '0',
|
|
99
|
+
pointerEvents: 'none',
|
|
100
|
+
display: 'none',
|
|
101
|
+
});
|
|
102
|
+
core.screenElement.prepend(this.canvas);
|
|
103
|
+
this.subscriptions.push(core.optionsService.onOptionChange(() => this.invalidate()), core._themeService.onChangeColors(() => this.invalidate()), core.linkifier.onShowLinkUnderline(() => {
|
|
104
|
+
this.hovering = true;
|
|
105
|
+
this.invalidate();
|
|
106
|
+
}), core.linkifier.onHideLinkUnderline(() => {
|
|
107
|
+
this.hovering = false;
|
|
108
|
+
this.invalidate();
|
|
109
|
+
}));
|
|
110
|
+
this.timer = setInterval(() => {
|
|
111
|
+
if (!this.disposed &&
|
|
112
|
+
this.state === 'webgpu' &&
|
|
113
|
+
(core.coreService.decPrivateModes.cursorBlink ?? terminal.options.cursorBlink)) {
|
|
114
|
+
this.blink = !this.blink;
|
|
115
|
+
this.invalidate(false);
|
|
116
|
+
}
|
|
117
|
+
}, 600);
|
|
118
|
+
this.ready = this.initialize();
|
|
119
|
+
}
|
|
120
|
+
static install(terminal) {
|
|
121
|
+
const core = internals(terminal);
|
|
122
|
+
if (!core)
|
|
123
|
+
return undefined;
|
|
124
|
+
const fallback = core._renderService._renderer.clearAndLeak();
|
|
125
|
+
if (!fallback)
|
|
126
|
+
return undefined;
|
|
127
|
+
const renderer = new XtermRenderer(terminal, core, fallback);
|
|
128
|
+
core._renderService.setRenderer(renderer);
|
|
129
|
+
return renderer;
|
|
130
|
+
}
|
|
131
|
+
async initialize() {
|
|
132
|
+
try {
|
|
133
|
+
if (!navigator.gpu || !this.canvas.transferControlToOffscreen)
|
|
134
|
+
throw new Error('WebGPU or OffscreenCanvas is unavailable');
|
|
135
|
+
initialization ??= init();
|
|
136
|
+
const wasm = await initialization;
|
|
137
|
+
if (this.disposed)
|
|
138
|
+
return false;
|
|
139
|
+
const gpu = await Compositor.create(this.canvas.transferControlToOffscreen());
|
|
140
|
+
if (this.disposed) {
|
|
141
|
+
gpu.free();
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
this.gpu = gpu;
|
|
145
|
+
this.memory = wasm.memory;
|
|
146
|
+
this.state = 'webgpu';
|
|
147
|
+
this.invalidate();
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (!this.disposed)
|
|
152
|
+
this.fail(String(error));
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
invalidate(full = true) {
|
|
157
|
+
this.full ||= full;
|
|
158
|
+
if (!this.disposed)
|
|
159
|
+
this.core._renderService.refreshRows(0, full ? this.terminal.rows - 1 : 0, true);
|
|
160
|
+
}
|
|
161
|
+
fail(reason) {
|
|
162
|
+
this.fatal = true;
|
|
163
|
+
this.reason = reason;
|
|
164
|
+
this.gpu?.free();
|
|
165
|
+
this.gpu = undefined;
|
|
166
|
+
this.atlas = undefined;
|
|
167
|
+
this.show(false);
|
|
168
|
+
}
|
|
169
|
+
show(gpu) {
|
|
170
|
+
this.state = gpu ? 'webgpu' : 'dom';
|
|
171
|
+
this.canvas.style.display = gpu ? 'block' : 'none';
|
|
172
|
+
if (this.rows)
|
|
173
|
+
this.rows.style.visibility = gpu ? 'hidden' : '';
|
|
174
|
+
// GPU selection colors are resolved per cell; avoid drawing the DOM
|
|
175
|
+
// selection tint twice. Accessibility lives outside this visual layer.
|
|
176
|
+
const selection = this.core.screenElement.querySelector('.xterm-selection');
|
|
177
|
+
if (selection)
|
|
178
|
+
selection.style.visibility = gpu ? 'hidden' : '';
|
|
179
|
+
}
|
|
180
|
+
fallbackReason() {
|
|
181
|
+
if (this.fatal)
|
|
182
|
+
return this.reason;
|
|
183
|
+
if (!this.gpu)
|
|
184
|
+
return 'GPU initialization';
|
|
185
|
+
if (this.terminal.options.allowTransparency)
|
|
186
|
+
return 'Transparency';
|
|
187
|
+
if (this.terminal.options.minimumContrastRatio !== 1)
|
|
188
|
+
return 'Minimum contrast adjustment';
|
|
189
|
+
if (this.core._characterJoinerService._characterJoiners.length)
|
|
190
|
+
return 'Character joiners';
|
|
191
|
+
if (!this.core._decorationService.decorations.next().done)
|
|
192
|
+
return 'Buffer decorations';
|
|
193
|
+
if (this.hovering)
|
|
194
|
+
return 'Link hover decorations';
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
renderRows(start, end) {
|
|
198
|
+
if (this.disposed)
|
|
199
|
+
return;
|
|
200
|
+
const reason = this.fallbackReason();
|
|
201
|
+
if (reason) {
|
|
202
|
+
if (this.state !== 'dom') {
|
|
203
|
+
this.full = true;
|
|
204
|
+
start = 0;
|
|
205
|
+
end = this.terminal.rows - 1;
|
|
206
|
+
}
|
|
207
|
+
this.reason = reason;
|
|
208
|
+
this.show(false);
|
|
209
|
+
this.fallback.renderRows(start, end);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const d = this.dimensions, o = this.terminal.options;
|
|
214
|
+
const geometry = `${this.terminal.cols},${this.terminal.rows},${d.device.canvas.width},${d.device.canvas.height}`;
|
|
215
|
+
if (!d.device.cell.width || !d.device.cell.height)
|
|
216
|
+
return;
|
|
217
|
+
if (geometry !== this.geometry) {
|
|
218
|
+
this.gpu.configure(this.terminal.cols, this.terminal.rows, Math.round(d.device.canvas.width), Math.round(d.device.canvas.height));
|
|
219
|
+
this.canvas.style.width = `${d.css.canvas.width}px`;
|
|
220
|
+
this.canvas.style.height = `${d.css.canvas.height}px`;
|
|
221
|
+
this.geometry = geometry;
|
|
222
|
+
this.full = true;
|
|
223
|
+
const rows = this.terminal.rows;
|
|
224
|
+
this.rowWords = new Uint32Array(rows * this.terminal.cols * 3);
|
|
225
|
+
this.rowCached = new Uint8Array(rows);
|
|
226
|
+
this.rowStamp = new Uint32Array(rows);
|
|
227
|
+
}
|
|
228
|
+
const font = `${o.fontFamily}|${o.fontSize}|${o.fontWeight}|${o.fontWeightBold}|${d.device.cell.width}|${d.device.cell.height}|${this.core._coreBrowserService.dpr}`;
|
|
229
|
+
if (font !== this.font) {
|
|
230
|
+
this.atlas = new BrowserAtlas(this.canvas.ownerDocument, this.gpu, o, this.core._coreBrowserService.dpr, d.device.cell.width, d.device.cell.height);
|
|
231
|
+
this.font = font;
|
|
232
|
+
this.full = true;
|
|
233
|
+
}
|
|
234
|
+
if (this.full || this.state !== 'webgpu') {
|
|
235
|
+
start = 0;
|
|
236
|
+
end = this.terminal.rows - 1;
|
|
237
|
+
this.rowCached.fill(0);
|
|
238
|
+
}
|
|
239
|
+
let changed;
|
|
240
|
+
try {
|
|
241
|
+
changed = this.pack(start, end);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
if (!(error instanceof AtlasFull))
|
|
245
|
+
throw error;
|
|
246
|
+
this.atlas.reset();
|
|
247
|
+
this.rowCached.fill(0);
|
|
248
|
+
changed = this.pack(0, this.terminal.rows - 1);
|
|
249
|
+
}
|
|
250
|
+
const b = this.terminal.buffer.active, colors = this.core._themeService.colors;
|
|
251
|
+
const cs = this.core.coreService;
|
|
252
|
+
const focused = this.core._coreBrowserService.isFocused;
|
|
253
|
+
const style = focused
|
|
254
|
+
? (cs.decPrivateModes.cursorStyle ?? o.cursorStyle)
|
|
255
|
+
: o.cursorInactiveStyle;
|
|
256
|
+
const styles = { bar: 0, block: 1, underline: 2, outline: 3 };
|
|
257
|
+
const y = b.baseY + b.cursorY - b.viewportY;
|
|
258
|
+
const visible = cs.isCursorInitialized &&
|
|
259
|
+
!cs.isCursorHidden &&
|
|
260
|
+
style !== 'none' &&
|
|
261
|
+
y >= 0 &&
|
|
262
|
+
y < this.terminal.rows &&
|
|
263
|
+
(!focused || !(cs.decPrivateModes.cursorBlink ?? o.cursorBlink) || this.blink);
|
|
264
|
+
this.view[0] = d.device.cell.width;
|
|
265
|
+
this.view[1] = d.device.cell.height;
|
|
266
|
+
this.view[2] = this.atlas.width;
|
|
267
|
+
this.view[3] = this.atlas.height;
|
|
268
|
+
this.frame[0] = this.terminal.cols;
|
|
269
|
+
this.frame[1] = this.terminal.rows;
|
|
270
|
+
this.frame[2] = y * this.terminal.cols + Math.min(b.cursorX, this.terminal.cols - 1);
|
|
271
|
+
this.frame[3] = +visible | ((styles[style ?? 'outline'] ?? 3) << 1) | 65536;
|
|
272
|
+
this.frame[4] = rgba(colors.cursor.rgba);
|
|
273
|
+
this.frame[5] = rgba(colors.cursorAccent.rgba);
|
|
274
|
+
this.frame[7] =
|
|
275
|
+
255 | (Math.max(1, Math.round(o.cursorWidth * this.core._coreBrowserService.dpr)) << 8);
|
|
276
|
+
const cols = this.terminal.cols;
|
|
277
|
+
const [first, last] = changed ?? [0, -1];
|
|
278
|
+
if (!this.gpu.render_staged((last - first + 1) * cols, first * cols)) {
|
|
279
|
+
this.invalidate();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
this.full = false;
|
|
283
|
+
this.reason = undefined;
|
|
284
|
+
this.show(true);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
this.fail(String(error));
|
|
288
|
+
this.fallback.renderRows(0, this.terminal.rows - 1);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
refreshStaging() {
|
|
292
|
+
const pointer = this.gpu.staging_ptr;
|
|
293
|
+
const words = this.gpu.staging_words;
|
|
294
|
+
const buffer = this.memory.buffer;
|
|
295
|
+
if (this.staging.buffer !== buffer ||
|
|
296
|
+
this.staging.byteOffset !== pointer ||
|
|
297
|
+
this.staging.length !== words) {
|
|
298
|
+
this.staging = new Uint32Array(buffer, pointer, words);
|
|
299
|
+
this.view = new Float32Array(buffer, pointer + words * 4, 4);
|
|
300
|
+
this.frame = new Uint32Array(buffer, pointer + (words + 4) * 4, 8);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
selected(x, y) {
|
|
304
|
+
const a = this.selectedStart, b = this.selectedEnd;
|
|
305
|
+
if (!a || !b)
|
|
306
|
+
return false;
|
|
307
|
+
if (this.columnSelection)
|
|
308
|
+
return (y >= Math.min(a[1], b[1]) &&
|
|
309
|
+
y <= Math.max(a[1], b[1]) &&
|
|
310
|
+
x >= Math.min(a[0], b[0]) &&
|
|
311
|
+
x < Math.max(a[0], b[0]));
|
|
312
|
+
return (y > a[1] || (y === a[1] && x >= a[0])) && (y < b[1] || (y === b[1] && x < b[0]));
|
|
313
|
+
}
|
|
314
|
+
/** Bring staging rows start..end up to date with the buffer. Returns the
|
|
315
|
+
* first and last rows whose staging changed, or undefined when none did. */
|
|
316
|
+
pack(start, end) {
|
|
317
|
+
const { cols, rows, buffer, options } = this.terminal;
|
|
318
|
+
const b = buffer.active, c = this.core._themeService.colors, atlas = this.atlas;
|
|
319
|
+
this.refreshStaging();
|
|
320
|
+
if (rows * cols * CELL_WORDS > this.staging.length || end >= rows)
|
|
321
|
+
throw new Error('Packed rows exceed configured staging');
|
|
322
|
+
let values = this.staging;
|
|
323
|
+
const rowWords = this.rowWords, cached = this.rowCached, stamps = this.rowStamp, stamp = ++this.stamp, raw = cols * 3, packed = cols * CELL_WORDS;
|
|
324
|
+
// Content moves up when the viewport advances, so copy from rows below
|
|
325
|
+
// first; when it moves back, walk upwards so copy sources stay intact.
|
|
326
|
+
const delta = b.viewportY - this.lastViewportY;
|
|
327
|
+
this.lastViewportY = b.viewportY;
|
|
328
|
+
const step = delta < 0 ? -1 : 1;
|
|
329
|
+
let first = rows, last = -1, searched = false;
|
|
330
|
+
const hasSelection = !!this.selectedStart && !!this.selectedEnd;
|
|
331
|
+
const selectionBackground = rgba((this.core._coreBrowserService.isFocused
|
|
332
|
+
? c.selectionBackgroundOpaque
|
|
333
|
+
: c.selectionInactiveBackgroundOpaque).rgba);
|
|
334
|
+
const selectionForeground = c.selectionForeground
|
|
335
|
+
? rgba(c.selectionForeground.rgba)
|
|
336
|
+
: undefined;
|
|
337
|
+
const brighten = !!options.drawBoldTextInBrightColors;
|
|
338
|
+
// Attribute runs are common even when every glyph differs. Keep just the
|
|
339
|
+
// previous decoded style, so RGB churn cannot grow or thrash a style cache.
|
|
340
|
+
// Words are unsigned, so -1 never matches a real attribute word.
|
|
341
|
+
let lastFg = -1, lastBg = -1, styleFg = 0, styleBg = 0, styleUnderline = 0, styleFlags = 0;
|
|
342
|
+
rowLoop: for (let y = step > 0 ? start : end; y >= start && y <= end; y += step) {
|
|
343
|
+
const row = b.viewportY + y;
|
|
344
|
+
const line = b.getLine(row);
|
|
345
|
+
const words = packedRow(line, cols);
|
|
346
|
+
const selectable = hasSelection && this.rowSelected(row);
|
|
347
|
+
if (words !== undefined && !selectable) {
|
|
348
|
+
if (cached[y] && sameRow(words, rowWords, y * raw, raw))
|
|
349
|
+
continue;
|
|
350
|
+
// Scrolled content: find this row's words among rows staged last
|
|
351
|
+
// frame that have not been overwritten yet, and move them.
|
|
352
|
+
const candidates = [this.shift, delta, 1];
|
|
353
|
+
for (let k = 0; k <= candidates.length; k++) {
|
|
354
|
+
let source = -1;
|
|
355
|
+
if (k < candidates.length) {
|
|
356
|
+
const s = y + candidates[k];
|
|
357
|
+
if (s !== y && s >= 0 && s < rows && cached[s] && stamps[s] !== stamp)
|
|
358
|
+
if (sameRow(words, rowWords, s * raw, raw))
|
|
359
|
+
source = s;
|
|
360
|
+
}
|
|
361
|
+
else if (!searched) {
|
|
362
|
+
searched = true;
|
|
363
|
+
for (let s = 0; s < rows && source < 0; s++)
|
|
364
|
+
if (s !== y &&
|
|
365
|
+
cached[s] &&
|
|
366
|
+
stamps[s] !== stamp &&
|
|
367
|
+
sameRow(words, rowWords, s * raw, raw))
|
|
368
|
+
source = s;
|
|
369
|
+
}
|
|
370
|
+
if (source < 0)
|
|
371
|
+
continue;
|
|
372
|
+
values.copyWithin(y * packed, source * packed, (source + 1) * packed);
|
|
373
|
+
rowWords.copyWithin(y * raw, source * raw, (source + 1) * raw);
|
|
374
|
+
cached[y] = 1;
|
|
375
|
+
stamps[y] = stamp;
|
|
376
|
+
this.shift = source - y;
|
|
377
|
+
first = Math.min(first, y);
|
|
378
|
+
last = Math.max(last, y);
|
|
379
|
+
continue rowLoop;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
let direct = words !== undefined && !selectable;
|
|
383
|
+
for (let x = 0, i = y * packed; x < cols; x++, i += CELL_WORDS) {
|
|
384
|
+
if (words !== undefined) {
|
|
385
|
+
const content = words[x * 3], fgWord = words[x * 3 + 1], bgWord = words[x * 3 + 2];
|
|
386
|
+
// Ordinary scalar cells decode straight from xterm's row storage.
|
|
387
|
+
// Combined text, extended attributes and unknown widths use getters.
|
|
388
|
+
if (!(bgWord & CELL_HAS_EXTENDED) &&
|
|
389
|
+
!(content & CELL_IS_COMBINED) &&
|
|
390
|
+
content >>> 22 <= 2 &&
|
|
391
|
+
(content & CELL_CODEPOINT_MASK) <= 0x10ffff) {
|
|
392
|
+
if (fgWord !== lastFg || bgWord !== lastBg) {
|
|
393
|
+
const inverse = !!(fgWord & 0x4000000);
|
|
394
|
+
styleFg = wordColor(inverse ? bgWord : fgWord, !inverse, c, !!(fgWord & 0x8000000) && brighten);
|
|
395
|
+
styleBg = wordColor(inverse ? fgWord : bgWord, inverse, c, false);
|
|
396
|
+
styleUnderline = fgWord & 0x3000000 ? wordColor(fgWord, true, c, false) : -1;
|
|
397
|
+
styleFlags =
|
|
398
|
+
((fgWord >>> 27) & 1) |
|
|
399
|
+
(((bgWord >>> 26) & 1) << 1) |
|
|
400
|
+
(((bgWord >>> 27) & 1) << 2) |
|
|
401
|
+
(((fgWord >>> 30) & 1) << 4) |
|
|
402
|
+
((fgWord >>> 31) << 5) |
|
|
403
|
+
(((bgWord >>> 30) & 1) << 6) |
|
|
404
|
+
(((fgWord >>> 28) & 1) << 8);
|
|
405
|
+
lastFg = fgWord;
|
|
406
|
+
lastBg = bgWord;
|
|
407
|
+
}
|
|
408
|
+
let fg = styleFg, bg = styleBg;
|
|
409
|
+
if (selectable && this.selected(x, row)) {
|
|
410
|
+
bg = selectionBackground;
|
|
411
|
+
if (selectionForeground !== undefined)
|
|
412
|
+
fg = selectionForeground;
|
|
413
|
+
}
|
|
414
|
+
const width = content >>> 22;
|
|
415
|
+
values[i] = fg;
|
|
416
|
+
values[i + 1] = bg;
|
|
417
|
+
values[i + 2] = styleUnderline < 0 ? fg : styleUnderline;
|
|
418
|
+
values[i + 3] = width === 2 ? styleFlags | 65536 : styleFlags;
|
|
419
|
+
values[i + 4] = width ? atlas.scalar(content & CELL_CODEPOINT_MASK, styleFlags & 3) : 0;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
lastFg = lastBg = -1;
|
|
424
|
+
direct = false;
|
|
425
|
+
const data = line?.getCell(x, this.cell);
|
|
426
|
+
if (!data) {
|
|
427
|
+
values[i] = rgba(c.foreground.rgba);
|
|
428
|
+
values[i + 1] = rgba(c.background.rgba);
|
|
429
|
+
values.fill(0, i + 2, i + CELL_WORDS);
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
let fg = resolveColor(data, !data.isInverse(), true, c, brighten), bg = resolveColor(data, !!data.isInverse(), false, c, false);
|
|
433
|
+
const flags = +!!data.isBold() |
|
|
434
|
+
(+!!data.isItalic() << 1) |
|
|
435
|
+
(+!!data.isDim() << 2) |
|
|
436
|
+
(+!!data.isInvisible() << 4) |
|
|
437
|
+
(+!!data.isStrikethrough() << 5) |
|
|
438
|
+
(+!!data.isOverline() << 6) |
|
|
439
|
+
(data.getUnderlineStyle() << 8);
|
|
440
|
+
if (selectable && this.selected(x, row)) {
|
|
441
|
+
bg = selectionBackground;
|
|
442
|
+
if (selectionForeground !== undefined)
|
|
443
|
+
fg = selectionForeground;
|
|
444
|
+
}
|
|
445
|
+
const width = data.getWidth();
|
|
446
|
+
const content = data.content;
|
|
447
|
+
values[i] = fg;
|
|
448
|
+
values[i + 1] = bg;
|
|
449
|
+
values[i + 2] = data.isUnderlineColorRGB()
|
|
450
|
+
? rgb(data.getUnderlineColor())
|
|
451
|
+
: data.isUnderlineColorPalette()
|
|
452
|
+
? rgba(c.ansi[data.getUnderlineColor()].rgba)
|
|
453
|
+
: fg;
|
|
454
|
+
values[i + 3] = width === 2 ? flags | 65536 : flags;
|
|
455
|
+
values[i + 4] = !width
|
|
456
|
+
? 0
|
|
457
|
+
: typeof content === 'number' &&
|
|
458
|
+
!(content & CELL_IS_COMBINED) &&
|
|
459
|
+
(content & CELL_CODEPOINT_MASK) <= 0x10ffff
|
|
460
|
+
? atlas.scalar(content & CELL_CODEPOINT_MASK, flags & 3)
|
|
461
|
+
: atlas.tile(data.getChars(), flags & 3);
|
|
462
|
+
}
|
|
463
|
+
if (values.buffer !== this.memory.buffer) {
|
|
464
|
+
// A cold glyph upload can grow Wasm memory mid-row and detach views.
|
|
465
|
+
// Earlier writes survive at the same addresses; repeat this row with
|
|
466
|
+
// fresh views to replace any writes skipped after detachment.
|
|
467
|
+
this.refreshStaging();
|
|
468
|
+
values = this.staging;
|
|
469
|
+
lastFg = lastBg = -1;
|
|
470
|
+
y -= step;
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
// Rows with combined text, extended attributes or selection depend on
|
|
474
|
+
// more than their words; they are always repacked.
|
|
475
|
+
if (direct)
|
|
476
|
+
rowWords.set(words.subarray(0, raw), y * raw);
|
|
477
|
+
cached[y] = +direct;
|
|
478
|
+
stamps[y] = stamp;
|
|
479
|
+
first = Math.min(first, y);
|
|
480
|
+
last = Math.max(last, y);
|
|
481
|
+
}
|
|
482
|
+
return last < 0 ? undefined : [first, last];
|
|
483
|
+
}
|
|
484
|
+
rowSelected(row) {
|
|
485
|
+
const a = this.selectedStart, b = this.selectedEnd;
|
|
486
|
+
return row >= Math.min(a[1], b[1]) && row <= Math.max(a[1], b[1]);
|
|
487
|
+
}
|
|
488
|
+
handleDevicePixelRatioChange() {
|
|
489
|
+
this.fallback.handleDevicePixelRatioChange();
|
|
490
|
+
this.invalidate();
|
|
491
|
+
}
|
|
492
|
+
handleResize(cols, rows) {
|
|
493
|
+
this.fallback.handleResize(cols, rows);
|
|
494
|
+
this.invalidate();
|
|
495
|
+
}
|
|
496
|
+
handleCharSizeChanged() {
|
|
497
|
+
this.fallback.handleCharSizeChanged();
|
|
498
|
+
this.invalidate();
|
|
499
|
+
}
|
|
500
|
+
handleBlur() {
|
|
501
|
+
this.fallback.handleBlur();
|
|
502
|
+
this.invalidate();
|
|
503
|
+
}
|
|
504
|
+
handleFocus() {
|
|
505
|
+
this.blink = true;
|
|
506
|
+
this.fallback.handleFocus();
|
|
507
|
+
this.invalidate();
|
|
508
|
+
}
|
|
509
|
+
handleSelectionChanged(start, end, column) {
|
|
510
|
+
this.selectedStart = start;
|
|
511
|
+
this.selectedEnd = end;
|
|
512
|
+
this.columnSelection = column;
|
|
513
|
+
this.fallback.handleSelectionChanged(start, end, column);
|
|
514
|
+
this.invalidate();
|
|
515
|
+
}
|
|
516
|
+
handleCursorMove() {
|
|
517
|
+
this.blink = true;
|
|
518
|
+
this.fallback.handleCursorMove();
|
|
519
|
+
this.invalidate(false);
|
|
520
|
+
}
|
|
521
|
+
clear() {
|
|
522
|
+
this.fallback.clear();
|
|
523
|
+
this.invalidate();
|
|
524
|
+
}
|
|
525
|
+
clearTextureAtlas() {
|
|
526
|
+
this.atlas?.reset();
|
|
527
|
+
this.invalidate();
|
|
528
|
+
}
|
|
529
|
+
dispose() {
|
|
530
|
+
if (this.disposed)
|
|
531
|
+
return;
|
|
532
|
+
this.disposed = true;
|
|
533
|
+
clearInterval(this.timer);
|
|
534
|
+
for (const subscription of this.subscriptions)
|
|
535
|
+
subscription.dispose();
|
|
536
|
+
this.gpu?.free();
|
|
537
|
+
this.canvas.remove();
|
|
538
|
+
this.fallback.dispose();
|
|
539
|
+
}
|
|
540
|
+
}
|
package/dist/xterm.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Terminal as TerminalApi, ITerminalOptions, ITerminalInitOnlyOptions } from './xterm-api.js';
|
|
2
|
+
import { type RendererState } from './xterm-renderer.js';
|
|
3
|
+
declare const XtermTerminal: typeof TerminalApi;
|
|
4
|
+
export type * from './xterm-api.js';
|
|
5
|
+
/** Complete xterm.js 6.0 public API. Construction/open remain synchronous;
|
|
6
|
+
* WebGPU warms asynchronously while xterm's DOM renderer remains usable. */
|
|
7
|
+
export declare class Terminal extends XtermTerminal {
|
|
8
|
+
private wraithRenderer;
|
|
9
|
+
private wraithDisposed;
|
|
10
|
+
constructor(options?: ITerminalOptions & ITerminalInitOnlyOptions);
|
|
11
|
+
/** Resolves after GPU initialization. False means the DOM fallback is active. */
|
|
12
|
+
get webgpuReady(): Promise<boolean>;
|
|
13
|
+
get renderer(): RendererState;
|
|
14
|
+
get rendererFallbackReason(): string | undefined;
|
|
15
|
+
open(parent: HTMLElement): void;
|
|
16
|
+
dispose(): void;
|
|
17
|
+
}
|
package/dist/xterm.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Terminal as RuntimeTerminal } from '@wraith-terminal/xterm-base/lib/xterm.mjs';
|
|
2
|
+
import { XtermRenderer } from './xterm-renderer.js';
|
|
3
|
+
const XtermTerminal = RuntimeTerminal;
|
|
4
|
+
/** Complete xterm.js 6.0 public API. Construction/open remain synchronous;
|
|
5
|
+
* WebGPU warms asynchronously while xterm's DOM renderer remains usable. */
|
|
6
|
+
export class Terminal extends XtermTerminal {
|
|
7
|
+
wraithRenderer;
|
|
8
|
+
wraithDisposed = false;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
}
|
|
12
|
+
/** Resolves after GPU initialization. False means the DOM fallback is active. */
|
|
13
|
+
get webgpuReady() {
|
|
14
|
+
return this.wraithRenderer?.ready ?? Promise.resolve(false);
|
|
15
|
+
}
|
|
16
|
+
get renderer() {
|
|
17
|
+
return this.wraithRenderer
|
|
18
|
+
? this.wraithRenderer.active
|
|
19
|
+
? this.wraithRenderer.state
|
|
20
|
+
: 'external'
|
|
21
|
+
: 'dom';
|
|
22
|
+
}
|
|
23
|
+
get rendererFallbackReason() {
|
|
24
|
+
return this.wraithRenderer?.reason;
|
|
25
|
+
}
|
|
26
|
+
open(parent) {
|
|
27
|
+
super.open(parent);
|
|
28
|
+
if (!this.wraithRenderer && !this.wraithDisposed)
|
|
29
|
+
this.wraithRenderer = XtermRenderer.install(this);
|
|
30
|
+
}
|
|
31
|
+
dispose() {
|
|
32
|
+
this.wraithDisposed = true;
|
|
33
|
+
super.dispose();
|
|
34
|
+
}
|
|
35
|
+
}
|