@floegence/floeterm-terminal-web 0.4.31 → 0.5.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/README.md +96 -47
- package/dist/core/TerminalCore.d.ts +10 -2
- package/dist/core/TerminalCore.d.ts.map +1 -1
- package/dist/core/TerminalCore.js +88 -14
- package/dist/core/TerminalCore.js.map +1 -1
- package/dist/core/TerminalRenderScheduler.d.ts +41 -0
- package/dist/core/TerminalRenderScheduler.d.ts.map +1 -0
- package/dist/core/TerminalRenderScheduler.js +112 -0
- package/dist/core/TerminalRenderScheduler.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/manager/TerminalInstanceController.d.ts +70 -0
- package/dist/manager/TerminalInstanceController.d.ts.map +1 -0
- package/dist/manager/TerminalInstanceController.js +633 -0
- package/dist/manager/TerminalInstanceController.js.map +1 -0
- package/dist/types.d.ts +45 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -12
- package/dist/hooks/useTerminalInstance.d.ts +0 -3
- package/dist/hooks/useTerminalInstance.d.ts.map +0 -1
- package/dist/hooks/useTerminalInstance.js +0 -544
- package/dist/hooks/useTerminalInstance.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,43 +1,70 @@
|
|
|
1
1
|
# terminal-web
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
`useTerminalInstance` without UI components.
|
|
3
|
+
Framework-neutral ghostty-web (xterm.js API-compatible) integration with terminal core, session, and data flow utilities.
|
|
5
4
|
|
|
6
5
|
## Install
|
|
6
|
+
|
|
7
7
|
```bash
|
|
8
8
|
npm i @floegence/floeterm-terminal-web
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
## Usage
|
|
12
|
-
```tsx
|
|
13
|
-
import { useTerminalInstance } from '@floegence/floeterm-terminal-web';
|
|
11
|
+
## Usage
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
const { containerRef } = useTerminalInstance({
|
|
17
|
-
sessionId: 'session-1',
|
|
18
|
-
isActive: true,
|
|
19
|
-
transport: myTransport,
|
|
20
|
-
eventSource: myEventSource
|
|
21
|
-
});
|
|
13
|
+
Use the managed controller when you want attach, reconnect-friendly replay, ordered writes, resize, and action helpers handled for you:
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
}
|
|
15
|
+
```ts
|
|
16
|
+
import { createTerminalInstance } from '@floegence/floeterm-terminal-web';
|
|
17
|
+
|
|
18
|
+
const controller = createTerminalInstance({
|
|
19
|
+
sessionId: 'session-1',
|
|
20
|
+
isActive: true,
|
|
21
|
+
transport: myTransport,
|
|
22
|
+
eventSource: myEventSource,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const unsubscribe = controller.subscribe((snapshot) => {
|
|
26
|
+
console.log(snapshot.connection.state, snapshot.loadingMessage);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await controller.mount(container);
|
|
30
|
+
|
|
31
|
+
// Later:
|
|
32
|
+
controller.actions.copySelection('command');
|
|
33
|
+
unsubscribe();
|
|
34
|
+
controller.dispose();
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Use `TerminalCore` directly when the host product owns its own session lifecycle, paging, shell integration, or workbench coordination:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { TerminalCore, getDefaultTerminalConfig } from '@floegence/floeterm-terminal-web';
|
|
41
|
+
|
|
42
|
+
const core = new TerminalCore(
|
|
43
|
+
container,
|
|
44
|
+
getDefaultTerminalConfig('dark', { clipboard: { copyOnSelect: false } }),
|
|
45
|
+
{
|
|
46
|
+
onData: data => transport.sendInput(sessionId, data),
|
|
47
|
+
onResize: size => transport.resize(sessionId, size.cols, size.rows),
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
await core.initialize();
|
|
25
52
|
```
|
|
26
53
|
|
|
27
54
|
## Notes
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
- `
|
|
55
|
+
|
|
56
|
+
- You must provide a `TerminalTransport` and `TerminalEventSource` for the managed controller.
|
|
57
|
+
- `ghostty-web` needs a one-time `init()`; `TerminalCore` handles that internally.
|
|
58
|
+
- `TerminalCore` bridges the hidden textarea used by `ghostty-web`, so soft-keyboard and composition input continue to work on touch devices.
|
|
31
59
|
- Explicit terminal copy is handled through shared selection-copy APIs, so keyboard shortcuts, native app menus, and product context menus can reuse the same selection logic.
|
|
32
|
-
- `TerminalCore`
|
|
60
|
+
- `TerminalCore` exposes runtime appearance updates, shell bell/title events, custom terminal link providers, buffer line reads, and touch-scroll helpers without requiring consumers to reach into private runtime objects.
|
|
61
|
+
- Multiple live `TerminalCore` instances share one render scheduler, so large terminal grids coalesce demand-driven canvas work into browser frames.
|
|
33
62
|
|
|
34
|
-
## Responsive
|
|
35
|
-
When the same remote terminal session can be displayed in multiple views (e.g. a Deck widget and a dedicated Terminal page),
|
|
36
|
-
enable the responsive options so the focused terminal re-syncs cols/rows to the remote PTY:
|
|
63
|
+
## Responsive Resize
|
|
37
64
|
|
|
38
|
-
|
|
39
|
-
import { TerminalCore } from '@floegence/floeterm-terminal-web';
|
|
65
|
+
When the same remote terminal session can be displayed in multiple views, enable responsive options so the focused terminal re-syncs cols/rows to the remote PTY:
|
|
40
66
|
|
|
67
|
+
```ts
|
|
41
68
|
const core = new TerminalCore(container, {
|
|
42
69
|
responsive: {
|
|
43
70
|
fitOnFocus: true,
|
|
@@ -47,21 +74,18 @@ const core = new TerminalCore(container, {
|
|
|
47
74
|
});
|
|
48
75
|
```
|
|
49
76
|
|
|
50
|
-
Passive mirrors of a remote PTY can render with the session owner's current dimensions
|
|
51
|
-
container:
|
|
77
|
+
Passive mirrors of a remote PTY can render with the session owner's current dimensions:
|
|
52
78
|
|
|
53
79
|
```ts
|
|
54
80
|
const core = new TerminalCore(container, {
|
|
55
81
|
fixedDimensions: { cols: 100, rows: 30 },
|
|
56
82
|
});
|
|
57
83
|
|
|
58
|
-
// Later, when this surface becomes the active geometry owner:
|
|
59
84
|
core.setFixedDimensions(null);
|
|
60
85
|
core.forceResize();
|
|
61
86
|
```
|
|
62
87
|
|
|
63
|
-
Hosts with overlay scrollbars can remove the default ghostty-web scrollbar reserve
|
|
64
|
-
terminal surface:
|
|
88
|
+
Hosts with overlay scrollbars can remove the default ghostty-web scrollbar reserve:
|
|
65
89
|
|
|
66
90
|
```ts
|
|
67
91
|
const core = new TerminalCore(container, {
|
|
@@ -71,13 +95,11 @@ const core = new TerminalCore(container, {
|
|
|
71
95
|
});
|
|
72
96
|
```
|
|
73
97
|
|
|
74
|
-
## Clipboard
|
|
75
|
-
By default, upstream mouse selection keeps the `ghostty-web` behavior and copies immediately on selection.
|
|
76
|
-
Consumers that want explicit copy commands only can disable that side effect:
|
|
98
|
+
## Clipboard
|
|
77
99
|
|
|
78
|
-
|
|
79
|
-
import { TerminalCore } from '@floegence/floeterm-terminal-web';
|
|
100
|
+
By default, upstream mouse selection keeps the `ghostty-web` behavior and copies immediately on selection. Consumers that want explicit copy commands only can disable that side effect:
|
|
80
101
|
|
|
102
|
+
```ts
|
|
81
103
|
const core = new TerminalCore(container, {
|
|
82
104
|
clipboard: {
|
|
83
105
|
copyOnSelect: false,
|
|
@@ -91,9 +113,10 @@ With `copyOnSelect: false`, `TerminalCore` keeps selection explicit:
|
|
|
91
113
|
- `core.copySelection()` writes the current terminal selection to the clipboard.
|
|
92
114
|
- `Cmd+C` / `Ctrl+C` only claims the shortcut when the terminal currently has a selection. Otherwise the shortcut falls through unchanged.
|
|
93
115
|
|
|
94
|
-
|
|
116
|
+
The managed controller exposes the same helpers through `controller.actions`.
|
|
117
|
+
|
|
118
|
+
## Link Providers And Buffer Reads
|
|
95
119
|
|
|
96
|
-
## Link providers and shell events
|
|
97
120
|
`TerminalCore` forwards shell lifecycle events and lets consumers register custom links over rendered terminal rows:
|
|
98
121
|
|
|
99
122
|
```ts
|
|
@@ -101,26 +124,40 @@ import { TerminalCore, type TerminalLinkProvider } from '@floegence/floeterm-ter
|
|
|
101
124
|
|
|
102
125
|
const linkProvider: TerminalLinkProvider = {
|
|
103
126
|
provideLinks(y, callback) {
|
|
104
|
-
|
|
127
|
+
const line = core.readBufferLine(y);
|
|
128
|
+
void line;
|
|
105
129
|
callback(undefined);
|
|
106
130
|
},
|
|
107
131
|
};
|
|
108
132
|
|
|
109
133
|
const core = new TerminalCore(container, {}, {
|
|
110
134
|
onBell: () => console.log('bell'),
|
|
111
|
-
onTitleChange:
|
|
135
|
+
onTitleChange: title => console.log('title', title),
|
|
112
136
|
});
|
|
113
137
|
|
|
114
138
|
await core.initialize();
|
|
115
139
|
core.registerLinkProvider(linkProvider);
|
|
116
140
|
```
|
|
117
141
|
|
|
118
|
-
This is the intended extension point for product features such as modifier-click file navigation,
|
|
119
|
-
build-log deep links, or shell attention badges driven by bell events.
|
|
142
|
+
This is the intended extension point for product features such as modifier-click file navigation, build-log deep links, or shell attention badges driven by bell events.
|
|
120
143
|
|
|
121
|
-
##
|
|
122
|
-
|
|
123
|
-
|
|
144
|
+
## Touch Scroll Helpers
|
|
145
|
+
|
|
146
|
+
Hosts with custom mobile input surfaces can ask `TerminalCore` for a safe touch-scroll facade instead of reaching into the underlying runtime:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const touch = core.getTouchScrollRuntime();
|
|
150
|
+
|
|
151
|
+
if (touch?.isAlternateScreen()) {
|
|
152
|
+
touch.sendAlternateScreenInput('\x1B[A');
|
|
153
|
+
} else {
|
|
154
|
+
touch?.scrollLines(-3);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Visual Work Suspension
|
|
159
|
+
|
|
160
|
+
Hosts that animate a surrounding workbench can temporarily suspend expensive terminal visual work while keeping PTY output and the terminal buffer live:
|
|
124
161
|
|
|
125
162
|
```ts
|
|
126
163
|
const suspend = core.beginVisualSuspend({ reason: 'workbench_widget_drag' });
|
|
@@ -132,12 +169,24 @@ try {
|
|
|
132
169
|
}
|
|
133
170
|
```
|
|
134
171
|
|
|
135
|
-
While suspended, `write()` continues to update terminal state. Rendering, fit, full repaint, and overlay refresh requests
|
|
136
|
-
|
|
172
|
+
While suspended, `write()` continues to update terminal state. Rendering, fit, full repaint, and overlay refresh requests are coalesced and reconciled when the final nested suspend handle is disposed.
|
|
173
|
+
|
|
174
|
+
## Multi-Terminal Render Scheduling
|
|
175
|
+
|
|
176
|
+
`TerminalCore` keeps ghostty-web rendering demand-driven and routes visible terminal repaints through a shared scheduler. Demo or profiling surfaces can inspect the scheduler without reaching into private instances:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { getTerminalRenderSchedulerStats } from '@floegence/floeterm-terminal-web';
|
|
180
|
+
|
|
181
|
+
const stats = getTerminalRenderSchedulerStats();
|
|
182
|
+
console.log(stats.lastFrameRendered, stats.pending);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Product code should continue to interact with `TerminalCore` or the managed controller.
|
|
186
|
+
|
|
187
|
+
## Runtime Appearance Updates
|
|
137
188
|
|
|
138
|
-
|
|
139
|
-
Consumers that need to react to user preferences can update appearance without rebuilding the
|
|
140
|
-
terminal session:
|
|
189
|
+
Consumers that need to respond to user preferences can update appearance without rebuilding the terminal session:
|
|
141
190
|
|
|
142
191
|
```ts
|
|
143
192
|
import { getThemeColors } from '@floegence/floeterm-terminal-web';
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { TerminalState, type Logger, type TerminalConfig, type TerminalCopySelectionResult, type TerminalCopySelectionSource, type TerminalDimensions, type TerminalEventHandlers, type TerminalAppearance, type TerminalLinkProvider, type TerminalVisualSuspendHandle, type TerminalVisualSuspendOptions } from '../types';
|
|
1
|
+
import { TerminalState, type Logger, type TerminalConfig, type TerminalCopySelectionResult, type TerminalCopySelectionSource, type TerminalDimensions, type TerminalEventHandlers, type TerminalAppearance, type TerminalLinkProvider, type TerminalRuntimeLineSnapshot, type TerminalTouchScrollRuntime, type TerminalVisualSuspendHandle, type TerminalVisualSuspendOptions } from '../types';
|
|
2
2
|
export declare class TerminalCore {
|
|
3
3
|
private container;
|
|
4
4
|
private config;
|
|
5
5
|
private terminal;
|
|
6
6
|
private fitAddon;
|
|
7
7
|
private needsFullRenderOnNextWrite;
|
|
8
|
-
private demandRenderRaf;
|
|
9
8
|
private demandRenderForceAll;
|
|
9
|
+
private readonly renderTask;
|
|
10
10
|
private viewportHost;
|
|
11
11
|
private renderHost;
|
|
12
12
|
private resizeObserver;
|
|
@@ -51,6 +51,7 @@ export declare class TerminalCore {
|
|
|
51
51
|
private readonly registeredLinkProviders;
|
|
52
52
|
private readonly appliedLinkProviders;
|
|
53
53
|
private readonly visualRenderState;
|
|
54
|
+
private static nextRenderTaskId;
|
|
54
55
|
constructor(container: HTMLElement, config?: TerminalConfig, eventHandlers?: TerminalEventHandlers, logger?: Logger);
|
|
55
56
|
initialize(): Promise<void>;
|
|
56
57
|
private createTerminalInstance;
|
|
@@ -109,6 +110,13 @@ export declare class TerminalCore {
|
|
|
109
110
|
cols: number;
|
|
110
111
|
bufferLength: number;
|
|
111
112
|
} | null;
|
|
113
|
+
readBufferLine(row: number, options?: {
|
|
114
|
+
trimRight?: boolean;
|
|
115
|
+
}): string;
|
|
116
|
+
readBufferLines(startRow: number, endRowInclusive: number, options?: {
|
|
117
|
+
trimRight?: boolean;
|
|
118
|
+
}): TerminalRuntimeLineSnapshot[];
|
|
119
|
+
getTouchScrollRuntime(): TerminalTouchScrollRuntime | null;
|
|
112
120
|
findNext(term: string, options?: {
|
|
113
121
|
caseSensitive?: boolean;
|
|
114
122
|
wholeWord?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TerminalCore.d.ts","sourceRoot":"","sources":["../../src/core/TerminalCore.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,aAAa,EACb,KAAK,MAAM,EAEX,KAAK,cAAc,EACnB,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAE1B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAGzB,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EAElC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"TerminalCore.d.ts","sourceRoot":"","sources":["../../src/core/TerminalCore.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { filterXtermAutoResponses } from '../utils/xtermAutoResponseFilter';
|
|
|
2
2
|
import { createConsoleLogger, noopLogger } from '../utils/logger';
|
|
3
3
|
import { TerminalState, } from '../types';
|
|
4
4
|
import { resolveTerminalInputElement, TerminalInputBridge } from './TerminalInputBridge';
|
|
5
|
+
import { terminalRenderScheduler } from './TerminalRenderScheduler';
|
|
5
6
|
const TERMINAL_SEARCH_MAX_RESULTS = 5000;
|
|
6
7
|
const PRESENTATION_SCALE_EPSILON = 0.0001;
|
|
7
8
|
const GHOSTTY_DEFAULT_SCROLLBAR_RESERVE_PX = 15;
|
|
@@ -280,7 +281,6 @@ export class TerminalCore {
|
|
|
280
281
|
this.terminal = null;
|
|
281
282
|
this.fitAddon = null;
|
|
282
283
|
this.needsFullRenderOnNextWrite = false;
|
|
283
|
-
this.demandRenderRaf = null;
|
|
284
284
|
this.demandRenderForceAll = false;
|
|
285
285
|
this.viewportHost = null;
|
|
286
286
|
this.renderHost = null;
|
|
@@ -338,6 +338,14 @@ export class TerminalCore {
|
|
|
338
338
|
this.logicalFontSize = TerminalCore.normalizeFontSize(config?.fontSize);
|
|
339
339
|
this.presentationScale = TerminalCore.normalizePresentationScale(config?.presentationScale);
|
|
340
340
|
this.fixedDimensions = normalizeTerminalDimensions(config?.fixedDimensions);
|
|
341
|
+
this.renderTask = {
|
|
342
|
+
id: TerminalCore.nextRenderTaskId,
|
|
343
|
+
run: forceAll => {
|
|
344
|
+
this.demandRenderForceAll = false;
|
|
345
|
+
this.renderDemandFrame(forceAll);
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
TerminalCore.nextRenderTaskId += 1;
|
|
341
349
|
}
|
|
342
350
|
// initialize creates the ghostty-web terminal instance and binds addons.
|
|
343
351
|
async initialize() {
|
|
@@ -1246,6 +1254,82 @@ export class TerminalCore {
|
|
|
1246
1254
|
bufferLength: this.terminal.buffer.active.length
|
|
1247
1255
|
};
|
|
1248
1256
|
}
|
|
1257
|
+
readBufferLine(row, options = {}) {
|
|
1258
|
+
if (!this.terminal) {
|
|
1259
|
+
return '';
|
|
1260
|
+
}
|
|
1261
|
+
const normalizedRow = Math.floor(Number(row));
|
|
1262
|
+
if (!Number.isFinite(normalizedRow) || normalizedRow < 0) {
|
|
1263
|
+
return '';
|
|
1264
|
+
}
|
|
1265
|
+
try {
|
|
1266
|
+
const line = this.terminal.buffer?.active?.getLine?.(normalizedRow);
|
|
1267
|
+
const text = line?.translateToString?.(options.trimRight ?? false);
|
|
1268
|
+
return typeof text === 'string' ? text : '';
|
|
1269
|
+
}
|
|
1270
|
+
catch {
|
|
1271
|
+
return '';
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
readBufferLines(startRow, endRowInclusive, options = {}) {
|
|
1275
|
+
const start = Math.floor(Number(startRow));
|
|
1276
|
+
const end = Math.floor(Number(endRowInclusive));
|
|
1277
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) {
|
|
1278
|
+
return [];
|
|
1279
|
+
}
|
|
1280
|
+
const lines = [];
|
|
1281
|
+
for (let row = Math.max(0, start); row <= end; row += 1) {
|
|
1282
|
+
const text = this.readBufferLine(row, options);
|
|
1283
|
+
if (text.length > 0) {
|
|
1284
|
+
lines.push({ row, text });
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
return lines;
|
|
1288
|
+
}
|
|
1289
|
+
getTouchScrollRuntime() {
|
|
1290
|
+
const terminal = this.terminal;
|
|
1291
|
+
if (!terminal) {
|
|
1292
|
+
return null;
|
|
1293
|
+
}
|
|
1294
|
+
return {
|
|
1295
|
+
scrollLines: amount => {
|
|
1296
|
+
const normalizedAmount = Math.trunc(Number(amount));
|
|
1297
|
+
if (!Number.isFinite(normalizedAmount) || normalizedAmount === 0) {
|
|
1298
|
+
return false;
|
|
1299
|
+
}
|
|
1300
|
+
if (typeof terminal.scrollLines !== 'function') {
|
|
1301
|
+
return false;
|
|
1302
|
+
}
|
|
1303
|
+
terminal.scrollLines(normalizedAmount);
|
|
1304
|
+
this.requestDemandRender(false);
|
|
1305
|
+
return true;
|
|
1306
|
+
},
|
|
1307
|
+
getScrollbackLength: () => {
|
|
1308
|
+
if (typeof terminal.getScrollbackLength !== 'function') {
|
|
1309
|
+
return 0;
|
|
1310
|
+
}
|
|
1311
|
+
const length = Number(terminal.getScrollbackLength());
|
|
1312
|
+
return Number.isFinite(length) && length > 0 ? length : 0;
|
|
1313
|
+
},
|
|
1314
|
+
isAlternateScreen: () => {
|
|
1315
|
+
if (typeof terminal.isAlternateScreen !== 'function') {
|
|
1316
|
+
return false;
|
|
1317
|
+
}
|
|
1318
|
+
return Boolean(terminal.isAlternateScreen());
|
|
1319
|
+
},
|
|
1320
|
+
sendAlternateScreenInput: data => {
|
|
1321
|
+
const text = String(data ?? '');
|
|
1322
|
+
if (!text) {
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
if (typeof terminal.input === 'function') {
|
|
1326
|
+
terminal.input(text, true);
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
this.eventHandlers.onData?.(text);
|
|
1330
|
+
},
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1249
1333
|
findNext(term, options) {
|
|
1250
1334
|
return this.findInternal(term, options, 1);
|
|
1251
1335
|
}
|
|
@@ -2119,21 +2203,10 @@ export class TerminalCore {
|
|
|
2119
2203
|
return;
|
|
2120
2204
|
}
|
|
2121
2205
|
this.demandRenderForceAll = this.demandRenderForceAll || forceAll;
|
|
2122
|
-
|
|
2123
|
-
return;
|
|
2124
|
-
}
|
|
2125
|
-
this.demandRenderRaf = requestAnimationFrame(() => {
|
|
2126
|
-
this.demandRenderRaf = null;
|
|
2127
|
-
const shouldForce = this.demandRenderForceAll;
|
|
2128
|
-
this.demandRenderForceAll = false;
|
|
2129
|
-
this.renderDemandFrame(shouldForce);
|
|
2130
|
-
});
|
|
2206
|
+
terminalRenderScheduler.schedule(this.renderTask, this.demandRenderForceAll);
|
|
2131
2207
|
}
|
|
2132
2208
|
cancelDemandRender() {
|
|
2133
|
-
|
|
2134
|
-
cancelAnimationFrame(this.demandRenderRaf);
|
|
2135
|
-
this.demandRenderRaf = null;
|
|
2136
|
-
}
|
|
2209
|
+
terminalRenderScheduler.cancel(this.renderTask);
|
|
2137
2210
|
this.demandRenderForceAll = false;
|
|
2138
2211
|
this.stopGhosttyRenderLoop();
|
|
2139
2212
|
}
|
|
@@ -2169,4 +2242,5 @@ export class TerminalCore {
|
|
|
2169
2242
|
}
|
|
2170
2243
|
}
|
|
2171
2244
|
}
|
|
2245
|
+
TerminalCore.nextRenderTaskId = 1;
|
|
2172
2246
|
//# sourceMappingURL=TerminalCore.js.map
|