@simon_he/vue-tui 1.0.2 → 1.1.1
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 +44 -26
- package/dist/TMermaidText-CXm_L969.js +885 -0
- package/dist/{TSelect-DR0FomSu.js → TSelect-CiyMvwl-.js} +60 -81
- package/dist/{TTree-kzhlB5P0.js → TTree-DKGiuIcM.js} +140 -103
- package/dist/agent/mermaid.cjs +2 -0
- package/dist/agent/mermaid.d.cts +2 -0
- package/dist/agent/mermaid.d.ts +2 -0
- package/dist/agent/mermaid.js +1 -0
- package/dist/agent.cjs +31184 -24907
- package/dist/agent.d.cts +11 -1
- package/dist/agent.d.ts +11 -1
- package/dist/agent.js +1700 -13
- package/dist/block-source-5CQp4tF8.js +3230 -0
- package/dist/cli/stdin-buffer.d.ts +1 -1
- package/dist/cli.cjs +5037 -6767
- package/dist/cli.d.cts +4 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +2733 -148
- package/dist/core/buffer/eaw-ranges-unicode-17.d.ts +14 -0
- package/dist/core/perf/instrumentation-noop.d.ts +48 -0
- package/dist/core/perf/instrumentation.d.ts +136 -0
- package/dist/core/terminal/create-terminal.d.ts +1 -0
- package/dist/core.cjs +843 -1469
- package/dist/core.js +6 -6
- package/dist/{create-terminal-DBFNYr8f.js → create-terminal-DXuZ2fci.js} +39 -13
- package/dist/debug-logger-ChY_PXVk.js +74 -0
- package/dist/{dom-renderer-BniJSQyX.js → dom-renderer-DNzmg2As.js} +2 -2
- package/dist/experimental.cjs +4115 -5928
- package/dist/experimental.d.cts +2 -0
- package/dist/experimental.d.ts +2 -0
- package/dist/experimental.js +1490 -9
- package/dist/frame-perf-BBhE-iuS.js +111 -0
- package/dist/{sgr-BmzxEjAO.js → hyperlink-B35-O-cW.js} +100 -1
- package/dist/index.cjs +5017 -10339
- package/dist/index.js +16 -14
- package/dist/{linkify-D_gzn9Xq.js → linkify-CuuquMQT.js} +32 -3
- package/dist/markdown.cjs +21295 -12691
- package/dist/markdown.d.cts +1 -1
- package/dist/markdown.d.ts +1 -1
- package/dist/markdown.js +211 -51
- package/dist/mermaid-CWto52Wk.js +123 -0
- package/dist/mermaid.cjs +1707 -0
- package/dist/mermaid.d.cts +3 -0
- package/dist/mermaid.d.ts +3 -0
- package/dist/mermaid.js +6 -0
- package/dist/observability/frame-perf-store.d.ts +2 -1
- package/dist/observability/frame-perf.d.ts +33 -0
- package/dist/observability.cjs +106 -107
- package/dist/observability.d.cts +2 -2
- package/dist/observability.d.ts +2 -2
- package/dist/observability.js +3 -3
- package/dist/{path-suggest-BNqcuE3-.js → path-suggest-fPzRsgPv.js} +1 -1
- package/dist/{wheel-scroll-vBRaQ7p-.js → rect-Ng-3eKzF.js} +253 -117
- package/dist/renderer/cli/stdout-metrics.d.ts +10 -0
- package/dist/renderer/cli/stdout-renderer.d.ts +3 -0
- package/dist/renderer/terminal-graphic-render-queue.d.ts +50 -0
- package/dist/renderer/terminal-graphics-trace.d.ts +53 -0
- package/dist/renderer/terminal-graphics.d.ts +146 -0
- package/dist/renderer-dom.cjs +364 -903
- package/dist/renderer-dom.js +4 -4
- package/dist/runtime/index.d.ts +2 -0
- package/dist/{runtime-rfcZCyJq.js → runtime-D77C03RM.js} +28 -15
- package/dist/runtime.cjs +427 -889
- package/dist/runtime.js +2 -2
- package/dist/{terminal-selection-DBinO6p5.js → terminal-selection-CQYr--26.js} +4 -1
- package/dist/{tlog-theme-CvLFNMwk.js → tlog-theme-CopRt9SC.js} +37 -6
- package/dist/{trace-CjzYeIxN.js → trace-CYHDKM1m.js} +5 -0
- package/dist/vue/agent/create-png-terminal-graphic-renderer.d.ts +19 -0
- package/dist/vue/components/TAgentTerminalGraphic.d.ts +481 -0
- package/dist/vue/components/TCharts.d.ts +1121 -0
- package/dist/vue/components/TFeedback.d.ts +1 -1
- package/dist/vue/components/TFlex.d.ts +389 -0
- package/dist/vue/components/TForm.d.ts +4 -4
- package/dist/vue/components/TLogSearchBar.d.ts +3 -3
- package/dist/vue/components/TLogSearchPager.d.ts +2 -2
- package/dist/vue/components/TMarkdownText.d.ts +162 -4
- package/dist/vue/components/TMermaidText.d.ts +900 -0
- package/dist/vue/components/TVirtualList.d.ts +9 -0
- package/dist/vue/components/TVirtualMarkdown.d.ts +170 -9
- package/dist/vue/components/TVirtualRows.d.ts +9 -0
- package/dist/vue/components/TerminalProvider.d.ts +2 -0
- package/dist/vue/context.d.ts +24 -0
- package/dist/vue/index.d.ts +5 -0
- package/dist/vue/layout/flex.d.ts +67 -0
- package/dist/vue/markdown/ast.d.ts +5 -2
- package/dist/vue/markdown/document.d.ts +5 -0
- package/dist/vue/markdown/image-actions.d.ts +14 -0
- package/dist/vue/markdown/image.d.ts +11 -0
- package/dist/vue/markdown/link-actions.d.ts +14 -0
- package/dist/vue/markdown/math-actions.d.ts +14 -0
- package/dist/vue/markdown/math.d.ts +6 -0
- package/dist/vue/markdown/render.d.ts +28 -0
- package/dist/vue/markdown/types.d.ts +78 -0
- package/dist/vue/mermaid/beautiful-mermaid.d.ts +1436 -0
- package/dist/vue/render/render-manager.d.ts +7 -0
- package/dist/vue.cjs +7207 -12437
- package/dist/vue.js +706 -39
- package/dist/wheel-scroll-CQ22Hcyj.js +106 -0
- package/dist/{hyperlink-Bn02UXJb.js → width-GqllnV8C.js} +166 -111
- package/package.json +85 -14
- package/dist/block-source-CKUOnkgT.js +0 -1663
- package/dist/frame-perf-C6Xfg85O.js +0 -24
- /package/dist/{env-Cl8qmNFN.js → env-DNCzvX8b.js} +0 -0
- /package/dist/{path-mnSgEpCm.js → path-BI9W15Zt.js} +0 -0
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ function envFlag(env, primary, legacy) {
|
|
|
20
20
|
const raw = String(firstNonEmptyEnv(env, primary, legacy) ?? "").trim().toLowerCase();
|
|
21
21
|
return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
|
|
22
22
|
}
|
|
23
|
-
function envString(env, primary, legacy, fallback = "") {
|
|
23
|
+
function envString$1(env, primary, legacy, fallback = "") {
|
|
24
24
|
return String(firstNonEmptyEnv(env, primary, legacy) ?? fallback).trim() || fallback;
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -33,7 +33,7 @@ const MAX_OP_AGE_MS = 5e3;
|
|
|
33
33
|
const GLOBAL_PROFILER_KEY = "__vueTuiCliLatencyProfiler";
|
|
34
34
|
let nextOpId = 1;
|
|
35
35
|
let singleton;
|
|
36
|
-
function now$
|
|
36
|
+
function now$2() {
|
|
37
37
|
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
38
38
|
}
|
|
39
39
|
function diffMs(end, start) {
|
|
@@ -68,7 +68,7 @@ function createProfiler() {
|
|
|
68
68
|
const processLike = process;
|
|
69
69
|
const env = (processLike === null || processLike === void 0 ? void 0 : processLike.env) ?? {};
|
|
70
70
|
if (!envFlag(env, "VUE_TUI_PROFILE_INPUT_LATENCY", "DIMCODE_PROFILE_INPUT_LATENCY")) return createDisabledProfiler();
|
|
71
|
-
const logPath = envString(env, "VUE_TUI_PROFILE_INPUT_LATENCY_LOG_PATH", "DIMCODE_PROFILE_INPUT_LATENCY_LOG_PATH", defaultCliLatencyLogPath());
|
|
71
|
+
const logPath = envString$1(env, "VUE_TUI_PROFILE_INPUT_LATENCY_LOG_PATH", "DIMCODE_PROFILE_INPUT_LATENCY_LOG_PATH", defaultCliLatencyLogPath());
|
|
72
72
|
const ops = new Map();
|
|
73
73
|
const pendingCommitIds = new Set();
|
|
74
74
|
const pendingWriteIds = new Set();
|
|
@@ -146,7 +146,7 @@ function createProfiler() {
|
|
|
146
146
|
cleanupOp(op.id);
|
|
147
147
|
};
|
|
148
148
|
const expireOldOps = () => {
|
|
149
|
-
const currentTime = now$
|
|
149
|
+
const currentTime = now$2();
|
|
150
150
|
for (const op of ops.values()) {
|
|
151
151
|
if (currentTime - op.createdAt < MAX_OP_AGE_MS) continue;
|
|
152
152
|
flushOp(op, op.writeEndAt != null ? "completed" : "timeout");
|
|
@@ -163,7 +163,7 @@ function createProfiler() {
|
|
|
163
163
|
const id = nextOpId++;
|
|
164
164
|
const op = {
|
|
165
165
|
id,
|
|
166
|
-
createdAt: now$
|
|
166
|
+
createdAt: now$2(),
|
|
167
167
|
createdAtIso: new Date().toISOString(),
|
|
168
168
|
eventType: type,
|
|
169
169
|
key: String((event === null || event === void 0 ? void 0 : event.key) ?? ""),
|
|
@@ -206,7 +206,7 @@ function createProfiler() {
|
|
|
206
206
|
};
|
|
207
207
|
const resolveActiveOp = () => {
|
|
208
208
|
if (currentDispatchOpId != null) return ops.get(currentDispatchOpId) ?? null;
|
|
209
|
-
if (lastDispatchOpId != null && lastDispatchEndedAt != null && now$
|
|
209
|
+
if (lastDispatchOpId != null && lastDispatchEndedAt != null && now$2() - lastDispatchEndedAt <= INVALIDATE_ASSOCIATION_WINDOW_MS) return ops.get(lastDispatchOpId) ?? null;
|
|
210
210
|
return null;
|
|
211
211
|
};
|
|
212
212
|
processLike === null || processLike === void 0 || (_processLike$once = processLike.once) === null || _processLike$once === void 0 || _processLike$once.call(processLike, "exit", () => {
|
|
@@ -215,27 +215,27 @@ function createProfiler() {
|
|
|
215
215
|
return {
|
|
216
216
|
enabled: true,
|
|
217
217
|
recordRawInput(_info) {
|
|
218
|
-
lastRawInputAt = now$
|
|
218
|
+
lastRawInputAt = now$2();
|
|
219
219
|
expireOldOps();
|
|
220
220
|
},
|
|
221
221
|
recordStdinDispatch(event, info) {
|
|
222
222
|
const op = ensureOp(event);
|
|
223
223
|
if (!op) return;
|
|
224
224
|
if (op.rawInputAt == null && lastRawInputAt != null) op.rawInputAt = lastRawInputAt;
|
|
225
|
-
if (op.stdinDispatchAt == null) op.stdinDispatchAt = now$
|
|
225
|
+
if (op.stdinDispatchAt == null) op.stdinDispatchAt = now$2();
|
|
226
226
|
if (!op.parser && (info === null || info === void 0 ? void 0 : info.parser)) op.parser = String(info.parser);
|
|
227
227
|
},
|
|
228
228
|
recordEventDispatchStart(event) {
|
|
229
229
|
const op = ensureOp(event);
|
|
230
230
|
if (!op) return;
|
|
231
231
|
currentDispatchOpId = op.id;
|
|
232
|
-
if (op.dispatchStartAt == null) op.dispatchStartAt = now$
|
|
232
|
+
if (op.dispatchStartAt == null) op.dispatchStartAt = now$2();
|
|
233
233
|
},
|
|
234
234
|
recordEventDispatchEnd(event, info) {
|
|
235
235
|
const op = ensureOp(event);
|
|
236
236
|
if (!op) return;
|
|
237
237
|
op.defaultPrevented = Boolean(info.defaultPrevented);
|
|
238
|
-
if (op.dispatchEndAt == null) op.dispatchEndAt = now$
|
|
238
|
+
if (op.dispatchEndAt == null) op.dispatchEndAt = now$2();
|
|
239
239
|
currentDispatchOpId = currentDispatchOpId === op.id ? null : currentDispatchOpId;
|
|
240
240
|
lastDispatchOpId = op.id;
|
|
241
241
|
lastDispatchEndedAt = op.dispatchEndAt;
|
|
@@ -243,7 +243,7 @@ function createProfiler() {
|
|
|
243
243
|
recordSchedulerInvalidate(info) {
|
|
244
244
|
const op = resolveActiveOp();
|
|
245
245
|
if (!op) return;
|
|
246
|
-
if (op.invalidateAt == null) op.invalidateAt = now$
|
|
246
|
+
if (op.invalidateAt == null) op.invalidateAt = now$2();
|
|
247
247
|
if (!op.invalidatePriority && (info === null || info === void 0 ? void 0 : info.priority)) op.invalidatePriority = String(info.priority);
|
|
248
248
|
if (!op.invalidatePlane && (info === null || info === void 0 ? void 0 : info.plane)) op.invalidatePlane = String(info.plane);
|
|
249
249
|
pendingCommitIds.add(op.id);
|
|
@@ -251,7 +251,7 @@ function createProfiler() {
|
|
|
251
251
|
recordFlushStart(info) {
|
|
252
252
|
currentFlushIds = Array.from(pendingCommitIds);
|
|
253
253
|
if (!currentFlushIds.length) return;
|
|
254
|
-
const flushTime = now$
|
|
254
|
+
const flushTime = now$2();
|
|
255
255
|
forIds(currentFlushIds, (op) => {
|
|
256
256
|
if (op.flushStartAt == null) op.flushStartAt = flushTime;
|
|
257
257
|
if (op.commitSync == null && (info === null || info === void 0 ? void 0 : info.sync) != null) op.commitSync = Boolean(info.sync);
|
|
@@ -260,7 +260,7 @@ function createProfiler() {
|
|
|
260
260
|
},
|
|
261
261
|
recordFlushEnd() {
|
|
262
262
|
if (!currentFlushIds.length) return;
|
|
263
|
-
const flushTime = now$
|
|
263
|
+
const flushTime = now$2();
|
|
264
264
|
forIds(currentFlushIds, (op) => {
|
|
265
265
|
if (op.flushEndAt == null) op.flushEndAt = flushTime;
|
|
266
266
|
});
|
|
@@ -268,7 +268,7 @@ function createProfiler() {
|
|
|
268
268
|
},
|
|
269
269
|
recordCommit(info) {
|
|
270
270
|
if (!pendingCommitIds.size) return;
|
|
271
|
-
const commitTime = now$
|
|
271
|
+
const commitTime = now$2();
|
|
272
272
|
const ids = Array.from(pendingCommitIds);
|
|
273
273
|
pendingCommitIds.clear();
|
|
274
274
|
forIds(ids, (op) => {
|
|
@@ -288,7 +288,7 @@ function createProfiler() {
|
|
|
288
288
|
},
|
|
289
289
|
recordStdoutRenderStart() {
|
|
290
290
|
if (!pendingWriteIds.size) return;
|
|
291
|
-
const renderTime = now$
|
|
291
|
+
const renderTime = now$2();
|
|
292
292
|
forIds(pendingWriteIds, (op) => {
|
|
293
293
|
if (op.stdoutRenderStartAt == null) op.stdoutRenderStartAt = renderTime;
|
|
294
294
|
});
|
|
@@ -301,7 +301,7 @@ function createProfiler() {
|
|
|
301
301
|
},
|
|
302
302
|
recordStdoutWrite(info) {
|
|
303
303
|
if (!pendingWriteIds.size) return;
|
|
304
|
-
const writeEndTime = now$
|
|
304
|
+
const writeEndTime = now$2();
|
|
305
305
|
const ids = Array.from(pendingWriteIds);
|
|
306
306
|
pendingWriteIds.clear();
|
|
307
307
|
forIds(ids, (op) => {
|
|
@@ -966,7 +966,7 @@ function setDebugFileWriter(writer) {
|
|
|
966
966
|
if (!writer) initializedDebugLogPaths.clear();
|
|
967
967
|
}
|
|
968
968
|
function resolveDebugLogPath(env, fallback = DEFAULT_LOG_FILE) {
|
|
969
|
-
return envString(env, "VUE_TUI_DEBUG_LOG_PATH", "DIMCODE_DEBUG_LOG_PATH", fallback);
|
|
969
|
+
return envString$1(env, "VUE_TUI_DEBUG_LOG_PATH", "DIMCODE_DEBUG_LOG_PATH", fallback);
|
|
970
970
|
}
|
|
971
971
|
function setDebugLogDefaultPath(path) {
|
|
972
972
|
debugLogDefaultPath = path || DEFAULT_LOG_FILE;
|
|
@@ -1076,7 +1076,7 @@ function createTuiProfiler(name, options = {}) {
|
|
|
1076
1076
|
if (!envFlag(env, "VUE_TUI_PROFILE", "DIMCODE_PROFILE_TUI")) return null;
|
|
1077
1077
|
const format = parseLogFormat(firstNonEmptyEnv(env, "VUE_TUI_PROFILE_FORMAT", "DIMCODE_PROFILE_TUI_FORMAT")) ?? (String(firstNonEmptyEnv(env, "VUE_TUI_PROFILE_LOG_PATH", "DIMCODE_PROFILE_TUI_LOG_PATH") ?? "").trim().endsWith(".jsonl") ? "json" : "text");
|
|
1078
1078
|
const logDest = parseLogDest(firstNonEmptyEnv(env, "VUE_TUI_PROFILE_LOG_DEST", "DIMCODE_PROFILE_TUI_LOG_DEST")) ?? options.defaultLogDest ?? "stdout";
|
|
1079
|
-
const logPath = envString(env, "VUE_TUI_PROFILE_LOG_PATH", "DIMCODE_PROFILE_TUI_LOG_PATH") || options.defaultLogPath || "";
|
|
1079
|
+
const logPath = envString$1(env, "VUE_TUI_PROFILE_LOG_PATH", "DIMCODE_PROFILE_TUI_LOG_PATH") || options.defaultLogPath || "";
|
|
1080
1080
|
let invalidates = 0;
|
|
1081
1081
|
let renders = 0;
|
|
1082
1082
|
let fullRenders = 0;
|
|
@@ -1095,8 +1095,8 @@ function createTuiProfiler(name, options = {}) {
|
|
|
1095
1095
|
const invalidatePlaneCounts = new Map();
|
|
1096
1096
|
const renderPlaneCounts = new Map();
|
|
1097
1097
|
const logEveryMs = parseLogEveryMs(firstNonEmptyEnv(env, "VUE_TUI_PROFILE_LOG_EVERY_MS", "DIMCODE_PROFILE_TUI_LOG_EVERY_MS")) ?? 1e3;
|
|
1098
|
-
const now$
|
|
1099
|
-
let lastLogAt = now$
|
|
1098
|
+
const now$3 = defaultNow;
|
|
1099
|
+
let lastLogAt = now$3();
|
|
1100
1100
|
let disposed = false;
|
|
1101
1101
|
function incrementPlaneCount(target, key) {
|
|
1102
1102
|
const normalized = String(key ?? "all").trim() || "all";
|
|
@@ -1117,7 +1117,7 @@ function createTuiProfiler(name, options = {}) {
|
|
|
1117
1117
|
function flushLog(force = false) {
|
|
1118
1118
|
if (disposed) return;
|
|
1119
1119
|
if (!hasPendingSamples()) return;
|
|
1120
|
-
const at = now$
|
|
1120
|
+
const at = now$3();
|
|
1121
1121
|
const elapsedRaw = at - lastLogAt;
|
|
1122
1122
|
if (!force && elapsedRaw <= 0) return;
|
|
1123
1123
|
const elapsed = Math.max(1, elapsedRaw);
|
|
@@ -1189,7 +1189,7 @@ function createTuiProfiler(name, options = {}) {
|
|
|
1189
1189
|
const timer = setInterval(flushLog, Number.isFinite(logEveryMs) ? Math.max(100, logEveryMs) : 1e3);
|
|
1190
1190
|
(_unref = timer.unref) === null || _unref === void 0 || _unref.call(timer);
|
|
1191
1191
|
return {
|
|
1192
|
-
now: now$
|
|
1192
|
+
now: now$3,
|
|
1193
1193
|
recordInvalidate(info) {
|
|
1194
1194
|
if (disposed) return;
|
|
1195
1195
|
invalidates++;
|
|
@@ -1247,7 +1247,7 @@ function legacyDebugFlag(env) {
|
|
|
1247
1247
|
return String((env === null || env === void 0 ? void 0 : env.DEBUG) ?? "").trim() === "1";
|
|
1248
1248
|
}
|
|
1249
1249
|
function shouldInstallFileWriters(env) {
|
|
1250
|
-
const profileLogDest = envString(env, "VUE_TUI_PROFILE_LOG_DEST", "DIMCODE_PROFILE_TUI_LOG_DEST").toLowerCase();
|
|
1250
|
+
const profileLogDest = envString$1(env, "VUE_TUI_PROFILE_LOG_DEST", "DIMCODE_PROFILE_TUI_LOG_DEST").toLowerCase();
|
|
1251
1251
|
return envFlag(env, "VUE_TUI_DEBUG", "DIMCODE_DEBUG") || legacyDebugFlag(env) || profileLogDest === "file" || profileLogDest === "both";
|
|
1252
1252
|
}
|
|
1253
1253
|
function installNodeFileWriters(options = {}) {
|
|
@@ -1277,7 +1277,7 @@ function parseMouseSgr(sequence) {
|
|
|
1277
1277
|
const env = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
1278
1278
|
const invertWheel = envFlag(env, "VUE_TUI_WHEEL_INVERT", "DIMCODE_WHEEL_INVERT");
|
|
1279
1279
|
const mouseDebugEnabled = envFlag(env, "VUE_TUI_MOUSE_DEBUG", "DIMCODE_MOUSE_DEBUG");
|
|
1280
|
-
const mouseDebugPath = envString(env, "VUE_TUI_MOUSE_DEBUG_PATH", "DIMCODE_MOUSE_DEBUG_PATH", defaultVueTuiMouseDebugLogPath());
|
|
1280
|
+
const mouseDebugPath = envString$1(env, "VUE_TUI_MOUSE_DEBUG_PATH", "DIMCODE_MOUSE_DEBUG_PATH", defaultVueTuiMouseDebugLogPath());
|
|
1281
1281
|
const debug = (msg) => {
|
|
1282
1282
|
if (!mouseDebugEnabled) return;
|
|
1283
1283
|
try {
|
|
@@ -1696,13 +1696,13 @@ function parseXtermSequence(sequence) {
|
|
|
1696
1696
|
|
|
1697
1697
|
//#endregion
|
|
1698
1698
|
//#region src/cli/stdin-buffer.ts
|
|
1699
|
-
const ESC$
|
|
1699
|
+
const ESC$3 = "\x1B";
|
|
1700
1700
|
const BRACKETED_PASTE_START = "\x1B[200~";
|
|
1701
1701
|
const BRACKETED_PASTE_END = "\x1B[201~";
|
|
1702
1702
|
const ESC_CONTINUATION_RESCUE_WINDOW_MS = 64;
|
|
1703
1703
|
function looksLikeQuotedPathPaste(value) {
|
|
1704
1704
|
if (!value) return false;
|
|
1705
|
-
if (value.includes(ESC$
|
|
1705
|
+
if (value.includes(ESC$3)) return false;
|
|
1706
1706
|
if (value.length < 12) return false;
|
|
1707
1707
|
if (!/['"]/.test(value)) return false;
|
|
1708
1708
|
if (!/[\\/]/.test(value)) return false;
|
|
@@ -1712,7 +1712,7 @@ function looksLikeQuotedPathPaste(value) {
|
|
|
1712
1712
|
return false;
|
|
1713
1713
|
}
|
|
1714
1714
|
function isCompleteSequence(data) {
|
|
1715
|
-
if (!data.startsWith(ESC$
|
|
1715
|
+
if (!data.startsWith(ESC$3)) return "not-escape";
|
|
1716
1716
|
if (data.length === 1) return "incomplete";
|
|
1717
1717
|
const afterEsc = data.slice(1);
|
|
1718
1718
|
if (afterEsc.startsWith("[")) {
|
|
@@ -1727,7 +1727,7 @@ function isCompleteSequence(data) {
|
|
|
1727
1727
|
return "complete";
|
|
1728
1728
|
}
|
|
1729
1729
|
function isCompleteCsiSequence(data) {
|
|
1730
|
-
if (!data.startsWith(`${ESC$
|
|
1730
|
+
if (!data.startsWith(`${ESC$3}[`)) return "complete";
|
|
1731
1731
|
if (data.length < 3) return "incomplete";
|
|
1732
1732
|
const payload = data.slice(2);
|
|
1733
1733
|
const lastChar = payload[payload.length - 1];
|
|
@@ -1745,19 +1745,35 @@ function isCompleteCsiSequence(data) {
|
|
|
1745
1745
|
}
|
|
1746
1746
|
return "incomplete";
|
|
1747
1747
|
}
|
|
1748
|
+
function isPotentialSgrMousePayloadPrefix(payload) {
|
|
1749
|
+
if (!payload.startsWith("<")) return false;
|
|
1750
|
+
let semicolons = 0;
|
|
1751
|
+
for (let i = 1; i < payload.length; i++) {
|
|
1752
|
+
const c = payload.charCodeAt(i);
|
|
1753
|
+
if (c >= 48 && c <= 57) continue;
|
|
1754
|
+
if (payload[i] === ";") {
|
|
1755
|
+
semicolons++;
|
|
1756
|
+
if (semicolons > 2) return false;
|
|
1757
|
+
continue;
|
|
1758
|
+
}
|
|
1759
|
+
if (payload[i] === "M" || payload[i] === "m") return semicolons === 2;
|
|
1760
|
+
return false;
|
|
1761
|
+
}
|
|
1762
|
+
return true;
|
|
1763
|
+
}
|
|
1748
1764
|
function isCompleteOscSequence(data) {
|
|
1749
|
-
if (!data.startsWith(`${ESC$
|
|
1750
|
-
if (data.endsWith(`${ESC$
|
|
1765
|
+
if (!data.startsWith(`${ESC$3}]`)) return "complete";
|
|
1766
|
+
if (data.endsWith(`${ESC$3}\\`) || data.endsWith("\x07")) return "complete";
|
|
1751
1767
|
return "incomplete";
|
|
1752
1768
|
}
|
|
1753
1769
|
function isCompleteDcsSequence(data) {
|
|
1754
|
-
if (!data.startsWith(`${ESC$
|
|
1755
|
-
if (data.endsWith(`${ESC$
|
|
1770
|
+
if (!data.startsWith(`${ESC$3}P`)) return "complete";
|
|
1771
|
+
if (data.endsWith(`${ESC$3}\\`)) return "complete";
|
|
1756
1772
|
return "incomplete";
|
|
1757
1773
|
}
|
|
1758
1774
|
function isCompleteApcSequence(data) {
|
|
1759
|
-
if (!data.startsWith(`${ESC$
|
|
1760
|
-
if (data.endsWith(`${ESC$
|
|
1775
|
+
if (!data.startsWith(`${ESC$3}_`)) return "complete";
|
|
1776
|
+
if (data.endsWith(`${ESC$3}\\`)) return "complete";
|
|
1761
1777
|
return "incomplete";
|
|
1762
1778
|
}
|
|
1763
1779
|
function extractCompleteSequences(buffer) {
|
|
@@ -1765,9 +1781,9 @@ function extractCompleteSequences(buffer) {
|
|
|
1765
1781
|
let pos = 0;
|
|
1766
1782
|
while (pos < buffer.length) {
|
|
1767
1783
|
const remaining = buffer.slice(pos);
|
|
1768
|
-
if (remaining.startsWith(ESC$
|
|
1769
|
-
if (remaining.length >= 2 && remaining[1] === ESC$
|
|
1770
|
-
sequences.push(ESC$
|
|
1784
|
+
if (remaining.startsWith(ESC$3)) {
|
|
1785
|
+
if (remaining.length >= 2 && remaining[1] === ESC$3) {
|
|
1786
|
+
sequences.push(ESC$3);
|
|
1771
1787
|
pos += 1;
|
|
1772
1788
|
continue;
|
|
1773
1789
|
}
|
|
@@ -1802,17 +1818,24 @@ function extractCompleteSequences(buffer) {
|
|
|
1802
1818
|
remainder: ""
|
|
1803
1819
|
};
|
|
1804
1820
|
}
|
|
1805
|
-
function looksLikeSplitEscapeContinuation(value) {
|
|
1821
|
+
function looksLikeSplitEscapeContinuation(value, prefix = ESC$3) {
|
|
1822
|
+
if (prefix.startsWith(`${ESC$3}[`) && isPotentialSgrMousePayloadPrefix(`${prefix.slice(2)}${value}`)) return true;
|
|
1806
1823
|
const first = value[0];
|
|
1807
1824
|
if (first !== "[" && first !== "]" && first !== "P" && first !== "_" && first !== "O") return false;
|
|
1808
|
-
return isCompleteSequence(`${ESC$
|
|
1825
|
+
return prefix === ESC$3 && isCompleteSequence(`${ESC$3}${value}`) !== "not-escape";
|
|
1826
|
+
}
|
|
1827
|
+
function rescuableEscapePrefix(value) {
|
|
1828
|
+
if (value === ESC$3) return ESC$3;
|
|
1829
|
+
if (value === `${ESC$3}[`) return value;
|
|
1830
|
+
if (value.startsWith(`${ESC$3}[`) && isPotentialSgrMousePayloadPrefix(value.slice(2))) return value;
|
|
1831
|
+
return null;
|
|
1809
1832
|
}
|
|
1810
1833
|
var StdinBuffer = class extends EventEmitter {
|
|
1811
1834
|
buffer = "";
|
|
1812
1835
|
timeout = null;
|
|
1813
1836
|
timeoutMs;
|
|
1814
1837
|
escTimeoutMs;
|
|
1815
|
-
|
|
1838
|
+
pendingEscContinuation = null;
|
|
1816
1839
|
pasteMode = false;
|
|
1817
1840
|
pasteBuffer = "";
|
|
1818
1841
|
constructor(options = {}) {
|
|
@@ -1831,10 +1854,11 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
1831
1854
|
str = `\x1B${String.fromCharCode(byte)}`;
|
|
1832
1855
|
} else str = data.toString();
|
|
1833
1856
|
else str = data;
|
|
1834
|
-
if (this.
|
|
1835
|
-
const
|
|
1836
|
-
|
|
1837
|
-
|
|
1857
|
+
if (this.pendingEscContinuation != null) {
|
|
1858
|
+
const pending = this.pendingEscContinuation;
|
|
1859
|
+
const canRescue = Date.now() - pending.at <= ESC_CONTINUATION_RESCUE_WINDOW_MS;
|
|
1860
|
+
this.pendingEscContinuation = null;
|
|
1861
|
+
if (canRescue && looksLikeSplitEscapeContinuation(str, pending.prefix)) str = `${pending.prefix}${str}`;
|
|
1838
1862
|
}
|
|
1839
1863
|
if (str.length === 0 && this.buffer.length === 0) {
|
|
1840
1864
|
this.emit("data", "");
|
|
@@ -1887,11 +1911,14 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
1887
1911
|
this.buffer = result.remainder;
|
|
1888
1912
|
for (const sequence of result.sequences) this.emit("data", sequence);
|
|
1889
1913
|
if (this.buffer.length > 0) {
|
|
1890
|
-
const timeoutMs = this.buffer === ESC$
|
|
1914
|
+
const timeoutMs = this.buffer === ESC$3 ? this.escTimeoutMs : this.timeoutMs;
|
|
1891
1915
|
this.timeout = setTimeout(() => {
|
|
1892
|
-
const
|
|
1916
|
+
const prefix = rescuableEscapePrefix(this.buffer);
|
|
1893
1917
|
const flushed = this.flush();
|
|
1894
|
-
if (
|
|
1918
|
+
if (prefix && flushed.length === 1 && flushed[0] === prefix) this.pendingEscContinuation = {
|
|
1919
|
+
prefix,
|
|
1920
|
+
at: Date.now()
|
|
1921
|
+
};
|
|
1895
1922
|
for (const sequence of flushed) this.emit("data", sequence);
|
|
1896
1923
|
}, timeoutMs);
|
|
1897
1924
|
}
|
|
@@ -1912,7 +1939,7 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
1912
1939
|
this.timeout = null;
|
|
1913
1940
|
}
|
|
1914
1941
|
this.buffer = "";
|
|
1915
|
-
this.
|
|
1942
|
+
this.pendingEscContinuation = null;
|
|
1916
1943
|
this.pasteMode = false;
|
|
1917
1944
|
this.pasteBuffer = "";
|
|
1918
1945
|
}
|
|
@@ -2649,7 +2676,7 @@ function segmentedGraphemes(text) {
|
|
|
2649
2676
|
|
|
2650
2677
|
//#endregion
|
|
2651
2678
|
//#region src/core/ansi/sgr.ts
|
|
2652
|
-
const ESC$
|
|
2679
|
+
const ESC$2 = "\x1B";
|
|
2653
2680
|
function ansi16ToColorName(code) {
|
|
2654
2681
|
switch (code) {
|
|
2655
2682
|
case 30: return "black";
|
|
@@ -2922,7 +2949,7 @@ function parseAnsiSgr(input, baseStyle = {}) {
|
|
|
2922
2949
|
let style = { ...baseStyle };
|
|
2923
2950
|
let lastIndex = 0;
|
|
2924
2951
|
for (let i = 0; i < input.length; i++) {
|
|
2925
|
-
if (input[i] !== ESC$
|
|
2952
|
+
if (input[i] !== ESC$2 || input[i + 1] !== "[") continue;
|
|
2926
2953
|
let j = i + 2;
|
|
2927
2954
|
while (j < input.length) {
|
|
2928
2955
|
const c = input.charCodeAt(j);
|
|
@@ -2951,17 +2978,131 @@ function parseAnsiSgr(input, baseStyle = {}) {
|
|
|
2951
2978
|
}
|
|
2952
2979
|
|
|
2953
2980
|
//#endregion
|
|
2954
|
-
//#region src/core/buffer/
|
|
2981
|
+
//#region src/core/buffer/eaw-ranges-unicode-17.ts
|
|
2955
2982
|
const fullWidthRanges = [
|
|
2956
2983
|
[4352, 4447],
|
|
2984
|
+
[8986, 8987],
|
|
2957
2985
|
[9001, 9002],
|
|
2958
|
-
[
|
|
2986
|
+
[9193, 9196],
|
|
2987
|
+
[9200, 9200],
|
|
2988
|
+
[9203, 9203],
|
|
2989
|
+
[9725, 9726],
|
|
2990
|
+
[9748, 9749],
|
|
2991
|
+
[9776, 9783],
|
|
2992
|
+
[9800, 9811],
|
|
2993
|
+
[9855, 9855],
|
|
2994
|
+
[9866, 9871],
|
|
2995
|
+
[9875, 9875],
|
|
2996
|
+
[9889, 9889],
|
|
2997
|
+
[9898, 9899],
|
|
2998
|
+
[9917, 9918],
|
|
2999
|
+
[9924, 9925],
|
|
3000
|
+
[9934, 9934],
|
|
3001
|
+
[9940, 9940],
|
|
3002
|
+
[9962, 9962],
|
|
3003
|
+
[9970, 9971],
|
|
3004
|
+
[9973, 9973],
|
|
3005
|
+
[9978, 9978],
|
|
3006
|
+
[9981, 9981],
|
|
3007
|
+
[9989, 9989],
|
|
3008
|
+
[9994, 9995],
|
|
3009
|
+
[10024, 10024],
|
|
3010
|
+
[10060, 10060],
|
|
3011
|
+
[10062, 10062],
|
|
3012
|
+
[10067, 10069],
|
|
3013
|
+
[10071, 10071],
|
|
3014
|
+
[10133, 10135],
|
|
3015
|
+
[10160, 10160],
|
|
3016
|
+
[10175, 10175],
|
|
3017
|
+
[11035, 11036],
|
|
3018
|
+
[11088, 11088],
|
|
3019
|
+
[11093, 11093],
|
|
3020
|
+
[11904, 11929],
|
|
3021
|
+
[11931, 12019],
|
|
3022
|
+
[12032, 12245],
|
|
3023
|
+
[12272, 12350],
|
|
3024
|
+
[12353, 12438],
|
|
3025
|
+
[12441, 12543],
|
|
3026
|
+
[12549, 12591],
|
|
3027
|
+
[12593, 12686],
|
|
3028
|
+
[12688, 12773],
|
|
3029
|
+
[12783, 12830],
|
|
3030
|
+
[12832, 12871],
|
|
3031
|
+
[12880, 42124],
|
|
3032
|
+
[42128, 42182],
|
|
3033
|
+
[43360, 43388],
|
|
2959
3034
|
[44032, 55203],
|
|
2960
3035
|
[63744, 64255],
|
|
2961
3036
|
[65040, 65049],
|
|
2962
|
-
[65072,
|
|
2963
|
-
[
|
|
2964
|
-
[
|
|
3037
|
+
[65072, 65106],
|
|
3038
|
+
[65108, 65126],
|
|
3039
|
+
[65128, 65131],
|
|
3040
|
+
[65281, 65376],
|
|
3041
|
+
[65504, 65510],
|
|
3042
|
+
[94176, 94180],
|
|
3043
|
+
[94192, 94198],
|
|
3044
|
+
[94208, 101589],
|
|
3045
|
+
[101631, 101662],
|
|
3046
|
+
[101760, 101874],
|
|
3047
|
+
[110576, 110579],
|
|
3048
|
+
[110581, 110587],
|
|
3049
|
+
[110589, 110590],
|
|
3050
|
+
[110592, 110882],
|
|
3051
|
+
[110898, 110898],
|
|
3052
|
+
[110928, 110930],
|
|
3053
|
+
[110933, 110933],
|
|
3054
|
+
[110948, 110951],
|
|
3055
|
+
[110960, 111355],
|
|
3056
|
+
[119552, 119638],
|
|
3057
|
+
[119648, 119670],
|
|
3058
|
+
[126980, 126980],
|
|
3059
|
+
[127183, 127183],
|
|
3060
|
+
[127374, 127374],
|
|
3061
|
+
[127377, 127386],
|
|
3062
|
+
[127488, 127490],
|
|
3063
|
+
[127504, 127547],
|
|
3064
|
+
[127552, 127560],
|
|
3065
|
+
[127568, 127569],
|
|
3066
|
+
[127584, 127589],
|
|
3067
|
+
[127744, 127776],
|
|
3068
|
+
[127789, 127797],
|
|
3069
|
+
[127799, 127868],
|
|
3070
|
+
[127870, 127891],
|
|
3071
|
+
[127904, 127946],
|
|
3072
|
+
[127951, 127955],
|
|
3073
|
+
[127968, 127984],
|
|
3074
|
+
[127988, 127988],
|
|
3075
|
+
[127992, 128062],
|
|
3076
|
+
[128064, 128064],
|
|
3077
|
+
[128066, 128252],
|
|
3078
|
+
[128255, 128317],
|
|
3079
|
+
[128331, 128334],
|
|
3080
|
+
[128336, 128359],
|
|
3081
|
+
[128378, 128378],
|
|
3082
|
+
[128405, 128406],
|
|
3083
|
+
[128420, 128420],
|
|
3084
|
+
[128507, 128591],
|
|
3085
|
+
[128640, 128709],
|
|
3086
|
+
[128716, 128716],
|
|
3087
|
+
[128720, 128722],
|
|
3088
|
+
[128725, 128728],
|
|
3089
|
+
[128732, 128735],
|
|
3090
|
+
[128747, 128748],
|
|
3091
|
+
[128756, 128764],
|
|
3092
|
+
[128992, 129003],
|
|
3093
|
+
[129008, 129008],
|
|
3094
|
+
[129292, 129338],
|
|
3095
|
+
[129340, 129349],
|
|
3096
|
+
[129351, 129535],
|
|
3097
|
+
[129648, 129660],
|
|
3098
|
+
[129664, 129674],
|
|
3099
|
+
[129678, 129734],
|
|
3100
|
+
[129736, 129736],
|
|
3101
|
+
[129741, 129756],
|
|
3102
|
+
[129759, 129770],
|
|
3103
|
+
[129775, 129784],
|
|
3104
|
+
[131072, 196605],
|
|
3105
|
+
[196608, 262141]
|
|
2965
3106
|
];
|
|
2966
3107
|
const ambiguousWidthRanges = [
|
|
2967
3108
|
[161, 161],
|
|
@@ -3017,6 +3158,7 @@ const ambiguousWidthRanges = [
|
|
|
3017
3158
|
[728, 731],
|
|
3018
3159
|
[733, 733],
|
|
3019
3160
|
[735, 735],
|
|
3161
|
+
[768, 879],
|
|
3020
3162
|
[913, 929],
|
|
3021
3163
|
[931, 937],
|
|
3022
3164
|
[945, 961],
|
|
@@ -3024,7 +3166,8 @@ const ambiguousWidthRanges = [
|
|
|
3024
3166
|
[1025, 1025],
|
|
3025
3167
|
[1040, 1103],
|
|
3026
3168
|
[1105, 1105],
|
|
3027
|
-
[8208,
|
|
3169
|
+
[8208, 8208],
|
|
3170
|
+
[8211, 8214],
|
|
3028
3171
|
[8216, 8217],
|
|
3029
3172
|
[8220, 8221],
|
|
3030
3173
|
[8224, 8226],
|
|
@@ -3086,7 +3229,8 @@ const ambiguousWidthRanges = [
|
|
|
3086
3229
|
[8895, 8895],
|
|
3087
3230
|
[8978, 8978],
|
|
3088
3231
|
[9312, 9449],
|
|
3089
|
-
[9451,
|
|
3232
|
+
[9451, 9547],
|
|
3233
|
+
[9552, 9587],
|
|
3090
3234
|
[9600, 9615],
|
|
3091
3235
|
[9618, 9621],
|
|
3092
3236
|
[9632, 9633],
|
|
@@ -3112,14 +3256,40 @@ const ambiguousWidthRanges = [
|
|
|
3112
3256
|
[9831, 9834],
|
|
3113
3257
|
[9836, 9837],
|
|
3114
3258
|
[9839, 9839],
|
|
3259
|
+
[9886, 9887],
|
|
3260
|
+
[9919, 9919],
|
|
3261
|
+
[9926, 9933],
|
|
3262
|
+
[9935, 9939],
|
|
3263
|
+
[9941, 9953],
|
|
3264
|
+
[9955, 9955],
|
|
3265
|
+
[9960, 9961],
|
|
3266
|
+
[9963, 9969],
|
|
3267
|
+
[9972, 9972],
|
|
3268
|
+
[9974, 9977],
|
|
3269
|
+
[9979, 9980],
|
|
3270
|
+
[9982, 9983],
|
|
3115
3271
|
[10045, 10045],
|
|
3116
3272
|
[10102, 10111],
|
|
3117
|
-
[11094,
|
|
3273
|
+
[11094, 11097],
|
|
3274
|
+
[12872, 12879],
|
|
3118
3275
|
[57344, 63743],
|
|
3119
|
-
[
|
|
3276
|
+
[65024, 65039],
|
|
3277
|
+
[65533, 65533],
|
|
3278
|
+
[127232, 127242],
|
|
3279
|
+
[127248, 127277],
|
|
3280
|
+
[127280, 127337],
|
|
3281
|
+
[127344, 127373],
|
|
3282
|
+
[127375, 127376],
|
|
3283
|
+
[127387, 127404],
|
|
3284
|
+
[917760, 917999],
|
|
3285
|
+
[983040, 1048573],
|
|
3286
|
+
[1048576, 1114109]
|
|
3120
3287
|
];
|
|
3288
|
+
|
|
3289
|
+
//#endregion
|
|
3290
|
+
//#region src/core/buffer/width.ts
|
|
3121
3291
|
function isFullWidthCodePoint(codePoint) {
|
|
3122
|
-
if (codePoint < 4352
|
|
3292
|
+
if (codePoint < 4352) return false;
|
|
3123
3293
|
for (const [start, end] of fullWidthRanges) {
|
|
3124
3294
|
if (codePoint < start) return false;
|
|
3125
3295
|
if (codePoint <= end) return true;
|
|
@@ -3127,13 +3297,22 @@ function isFullWidthCodePoint(codePoint) {
|
|
|
3127
3297
|
return false;
|
|
3128
3298
|
}
|
|
3129
3299
|
function isAmbiguousWidthCodePoint(codePoint) {
|
|
3130
|
-
|
|
3300
|
+
const first = ambiguousWidthRanges[0];
|
|
3301
|
+
const last = ambiguousWidthRanges[ambiguousWidthRanges.length - 1];
|
|
3302
|
+
if (!first || !last) return false;
|
|
3303
|
+
if (codePoint < first[0] || codePoint > last[1]) return false;
|
|
3131
3304
|
for (const [start, end] of ambiguousWidthRanges) {
|
|
3132
3305
|
if (codePoint < start) return false;
|
|
3133
3306
|
if (codePoint <= end) return true;
|
|
3134
3307
|
}
|
|
3135
3308
|
return false;
|
|
3136
3309
|
}
|
|
3310
|
+
function isVariationSelectorCodePoint(codePoint) {
|
|
3311
|
+
return codePoint >= 65024 && codePoint <= 65039 || codePoint >= 917760 && codePoint <= 917999;
|
|
3312
|
+
}
|
|
3313
|
+
function isCombiningMarkCodePoint(codePoint) {
|
|
3314
|
+
return codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071 || codePoint >= 12330 && codePoint <= 12335 || codePoint >= 12441 && codePoint <= 12442 || codePoint === 94180;
|
|
3315
|
+
}
|
|
3137
3316
|
function isEmojiLike(codePoint) {
|
|
3138
3317
|
return codePoint >= 127744 && codePoint <= 129791 || codePoint >= 127462 && codePoint <= 127487;
|
|
3139
3318
|
}
|
|
@@ -3168,6 +3347,8 @@ function charCellWidth(text, provider = "default") {
|
|
|
3168
3347
|
const codePoint = text.codePointAt(0);
|
|
3169
3348
|
if (codePoint == null) return 1;
|
|
3170
3349
|
const hasVs16 = text.includes("️");
|
|
3350
|
+
if (isVariationSelectorCodePoint(codePoint) || isCombiningMarkCodePoint(codePoint)) return 1;
|
|
3351
|
+
if (codePoint >= 9472 && codePoint <= 9599) return 1;
|
|
3171
3352
|
if (isFullWidthCodePoint(codePoint)) return 2;
|
|
3172
3353
|
if (provider === "cjk" && isAmbiguousWidthCodePoint(codePoint)) return 2;
|
|
3173
3354
|
if (isEmojiLike(codePoint)) return 2;
|
|
@@ -3601,9 +3782,12 @@ function resizeBuffer(buffer, cols, rows) {
|
|
|
3601
3782
|
const nextCols = Math.max(0, Math.floor(cols));
|
|
3602
3783
|
const nextRows = Math.max(0, Math.floor(rows));
|
|
3603
3784
|
if (nextCols === buffer.cols && nextRows === buffer.rows) return;
|
|
3785
|
+
const prevRows = buffer.rows;
|
|
3786
|
+
const prevDirtyAll = buffer.dirtyAll;
|
|
3787
|
+
const prevDirtyBits = buffer.dirtyBits;
|
|
3604
3788
|
const blank = createBlankCell();
|
|
3605
3789
|
const nextGrid = Array.from({ length: nextRows }, () => Array.from({ length: nextCols }, () => blank));
|
|
3606
|
-
const copyRows = Math.min(
|
|
3790
|
+
const copyRows = Math.min(prevRows, nextRows);
|
|
3607
3791
|
const copyCols = Math.min(buffer.cols, nextCols);
|
|
3608
3792
|
for (let y = 0; y < copyRows; y++) {
|
|
3609
3793
|
const src = getBufferRow(buffer, y);
|
|
@@ -3629,10 +3813,21 @@ function resizeBuffer(buffer, cols, rows) {
|
|
|
3629
3813
|
buffer.cols = nextCols;
|
|
3630
3814
|
buffer.rows = nextRows;
|
|
3631
3815
|
buffer.dirtyBits = new Uint8Array(nextRows);
|
|
3632
|
-
buffer.dirtyCount =
|
|
3633
|
-
buffer.dirtyMin =
|
|
3634
|
-
buffer.dirtyMax =
|
|
3635
|
-
buffer.dirtyAll = nextRows > 0;
|
|
3816
|
+
buffer.dirtyCount = 0;
|
|
3817
|
+
buffer.dirtyMin = Number.POSITIVE_INFINITY;
|
|
3818
|
+
buffer.dirtyMax = -1;
|
|
3819
|
+
buffer.dirtyAll = prevDirtyAll && nextRows > 0;
|
|
3820
|
+
if (buffer.dirtyAll) {
|
|
3821
|
+
buffer.dirtyCount = nextRows;
|
|
3822
|
+
buffer.dirtyMin = 0;
|
|
3823
|
+
buffer.dirtyMax = nextRows - 1;
|
|
3824
|
+
} else for (let y = 0; y < copyRows; y++) {
|
|
3825
|
+
if (prevDirtyBits[y] !== 1) continue;
|
|
3826
|
+
buffer.dirtyBits[y] = 1;
|
|
3827
|
+
buffer.dirtyCount++;
|
|
3828
|
+
if (y < buffer.dirtyMin) buffer.dirtyMin = y;
|
|
3829
|
+
if (y > buffer.dirtyMax) buffer.dirtyMax = y;
|
|
3830
|
+
}
|
|
3636
3831
|
buffer.cursorX = clamp(buffer.cursorX, 0, Math.max(0, nextCols));
|
|
3637
3832
|
buffer.cursorY = clamp(buffer.cursorY, 0, Math.max(0, nextRows - 1));
|
|
3638
3833
|
if (buffer.fingerprintFn) {
|
|
@@ -3705,6 +3900,10 @@ function mergePlanes(prev, next) {
|
|
|
3705
3900
|
return Array.from(merged);
|
|
3706
3901
|
}
|
|
3707
3902
|
const TERMINAL_PLANE_INTERNALS = Symbol.for("@simon_he/vue-tui:v1:terminal-plane-internals");
|
|
3903
|
+
const TERMINAL_ROOT = Symbol.for("@simon_he/vue-tui:v1:terminal-root");
|
|
3904
|
+
function getRootTerminal(terminal) {
|
|
3905
|
+
return terminal[TERMINAL_ROOT] ?? terminal;
|
|
3906
|
+
}
|
|
3708
3907
|
function createCoverage(cols, rows) {
|
|
3709
3908
|
return Array.from({ length: rows }, () => new Uint8Array(cols));
|
|
3710
3909
|
}
|
|
@@ -3789,6 +3988,8 @@ function markPlaneCoverageRange(state, x0, y0, x1, y1, value) {
|
|
|
3789
3988
|
}
|
|
3790
3989
|
}
|
|
3791
3990
|
function markPlaneCoverageForPut(state, x, y, ch, prevCell) {
|
|
3991
|
+
if (!Number.isSafeInteger(x) || !Number.isSafeInteger(y)) return;
|
|
3992
|
+
if (x < 0 || x >= state.buffer.cols || y < 0 || y >= state.buffer.rows) return;
|
|
3792
3993
|
const row = state.coverage[y];
|
|
3793
3994
|
if (!row) return;
|
|
3794
3995
|
if ((prevCell === null || prevCell === void 0 ? void 0 : prevCell.continuation) && x > 0) row[x - 1] = 1;
|
|
@@ -3912,10 +4113,14 @@ function createTerminal(opts) {
|
|
|
3912
4113
|
}
|
|
3913
4114
|
function putForPlane(plane, x, y, ch, style) {
|
|
3914
4115
|
const state = getPlaneState(plane);
|
|
3915
|
-
if (
|
|
3916
|
-
const
|
|
3917
|
-
|
|
3918
|
-
|
|
4116
|
+
if (typeof x !== "number" || typeof y !== "number") return;
|
|
4117
|
+
const cellX = Math.floor(x);
|
|
4118
|
+
const cellY = Math.floor(y);
|
|
4119
|
+
if (!Number.isFinite(cellX) || !Number.isFinite(cellY)) return;
|
|
4120
|
+
if (cellY < 0 || cellY >= state.buffer.rows || cellX < 0 || cellX >= state.buffer.cols) return;
|
|
4121
|
+
const prevCell = getBufferCell(state.buffer, cellX, cellY);
|
|
4122
|
+
putCell(state.buffer, cellX, cellY, ch, style);
|
|
4123
|
+
markPlaneCoverageForPut(state, cellX, cellY, ch, prevCell);
|
|
3919
4124
|
}
|
|
3920
4125
|
function writeAtForPlane(plane, text, x, y, style) {
|
|
3921
4126
|
const state = getPlaneState(plane);
|
|
@@ -4419,6 +4624,7 @@ function createTerminal(opts) {
|
|
|
4419
4624
|
return getRowFingerprints(state.buffer, yy);
|
|
4420
4625
|
}
|
|
4421
4626
|
};
|
|
4627
|
+
api[TERMINAL_ROOT] = base;
|
|
4422
4628
|
planeTerminals.set(plane, api);
|
|
4423
4629
|
return api;
|
|
4424
4630
|
}
|
|
@@ -4502,7 +4708,7 @@ function createTerminal(opts) {
|
|
|
4502
4708
|
const rows = collectAndClearDirtyRows(state.buffer);
|
|
4503
4709
|
if (rows === null) {
|
|
4504
4710
|
composeAllRows = true;
|
|
4505
|
-
|
|
4711
|
+
continue;
|
|
4506
4712
|
}
|
|
4507
4713
|
for (const y of rows) dirtyRows.add(y);
|
|
4508
4714
|
}
|
|
@@ -4624,6 +4830,7 @@ function createTerminal(opts) {
|
|
|
4624
4830
|
scrollRowsForPlane(plane, startY, endY, lines);
|
|
4625
4831
|
}
|
|
4626
4832
|
};
|
|
4833
|
+
base[TERMINAL_ROOT] = base;
|
|
4627
4834
|
return base;
|
|
4628
4835
|
}
|
|
4629
4836
|
|
|
@@ -4650,7 +4857,7 @@ function sameRect$1(a, b) {
|
|
|
4650
4857
|
function isVisible(node) {
|
|
4651
4858
|
return node.visible !== false;
|
|
4652
4859
|
}
|
|
4653
|
-
function now() {
|
|
4860
|
+
function now$1() {
|
|
4654
4861
|
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
4655
4862
|
}
|
|
4656
4863
|
function rectRowRange(rect) {
|
|
@@ -4830,7 +5037,7 @@ function createCliEventManager(options) {
|
|
|
4830
5037
|
bubbles: true,
|
|
4831
5038
|
cancelable: true,
|
|
4832
5039
|
defaultPrevented: false,
|
|
4833
|
-
timeStamp: typeof time === "number" ? time : now(),
|
|
5040
|
+
timeStamp: typeof time === "number" ? time : now$1(),
|
|
4834
5041
|
__stopped: false,
|
|
4835
5042
|
stopPropagation() {
|
|
4836
5043
|
this.__stopped = true;
|
|
@@ -5196,6 +5403,94 @@ const FRAME_PERF_REASON_PRIORITY = {
|
|
|
5196
5403
|
scroll: 6,
|
|
5197
5404
|
input: 7
|
|
5198
5405
|
};
|
|
5406
|
+
const EMPTY_METRIC_STATS = Object.freeze({
|
|
5407
|
+
avg: 0,
|
|
5408
|
+
max: 0,
|
|
5409
|
+
min: 0
|
|
5410
|
+
});
|
|
5411
|
+
function metricStats(values) {
|
|
5412
|
+
if (!values.length) return EMPTY_METRIC_STATS;
|
|
5413
|
+
let sum = 0;
|
|
5414
|
+
let max = Number.NEGATIVE_INFINITY;
|
|
5415
|
+
let min = Number.POSITIVE_INFINITY;
|
|
5416
|
+
for (const value of values) {
|
|
5417
|
+
sum += value;
|
|
5418
|
+
if (value > max) max = value;
|
|
5419
|
+
if (value < min) min = value;
|
|
5420
|
+
}
|
|
5421
|
+
return {
|
|
5422
|
+
avg: sum / values.length,
|
|
5423
|
+
max,
|
|
5424
|
+
min
|
|
5425
|
+
};
|
|
5426
|
+
}
|
|
5427
|
+
function summarizeFramePerf(samples) {
|
|
5428
|
+
const durationMs = [];
|
|
5429
|
+
const renderManagerMs = [];
|
|
5430
|
+
const commitMs = [];
|
|
5431
|
+
const domFlushMs = [];
|
|
5432
|
+
const stdoutFlushMs = [];
|
|
5433
|
+
const dirtyRows = [];
|
|
5434
|
+
const scannedNodes = [];
|
|
5435
|
+
const paintedNodes = [];
|
|
5436
|
+
const reasons = {};
|
|
5437
|
+
const activePlanes = {};
|
|
5438
|
+
let fullDirtyFrames = 0;
|
|
5439
|
+
let coalescedInvalidates = 0;
|
|
5440
|
+
let coalescedFrameTasks = 0;
|
|
5441
|
+
let droppedUpdates = 0;
|
|
5442
|
+
let maxQueueDepth = 0;
|
|
5443
|
+
let rowBucketFallbacks = 0;
|
|
5444
|
+
for (const sample of samples) {
|
|
5445
|
+
var _sample$rowBucketFall;
|
|
5446
|
+
durationMs.push(sample.durationMs);
|
|
5447
|
+
renderManagerMs.push(sample.renderManagerMs);
|
|
5448
|
+
commitMs.push(sample.commitMs);
|
|
5449
|
+
scannedNodes.push(sample.scannedNodes);
|
|
5450
|
+
paintedNodes.push(sample.paintedNodes);
|
|
5451
|
+
if (sample.domFlushMs != null) domFlushMs.push(sample.domFlushMs);
|
|
5452
|
+
if (sample.stdoutFlushMs != null) stdoutFlushMs.push(sample.stdoutFlushMs);
|
|
5453
|
+
if (sample.dirtyRows == null) fullDirtyFrames++;
|
|
5454
|
+
else dirtyRows.push(sample.dirtyRows);
|
|
5455
|
+
reasons[sample.reason] = (reasons[sample.reason] ?? 0) + 1;
|
|
5456
|
+
const planes = sample.activePlanes;
|
|
5457
|
+
if (!planes) activePlanes.all = (activePlanes.all ?? 0) + 1;
|
|
5458
|
+
else for (const plane of planes) activePlanes[plane] = (activePlanes[plane] ?? 0) + 1;
|
|
5459
|
+
coalescedInvalidates += sample.coalescedInvalidates;
|
|
5460
|
+
coalescedFrameTasks += sample.coalescedFrameTasks;
|
|
5461
|
+
droppedUpdates += sample.droppedUpdates;
|
|
5462
|
+
if (sample.queueDepth > maxQueueDepth) maxQueueDepth = sample.queueDepth;
|
|
5463
|
+
rowBucketFallbacks += ((_sample$rowBucketFall = sample.rowBucketFallbacks) === null || _sample$rowBucketFall === void 0 ? void 0 : _sample$rowBucketFall.length) ?? 0;
|
|
5464
|
+
}
|
|
5465
|
+
const first = samples[0] ?? null;
|
|
5466
|
+
const latest = samples[samples.length - 1] ?? null;
|
|
5467
|
+
return {
|
|
5468
|
+
frames: samples.length,
|
|
5469
|
+
firstFrameId: (first === null || first === void 0 ? void 0 : first.frameId) ?? null,
|
|
5470
|
+
latestFrameId: (latest === null || latest === void 0 ? void 0 : latest.frameId) ?? null,
|
|
5471
|
+
windowMs: first && latest ? Math.max(0, latest.startedAt - first.startedAt) : 0,
|
|
5472
|
+
durationMs: metricStats(durationMs),
|
|
5473
|
+
renderManagerMs: metricStats(renderManagerMs),
|
|
5474
|
+
commitMs: metricStats(commitMs),
|
|
5475
|
+
domFlushMs: metricStats(domFlushMs),
|
|
5476
|
+
stdoutFlushMs: metricStats(stdoutFlushMs),
|
|
5477
|
+
dirtyRows: {
|
|
5478
|
+
avg: dirtyRows.length ? dirtyRows.reduce((sum, value) => sum + value, 0) / dirtyRows.length : 0,
|
|
5479
|
+
max: dirtyRows.length ? Math.max(...dirtyRows) : 0,
|
|
5480
|
+
sampledFrames: dirtyRows.length,
|
|
5481
|
+
fullFrames: fullDirtyFrames
|
|
5482
|
+
},
|
|
5483
|
+
scannedNodes: metricStats(scannedNodes),
|
|
5484
|
+
paintedNodes: metricStats(paintedNodes),
|
|
5485
|
+
coalescedInvalidates,
|
|
5486
|
+
coalescedFrameTasks,
|
|
5487
|
+
droppedUpdates,
|
|
5488
|
+
maxQueueDepth,
|
|
5489
|
+
rowBucketFallbacks,
|
|
5490
|
+
reasons,
|
|
5491
|
+
activePlanes
|
|
5492
|
+
};
|
|
5493
|
+
}
|
|
5199
5494
|
function framePerfNow() {
|
|
5200
5495
|
const p = globalThis.performance;
|
|
5201
5496
|
if (p && typeof p.now === "function") return p.now();
|
|
@@ -5336,6 +5631,9 @@ function createFramePerfStore(limit = 120, opts) {
|
|
|
5336
5631
|
function list() {
|
|
5337
5632
|
return samples.slice();
|
|
5338
5633
|
}
|
|
5634
|
+
function summary() {
|
|
5635
|
+
return summarizeFramePerf(samples);
|
|
5636
|
+
}
|
|
5339
5637
|
function clear() {
|
|
5340
5638
|
samples.length = 0;
|
|
5341
5639
|
}
|
|
@@ -5348,6 +5646,7 @@ function createFramePerfStore(limit = 120, opts) {
|
|
|
5348
5646
|
addSink,
|
|
5349
5647
|
latest,
|
|
5350
5648
|
list,
|
|
5649
|
+
summary,
|
|
5351
5650
|
clear
|
|
5352
5651
|
};
|
|
5353
5652
|
}
|
|
@@ -5463,6 +5762,9 @@ function clampPointToRect(point, rect) {
|
|
|
5463
5762
|
y: Math.max(rect.y, Math.min(rect.y + Math.max(0, rect.h - 1), Math.floor(point.y)))
|
|
5464
5763
|
};
|
|
5465
5764
|
}
|
|
5765
|
+
function clipboardCanWrite$1(api) {
|
|
5766
|
+
return api.canWrite ?? api.supported;
|
|
5767
|
+
}
|
|
5466
5768
|
function createTerminalSelectionController(options) {
|
|
5467
5769
|
const state = shallowRef(EMPTY_STATE);
|
|
5468
5770
|
let range = null;
|
|
@@ -5664,7 +5966,7 @@ function createTerminalSelectionController(options) {
|
|
|
5664
5966
|
const text = state.value.text || selectedText();
|
|
5665
5967
|
if (!text) return false;
|
|
5666
5968
|
setResolvedText(text);
|
|
5667
|
-
if (!options.clipboard
|
|
5969
|
+
if (!clipboardCanWrite$1(options.clipboard)) {
|
|
5668
5970
|
var _options$onCopy;
|
|
5669
5971
|
(_options$onCopy = options.onCopy) === null || _options$onCopy === void 0 || _options$onCopy.call(options, copyPayload(text, false, new Error("Clipboard unavailable")));
|
|
5670
5972
|
return false;
|
|
@@ -5769,16 +6071,19 @@ function createOsc52ClipboardProvider(options = {}) {
|
|
|
5769
6071
|
var _stdout$write;
|
|
5770
6072
|
stdout === null || stdout === void 0 || (_stdout$write = stdout.write) === null || _stdout$write === void 0 || _stdout$write.call(stdout, sequence);
|
|
5771
6073
|
});
|
|
5772
|
-
const
|
|
6074
|
+
const canWrite = options.supported ?? Boolean(options.write || (stdout === null || stdout === void 0 ? void 0 : stdout.write) && stdout.isTTY);
|
|
6075
|
+
const canRead = typeof options.readText === "function";
|
|
5773
6076
|
const target = normalizeOsc52Target(options.target);
|
|
5774
6077
|
return {
|
|
5775
|
-
supported,
|
|
6078
|
+
supported: canWrite,
|
|
6079
|
+
canRead,
|
|
6080
|
+
canWrite,
|
|
5776
6081
|
async readText() {
|
|
5777
|
-
if (!
|
|
6082
|
+
if (!canRead) throw new Error("Clipboard read not available in this runtime");
|
|
5778
6083
|
return options.readText();
|
|
5779
6084
|
},
|
|
5780
6085
|
async writeText(text) {
|
|
5781
|
-
if (!
|
|
6086
|
+
if (!canWrite) throw new Error("Clipboard not available in this runtime");
|
|
5782
6087
|
const bytes = encodeTextBytes(text);
|
|
5783
6088
|
const maxBytes = resolveMaxBytes(options.maxBytes, 100 * 1024);
|
|
5784
6089
|
if (bytes.byteLength > maxBytes) throw new Error(`OSC52 clipboard payload too large: ${bytes.byteLength} bytes`);
|
|
@@ -6133,6 +6438,120 @@ function normalizeTerminalLinkOpener(opener) {
|
|
|
6133
6438
|
return opener;
|
|
6134
6439
|
}
|
|
6135
6440
|
|
|
6441
|
+
//#endregion
|
|
6442
|
+
//#region src/renderer/terminal-graphics-trace.ts
|
|
6443
|
+
const metrics$1 = {
|
|
6444
|
+
requests: 0,
|
|
6445
|
+
skippedHidden: 0,
|
|
6446
|
+
skippedScrolling: 0,
|
|
6447
|
+
cacheHits: 0,
|
|
6448
|
+
cacheMisses: 0,
|
|
6449
|
+
cacheStores: 0,
|
|
6450
|
+
rendererRuns: 0,
|
|
6451
|
+
rendererAborts: 0,
|
|
6452
|
+
rendererErrors: 0,
|
|
6453
|
+
queued: 0,
|
|
6454
|
+
queueWaits: 0,
|
|
6455
|
+
queueDeduped: 0,
|
|
6456
|
+
cleared: 0,
|
|
6457
|
+
bytesQueued: 0,
|
|
6458
|
+
totalRendererMs: 0,
|
|
6459
|
+
totalValidateMs: 0,
|
|
6460
|
+
totalQueueWaitMs: 0,
|
|
6461
|
+
maxQueueWaitMs: 0,
|
|
6462
|
+
maxActiveRenders: 0,
|
|
6463
|
+
maxWaitingRenders: 0,
|
|
6464
|
+
maxCacheEntries: 0,
|
|
6465
|
+
maxCacheBytes: 0,
|
|
6466
|
+
scrollStarts: 0,
|
|
6467
|
+
scrollMarks: 0,
|
|
6468
|
+
scrollIdles: 0,
|
|
6469
|
+
totalScrollMs: 0,
|
|
6470
|
+
maxScrollMs: 0
|
|
6471
|
+
};
|
|
6472
|
+
const subscribers = new Set();
|
|
6473
|
+
function nowTerminalGraphicTraceTime() {
|
|
6474
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
6475
|
+
}
|
|
6476
|
+
function recordTerminalGraphicTrace(event) {
|
|
6477
|
+
const normalized = {
|
|
6478
|
+
...event,
|
|
6479
|
+
timestamp: event.timestamp ?? nowTerminalGraphicTraceTime()
|
|
6480
|
+
};
|
|
6481
|
+
switch (normalized.type) {
|
|
6482
|
+
case "request":
|
|
6483
|
+
metrics$1.requests++;
|
|
6484
|
+
break;
|
|
6485
|
+
case "skip-hidden":
|
|
6486
|
+
metrics$1.skippedHidden++;
|
|
6487
|
+
break;
|
|
6488
|
+
case "skip-scrolling":
|
|
6489
|
+
metrics$1.skippedScrolling++;
|
|
6490
|
+
break;
|
|
6491
|
+
case "cache-hit":
|
|
6492
|
+
metrics$1.cacheHits++;
|
|
6493
|
+
break;
|
|
6494
|
+
case "cache-miss":
|
|
6495
|
+
metrics$1.cacheMisses++;
|
|
6496
|
+
break;
|
|
6497
|
+
case "cache-store":
|
|
6498
|
+
metrics$1.cacheStores++;
|
|
6499
|
+
break;
|
|
6500
|
+
case "renderer-start":
|
|
6501
|
+
metrics$1.rendererRuns++;
|
|
6502
|
+
break;
|
|
6503
|
+
case "renderer-end":
|
|
6504
|
+
metrics$1.totalRendererMs += normalized.durationMs ?? 0;
|
|
6505
|
+
break;
|
|
6506
|
+
case "renderer-abort":
|
|
6507
|
+
metrics$1.rendererAborts++;
|
|
6508
|
+
break;
|
|
6509
|
+
case "renderer-error":
|
|
6510
|
+
metrics$1.rendererErrors++;
|
|
6511
|
+
break;
|
|
6512
|
+
case "validate-end":
|
|
6513
|
+
metrics$1.totalValidateMs += normalized.durationMs ?? 0;
|
|
6514
|
+
break;
|
|
6515
|
+
case "queue":
|
|
6516
|
+
metrics$1.queued++;
|
|
6517
|
+
metrics$1.bytesQueued += normalized.bytes ?? 0;
|
|
6518
|
+
break;
|
|
6519
|
+
case "queue-wait": {
|
|
6520
|
+
const durationMs = normalized.durationMs ?? 0;
|
|
6521
|
+
metrics$1.queueWaits++;
|
|
6522
|
+
metrics$1.totalQueueWaitMs += durationMs;
|
|
6523
|
+
metrics$1.maxQueueWaitMs = Math.max(metrics$1.maxQueueWaitMs, durationMs);
|
|
6524
|
+
break;
|
|
6525
|
+
}
|
|
6526
|
+
case "queue-dedupe":
|
|
6527
|
+
metrics$1.queueDeduped++;
|
|
6528
|
+
break;
|
|
6529
|
+
case "clear":
|
|
6530
|
+
metrics$1.cleared++;
|
|
6531
|
+
break;
|
|
6532
|
+
case "scroll-start":
|
|
6533
|
+
metrics$1.scrollStarts++;
|
|
6534
|
+
break;
|
|
6535
|
+
case "scroll-mark":
|
|
6536
|
+
metrics$1.scrollMarks++;
|
|
6537
|
+
break;
|
|
6538
|
+
case "scroll-idle": {
|
|
6539
|
+
const durationMs = normalized.durationMs ?? 0;
|
|
6540
|
+
metrics$1.scrollIdles++;
|
|
6541
|
+
metrics$1.totalScrollMs += durationMs;
|
|
6542
|
+
metrics$1.maxScrollMs = Math.max(metrics$1.maxScrollMs, durationMs);
|
|
6543
|
+
break;
|
|
6544
|
+
}
|
|
6545
|
+
}
|
|
6546
|
+
if (normalized.active != null && Number.isFinite(normalized.active)) metrics$1.maxActiveRenders = Math.max(metrics$1.maxActiveRenders, Math.max(0, normalized.active));
|
|
6547
|
+
if (normalized.waiting != null && Number.isFinite(normalized.waiting)) metrics$1.maxWaitingRenders = Math.max(metrics$1.maxWaitingRenders, Math.max(0, normalized.waiting));
|
|
6548
|
+
if (normalized.cacheEntries != null && Number.isFinite(normalized.cacheEntries)) metrics$1.maxCacheEntries = Math.max(metrics$1.maxCacheEntries, Math.max(0, normalized.cacheEntries));
|
|
6549
|
+
if (normalized.cacheBytes != null && Number.isFinite(normalized.cacheBytes)) metrics$1.maxCacheBytes = Math.max(metrics$1.maxCacheBytes, Math.max(0, normalized.cacheBytes));
|
|
6550
|
+
for (const subscriber of subscribers) try {
|
|
6551
|
+
subscriber(normalized);
|
|
6552
|
+
} catch {}
|
|
6553
|
+
}
|
|
6554
|
+
|
|
6136
6555
|
//#endregion
|
|
6137
6556
|
//#region src/vue/context.ts
|
|
6138
6557
|
const TerminalContextKey = injectionKey("TerminalContext");
|
|
@@ -6143,6 +6562,7 @@ const RenderPlaneContextKey = injectionKey("RenderPlane");
|
|
|
6143
6562
|
const ImeAnchorContextKey = injectionKey("ImeAnchor");
|
|
6144
6563
|
const TInputPluginsContextKey = injectionKey("TInputPlugins");
|
|
6145
6564
|
const TPathPickerProviderContextKey = injectionKey("TPathPickerProvider");
|
|
6565
|
+
const TerminalGraphicsActivityKey = injectionKey("TerminalGraphicsActivity");
|
|
6146
6566
|
const DialogContextKey = injectionKey("DialogContext");
|
|
6147
6567
|
|
|
6148
6568
|
//#endregion
|
|
@@ -6293,6 +6713,10 @@ function sameRect(a, b) {
|
|
|
6293
6713
|
if (!a || !b) return false;
|
|
6294
6714
|
return a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;
|
|
6295
6715
|
}
|
|
6716
|
+
function rectsIntersect(a, b) {
|
|
6717
|
+
if (isEmptyRect(a) || isEmptyRect(b)) return false;
|
|
6718
|
+
return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
|
|
6719
|
+
}
|
|
6296
6720
|
function createRenderManager(terminal, options = {}) {
|
|
6297
6721
|
const widthProvider = options.widthProvider ?? "default";
|
|
6298
6722
|
const withRenderTextPass = (fn) => withTextRenderPass(fn, widthProvider);
|
|
@@ -6300,6 +6724,7 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6300
6724
|
const nodes = new Map();
|
|
6301
6725
|
const planeDirtyStates = new Map();
|
|
6302
6726
|
const initialSize = terminal.size();
|
|
6727
|
+
let terminalCols = initialSize.cols;
|
|
6303
6728
|
let terminalRows = initialSize.rows;
|
|
6304
6729
|
let allRows = Array.from({ length: terminalRows }, (_, index) => index);
|
|
6305
6730
|
let sortedNodes = [];
|
|
@@ -6320,19 +6745,37 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6320
6745
|
let disposed = false;
|
|
6321
6746
|
const stackPathCache = new WeakMap();
|
|
6322
6747
|
const profiler = createTuiProfiler("render-manager", options.profiler);
|
|
6323
|
-
const offResize = terminal.on("resize", ({ rows }) => {
|
|
6748
|
+
const offResize = terminal.on("resize", ({ cols, rows }) => {
|
|
6324
6749
|
if (disposed) return;
|
|
6750
|
+
const colsChanged = cols !== terminalCols;
|
|
6751
|
+
const prevRows = terminalRows;
|
|
6752
|
+
terminalCols = cols;
|
|
6325
6753
|
terminalRows = rows;
|
|
6326
6754
|
allRows = Array.from({ length: terminalRows }, (_, index) => index);
|
|
6327
6755
|
for (const state of planeDirtyStates.values()) {
|
|
6328
|
-
|
|
6756
|
+
const prevBits = state.dirtyRowBits;
|
|
6329
6757
|
state.dirtyRowBits = new Uint8Array(terminalRows);
|
|
6330
6758
|
state.dirtyRowCount = 0;
|
|
6331
6759
|
state.dirtyMinY = Number.POSITIVE_INFINITY;
|
|
6332
6760
|
state.dirtyMaxY = -1;
|
|
6761
|
+
const limit = Math.min(terminalRows, prevBits.length);
|
|
6762
|
+
for (let y = 0; y < limit; y++) {
|
|
6763
|
+
if (prevBits[y] !== 1) continue;
|
|
6764
|
+
state.dirtyRowBits[y] = 1;
|
|
6765
|
+
state.dirtyRowCount++;
|
|
6766
|
+
if (y < state.dirtyMinY) state.dirtyMinY = y;
|
|
6767
|
+
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6768
|
+
}
|
|
6769
|
+
for (let y = prevRows; y < terminalRows; y++) {
|
|
6770
|
+
if (state.dirtyRowBits[y] === 1) continue;
|
|
6771
|
+
state.dirtyRowBits[y] = 1;
|
|
6772
|
+
state.dirtyRowCount++;
|
|
6773
|
+
if (y < state.dirtyMinY) state.dirtyMinY = y;
|
|
6774
|
+
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6775
|
+
}
|
|
6333
6776
|
}
|
|
6334
6777
|
rebuildRowBuckets();
|
|
6335
|
-
clearTextCaches();
|
|
6778
|
+
if (colsChanged) clearTextCaches();
|
|
6336
6779
|
});
|
|
6337
6780
|
const rootStack = Object.freeze({
|
|
6338
6781
|
id: `s${nextStackId++}`,
|
|
@@ -6531,6 +6974,33 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6531
6974
|
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6532
6975
|
}
|
|
6533
6976
|
}
|
|
6977
|
+
function markLowerPlanesForRect(plane, rect) {
|
|
6978
|
+
const planeIndex = TERMINAL_RENDER_PLANES.indexOf(plane);
|
|
6979
|
+
if (planeIndex <= 0) return;
|
|
6980
|
+
for (let i = 0; i < planeIndex; i++) markRect(TERMINAL_RENDER_PLANES[i], rect);
|
|
6981
|
+
}
|
|
6982
|
+
function markRowRange(plane, startY, endY) {
|
|
6983
|
+
const state = getDirtyState(plane);
|
|
6984
|
+
const start = Math.max(0, Math.min(terminalRows, Math.floor(startY)));
|
|
6985
|
+
const end = Math.max(start, Math.min(terminalRows, Math.floor(endY)));
|
|
6986
|
+
for (let y = start; y < end; y++) {
|
|
6987
|
+
if (state.dirtyRowBits[y] === 1) continue;
|
|
6988
|
+
state.dirtyRowBits[y] = 1;
|
|
6989
|
+
state.dirtyRowCount++;
|
|
6990
|
+
if (y < state.dirtyMinY) state.dirtyMinY = y;
|
|
6991
|
+
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6994
|
+
function markRectHeightDelta(plane, prev, next) {
|
|
6995
|
+
if (!prev || !next) return false;
|
|
6996
|
+
if (prev.x !== next.x || prev.y !== next.y || prev.w !== next.w) return false;
|
|
6997
|
+
const prevBounds = rectToYBounds(prev);
|
|
6998
|
+
const nextBounds = rectToYBounds(next);
|
|
6999
|
+
if (prevBounds.y0 !== nextBounds.y0) return false;
|
|
7000
|
+
if (nextBounds.y1 > prevBounds.y1) markRowRange(plane, prevBounds.y1, nextBounds.y1);
|
|
7001
|
+
else if (prevBounds.y1 > nextBounds.y1) markRowRange(plane, nextBounds.y1, prevBounds.y1);
|
|
7002
|
+
return true;
|
|
7003
|
+
}
|
|
6534
7004
|
function markRowsForNode(node, rows) {
|
|
6535
7005
|
if (!rows.length) return false;
|
|
6536
7006
|
warnIfRowsLookLocal(node, rows);
|
|
@@ -6578,6 +7048,7 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6578
7048
|
nodes.set(id, full);
|
|
6579
7049
|
addToRowBuckets(full);
|
|
6580
7050
|
markRect(full.plane, full.rect);
|
|
7051
|
+
markLowerPlanesForRect(full.plane, full.rect);
|
|
6581
7052
|
sortedDirty = true;
|
|
6582
7053
|
return full;
|
|
6583
7054
|
}
|
|
@@ -6589,6 +7060,7 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6589
7060
|
const nextPlane = next.plane ?? prev.plane;
|
|
6590
7061
|
const planeChanged = nextPlane !== prev.plane;
|
|
6591
7062
|
const hasRect = Object.prototype.hasOwnProperty.call(next, "rect");
|
|
7063
|
+
const paintChanged = Object.prototype.hasOwnProperty.call(next, "paint");
|
|
6592
7064
|
const nextRect = hasRect ? next.rect ?? null : prev.rect;
|
|
6593
7065
|
const rectChanged = !sameRect(prev.rect, nextRect);
|
|
6594
7066
|
const bucketChanged = planeChanged || rectChanged;
|
|
@@ -6596,10 +7068,12 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6596
7068
|
const dirtyRowsHint = next.dirtyRowsHint;
|
|
6597
7069
|
const canUseDirtyRowsHint = !sortChanged && !rectChanged && nextPlane === prev.plane && dirtyRowsHint != null && dirtyRowsHint.length > 0;
|
|
6598
7070
|
if (canUseDirtyRowsHint) markRowsForNode(prev, dirtyRowsHint);
|
|
6599
|
-
else {
|
|
7071
|
+
else if (rectChanged && !paintChanged && !sortChanged && !planeChanged && markRectHeightDelta(prev.plane, prev.rect, nextRect)) {} else {
|
|
6600
7072
|
markRect(prev.plane, prev.rect);
|
|
6601
7073
|
markRect(nextPlane, nextRect);
|
|
6602
7074
|
}
|
|
7075
|
+
markLowerPlanesForRect(prev.plane, prev.rect);
|
|
7076
|
+
markLowerPlanesForRect(nextPlane, nextRect);
|
|
6603
7077
|
if (bucketChanged) removeFromRowBuckets(prev);
|
|
6604
7078
|
const full = Object.freeze({
|
|
6605
7079
|
...prev,
|
|
@@ -6629,11 +7103,41 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6629
7103
|
if (!node) return false;
|
|
6630
7104
|
return markRowsForNode(node, rows);
|
|
6631
7105
|
}
|
|
7106
|
+
function isRectCoveredByHigherNode(id, rect, options$1 = {}) {
|
|
7107
|
+
return higherNodeCoverageRects(id, rect, options$1).length > 0;
|
|
7108
|
+
}
|
|
7109
|
+
function higherNodeCoverageRects(id, rect, options$1 = {}) {
|
|
7110
|
+
if (disposed || isEmptyRect(rect)) return [];
|
|
7111
|
+
const owner = nodes.get(id);
|
|
7112
|
+
if (!owner) return [];
|
|
7113
|
+
const ownerPlaneIndex = TERMINAL_RENDER_PLANES.indexOf(owner.plane);
|
|
7114
|
+
if (ownerPlaneIndex < 0) return [];
|
|
7115
|
+
const out = [];
|
|
7116
|
+
for (const candidate of nodes.values()) {
|
|
7117
|
+
if (candidate.id === id || !candidate.rect || isEmptyRect(candidate.rect)) continue;
|
|
7118
|
+
if (!rectsIntersect(rect, candidate.rect)) continue;
|
|
7119
|
+
const candidatePlaneIndex = TERMINAL_RENDER_PLANES.indexOf(candidate.plane);
|
|
7120
|
+
const covered = candidatePlaneIndex > ownerPlaneIndex || !options$1.ignoreSamePlane && candidatePlaneIndex === ownerPlaneIndex && compareNodes(owner, candidate) < 0;
|
|
7121
|
+
if (!covered) continue;
|
|
7122
|
+
const x0 = Math.max(rect.x, candidate.rect.x);
|
|
7123
|
+
const y0 = Math.max(rect.y, candidate.rect.y);
|
|
7124
|
+
const x1 = Math.min(rect.x + rect.w, candidate.rect.x + candidate.rect.w);
|
|
7125
|
+
const y1 = Math.min(rect.y + rect.h, candidate.rect.y + candidate.rect.h);
|
|
7126
|
+
if (x1 > x0 && y1 > y0) out.push({
|
|
7127
|
+
x: x0,
|
|
7128
|
+
y: y0,
|
|
7129
|
+
w: x1 - x0,
|
|
7130
|
+
h: y1 - y0
|
|
7131
|
+
});
|
|
7132
|
+
}
|
|
7133
|
+
return out;
|
|
7134
|
+
}
|
|
6632
7135
|
function unregister(id) {
|
|
6633
7136
|
if (disposed) return;
|
|
6634
7137
|
const prev = nodes.get(id);
|
|
6635
7138
|
if (prev) {
|
|
6636
7139
|
markRect(prev.plane, prev.rect);
|
|
7140
|
+
markLowerPlanesForRect(prev.plane, prev.rect);
|
|
6637
7141
|
removeFromRowBuckets(prev);
|
|
6638
7142
|
warnedLocalDirtyRows.delete(id);
|
|
6639
7143
|
}
|
|
@@ -6849,6 +7353,8 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6849
7353
|
register,
|
|
6850
7354
|
update,
|
|
6851
7355
|
markDirtyRows,
|
|
7356
|
+
isRectCoveredByHigherNode,
|
|
7357
|
+
higherNodeCoverageRects,
|
|
6852
7358
|
unregister,
|
|
6853
7359
|
render,
|
|
6854
7360
|
dispose() {
|
|
@@ -7247,6 +7753,8 @@ function resolveSelectionConfig(config) {
|
|
|
7247
7753
|
}
|
|
7248
7754
|
const unsupportedClipboard = {
|
|
7249
7755
|
supported: false,
|
|
7756
|
+
canRead: false,
|
|
7757
|
+
canWrite: false,
|
|
7250
7758
|
async readText() {
|
|
7251
7759
|
return "";
|
|
7252
7760
|
},
|
|
@@ -7254,6 +7762,12 @@ const unsupportedClipboard = {
|
|
|
7254
7762
|
throw new Error("Clipboard unavailable");
|
|
7255
7763
|
}
|
|
7256
7764
|
};
|
|
7765
|
+
function clipboardCanRead(api) {
|
|
7766
|
+
return api.canRead ?? api.supported;
|
|
7767
|
+
}
|
|
7768
|
+
function clipboardCanWrite(api) {
|
|
7769
|
+
return api.canWrite ?? api.supported;
|
|
7770
|
+
}
|
|
7257
7771
|
function isPlainObject(v) {
|
|
7258
7772
|
if (!v || typeof v !== "object") return false;
|
|
7259
7773
|
const proto = Object.getPrototypeOf(v);
|
|
@@ -7285,10 +7799,12 @@ function shallowEqualRecord(a, b) {
|
|
|
7285
7799
|
function createTerminalApp(options) {
|
|
7286
7800
|
const env = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
7287
7801
|
if (shouldInstallFileWriters(env)) installNodeFileWriters();
|
|
7802
|
+
const debugEnabled = isDebugEnabled();
|
|
7803
|
+
const debugLog$1 = createDebugLogger(debugEnabled);
|
|
7288
7804
|
const widthProvider = options.widthProvider ?? "default";
|
|
7289
7805
|
const profileEnabled = envFlag(env, "VUE_TUI_PROFILE", "DIMCODE_PROFILE_TUI");
|
|
7290
|
-
const profileLogPath = envString(env, "VUE_TUI_PROFILE_LOG_PATH", "DIMCODE_PROFILE_TUI_LOG_PATH");
|
|
7291
|
-
const framePerfLogPath = envString(env, "VUE_TUI_FRAME_PERF_LOG_PATH", "DIMCODE_TUI_PERF_LOG") || (profileLogPath.endsWith(".jsonl") ? profileLogPath : defaultVueTuiFramePerfLogPath());
|
|
7806
|
+
const profileLogPath = envString$1(env, "VUE_TUI_PROFILE_LOG_PATH", "DIMCODE_PROFILE_TUI_LOG_PATH");
|
|
7807
|
+
const framePerfLogPath = envString$1(env, "VUE_TUI_FRAME_PERF_LOG_PATH", "DIMCODE_TUI_PERF_LOG") || (profileLogPath.endsWith(".jsonl") ? profileLogPath : defaultVueTuiFramePerfLogPath());
|
|
7292
7808
|
const framePerfSink = profileEnabled ? createJsonlPerfSink({
|
|
7293
7809
|
file: framePerfLogPath,
|
|
7294
7810
|
fileWriter: nodeProfilerFileWriter,
|
|
@@ -7339,6 +7855,10 @@ function createTerminalApp(options) {
|
|
|
7339
7855
|
}
|
|
7340
7856
|
});
|
|
7341
7857
|
const offCommit = terminal.on("commit", ({ dirtyRows, planes, sync }) => {
|
|
7858
|
+
if (debugEnabled) {
|
|
7859
|
+
const size = terminal.size();
|
|
7860
|
+
debugLog$1.render(`app commit: size=${size.cols}x${size.rows}, dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}, planes=${(planes === null || planes === void 0 ? void 0 : planes.join(",")) ?? "all"}${sync ? ", sync" : ""}`);
|
|
7861
|
+
}
|
|
7342
7862
|
latency === null || latency === void 0 || latency.recordCommit({
|
|
7343
7863
|
dirtyRows,
|
|
7344
7864
|
planes,
|
|
@@ -7431,6 +7951,10 @@ function createTerminalApp(options) {
|
|
|
7431
7951
|
scheduled = false;
|
|
7432
7952
|
flushing = true;
|
|
7433
7953
|
const activePlanes = takeActivePlanes();
|
|
7954
|
+
if (debugEnabled) {
|
|
7955
|
+
const size = terminal.size();
|
|
7956
|
+
debugLog$1.render(`app flush start: size=${size.cols}x${size.rows}, activePlanes=${(activePlanes === null || activePlanes === void 0 ? void 0 : activePlanes.join(",")) ?? "all"}, sync=${sync ? "true" : "false"}, frameTasks=${frameTasks.frameTaskCount}`);
|
|
7957
|
+
}
|
|
7434
7958
|
latency === null || latency === void 0 || latency.recordFlushStart({
|
|
7435
7959
|
sync,
|
|
7436
7960
|
activePlanes
|
|
@@ -7556,6 +8080,10 @@ function createTerminalApp(options) {
|
|
|
7556
8080
|
function invalidate(options$1) {
|
|
7557
8081
|
if (disposed) return;
|
|
7558
8082
|
const priority = (options$1 === null || options$1 === void 0 ? void 0 : options$1.priority) ?? "normal";
|
|
8083
|
+
if (debugEnabled) {
|
|
8084
|
+
const size = terminal.size();
|
|
8085
|
+
debugLog$1.render(`app invalidate: size=${size.cols}x${size.rows}, reason=${(options$1 === null || options$1 === void 0 ? void 0 : options$1.reason) ?? "unknown"}, priority=${priority}, plane=${(options$1 === null || options$1 === void 0 ? void 0 : options$1.plane) ?? "all"}, scheduled=${scheduled}, flushing=${flushing}, queueDepth=${queueDepth()}`);
|
|
8086
|
+
}
|
|
7559
8087
|
noteFrameReason(options$1 === null || options$1 === void 0 ? void 0 : options$1.reason);
|
|
7560
8088
|
latency === null || latency === void 0 || latency.recordSchedulerInvalidate({
|
|
7561
8089
|
priority,
|
|
@@ -7640,6 +8168,7 @@ function createTerminalApp(options) {
|
|
|
7640
8168
|
invalidate({ plane: portal.plane });
|
|
7641
8169
|
return handle;
|
|
7642
8170
|
} };
|
|
8171
|
+
const clipboard = options.clipboard ?? unsupportedClipboard;
|
|
7643
8172
|
const rootLayout = shallowReactive({
|
|
7644
8173
|
originX: 0,
|
|
7645
8174
|
originY: 0,
|
|
@@ -7679,10 +8208,11 @@ function createTerminalApp(options) {
|
|
|
7679
8208
|
"chrome"
|
|
7680
8209
|
];
|
|
7681
8210
|
let selectionRenderNodeId = null;
|
|
8211
|
+
const selectionRenderRect = () => null;
|
|
7682
8212
|
const selection = createTerminalSelectionController({
|
|
7683
8213
|
terminal,
|
|
7684
8214
|
overlayTerminal: selectionOverlay,
|
|
7685
|
-
clipboard
|
|
8215
|
+
clipboard,
|
|
7686
8216
|
getRow: (y) => readTerminalRowForPlanes(terminal, y, selectionReadPlanes),
|
|
7687
8217
|
getTextProviders: () => Array.from(selectionTextProviders.values()),
|
|
7688
8218
|
getOptions: () => {
|
|
@@ -7728,12 +8258,7 @@ function createTerminalApp(options) {
|
|
|
7728
8258
|
stack: render.rootStack,
|
|
7729
8259
|
plane: "overlay",
|
|
7730
8260
|
zIndex: -1e4,
|
|
7731
|
-
rect:
|
|
7732
|
-
x: 0,
|
|
7733
|
-
y: 0,
|
|
7734
|
-
w: options.cols,
|
|
7735
|
-
h: options.rows
|
|
7736
|
-
},
|
|
8261
|
+
rect: selectionRenderRect(),
|
|
7737
8262
|
paint: selection.paint
|
|
7738
8263
|
});
|
|
7739
8264
|
selectionRenderNodeId = selectionRenderNode.id;
|
|
@@ -7848,19 +8373,17 @@ function createTerminalApp(options) {
|
|
|
7848
8373
|
...createDefaultTInputHostAdapter(),
|
|
7849
8374
|
isTerminalLike: true,
|
|
7850
8375
|
async readClipboardText() {
|
|
7851
|
-
|
|
7852
|
-
if (!((_options$clipboard = options.clipboard) === null || _options$clipboard === void 0 ? void 0 : _options$clipboard.supported)) return "";
|
|
8376
|
+
if (!clipboardCanRead(clipboard)) return "";
|
|
7853
8377
|
try {
|
|
7854
|
-
return await
|
|
8378
|
+
return await clipboard.readText();
|
|
7855
8379
|
} catch {
|
|
7856
8380
|
return "";
|
|
7857
8381
|
}
|
|
7858
8382
|
},
|
|
7859
8383
|
async writeClipboardText(text) {
|
|
7860
|
-
|
|
7861
|
-
if (!text || !((_options$clipboard2 = options.clipboard) === null || _options$clipboard2 === void 0 ? void 0 : _options$clipboard2.supported)) return false;
|
|
8384
|
+
if (!text || !clipboardCanWrite(clipboard)) return false;
|
|
7862
8385
|
try {
|
|
7863
|
-
await
|
|
8386
|
+
await clipboard.writeText(text);
|
|
7864
8387
|
return true;
|
|
7865
8388
|
} catch {
|
|
7866
8389
|
return false;
|
|
@@ -7869,6 +8392,7 @@ function createTerminalApp(options) {
|
|
|
7869
8392
|
}))] : [defaultTInputHostPlugin]);
|
|
7870
8393
|
const linkOpener = ref(normalizeTerminalLinkOpener(options.linkOpener));
|
|
7871
8394
|
const offResize = terminal.on("resize", ({ cols, rows }) => {
|
|
8395
|
+
if (debugEnabled) debugLog$1.render(`app resize event: size=${cols}x${rows}, scheduled=${scheduled}, flushing=${flushing}, queueDepth=${queueDepth()}`);
|
|
7872
8396
|
rootLayout.clipRect = {
|
|
7873
8397
|
x: 0,
|
|
7874
8398
|
y: 0,
|
|
@@ -7876,12 +8400,7 @@ function createTerminalApp(options) {
|
|
|
7876
8400
|
h: rows
|
|
7877
8401
|
};
|
|
7878
8402
|
selection.clear();
|
|
7879
|
-
if (selectionRenderNodeId) render.update(selectionRenderNodeId, { rect:
|
|
7880
|
-
x: 0,
|
|
7881
|
-
y: 0,
|
|
7882
|
-
w: cols,
|
|
7883
|
-
h: rows
|
|
7884
|
-
} });
|
|
8403
|
+
if (selectionRenderNodeId) render.update(selectionRenderNodeId, { rect: selectionRenderRect() });
|
|
7885
8404
|
invalidate({ reason: "resize" });
|
|
7886
8405
|
});
|
|
7887
8406
|
schedulerApi = {
|
|
@@ -7902,6 +8421,7 @@ function createTerminalApp(options) {
|
|
|
7902
8421
|
events: shallowRef(events),
|
|
7903
8422
|
scheduler: schedulerApi,
|
|
7904
8423
|
runtime,
|
|
8424
|
+
clipboard,
|
|
7905
8425
|
observability: {
|
|
7906
8426
|
trace,
|
|
7907
8427
|
framePerf
|
|
@@ -7975,7 +8495,11 @@ const metrics = {
|
|
|
7975
8495
|
writeEmaMs: 0,
|
|
7976
8496
|
writeMode: "stream",
|
|
7977
8497
|
fps: 0,
|
|
7978
|
-
bytesPerSec: 0
|
|
8498
|
+
bytesPerSec: 0,
|
|
8499
|
+
terminalGraphicsDraws: 0,
|
|
8500
|
+
terminalGraphicsClears: 0,
|
|
8501
|
+
terminalGraphicsBytes: 0,
|
|
8502
|
+
terminalGraphicsActive: 0
|
|
7979
8503
|
};
|
|
7980
8504
|
let bucketStart = 0;
|
|
7981
8505
|
let bucketFrames = 0;
|
|
@@ -8009,6 +8533,291 @@ function recordStdoutFrame(info) {
|
|
|
8009
8533
|
bucketBytes = 0;
|
|
8010
8534
|
}
|
|
8011
8535
|
}
|
|
8536
|
+
function recordStdoutTerminalGraphics(info) {
|
|
8537
|
+
metrics.terminalGraphicsDraws += Math.max(0, Math.floor(Number(info.draws) || 0));
|
|
8538
|
+
metrics.terminalGraphicsClears += Math.max(0, Math.floor(Number(info.clears) || 0));
|
|
8539
|
+
metrics.terminalGraphicsBytes += Math.max(0, Math.floor(Number(info.bytes) || 0));
|
|
8540
|
+
metrics.terminalGraphicsActive = Math.max(0, Math.floor(Number(info.active) || 0));
|
|
8541
|
+
}
|
|
8542
|
+
|
|
8543
|
+
//#endregion
|
|
8544
|
+
//#region src/renderer/terminal-graphic-render-queue.ts
|
|
8545
|
+
const CACHE_MISS = Symbol("terminal-graphic-cache-miss");
|
|
8546
|
+
function now() {
|
|
8547
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
8548
|
+
}
|
|
8549
|
+
function createAbortError() {
|
|
8550
|
+
const error = new Error("Terminal graphic render aborted");
|
|
8551
|
+
error.name = "AbortError";
|
|
8552
|
+
return error;
|
|
8553
|
+
}
|
|
8554
|
+
function positiveFiniteInt(value, fallback) {
|
|
8555
|
+
const n = Number(value);
|
|
8556
|
+
if (!Number.isFinite(n)) return fallback;
|
|
8557
|
+
const int = Math.floor(n);
|
|
8558
|
+
return int > 0 ? int : fallback;
|
|
8559
|
+
}
|
|
8560
|
+
function throwIfAborted(signal) {
|
|
8561
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) throw createAbortError();
|
|
8562
|
+
}
|
|
8563
|
+
function raceAbort(promise, signal) {
|
|
8564
|
+
if (!signal) return promise;
|
|
8565
|
+
if (signal.aborted) return Promise.reject(createAbortError());
|
|
8566
|
+
return new Promise((resolve, reject) => {
|
|
8567
|
+
const onAbort = () => reject(createAbortError());
|
|
8568
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
8569
|
+
promise.then((value) => {
|
|
8570
|
+
signal.removeEventListener("abort", onAbort);
|
|
8571
|
+
resolve(value);
|
|
8572
|
+
}, (error) => {
|
|
8573
|
+
signal.removeEventListener("abort", onAbort);
|
|
8574
|
+
reject(error);
|
|
8575
|
+
});
|
|
8576
|
+
});
|
|
8577
|
+
}
|
|
8578
|
+
function createTerminalGraphicRenderQueue(options = {}) {
|
|
8579
|
+
const maxConcurrency = positiveFiniteInt(options.maxConcurrency, 2);
|
|
8580
|
+
const maxEntries = positiveFiniteInt(options.maxEntries, 128);
|
|
8581
|
+
const maxBytes = positiveFiniteInt(options.maxBytes, 32 * 1024 * 1024);
|
|
8582
|
+
const ttlMs = positiveFiniteInt(options.ttlMs, 5 * 6e4);
|
|
8583
|
+
const dedupeInflight = options.dedupeInflight ?? false;
|
|
8584
|
+
let active = 0;
|
|
8585
|
+
let cacheBytes = 0;
|
|
8586
|
+
let generation = 0;
|
|
8587
|
+
const waiters = [];
|
|
8588
|
+
const cache = new Map();
|
|
8589
|
+
const inflight = new Map();
|
|
8590
|
+
function traceQueueState(event) {
|
|
8591
|
+
recordTerminalGraphicTrace({
|
|
8592
|
+
...event,
|
|
8593
|
+
active,
|
|
8594
|
+
waiting: waiters.length,
|
|
8595
|
+
cacheEntries: cache.size,
|
|
8596
|
+
cacheBytes
|
|
8597
|
+
});
|
|
8598
|
+
}
|
|
8599
|
+
function evictUntilBudget() {
|
|
8600
|
+
while (cache.size > maxEntries || cacheBytes > maxBytes) {
|
|
8601
|
+
const oldestKey = cache.keys().next().value;
|
|
8602
|
+
if (!oldestKey) break;
|
|
8603
|
+
const entry = cache.get(oldestKey);
|
|
8604
|
+
cache.delete(oldestKey);
|
|
8605
|
+
if (entry) {
|
|
8606
|
+
var _options$onMetric;
|
|
8607
|
+
cacheBytes -= entry.bytes;
|
|
8608
|
+
(_options$onMetric = options.onMetric) === null || _options$onMetric === void 0 || _options$onMetric.call(options, {
|
|
8609
|
+
type: "evict",
|
|
8610
|
+
key: oldestKey,
|
|
8611
|
+
bytes: entry.bytes
|
|
8612
|
+
});
|
|
8613
|
+
}
|
|
8614
|
+
}
|
|
8615
|
+
}
|
|
8616
|
+
function setCache(key, value, bytes) {
|
|
8617
|
+
var _options$onMetric2;
|
|
8618
|
+
const prev = cache.get(key);
|
|
8619
|
+
if (prev) {
|
|
8620
|
+
cache.delete(key);
|
|
8621
|
+
cacheBytes -= prev.bytes;
|
|
8622
|
+
}
|
|
8623
|
+
if (bytes > maxBytes) return;
|
|
8624
|
+
cache.set(key, {
|
|
8625
|
+
value,
|
|
8626
|
+
bytes,
|
|
8627
|
+
expiresAt: Date.now() + ttlMs
|
|
8628
|
+
});
|
|
8629
|
+
cacheBytes += bytes;
|
|
8630
|
+
(_options$onMetric2 = options.onMetric) === null || _options$onMetric2 === void 0 || _options$onMetric2.call(options, {
|
|
8631
|
+
type: "cache-store",
|
|
8632
|
+
key,
|
|
8633
|
+
bytes
|
|
8634
|
+
});
|
|
8635
|
+
traceQueueState({
|
|
8636
|
+
type: "cache-store",
|
|
8637
|
+
id: key,
|
|
8638
|
+
key,
|
|
8639
|
+
bytes
|
|
8640
|
+
});
|
|
8641
|
+
evictUntilBudget();
|
|
8642
|
+
}
|
|
8643
|
+
function getCache(key) {
|
|
8644
|
+
var _options$onMetric3;
|
|
8645
|
+
const entry = cache.get(key);
|
|
8646
|
+
if (!entry) return CACHE_MISS;
|
|
8647
|
+
if (entry.expiresAt < Date.now()) {
|
|
8648
|
+
cache.delete(key);
|
|
8649
|
+
cacheBytes -= entry.bytes;
|
|
8650
|
+
return CACHE_MISS;
|
|
8651
|
+
}
|
|
8652
|
+
cache.delete(key);
|
|
8653
|
+
cache.set(key, entry);
|
|
8654
|
+
(_options$onMetric3 = options.onMetric) === null || _options$onMetric3 === void 0 || _options$onMetric3.call(options, {
|
|
8655
|
+
type: "cache-hit",
|
|
8656
|
+
key
|
|
8657
|
+
});
|
|
8658
|
+
traceQueueState({
|
|
8659
|
+
type: "cache-hit",
|
|
8660
|
+
id: key,
|
|
8661
|
+
key,
|
|
8662
|
+
bytes: entry.bytes
|
|
8663
|
+
});
|
|
8664
|
+
return entry.value;
|
|
8665
|
+
}
|
|
8666
|
+
function release() {
|
|
8667
|
+
active = Math.max(0, active - 1);
|
|
8668
|
+
pump();
|
|
8669
|
+
}
|
|
8670
|
+
function once(fn) {
|
|
8671
|
+
let called = false;
|
|
8672
|
+
return () => {
|
|
8673
|
+
if (called) return;
|
|
8674
|
+
called = true;
|
|
8675
|
+
fn();
|
|
8676
|
+
};
|
|
8677
|
+
}
|
|
8678
|
+
function observeActiveRenderAbort(key, signal) {
|
|
8679
|
+
if (!signal) return () => void 0;
|
|
8680
|
+
const onAbort = () => {
|
|
8681
|
+
var _options$onMetric4;
|
|
8682
|
+
(_options$onMetric4 = options.onMetric) === null || _options$onMetric4 === void 0 || _options$onMetric4.call(options, {
|
|
8683
|
+
type: "render-abort",
|
|
8684
|
+
key
|
|
8685
|
+
});
|
|
8686
|
+
traceQueueState({
|
|
8687
|
+
type: "renderer-abort",
|
|
8688
|
+
id: key,
|
|
8689
|
+
key
|
|
8690
|
+
});
|
|
8691
|
+
};
|
|
8692
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
8693
|
+
return () => signal.removeEventListener("abort", onAbort);
|
|
8694
|
+
}
|
|
8695
|
+
function pump() {
|
|
8696
|
+
while (active < maxConcurrency && waiters.length > 0) {
|
|
8697
|
+
const waiter = waiters.shift();
|
|
8698
|
+
active++;
|
|
8699
|
+
traceQueueState({
|
|
8700
|
+
type: "queue-depth",
|
|
8701
|
+
id: waiter.key,
|
|
8702
|
+
key: waiter.key
|
|
8703
|
+
});
|
|
8704
|
+
waiter.start();
|
|
8705
|
+
}
|
|
8706
|
+
}
|
|
8707
|
+
function acquire(key, signal) {
|
|
8708
|
+
throwIfAborted(signal);
|
|
8709
|
+
if (active < maxConcurrency) {
|
|
8710
|
+
active++;
|
|
8711
|
+
traceQueueState({
|
|
8712
|
+
type: "queue-depth",
|
|
8713
|
+
id: key,
|
|
8714
|
+
key
|
|
8715
|
+
});
|
|
8716
|
+
return Promise.resolve(release);
|
|
8717
|
+
}
|
|
8718
|
+
const waitStartedAt = now();
|
|
8719
|
+
return new Promise((resolve, reject) => {
|
|
8720
|
+
let onAbort = () => void 0;
|
|
8721
|
+
const cleanup = () => {
|
|
8722
|
+
signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
|
|
8723
|
+
};
|
|
8724
|
+
const waiter = {
|
|
8725
|
+
key,
|
|
8726
|
+
start: () => {
|
|
8727
|
+
var _options$onMetric5;
|
|
8728
|
+
cleanup();
|
|
8729
|
+
const waitMs = now() - waitStartedAt;
|
|
8730
|
+
(_options$onMetric5 = options.onMetric) === null || _options$onMetric5 === void 0 || _options$onMetric5.call(options, {
|
|
8731
|
+
type: "queue-wait",
|
|
8732
|
+
key,
|
|
8733
|
+
waitMs
|
|
8734
|
+
});
|
|
8735
|
+
traceQueueState({
|
|
8736
|
+
type: "queue-wait",
|
|
8737
|
+
id: key,
|
|
8738
|
+
key,
|
|
8739
|
+
durationMs: waitMs
|
|
8740
|
+
});
|
|
8741
|
+
resolve(release);
|
|
8742
|
+
},
|
|
8743
|
+
reject: (error) => {
|
|
8744
|
+
cleanup();
|
|
8745
|
+
reject(error);
|
|
8746
|
+
}
|
|
8747
|
+
};
|
|
8748
|
+
onAbort = () => {
|
|
8749
|
+
const index = waiters.indexOf(waiter);
|
|
8750
|
+
if (index >= 0) waiters.splice(index, 1);
|
|
8751
|
+
cleanup();
|
|
8752
|
+
reject(createAbortError());
|
|
8753
|
+
};
|
|
8754
|
+
signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
|
|
8755
|
+
waiters.push(waiter);
|
|
8756
|
+
traceQueueState({
|
|
8757
|
+
type: "queue-depth",
|
|
8758
|
+
id: key,
|
|
8759
|
+
key
|
|
8760
|
+
});
|
|
8761
|
+
});
|
|
8762
|
+
}
|
|
8763
|
+
async function cached(key, signal, render, estimateBytes = () => 0, cachedOptions = {}) {
|
|
8764
|
+
throwIfAborted(signal);
|
|
8765
|
+
const cachedValue = getCache(key);
|
|
8766
|
+
if (cachedValue !== CACHE_MISS) return cachedValue;
|
|
8767
|
+
traceQueueState({
|
|
8768
|
+
type: "cache-miss",
|
|
8769
|
+
id: key,
|
|
8770
|
+
key
|
|
8771
|
+
});
|
|
8772
|
+
const shouldDedupeInflight = cachedOptions.dedupeInflight ?? dedupeInflight;
|
|
8773
|
+
const existing = shouldDedupeInflight ? inflight.get(key) : void 0;
|
|
8774
|
+
if (existing) return raceAbort(existing, signal);
|
|
8775
|
+
let promise;
|
|
8776
|
+
promise = (async () => {
|
|
8777
|
+
let releaseSlot = null;
|
|
8778
|
+
let removeAbortObserver = null;
|
|
8779
|
+
const renderGeneration = generation;
|
|
8780
|
+
try {
|
|
8781
|
+
releaseSlot = once(await acquire(key, signal));
|
|
8782
|
+
removeAbortObserver = observeActiveRenderAbort(key, signal);
|
|
8783
|
+
throwIfAborted(signal);
|
|
8784
|
+
const cachedAfterWait = getCache(key);
|
|
8785
|
+
if (cachedAfterWait !== CACHE_MISS) return cachedAfterWait;
|
|
8786
|
+
const value = await render();
|
|
8787
|
+
throwIfAborted(signal);
|
|
8788
|
+
const rawBytes = Math.floor(Number(estimateBytes(value)));
|
|
8789
|
+
const bytes = Number.isFinite(rawBytes) && rawBytes > 0 ? rawBytes : 0;
|
|
8790
|
+
if (renderGeneration === generation) setCache(key, value, bytes);
|
|
8791
|
+
return value;
|
|
8792
|
+
} finally {
|
|
8793
|
+
removeAbortObserver === null || removeAbortObserver === void 0 || removeAbortObserver();
|
|
8794
|
+
releaseSlot === null || releaseSlot === void 0 || releaseSlot();
|
|
8795
|
+
if (shouldDedupeInflight && inflight.get(key) === promise) inflight.delete(key);
|
|
8796
|
+
}
|
|
8797
|
+
})();
|
|
8798
|
+
if (shouldDedupeInflight) inflight.set(key, promise);
|
|
8799
|
+
return raceAbort(promise, signal);
|
|
8800
|
+
}
|
|
8801
|
+
return {
|
|
8802
|
+
cached,
|
|
8803
|
+
clear() {
|
|
8804
|
+
generation++;
|
|
8805
|
+
cache.clear();
|
|
8806
|
+
inflight.clear();
|
|
8807
|
+
const pending = waiters.splice(0);
|
|
8808
|
+
for (const waiter of pending) waiter.reject(createAbortError());
|
|
8809
|
+
cacheBytes = 0;
|
|
8810
|
+
},
|
|
8811
|
+
stats() {
|
|
8812
|
+
return {
|
|
8813
|
+
active,
|
|
8814
|
+
waiting: waiters.length,
|
|
8815
|
+
cacheEntries: cache.size,
|
|
8816
|
+
cacheBytes
|
|
8817
|
+
};
|
|
8818
|
+
}
|
|
8819
|
+
};
|
|
8820
|
+
}
|
|
8012
8821
|
|
|
8013
8822
|
//#endregion
|
|
8014
8823
|
//#region src/core/ansi-palette.ts
|
|
@@ -8172,13 +8981,13 @@ const ANSI16_COLOR_NAMES = Object.freeze([
|
|
|
8172
8981
|
"cyanBright",
|
|
8173
8982
|
"whiteBright"
|
|
8174
8983
|
]);
|
|
8175
|
-
const ESC = "\x1B[";
|
|
8176
|
-
const SGR_RESET = `${ESC}0m`;
|
|
8177
|
-
const SGR_BOLD = `${ESC}1m`;
|
|
8178
|
-
const SGR_DIM = `${ESC}2m`;
|
|
8179
|
-
const SGR_ITALIC = `${ESC}3m`;
|
|
8180
|
-
const SGR_UNDERLINE = `${ESC}4m`;
|
|
8181
|
-
const SGR_INVERSE = `${ESC}7m`;
|
|
8984
|
+
const ESC$1 = "\x1B[";
|
|
8985
|
+
const SGR_RESET = `${ESC$1}0m`;
|
|
8986
|
+
const SGR_BOLD = `${ESC$1}1m`;
|
|
8987
|
+
const SGR_DIM = `${ESC$1}2m`;
|
|
8988
|
+
const SGR_ITALIC = `${ESC$1}3m`;
|
|
8989
|
+
const SGR_UNDERLINE = `${ESC$1}4m`;
|
|
8990
|
+
const SGR_INVERSE = `${ESC$1}7m`;
|
|
8182
8991
|
function toAnsi8ColorName(name) {
|
|
8183
8992
|
switch (name) {
|
|
8184
8993
|
case "black":
|
|
@@ -8238,32 +9047,32 @@ const ANSI16_BG_CODE = Object.freeze({
|
|
|
8238
9047
|
function ansi8FgOpen(name) {
|
|
8239
9048
|
const base = toAnsi8ColorName(name);
|
|
8240
9049
|
const idx = ANSI8_COLOR_NAMES.indexOf(base);
|
|
8241
|
-
return `${ESC}${30 + (idx < 0 ? 7 : idx)}m`;
|
|
9050
|
+
return `${ESC$1}${30 + (idx < 0 ? 7 : idx)}m`;
|
|
8242
9051
|
}
|
|
8243
9052
|
function ansi8BgOpen(name) {
|
|
8244
9053
|
const base = toAnsi8ColorName(name);
|
|
8245
9054
|
const idx = ANSI8_COLOR_NAMES.indexOf(base);
|
|
8246
|
-
return `${ESC}${40 + (idx < 0 ? 0 : idx)}m`;
|
|
9055
|
+
return `${ESC$1}${40 + (idx < 0 ? 0 : idx)}m`;
|
|
8247
9056
|
}
|
|
8248
9057
|
function ansi16FgOpen(name) {
|
|
8249
|
-
return `${ESC}${ANSI16_FG_CODE[name]}m`;
|
|
9058
|
+
return `${ESC$1}${ANSI16_FG_CODE[name]}m`;
|
|
8250
9059
|
}
|
|
8251
9060
|
function ansi16BgOpen(name) {
|
|
8252
|
-
return `${ESC}${ANSI16_BG_CODE[name]}m`;
|
|
9061
|
+
return `${ESC$1}${ANSI16_BG_CODE[name]}m`;
|
|
8253
9062
|
}
|
|
8254
9063
|
function ansi256FgOpen(index) {
|
|
8255
9064
|
const n = clampAnsiIndex(index);
|
|
8256
|
-
return `${ESC}38;5;${n}m`;
|
|
9065
|
+
return `${ESC$1}38;5;${n}m`;
|
|
8257
9066
|
}
|
|
8258
9067
|
function ansi256BgOpen(index) {
|
|
8259
9068
|
const n = clampAnsiIndex(index);
|
|
8260
|
-
return `${ESC}48;5;${n}m`;
|
|
9069
|
+
return `${ESC$1}48;5;${n}m`;
|
|
8261
9070
|
}
|
|
8262
9071
|
function truecolorFgOpen(rgb) {
|
|
8263
|
-
return `${ESC}38;2;${clampByte(rgb.r)};${clampByte(rgb.g)};${clampByte(rgb.b)}m`;
|
|
9072
|
+
return `${ESC$1}38;2;${clampByte(rgb.r)};${clampByte(rgb.g)};${clampByte(rgb.b)}m`;
|
|
8264
9073
|
}
|
|
8265
9074
|
function truecolorBgOpen(rgb) {
|
|
8266
|
-
return `${ESC}48;2;${clampByte(rgb.r)};${clampByte(rgb.g)};${clampByte(rgb.b)}m`;
|
|
9075
|
+
return `${ESC$1}48;2;${clampByte(rgb.r)};${clampByte(rgb.g)};${clampByte(rgb.b)}m`;
|
|
8267
9076
|
}
|
|
8268
9077
|
function ansi256ToRgb(index) {
|
|
8269
9078
|
const n = clampAnsiIndex(index);
|
|
@@ -8417,6 +9226,623 @@ function sanitizeTerminalHref(value, options = {}) {
|
|
|
8417
9226
|
return null;
|
|
8418
9227
|
}
|
|
8419
9228
|
|
|
9229
|
+
//#endregion
|
|
9230
|
+
//#region src/renderer/terminal-graphics.ts
|
|
9231
|
+
const TERMINAL_GRAPHICS_PROTOCOL_PRIORITY = [
|
|
9232
|
+
"kitty",
|
|
9233
|
+
"iterm2",
|
|
9234
|
+
"sixel"
|
|
9235
|
+
];
|
|
9236
|
+
const ESC = "\x1B";
|
|
9237
|
+
const BEL = "\x07";
|
|
9238
|
+
const ST = `${ESC}\\`;
|
|
9239
|
+
const ESC_RE = "\\u001B";
|
|
9240
|
+
const BEL_RE = "\\u0007";
|
|
9241
|
+
const CSI_RE = new RegExp(`${ESC_RE}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
9242
|
+
const OSC_RE = new RegExp(`${ESC_RE}\\][\\s\\S]*?(?:${BEL_RE}|${ESC_RE}\\\\)`, "g");
|
|
9243
|
+
const DCS_RE = new RegExp(`${ESC_RE}P[\\s\\S]*?${ESC_RE}\\\\`, "g");
|
|
9244
|
+
const APC_RE = new RegExp(`${ESC_RE}_[\\s\\S]*?${ESC_RE}\\\\`, "g");
|
|
9245
|
+
const C1_CSI_RE = new RegExp("\\u009B[0-?]*[ -/]*[@-~]", "g");
|
|
9246
|
+
const C1_OSC_RE = new RegExp(`\\u009D[\\s\\S]*?(?:${BEL_RE}|\\u009C)`, "g");
|
|
9247
|
+
const C1_DCS_RE = new RegExp("\\u0090[\\s\\S]*?\\u009C", "g");
|
|
9248
|
+
const C1_APC_RE = new RegExp("\\u009F[\\s\\S]*?\\u009C", "g");
|
|
9249
|
+
const MAX_TERMINAL_GRAPHICS_SEQUENCE_CHARS = 16 * 1024 * 1024;
|
|
9250
|
+
const MAX_TERMINAL_GRAPHICS_FALLBACK_CHARS = 16384;
|
|
9251
|
+
const MAX_TERMINAL_GRAPHIC_CELLS = 1e4;
|
|
9252
|
+
const TERMINAL_GRAPHICS_REGISTRY = Symbol.for("@simon_he/vue-tui:v1:terminal-graphics");
|
|
9253
|
+
const terminalGraphicsGlobal = globalThis;
|
|
9254
|
+
const terminalGraphicsRegistry = terminalGraphicsGlobal[TERMINAL_GRAPHICS_REGISTRY] ?? {
|
|
9255
|
+
outputs: new WeakMap(),
|
|
9256
|
+
outputVersions: new WeakMap(),
|
|
9257
|
+
outputListeners: new WeakMap()
|
|
9258
|
+
};
|
|
9259
|
+
terminalGraphicsGlobal[TERMINAL_GRAPHICS_REGISTRY] = terminalGraphicsRegistry;
|
|
9260
|
+
const terminalGraphicsOutputs = terminalGraphicsRegistry.outputs;
|
|
9261
|
+
const terminalGraphicsOutputVersions = terminalGraphicsRegistry.outputVersions;
|
|
9262
|
+
const terminalGraphicsOutputListeners = terminalGraphicsRegistry.outputListeners;
|
|
9263
|
+
function notifyTerminalGraphicsOutputChange(terminal) {
|
|
9264
|
+
const version = (terminalGraphicsOutputVersions.get(terminal) ?? 0) + 1;
|
|
9265
|
+
terminalGraphicsOutputVersions.set(terminal, version);
|
|
9266
|
+
const listeners = terminalGraphicsOutputListeners.get(terminal);
|
|
9267
|
+
if (!listeners) return;
|
|
9268
|
+
for (const listener of listeners) listener();
|
|
9269
|
+
}
|
|
9270
|
+
function registerTerminalGraphicsOutput(terminal, output) {
|
|
9271
|
+
const rootTerminal = getRootTerminal(terminal);
|
|
9272
|
+
terminalGraphicsOutputs.set(rootTerminal, output);
|
|
9273
|
+
notifyTerminalGraphicsOutputChange(rootTerminal);
|
|
9274
|
+
return () => {
|
|
9275
|
+
if (terminalGraphicsOutputs.get(rootTerminal) === output) {
|
|
9276
|
+
terminalGraphicsOutputs.delete(rootTerminal);
|
|
9277
|
+
notifyTerminalGraphicsOutputChange(rootTerminal);
|
|
9278
|
+
}
|
|
9279
|
+
};
|
|
9280
|
+
}
|
|
9281
|
+
function envString(env, key) {
|
|
9282
|
+
const value = env[key];
|
|
9283
|
+
return value == null ? void 0 : String(value);
|
|
9284
|
+
}
|
|
9285
|
+
function truthy(value) {
|
|
9286
|
+
if (value == null) return false;
|
|
9287
|
+
return /^(1|true|yes|on)$/i.test(String(value));
|
|
9288
|
+
}
|
|
9289
|
+
function readStdoutIsTTY() {
|
|
9290
|
+
var _maybeProcess$stdout;
|
|
9291
|
+
const maybeProcess = globalThis.process;
|
|
9292
|
+
return Boolean(maybeProcess === null || maybeProcess === void 0 || (_maybeProcess$stdout = maybeProcess.stdout) === null || _maybeProcess$stdout === void 0 ? void 0 : _maybeProcess$stdout.isTTY);
|
|
9293
|
+
}
|
|
9294
|
+
function readProcessEnv() {
|
|
9295
|
+
const maybeProcess = globalThis.process;
|
|
9296
|
+
return (maybeProcess === null || maybeProcess === void 0 ? void 0 : maybeProcess.env) ?? {};
|
|
9297
|
+
}
|
|
9298
|
+
function normalizeMode(value) {
|
|
9299
|
+
const raw = String(value ?? "auto").trim().toLowerCase();
|
|
9300
|
+
if (raw === "auto" || raw === "off" || raw === "none" || raw === "kitty" || raw === "iterm2" || raw === "sixel" || raw === "unicode") return raw === "off" ? "none" : raw;
|
|
9301
|
+
return "auto";
|
|
9302
|
+
}
|
|
9303
|
+
function isTerminalGraphicsProtocol(value) {
|
|
9304
|
+
return value === "kitty" || value === "iterm2" || value === "sixel";
|
|
9305
|
+
}
|
|
9306
|
+
function uniqueProtocols(protocols) {
|
|
9307
|
+
return [...new Set(protocols)];
|
|
9308
|
+
}
|
|
9309
|
+
function pickBestTerminalGraphicsProtocol(protocols) {
|
|
9310
|
+
const available = new Set(protocols);
|
|
9311
|
+
for (const protocol of TERMINAL_GRAPHICS_PROTOCOL_PRIORITY) if (available.has(protocol)) return protocol;
|
|
9312
|
+
return null;
|
|
9313
|
+
}
|
|
9314
|
+
function detectCandidates(env) {
|
|
9315
|
+
const candidates = [];
|
|
9316
|
+
const term = String(envString(env, "TERM") ?? "").toLowerCase();
|
|
9317
|
+
const termProgram = String(envString(env, "TERM_PROGRAM") ?? "").toLowerCase();
|
|
9318
|
+
const termProgramVersion = String(envString(env, "TERM_PROGRAM_VERSION") ?? "").toLowerCase();
|
|
9319
|
+
if (envString(env, "KITTY_WINDOW_ID") || envString(env, "GHOSTTY_RESOURCES_DIR") || /(?:^|-)kitty(?:-|$)/i.test(term) || term.includes("ghostty") || termProgram.includes("ghostty")) candidates.push("kitty");
|
|
9320
|
+
if (termProgram.includes("iterm") || termProgram.includes("wezterm") || envString(env, "WEZTERM_PANE") || envString(env, "WEZTERM_EXECUTABLE")) candidates.push("iterm2");
|
|
9321
|
+
if (truthy(envString(env, "VUE_TUI_SIXEL")) || truthy(envString(env, "VUE_TUI_GRAPHICS_SIXEL")) || String(envString(env, "TERMINAL_GRAPHICS") ?? "").toLowerCase().includes("sixel") || /\bsixel\b/i.test(`${term} ${termProgram} ${termProgramVersion}`)) candidates.push("sixel");
|
|
9322
|
+
return uniqueProtocols(candidates);
|
|
9323
|
+
}
|
|
9324
|
+
function capabilitiesFor(protocol, input) {
|
|
9325
|
+
const supported = protocol === "kitty" || protocol === "iterm2" || protocol === "sixel";
|
|
9326
|
+
const candidates = uniqueProtocols([...input.candidates ?? (supported ? [protocol] : [])]);
|
|
9327
|
+
return {
|
|
9328
|
+
supported,
|
|
9329
|
+
kitty: protocol === "kitty" || candidates.includes("kitty"),
|
|
9330
|
+
iterm2: protocol === "iterm2" || candidates.includes("iterm2"),
|
|
9331
|
+
sixel: protocol === "sixel" || candidates.includes("sixel"),
|
|
9332
|
+
preferredProtocol: supported ? protocol : null,
|
|
9333
|
+
protocol,
|
|
9334
|
+
candidates,
|
|
9335
|
+
stdoutIsTTY: input.stdoutIsTTY,
|
|
9336
|
+
insideTmux: input.insideTmux,
|
|
9337
|
+
insideScreen: input.insideScreen,
|
|
9338
|
+
insideZellij: input.insideZellij,
|
|
9339
|
+
multiplexer: input.multiplexer,
|
|
9340
|
+
passthrough: input.passthrough,
|
|
9341
|
+
forced: input.forced,
|
|
9342
|
+
reason: input.reason
|
|
9343
|
+
};
|
|
9344
|
+
}
|
|
9345
|
+
function detectTerminalGraphicsCapabilities(options = {}) {
|
|
9346
|
+
const env = options.env ?? readProcessEnv();
|
|
9347
|
+
const stdoutIsTTY = options.stdoutIsTTY ?? options.isTTY ?? readStdoutIsTTY();
|
|
9348
|
+
const term = String(envString(env, "TERM") ?? "").toLowerCase();
|
|
9349
|
+
const insideTmux = Boolean(envString(env, "TMUX")) || term.includes("tmux");
|
|
9350
|
+
const insideScreen = Boolean(envString(env, "STY")) || term.startsWith("screen");
|
|
9351
|
+
const insideZellij = Boolean(envString(env, "ZELLIJ") || envString(env, "ZELLIJ_SESSION_NAME")) || term.includes("zellij");
|
|
9352
|
+
const multiplexer = insideTmux ? "tmux" : insideScreen ? "screen" : insideZellij ? "zellij" : null;
|
|
9353
|
+
const passthroughRequested = options.passthrough ?? (truthy(envString(env, "VUE_TUI_TERMINAL_GRAPHICS_PASSTHROUGH")) || truthy(envString(env, "VUE_TUI_GRAPHICS_TMUX_PASSTHROUGH")));
|
|
9354
|
+
const passthroughSupported = !multiplexer || multiplexer === "tmux";
|
|
9355
|
+
const passthrough = passthroughRequested && passthroughSupported;
|
|
9356
|
+
const protocolOptionProvided = options.protocol != null;
|
|
9357
|
+
const mode = normalizeMode(options.protocol ?? envString(env, "VUE_TUI_TERMINAL_GRAPHICS") ?? envString(env, "VUE_TUI_GRAPHICS_PROTOCOL"));
|
|
9358
|
+
const forceFromOption = options.force === true;
|
|
9359
|
+
const force = options.force ?? truthy(envString(env, "VUE_TUI_GRAPHICS_FORCE"));
|
|
9360
|
+
const base = {
|
|
9361
|
+
stdoutIsTTY,
|
|
9362
|
+
insideTmux,
|
|
9363
|
+
insideScreen,
|
|
9364
|
+
insideZellij,
|
|
9365
|
+
multiplexer,
|
|
9366
|
+
passthrough,
|
|
9367
|
+
forced: force
|
|
9368
|
+
};
|
|
9369
|
+
if (mode === "none") return capabilitiesFor("none", {
|
|
9370
|
+
...base,
|
|
9371
|
+
reason: protocolOptionProvided ? "disabled-by-option" : "disabled-by-env"
|
|
9372
|
+
});
|
|
9373
|
+
if (!stdoutIsTTY && !force) return capabilitiesFor("unicode", {
|
|
9374
|
+
...base,
|
|
9375
|
+
reason: "stdout-is-not-tty"
|
|
9376
|
+
});
|
|
9377
|
+
if (truthy(envString(env, "CI")) && !force) return capabilitiesFor("unicode", {
|
|
9378
|
+
...base,
|
|
9379
|
+
reason: "ci"
|
|
9380
|
+
});
|
|
9381
|
+
if (multiplexer && passthroughRequested && !passthroughSupported && !force) return capabilitiesFor("unicode", {
|
|
9382
|
+
...base,
|
|
9383
|
+
reason: `${multiplexer}-passthrough-not-implemented`
|
|
9384
|
+
});
|
|
9385
|
+
if (multiplexer && !passthrough && !force) return capabilitiesFor("unicode", {
|
|
9386
|
+
...base,
|
|
9387
|
+
reason: `${multiplexer}-without-passthrough`
|
|
9388
|
+
});
|
|
9389
|
+
if (mode === "kitty" || mode === "iterm2" || mode === "sixel") return capabilitiesFor(mode, {
|
|
9390
|
+
...base,
|
|
9391
|
+
candidates: [mode],
|
|
9392
|
+
reason: force ? forceFromOption ? "forced-by-option" : "forced-by-env" : protocolOptionProvided ? "selected-by-option" : "selected-by-env"
|
|
9393
|
+
});
|
|
9394
|
+
if (mode === "unicode") return capabilitiesFor("unicode", {
|
|
9395
|
+
...base,
|
|
9396
|
+
reason: protocolOptionProvided ? "unicode-forced-by-option" : "unicode-forced-by-env"
|
|
9397
|
+
});
|
|
9398
|
+
const candidates = detectCandidates(env);
|
|
9399
|
+
const preferredProtocol = pickBestTerminalGraphicsProtocol(candidates);
|
|
9400
|
+
const protocol = preferredProtocol ?? "unicode";
|
|
9401
|
+
return capabilitiesFor(protocol, {
|
|
9402
|
+
...base,
|
|
9403
|
+
candidates,
|
|
9404
|
+
reason: protocol === "unicode" ? "no-supported-graphics-protocol-detected" : "auto-detected"
|
|
9405
|
+
});
|
|
9406
|
+
}
|
|
9407
|
+
function hashTerminalGraphicsString(input) {
|
|
9408
|
+
let hash = 2166136261;
|
|
9409
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
9410
|
+
hash ^= input.charCodeAt(index);
|
|
9411
|
+
hash = Math.imul(hash, 16777619);
|
|
9412
|
+
}
|
|
9413
|
+
return (hash >>> 0).toString(36);
|
|
9414
|
+
}
|
|
9415
|
+
function stableId(input) {
|
|
9416
|
+
return `tg_${hashTerminalGraphicsString(input)}`;
|
|
9417
|
+
}
|
|
9418
|
+
function positiveGraphicInt(value, max) {
|
|
9419
|
+
const n = Math.trunc(Number(value));
|
|
9420
|
+
if (!Number.isFinite(n) || n <= 0) return null;
|
|
9421
|
+
return Math.min(max, n);
|
|
9422
|
+
}
|
|
9423
|
+
function normalizeTerminalGraphicSize(width, height) {
|
|
9424
|
+
const w = positiveGraphicInt(width, MAX_TERMINAL_GRAPHIC_CELLS);
|
|
9425
|
+
const h$1 = positiveGraphicInt(height, MAX_TERMINAL_GRAPHIC_CELLS);
|
|
9426
|
+
if (w == null || h$1 == null) return null;
|
|
9427
|
+
if (w * h$1 > MAX_TERMINAL_GRAPHIC_CELLS) return null;
|
|
9428
|
+
return {
|
|
9429
|
+
width: w,
|
|
9430
|
+
height: h$1
|
|
9431
|
+
};
|
|
9432
|
+
}
|
|
9433
|
+
function withoutNestedEscapes(body) {
|
|
9434
|
+
return !body.includes(ESC) && !body.includes(BEL);
|
|
9435
|
+
}
|
|
9436
|
+
function isBase64ish(value) {
|
|
9437
|
+
return /^[A-Za-z0-9+/=]*$/.test(value);
|
|
9438
|
+
}
|
|
9439
|
+
function parseKittyControls(raw) {
|
|
9440
|
+
const out = new Map();
|
|
9441
|
+
if (!/^[A-Za-z0-9_,=+.\-:]*$/.test(raw)) return null;
|
|
9442
|
+
for (const part of raw.split(",")) {
|
|
9443
|
+
if (!part) continue;
|
|
9444
|
+
const eq = part.indexOf("=");
|
|
9445
|
+
if (eq <= 0) return null;
|
|
9446
|
+
const key = part.slice(0, eq);
|
|
9447
|
+
const value = part.slice(eq + 1);
|
|
9448
|
+
if (!/^[A-Za-z]$/.test(key)) return null;
|
|
9449
|
+
if (!/^[A-Za-z0-9+.\-:]*$/.test(value)) return null;
|
|
9450
|
+
out.set(key, value);
|
|
9451
|
+
}
|
|
9452
|
+
return out;
|
|
9453
|
+
}
|
|
9454
|
+
function parseKittyPackets(sequence) {
|
|
9455
|
+
const packets = [];
|
|
9456
|
+
let index = 0;
|
|
9457
|
+
while (index < sequence.length) {
|
|
9458
|
+
if (!sequence.startsWith(`${ESC}_G`, index)) return null;
|
|
9459
|
+
const end = sequence.indexOf(ST, index + 3);
|
|
9460
|
+
if (end < 0) return null;
|
|
9461
|
+
const body = sequence.slice(index + 3, end);
|
|
9462
|
+
if (!withoutNestedEscapes(body)) return null;
|
|
9463
|
+
const semicolon = body.indexOf(";");
|
|
9464
|
+
const rawControls = semicolon >= 0 ? body.slice(0, semicolon) : body;
|
|
9465
|
+
const payload = semicolon >= 0 ? body.slice(semicolon + 1) : "";
|
|
9466
|
+
const controls = parseKittyControls(rawControls);
|
|
9467
|
+
if (!controls) return null;
|
|
9468
|
+
if (payload && !isBase64ish(payload)) return null;
|
|
9469
|
+
packets.push({
|
|
9470
|
+
controls,
|
|
9471
|
+
payload
|
|
9472
|
+
});
|
|
9473
|
+
index = end + ST.length;
|
|
9474
|
+
}
|
|
9475
|
+
return packets.length ? packets : null;
|
|
9476
|
+
}
|
|
9477
|
+
const KITTY_DRAW_FIRST_CONTROL_KEYS = new Set([
|
|
9478
|
+
"a",
|
|
9479
|
+
"f",
|
|
9480
|
+
"q",
|
|
9481
|
+
"C",
|
|
9482
|
+
"i",
|
|
9483
|
+
"I",
|
|
9484
|
+
"p",
|
|
9485
|
+
"c",
|
|
9486
|
+
"r",
|
|
9487
|
+
"x",
|
|
9488
|
+
"y",
|
|
9489
|
+
"w",
|
|
9490
|
+
"h",
|
|
9491
|
+
"z",
|
|
9492
|
+
"m",
|
|
9493
|
+
"t"
|
|
9494
|
+
]);
|
|
9495
|
+
const KITTY_DRAW_CONTINUATION_CONTROL_KEYS = new Set([
|
|
9496
|
+
"a",
|
|
9497
|
+
"q",
|
|
9498
|
+
"m"
|
|
9499
|
+
]);
|
|
9500
|
+
const KITTY_CLEAR_CONTROL_KEYS = new Set([
|
|
9501
|
+
"a",
|
|
9502
|
+
"d",
|
|
9503
|
+
"i",
|
|
9504
|
+
"I",
|
|
9505
|
+
"p",
|
|
9506
|
+
"q"
|
|
9507
|
+
]);
|
|
9508
|
+
function kittyControlsUseOnly(controls, allowed) {
|
|
9509
|
+
for (const key of controls.keys()) if (!allowed.has(key)) return false;
|
|
9510
|
+
return true;
|
|
9511
|
+
}
|
|
9512
|
+
const KITTY_UINT32_MAX = 4294967295;
|
|
9513
|
+
const KITTY_INT32_MIN = -2147483648;
|
|
9514
|
+
const KITTY_INT32_MAX = 2147483647;
|
|
9515
|
+
function kittyControlIsUint32(controls, key, min = 0) {
|
|
9516
|
+
const value = controls.get(key);
|
|
9517
|
+
if (value == null) return true;
|
|
9518
|
+
if (!/^\d+$/.test(value)) return false;
|
|
9519
|
+
const n = Number(value);
|
|
9520
|
+
return Number.isSafeInteger(n) && n >= min && n <= KITTY_UINT32_MAX;
|
|
9521
|
+
}
|
|
9522
|
+
function kittyControlIsInt32(controls, key) {
|
|
9523
|
+
const value = controls.get(key);
|
|
9524
|
+
if (value == null) return true;
|
|
9525
|
+
if (!/^-?\d+$/.test(value)) return false;
|
|
9526
|
+
const n = Number(value);
|
|
9527
|
+
return Number.isSafeInteger(n) && n >= KITTY_INT32_MIN && n <= KITTY_INT32_MAX;
|
|
9528
|
+
}
|
|
9529
|
+
function kittyControlPositiveInt(controls, key, fallback) {
|
|
9530
|
+
const value = controls.get(key);
|
|
9531
|
+
if (value == null) return fallback;
|
|
9532
|
+
if (!/^\d+$/.test(value)) return null;
|
|
9533
|
+
const n = Number(value);
|
|
9534
|
+
return Number.isSafeInteger(n) && n >= 1 ? n : null;
|
|
9535
|
+
}
|
|
9536
|
+
function kittyControlIsTerminalGraphicCellsBounded(controls) {
|
|
9537
|
+
const columns = kittyControlPositiveInt(controls, "c", 1);
|
|
9538
|
+
const rows = kittyControlPositiveInt(controls, "r", 1);
|
|
9539
|
+
return columns != null && rows != null && columns * rows <= MAX_TERMINAL_GRAPHIC_CELLS;
|
|
9540
|
+
}
|
|
9541
|
+
function validateKittySharedSafeControls(controls) {
|
|
9542
|
+
const q = controls.get("q");
|
|
9543
|
+
if (q != null && !/^[0-2]$/.test(q)) return false;
|
|
9544
|
+
const cursorMove = controls.get("C");
|
|
9545
|
+
if (cursorMove != null && !/^[01]$/.test(cursorMove)) return false;
|
|
9546
|
+
for (const key of [
|
|
9547
|
+
"i",
|
|
9548
|
+
"I",
|
|
9549
|
+
"p"
|
|
9550
|
+
]) if (!kittyControlIsUint32(controls, key)) return false;
|
|
9551
|
+
for (const key of ["c", "r"]) if (!kittyControlIsUint32(controls, key, 1)) return false;
|
|
9552
|
+
if (!kittyControlIsTerminalGraphicCellsBounded(controls)) return false;
|
|
9553
|
+
for (const key of ["x", "y"]) if (!kittyControlIsUint32(controls, key)) return false;
|
|
9554
|
+
for (const key of ["w", "h"]) if (!kittyControlIsUint32(controls, key, 1)) return false;
|
|
9555
|
+
if (!kittyControlIsInt32(controls, "z")) return false;
|
|
9556
|
+
const transmissionMedium = controls.get("t");
|
|
9557
|
+
if (transmissionMedium != null && transmissionMedium !== "d") return false;
|
|
9558
|
+
return true;
|
|
9559
|
+
}
|
|
9560
|
+
function validateKittySequence(sequence, op = "draw") {
|
|
9561
|
+
const packets = parseKittyPackets(sequence);
|
|
9562
|
+
if (!packets) return false;
|
|
9563
|
+
if (op === "clear") {
|
|
9564
|
+
if (packets.length !== 1) return false;
|
|
9565
|
+
const packet = packets[0];
|
|
9566
|
+
if (!kittyControlsUseOnly(packet.controls, KITTY_CLEAR_CONTROL_KEYS)) return false;
|
|
9567
|
+
if (!validateKittySharedSafeControls(packet.controls)) return false;
|
|
9568
|
+
if (packet.payload) return false;
|
|
9569
|
+
if (packet.controls.get("a") !== "d") return false;
|
|
9570
|
+
const d = packet.controls.get("d");
|
|
9571
|
+
return d == null || /^[aAcCiI]$/.test(d);
|
|
9572
|
+
}
|
|
9573
|
+
const first = packets[0];
|
|
9574
|
+
if (!kittyControlsUseOnly(first.controls, KITTY_DRAW_FIRST_CONTROL_KEYS)) return false;
|
|
9575
|
+
if (!validateKittySharedSafeControls(first.controls)) return false;
|
|
9576
|
+
if (first.controls.get("a") === "p") {
|
|
9577
|
+
if (packets.length !== 1) return false;
|
|
9578
|
+
if (first.payload) return false;
|
|
9579
|
+
if (!first.controls.has("i") && !first.controls.has("I")) return false;
|
|
9580
|
+
return true;
|
|
9581
|
+
}
|
|
9582
|
+
if (first.controls.get("a") !== "T") return false;
|
|
9583
|
+
if (!first.payload) return false;
|
|
9584
|
+
const f = first.controls.get("f");
|
|
9585
|
+
if (f != null && f !== "24" && f !== "32" && f !== "100") return false;
|
|
9586
|
+
const firstMore = first.controls.get("m");
|
|
9587
|
+
if (firstMore != null && firstMore !== "0" && firstMore !== "1") return false;
|
|
9588
|
+
if (packets.length > 1 && firstMore !== "1") return false;
|
|
9589
|
+
for (let i = 1; i < packets.length; i++) {
|
|
9590
|
+
const packet = packets[i];
|
|
9591
|
+
if (!kittyControlsUseOnly(packet.controls, KITTY_DRAW_CONTINUATION_CONTROL_KEYS)) return false;
|
|
9592
|
+
if (!validateKittySharedSafeControls(packet.controls)) return false;
|
|
9593
|
+
const action = packet.controls.get("a");
|
|
9594
|
+
if (action != null && action !== "T") return false;
|
|
9595
|
+
const m = packet.controls.get("m");
|
|
9596
|
+
if (m !== "0" && m !== "1") return false;
|
|
9597
|
+
if (!packet.payload && !(i === packets.length - 1 && m === "0")) return false;
|
|
9598
|
+
}
|
|
9599
|
+
if (packets.length > 1 && packets[packets.length - 1].controls.get("m") === "1") return false;
|
|
9600
|
+
return true;
|
|
9601
|
+
}
|
|
9602
|
+
function validateIterm2Dimension(value) {
|
|
9603
|
+
return /^auto$/i.test(value) || /^(?:[1-9]\d{0,4})(?:px|%)?$/.test(value);
|
|
9604
|
+
}
|
|
9605
|
+
function validateIterm2Params(params) {
|
|
9606
|
+
const seen = new Set();
|
|
9607
|
+
let inline = false;
|
|
9608
|
+
for (const part of params.split(";").filter(Boolean)) {
|
|
9609
|
+
const eq = part.indexOf("=");
|
|
9610
|
+
if (eq <= 0) return false;
|
|
9611
|
+
const key = part.slice(0, eq);
|
|
9612
|
+
const value = part.slice(eq + 1);
|
|
9613
|
+
if (seen.has(key)) return false;
|
|
9614
|
+
seen.add(key);
|
|
9615
|
+
switch (key) {
|
|
9616
|
+
case "inline":
|
|
9617
|
+
if (value !== "1") return false;
|
|
9618
|
+
inline = true;
|
|
9619
|
+
break;
|
|
9620
|
+
case "width":
|
|
9621
|
+
case "height":
|
|
9622
|
+
if (!validateIterm2Dimension(value)) return false;
|
|
9623
|
+
break;
|
|
9624
|
+
case "preserveAspectRatio":
|
|
9625
|
+
case "doNotMoveCursor":
|
|
9626
|
+
if (!/^[01]$/.test(value)) return false;
|
|
9627
|
+
break;
|
|
9628
|
+
default: return false;
|
|
9629
|
+
}
|
|
9630
|
+
}
|
|
9631
|
+
return inline;
|
|
9632
|
+
}
|
|
9633
|
+
function validateIterm2Sequence(sequence, op = "draw") {
|
|
9634
|
+
if (op === "clear") return false;
|
|
9635
|
+
let index = 0;
|
|
9636
|
+
while (index < sequence.length) {
|
|
9637
|
+
const prefix = `${ESC}]1337;File=`;
|
|
9638
|
+
if (!sequence.startsWith(prefix, index)) return false;
|
|
9639
|
+
const belEnd = sequence.indexOf(BEL, index + prefix.length);
|
|
9640
|
+
const stEnd = sequence.indexOf(ST, index + prefix.length);
|
|
9641
|
+
const end = belEnd >= 0 && stEnd >= 0 ? Math.min(belEnd, stEnd) : belEnd >= 0 ? belEnd : stEnd;
|
|
9642
|
+
if (end < 0) return false;
|
|
9643
|
+
const body = sequence.slice(index + `${ESC}]1337;`.length, end);
|
|
9644
|
+
if (!body.startsWith("File=")) return false;
|
|
9645
|
+
if (!withoutNestedEscapes(body)) return false;
|
|
9646
|
+
const colon = body.indexOf(":");
|
|
9647
|
+
if (colon < 0) return false;
|
|
9648
|
+
const params = body.slice(5, colon);
|
|
9649
|
+
const payload = body.slice(colon + 1);
|
|
9650
|
+
if (!/^[A-Za-z0-9_=;,.%+\-:]*$/.test(params)) return false;
|
|
9651
|
+
if (!payload || !isBase64ish(payload)) return false;
|
|
9652
|
+
if (!validateIterm2Params(params)) return false;
|
|
9653
|
+
index = end + (end === stEnd ? ST.length : BEL.length);
|
|
9654
|
+
}
|
|
9655
|
+
return sequence.length > 0;
|
|
9656
|
+
}
|
|
9657
|
+
function validateSixelSequence(sequence, op = "draw") {
|
|
9658
|
+
if (op === "clear") return false;
|
|
9659
|
+
let index = 0;
|
|
9660
|
+
while (index < sequence.length) {
|
|
9661
|
+
if (!sequence.startsWith(`${ESC}P`, index)) return false;
|
|
9662
|
+
const end = sequence.indexOf(ST, index + 2);
|
|
9663
|
+
if (end < 0) return false;
|
|
9664
|
+
const body = sequence.slice(index + 2, end);
|
|
9665
|
+
if (!withoutNestedEscapes(body)) return false;
|
|
9666
|
+
for (let i = 0; i < body.length; i++) {
|
|
9667
|
+
const code = body.charCodeAt(i);
|
|
9668
|
+
if (code < 32 || code > 126) return false;
|
|
9669
|
+
}
|
|
9670
|
+
const q = body.indexOf("q");
|
|
9671
|
+
if (q < 0 || q > 32) return false;
|
|
9672
|
+
const introducer = body.slice(0, q);
|
|
9673
|
+
if (!/^[0-9;?]*$/.test(introducer)) return false;
|
|
9674
|
+
const data = body.slice(q + 1);
|
|
9675
|
+
if (!data.length) return false;
|
|
9676
|
+
index = end + ST.length;
|
|
9677
|
+
}
|
|
9678
|
+
return sequence.length > 0;
|
|
9679
|
+
}
|
|
9680
|
+
function stripTerminalControlChars(value) {
|
|
9681
|
+
let out = "";
|
|
9682
|
+
for (let index = 0; index < value.length; index++) {
|
|
9683
|
+
const code = value.charCodeAt(index);
|
|
9684
|
+
if (code <= 8 || code === 11 || code === 12 || code >= 14 && code <= 31 || code === 127 || code >= 128 && code <= 159) continue;
|
|
9685
|
+
out += value[index];
|
|
9686
|
+
}
|
|
9687
|
+
return out;
|
|
9688
|
+
}
|
|
9689
|
+
function sanitizeTerminalFallbackText(text) {
|
|
9690
|
+
return stripTerminalControlChars(String(text ?? "").replace(OSC_RE, "").replace(CSI_RE, "").replace(DCS_RE, "").replace(APC_RE, "").replace(C1_OSC_RE, "").replace(C1_CSI_RE, "").replace(C1_DCS_RE, "").replace(C1_APC_RE, "")).slice(0, MAX_TERMINAL_GRAPHICS_FALLBACK_CHARS);
|
|
9691
|
+
}
|
|
9692
|
+
function validateTerminalGraphicFrame(frame) {
|
|
9693
|
+
const startedAt = nowTerminalGraphicTraceTime();
|
|
9694
|
+
const protocol = isTerminalGraphicsProtocol(frame.protocol) ? frame.protocol : void 0;
|
|
9695
|
+
const recordValidation = () => {
|
|
9696
|
+
recordTerminalGraphicTrace({
|
|
9697
|
+
type: "validate-end",
|
|
9698
|
+
id: frame.id ?? "",
|
|
9699
|
+
protocol,
|
|
9700
|
+
durationMs: nowTerminalGraphicTraceTime() - startedAt,
|
|
9701
|
+
bytes: typeof frame.sequence === "string" ? frame.sequence.length : void 0
|
|
9702
|
+
});
|
|
9703
|
+
};
|
|
9704
|
+
if (!protocol) {
|
|
9705
|
+
recordValidation();
|
|
9706
|
+
return null;
|
|
9707
|
+
}
|
|
9708
|
+
const sequence = String(frame.sequence ?? "");
|
|
9709
|
+
if (sequence.length <= 0 || sequence.length > MAX_TERMINAL_GRAPHICS_SEQUENCE_CHARS) {
|
|
9710
|
+
recordValidation();
|
|
9711
|
+
return null;
|
|
9712
|
+
}
|
|
9713
|
+
const size = normalizeTerminalGraphicSize(frame.width, frame.height);
|
|
9714
|
+
if (!size) {
|
|
9715
|
+
recordValidation();
|
|
9716
|
+
return null;
|
|
9717
|
+
}
|
|
9718
|
+
const ok = protocol === "kitty" ? validateKittySequence(sequence, "draw") : protocol === "iterm2" ? validateIterm2Sequence(sequence, "draw") : validateSixelSequence(sequence, "draw");
|
|
9719
|
+
if (!ok) {
|
|
9720
|
+
recordValidation();
|
|
9721
|
+
return null;
|
|
9722
|
+
}
|
|
9723
|
+
recordValidation();
|
|
9724
|
+
return {
|
|
9725
|
+
...frame,
|
|
9726
|
+
protocol,
|
|
9727
|
+
id: frame.id || stableId(`${protocol}:${sequence.slice(0, 4096)}`),
|
|
9728
|
+
sequence,
|
|
9729
|
+
fallbackText: sanitizeTerminalFallbackText(frame.fallbackText),
|
|
9730
|
+
width: size.width,
|
|
9731
|
+
height: size.height
|
|
9732
|
+
};
|
|
9733
|
+
}
|
|
9734
|
+
function isSafeTerminalGraphicsSequence(sequence, protocol, op = "draw") {
|
|
9735
|
+
if (!isTerminalGraphicsProtocol(protocol)) return false;
|
|
9736
|
+
if (!sequence || sequence.length > MAX_TERMINAL_GRAPHICS_SEQUENCE_CHARS) return false;
|
|
9737
|
+
return protocol === "kitty" ? validateKittySequence(sequence, op) : protocol === "iterm2" ? validateIterm2Sequence(sequence, op) : validateSixelSequence(sequence, op);
|
|
9738
|
+
}
|
|
9739
|
+
function validateTerminalGraphicsPayload(payload, capabilities) {
|
|
9740
|
+
if (!payload.id.trim()) return false;
|
|
9741
|
+
if (!Number.isFinite(payload.x) || !Number.isFinite(payload.y)) return false;
|
|
9742
|
+
if (!normalizeTerminalGraphicSize(payload.w ?? 1, payload.h ?? 1)) return false;
|
|
9743
|
+
if (!capabilities.supported) return false;
|
|
9744
|
+
if (!isTerminalGraphicsProtocol(payload.protocol)) return false;
|
|
9745
|
+
if (payload.protocol !== capabilities.preferredProtocol) return false;
|
|
9746
|
+
return isSafeTerminalGraphicsSequence(payload.sequence, payload.protocol, payload.op ?? "draw");
|
|
9747
|
+
}
|
|
9748
|
+
function uint32Control(key, value, min = 0) {
|
|
9749
|
+
if (value == null) return "";
|
|
9750
|
+
const n = Math.floor(value);
|
|
9751
|
+
return Number.isSafeInteger(n) && n >= min && n <= KITTY_UINT32_MAX ? `${key}=${n}` : "";
|
|
9752
|
+
}
|
|
9753
|
+
function int32Control(key, value) {
|
|
9754
|
+
if (value == null) return "";
|
|
9755
|
+
const n = Math.floor(value);
|
|
9756
|
+
return Number.isSafeInteger(n) && n >= KITTY_INT32_MIN && n <= KITTY_INT32_MAX ? `${key}=${n}` : "";
|
|
9757
|
+
}
|
|
9758
|
+
function sanitizeBase64(value) {
|
|
9759
|
+
const data = String(value ?? "").replace(/\s+/g, "");
|
|
9760
|
+
return isBase64ish(data) ? data : "";
|
|
9761
|
+
}
|
|
9762
|
+
function kittyGraphicCellControls(columns, rows) {
|
|
9763
|
+
if (columns == null && rows == null) return [];
|
|
9764
|
+
const size = normalizeTerminalGraphicSize(columns ?? 1, rows ?? 1);
|
|
9765
|
+
if (!size) return [];
|
|
9766
|
+
return [columns == null ? "" : `c=${size.width}`, rows == null ? "" : `r=${size.height}`];
|
|
9767
|
+
}
|
|
9768
|
+
function kittyGraphicSourceControls(sourceX, sourceY, sourceWidth, sourceHeight) {
|
|
9769
|
+
return [
|
|
9770
|
+
uint32Control("x", sourceX),
|
|
9771
|
+
uint32Control("y", sourceY),
|
|
9772
|
+
uint32Control("w", sourceWidth, 1),
|
|
9773
|
+
uint32Control("h", sourceHeight, 1)
|
|
9774
|
+
];
|
|
9775
|
+
}
|
|
9776
|
+
function chunkBase64(value, chunkSize) {
|
|
9777
|
+
const normalizedSize = Math.max(4, Math.floor(chunkSize / 4) * 4);
|
|
9778
|
+
const chunks = [];
|
|
9779
|
+
for (let index = 0; index < value.length; index += normalizedSize) chunks.push(value.slice(index, index + normalizedSize));
|
|
9780
|
+
return chunks.length ? chunks : [""];
|
|
9781
|
+
}
|
|
9782
|
+
function createKittyGraphicsSequence(base64Png, options = {}) {
|
|
9783
|
+
const data = sanitizeBase64(base64Png);
|
|
9784
|
+
if (!data) return "";
|
|
9785
|
+
const chunks = chunkBase64(data, options.chunkSize ?? 4096);
|
|
9786
|
+
const baseControls = [
|
|
9787
|
+
"a=T",
|
|
9788
|
+
"f=100",
|
|
9789
|
+
options.quiet === false ? "" : "q=2",
|
|
9790
|
+
options.noCursorMove === false ? "" : "C=1",
|
|
9791
|
+
uint32Control("i", options.imageId),
|
|
9792
|
+
uint32Control("I", options.imageNumber),
|
|
9793
|
+
uint32Control("p", options.placementId),
|
|
9794
|
+
...kittyGraphicCellControls(options.columns, options.rows),
|
|
9795
|
+
...kittyGraphicSourceControls(options.sourceX, options.sourceY, options.sourceWidth, options.sourceHeight),
|
|
9796
|
+
int32Control("z", options.zIndex)
|
|
9797
|
+
].filter(Boolean);
|
|
9798
|
+
return chunks.map((chunk, index) => {
|
|
9799
|
+
const last = index === chunks.length - 1;
|
|
9800
|
+
const controls = index === 0 ? [...baseControls, chunks.length > 1 ? `m=${last ? 0 : 1}` : ""] : [options.quiet === false ? "" : "q=2", `m=${last ? 0 : 1}`].filter(Boolean);
|
|
9801
|
+
return `${ESC}_G${controls.filter(Boolean).join(",")};${chunk}${ST}`;
|
|
9802
|
+
}).join("");
|
|
9803
|
+
}
|
|
9804
|
+
function createKittyDeleteGraphicsSequence(options = {}) {
|
|
9805
|
+
const controls = ["a=d"];
|
|
9806
|
+
if (options.allVisible) controls.push(`d=${options.freeImageData ? "A" : "a"}`);
|
|
9807
|
+
else if (options.imageId != null) {
|
|
9808
|
+
const imageId = uint32Control("i", options.imageId);
|
|
9809
|
+
const placementId = uint32Control("p", options.placementId);
|
|
9810
|
+
if (!imageId || options.placementId != null && !placementId) return "";
|
|
9811
|
+
controls.push(`d=${options.freeImageData ? "I" : "i"}`);
|
|
9812
|
+
controls.push(imageId);
|
|
9813
|
+
controls.push(placementId);
|
|
9814
|
+
} else if (options.currentCell) controls.push(`d=${options.freeImageData ? "C" : "c"}`);
|
|
9815
|
+
else return "";
|
|
9816
|
+
if (options.quiet !== false) controls.push("q=2");
|
|
9817
|
+
return `${ESC}_G${controls.filter(Boolean).join(",")}${ST}`;
|
|
9818
|
+
}
|
|
9819
|
+
function createIterm2InlineImageSequence(base64Data, options = {}) {
|
|
9820
|
+
const data = sanitizeBase64(base64Data);
|
|
9821
|
+
if (!data) return "";
|
|
9822
|
+
const params = [
|
|
9823
|
+
"inline=1",
|
|
9824
|
+
options.width != null ? `width=${formatItermDimension(options.width)}` : "",
|
|
9825
|
+
options.height != null ? `height=${formatItermDimension(options.height)}` : "",
|
|
9826
|
+
`preserveAspectRatio=${options.preserveAspectRatio === false ? 0 : 1}`,
|
|
9827
|
+
options.doNotMoveCursor === false ? "" : "doNotMoveCursor=1"
|
|
9828
|
+
].filter(Boolean);
|
|
9829
|
+
return `${ESC}]1337;File=${params.join(";")}:${data}${BEL}`;
|
|
9830
|
+
}
|
|
9831
|
+
function formatItermDimension(value) {
|
|
9832
|
+
if (typeof value === "number") {
|
|
9833
|
+
const n = Math.floor(value);
|
|
9834
|
+
if (!Number.isFinite(n)) return "auto";
|
|
9835
|
+
return String(Math.min(99999, Math.max(1, n)));
|
|
9836
|
+
}
|
|
9837
|
+
const raw = String(value ?? "").trim();
|
|
9838
|
+
return validateIterm2Dimension(raw) ? raw : "auto";
|
|
9839
|
+
}
|
|
9840
|
+
function wrapTerminalGraphicsForMultiplexer(sequence, capabilities) {
|
|
9841
|
+
if (!capabilities.passthrough) return sequence;
|
|
9842
|
+
if (capabilities.multiplexer === "tmux") return `${ESC}Ptmux;${sequence.split(ESC).join(`${ESC}${ESC}`)}${ST}`;
|
|
9843
|
+
return sequence;
|
|
9844
|
+
}
|
|
9845
|
+
|
|
8420
9846
|
//#endregion
|
|
8421
9847
|
//#region src/renderer/cli/stdout-renderer.ts
|
|
8422
9848
|
let debugLog = null;
|
|
@@ -8431,7 +9857,27 @@ const SYNC_START = "\x1B[?2026h";
|
|
|
8431
9857
|
const SYNC_END = "\x1B[?2026l";
|
|
8432
9858
|
const OSC8_OPEN = (href) => `\u001B]8;;${href}\u0007`;
|
|
8433
9859
|
const OSC8_CLOSE = "\x1B]8;;\x07";
|
|
9860
|
+
const CURSOR_SAVE = "\x1B7";
|
|
9861
|
+
const CURSOR_RESTORE = "\x1B8";
|
|
9862
|
+
const CURSOR_HOME = "\x1B[H";
|
|
8434
9863
|
const stdoutFingerprintOwners = new WeakMap();
|
|
9864
|
+
function isTerminalGraphicsCapabilities(value) {
|
|
9865
|
+
return typeof value === "object" && value !== null && "supported" in value && "protocol" in value && "preferredProtocol" in value && "candidates" in value;
|
|
9866
|
+
}
|
|
9867
|
+
function resolveTerminalGraphicsCapabilities(options, env, outputIsTTY) {
|
|
9868
|
+
const terminalGraphics = options === null || options === void 0 ? void 0 : options.terminalGraphics;
|
|
9869
|
+
if (terminalGraphics === false) return detectTerminalGraphicsCapabilities({
|
|
9870
|
+
env,
|
|
9871
|
+
isTTY: outputIsTTY,
|
|
9872
|
+
protocol: "none"
|
|
9873
|
+
});
|
|
9874
|
+
if (isTerminalGraphicsCapabilities(terminalGraphics)) return terminalGraphics;
|
|
9875
|
+
return detectTerminalGraphicsCapabilities({
|
|
9876
|
+
env,
|
|
9877
|
+
isTTY: outputIsTTY,
|
|
9878
|
+
...terminalGraphics ?? {}
|
|
9879
|
+
});
|
|
9880
|
+
}
|
|
8435
9881
|
function createStdoutRenderer(terminal, options) {
|
|
8436
9882
|
const env = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
8437
9883
|
if (shouldInstallFileWriters(env)) installNodeFileWriters();
|
|
@@ -8449,6 +9895,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8449
9895
|
const clear = (options === null || options === void 0 ? void 0 : options.clear) ?? true;
|
|
8450
9896
|
const hideCursor = (options === null || options === void 0 ? void 0 : options.hideCursor) ?? true;
|
|
8451
9897
|
const altScreen = (options === null || options === void 0 ? void 0 : options.altScreen) ?? outputIsTTY;
|
|
9898
|
+
const keepLineWrapDisabled = altScreen && outputIsTTY;
|
|
8452
9899
|
let defaultBg = (options === null || options === void 0 ? void 0 : options.defaultBg) == null || (options === null || options === void 0 ? void 0 : options.defaultBg) === "transparent" ? void 0 : (options === null || options === void 0 ? void 0 : options.defaultBg) ?? "black";
|
|
8453
9900
|
let palette = (options === null || options === void 0 ? void 0 : options.palette) ?? null;
|
|
8454
9901
|
const trackResize = (options === null || options === void 0 ? void 0 : options.trackResize) ?? true;
|
|
@@ -8581,6 +10028,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8581
10028
|
let lastFrameTime = 0;
|
|
8582
10029
|
let pendingRender = false;
|
|
8583
10030
|
let renderTimer = null;
|
|
10031
|
+
let rowsOnlyResizeRepaintTimer = null;
|
|
8584
10032
|
let writeEmaMs = 0;
|
|
8585
10033
|
let lastCursorX = null;
|
|
8586
10034
|
let lastCursorY = null;
|
|
@@ -8591,7 +10039,381 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8591
10039
|
let accumulatedDirtyMax = -1;
|
|
8592
10040
|
let accumulatedDirtyRowsRequireRepaint = false;
|
|
8593
10041
|
let accumulatedScrollOperations = null;
|
|
10042
|
+
let allowNextGraphicsOnlyRenderWithoutBaseline = false;
|
|
10043
|
+
let preserveNextRowsOnlyResizeBaseline = false;
|
|
10044
|
+
let deferGraphicsFlushUntilResizeCommit = false;
|
|
10045
|
+
const graphicsCapabilities = resolveTerminalGraphicsCapabilities(options, env, outputIsTTY);
|
|
10046
|
+
const pendingGraphics = new Map();
|
|
10047
|
+
const pendingGraphicClears = new Set();
|
|
10048
|
+
const activeGraphics = new Map();
|
|
10049
|
+
const pendingGraphicSignatures = new Map();
|
|
10050
|
+
const activeGraphicSignatures = new Map();
|
|
10051
|
+
const retainedGraphics = new Map();
|
|
10052
|
+
const terminalResizeDirtyGraphics = new Set();
|
|
10053
|
+
let nextGraphicsOrder = 0;
|
|
10054
|
+
let terminalGraphicsFlushTimer = null;
|
|
10055
|
+
const hasPendingTerminalGraphics = () => pendingGraphics.size > 0 || pendingGraphicClears.size > 0;
|
|
10056
|
+
function canUseTerminalGraphicsProtocol(protocol, capabilities) {
|
|
10057
|
+
return capabilities.supported && isTerminalGraphicsProtocol(protocol) && protocol === capabilities.preferredProtocol;
|
|
10058
|
+
}
|
|
10059
|
+
function requestTerminalGraphicsFlush(defer = false) {
|
|
10060
|
+
if (disposed) return;
|
|
10061
|
+
if (deferGraphicsFlushUntilResizeCommit) {
|
|
10062
|
+
if (isDebugEnabled()) getDebugLog().render("terminal graphics flush deferred until resize commit");
|
|
10063
|
+
return;
|
|
10064
|
+
}
|
|
10065
|
+
if (!defer) {
|
|
10066
|
+
render([], false);
|
|
10067
|
+
return;
|
|
10068
|
+
}
|
|
10069
|
+
if (terminalGraphicsFlushTimer) return;
|
|
10070
|
+
terminalGraphicsFlushTimer = setTimeout(() => {
|
|
10071
|
+
terminalGraphicsFlushTimer = null;
|
|
10072
|
+
if (!disposed) render([], false);
|
|
10073
|
+
}, 0);
|
|
10074
|
+
}
|
|
10075
|
+
function terminalGraphicsPayloadSignature(payload) {
|
|
10076
|
+
return [
|
|
10077
|
+
payload.id,
|
|
10078
|
+
payload.protocol,
|
|
10079
|
+
payload.x,
|
|
10080
|
+
payload.y,
|
|
10081
|
+
payload.w ?? "",
|
|
10082
|
+
payload.h ?? "",
|
|
10083
|
+
hashTerminalGraphicsString(payload.sequence),
|
|
10084
|
+
hashTerminalGraphicsString(payload.resizeSequence ?? ""),
|
|
10085
|
+
hashTerminalGraphicsString(payload.clearSequence ?? "")
|
|
10086
|
+
].join(":");
|
|
10087
|
+
}
|
|
10088
|
+
function kittyClearSequenceKeepsImageData(sequence) {
|
|
10089
|
+
let index = 0;
|
|
10090
|
+
while (index < sequence.length) {
|
|
10091
|
+
const start = sequence.indexOf("\x1B_G", index);
|
|
10092
|
+
if (start < 0) return false;
|
|
10093
|
+
const end = sequence.indexOf("\x1B\\", start + 3);
|
|
10094
|
+
if (end < 0) return false;
|
|
10095
|
+
const body = sequence.slice(start + 3, end);
|
|
10096
|
+
const controls = body.slice(0, body.indexOf(";") < 0 ? body.length : body.indexOf(";"));
|
|
10097
|
+
const parts = controls.split(",");
|
|
10098
|
+
if (parts.includes("a=d") && parts.includes("d=i")) return true;
|
|
10099
|
+
index = end + 2;
|
|
10100
|
+
}
|
|
10101
|
+
return false;
|
|
10102
|
+
}
|
|
10103
|
+
function retainTerminalGraphic(id, active, signature, options$1 = {}) {
|
|
10104
|
+
if (!signature || active.protocol !== "kitty" || !active.resizeSequence || !active.clearSequence || !kittyClearSequenceKeepsImageData(active.clearSequence)) {
|
|
10105
|
+
retainedGraphics.delete(id);
|
|
10106
|
+
return;
|
|
10107
|
+
}
|
|
10108
|
+
retainedGraphics.set(id, {
|
|
10109
|
+
active,
|
|
10110
|
+
signature,
|
|
10111
|
+
autoRedrawOnResize: Boolean(options$1.autoRedrawOnResize)
|
|
10112
|
+
});
|
|
10113
|
+
}
|
|
10114
|
+
function kittyPlacementKey(sequence) {
|
|
10115
|
+
if (!sequence) return null;
|
|
10116
|
+
const start = sequence.indexOf("\x1B_G");
|
|
10117
|
+
if (start < 0) return null;
|
|
10118
|
+
const end = sequence.indexOf("\x1B\\", start + 3);
|
|
10119
|
+
if (end < 0) return null;
|
|
10120
|
+
const body = sequence.slice(start + 3, end);
|
|
10121
|
+
const controlsRaw = body.slice(0, body.indexOf(";") < 0 ? body.length : body.indexOf(";"));
|
|
10122
|
+
const controls = new Map();
|
|
10123
|
+
for (const part of controlsRaw.split(",")) {
|
|
10124
|
+
const eq = part.indexOf("=");
|
|
10125
|
+
if (eq <= 0) continue;
|
|
10126
|
+
controls.set(part.slice(0, eq), part.slice(eq + 1));
|
|
10127
|
+
}
|
|
10128
|
+
const imageId = controls.get("i");
|
|
10129
|
+
const placementId = controls.get("p");
|
|
10130
|
+
if (controls.get("a") !== "p" || !imageId || !placementId) return null;
|
|
10131
|
+
if (imageId === "0" || placementId === "0") return null;
|
|
10132
|
+
return `${imageId}:${placementId}`;
|
|
10133
|
+
}
|
|
10134
|
+
function canReplaceKittyPlacementWithoutClear(previous, payload) {
|
|
10135
|
+
if (payload.terminalResizeRedraw) return false;
|
|
10136
|
+
if (!payload.resizeRedraw || previous.protocol !== "kitty" || payload.protocol !== "kitty") return false;
|
|
10137
|
+
const nextKey = kittyPlacementKey(payload.resizeSequence ?? payload.sequence);
|
|
10138
|
+
if (!nextKey) return false;
|
|
10139
|
+
return kittyPlacementKey(previous.resizeSequence ?? previous.sequence) === nextKey && (payload.placementMoveWithoutClear || sameGraphicRect(previous, {
|
|
10140
|
+
x: payload.x,
|
|
10141
|
+
y: payload.y,
|
|
10142
|
+
w: payload.w ?? previous.w,
|
|
10143
|
+
h: payload.h ?? previous.h
|
|
10144
|
+
}));
|
|
10145
|
+
}
|
|
10146
|
+
function queueTerminalGraphicClear(id) {
|
|
10147
|
+
if (disposed) return false;
|
|
10148
|
+
const removedPendingDraw = pendingGraphics.delete(`${id}:draw`);
|
|
10149
|
+
pendingGraphicSignatures.delete(id);
|
|
10150
|
+
terminalResizeDirtyGraphics.delete(id);
|
|
10151
|
+
const active = activeGraphics.get(id);
|
|
10152
|
+
if (!active) {
|
|
10153
|
+
retainedGraphics.delete(id);
|
|
10154
|
+
return removedPendingDraw;
|
|
10155
|
+
}
|
|
10156
|
+
if (active.clearSequence) {
|
|
10157
|
+
const payload = {
|
|
10158
|
+
id,
|
|
10159
|
+
x: active.x,
|
|
10160
|
+
y: active.y,
|
|
10161
|
+
w: active.w,
|
|
10162
|
+
h: active.h,
|
|
10163
|
+
protocol: active.protocol,
|
|
10164
|
+
sequence: active.clearSequence,
|
|
10165
|
+
op: "clear",
|
|
10166
|
+
order: nextGraphicsOrder++
|
|
10167
|
+
};
|
|
10168
|
+
if (validateTerminalGraphicsPayload(payload, graphicsCapabilities)) {
|
|
10169
|
+
pendingGraphics.set(`${id}:clear`, payload);
|
|
10170
|
+
recordTerminalGraphicTrace({
|
|
10171
|
+
type: "clear",
|
|
10172
|
+
id,
|
|
10173
|
+
protocol: payload.protocol
|
|
10174
|
+
});
|
|
10175
|
+
requestTerminalGraphicsFlush();
|
|
10176
|
+
return true;
|
|
10177
|
+
}
|
|
10178
|
+
}
|
|
10179
|
+
pendingGraphicClears.add(id);
|
|
10180
|
+
recordTerminalGraphicTrace({
|
|
10181
|
+
type: "clear",
|
|
10182
|
+
id
|
|
10183
|
+
});
|
|
10184
|
+
requestTerminalGraphicsFlush();
|
|
10185
|
+
return true;
|
|
10186
|
+
}
|
|
10187
|
+
function queueTerminalGraphicsForResizeRedraw(size) {
|
|
10188
|
+
if (isDebugEnabled()) getDebugLog().render(`graphics resize redraw queue: size=${size.cols}x${size.rows}, activeGraphics=${activeGraphics.size}, pendingGraphics=${pendingGraphics.size}, pendingClears=${pendingGraphicClears.size}`);
|
|
10189
|
+
for (const [id, active] of activeGraphics) {
|
|
10190
|
+
terminalResizeDirtyGraphics.add(id);
|
|
10191
|
+
pendingGraphics.delete(`${id}:draw`);
|
|
10192
|
+
const anchored = anchoredGraphicRectInViewport(active, size);
|
|
10193
|
+
if (anchored && !active.resizeSequence) {
|
|
10194
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic resize active: id=${id}, x=${active.x}, y=${active.y}, w=${active.w}, h=${active.h}, viewport=${size.cols}x${size.rows}, anchored=true, skipped=no-resize-sequence`);
|
|
10195
|
+
continue;
|
|
10196
|
+
}
|
|
10197
|
+
const signature = activeGraphicSignatures.get(id);
|
|
10198
|
+
const sequence = active.resizeSequence ?? active.sequence;
|
|
10199
|
+
pendingGraphics.set(`${id}:draw`, {
|
|
10200
|
+
id,
|
|
10201
|
+
x: active.x,
|
|
10202
|
+
y: active.y,
|
|
10203
|
+
w: active.w,
|
|
10204
|
+
h: active.h,
|
|
10205
|
+
protocol: active.protocol,
|
|
10206
|
+
sequence,
|
|
10207
|
+
resizeSequence: active.resizeSequence,
|
|
10208
|
+
clearSequence: active.clearSequence,
|
|
10209
|
+
op: "draw",
|
|
10210
|
+
order: nextGraphicsOrder++,
|
|
10211
|
+
resizeRedraw: true,
|
|
10212
|
+
terminalResizeRedraw: true
|
|
10213
|
+
});
|
|
10214
|
+
if (signature) pendingGraphicSignatures.set(id, signature);
|
|
10215
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic resize active: id=${id}, x=${active.x}, y=${active.y}, w=${active.w}, h=${active.h}, viewport=${size.cols}x${size.rows}, anchored=${anchored ? "true" : "false"}, bytes=${sequence.length}`);
|
|
10216
|
+
}
|
|
10217
|
+
for (const [id, retained] of retainedGraphics) {
|
|
10218
|
+
if (activeGraphics.has(id) || !retained.autoRedrawOnResize) continue;
|
|
10219
|
+
const { active, signature } = retained;
|
|
10220
|
+
if (!anchoredGraphicRectInViewport(active, size)) continue;
|
|
10221
|
+
retainedGraphics.delete(id);
|
|
10222
|
+
activeGraphics.set(id, active);
|
|
10223
|
+
activeGraphicSignatures.set(id, signature);
|
|
10224
|
+
pendingGraphicClears.delete(id);
|
|
10225
|
+
pendingGraphics.delete(`${id}:clear`);
|
|
10226
|
+
pendingGraphics.set(`${id}:draw`, {
|
|
10227
|
+
id,
|
|
10228
|
+
x: active.x,
|
|
10229
|
+
y: active.y,
|
|
10230
|
+
w: active.w,
|
|
10231
|
+
h: active.h,
|
|
10232
|
+
protocol: active.protocol,
|
|
10233
|
+
sequence: active.resizeSequence ?? active.sequence,
|
|
10234
|
+
resizeSequence: active.resizeSequence,
|
|
10235
|
+
clearSequence: active.clearSequence,
|
|
10236
|
+
op: "draw",
|
|
10237
|
+
order: nextGraphicsOrder++,
|
|
10238
|
+
resizeRedraw: true,
|
|
10239
|
+
terminalResizeRedraw: true
|
|
10240
|
+
});
|
|
10241
|
+
pendingGraphicSignatures.set(id, signature);
|
|
10242
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic retained resize redraw: id=${id}, x=${active.x}, y=${active.y}, w=${active.w}, h=${active.h}, bytes=${(active.resizeSequence ?? active.sequence).length}`);
|
|
10243
|
+
}
|
|
10244
|
+
}
|
|
10245
|
+
const graphicsOutput = {
|
|
10246
|
+
capabilities: graphicsCapabilities,
|
|
10247
|
+
isActive(id) {
|
|
10248
|
+
if (pendingGraphicClears.has(id) || pendingGraphics.has(`${id}:clear`)) return false;
|
|
10249
|
+
return activeGraphics.has(id) || retainedGraphics.has(id) || pendingGraphics.has(`${id}:draw`);
|
|
10250
|
+
},
|
|
10251
|
+
queue(payload) {
|
|
10252
|
+
if (disposed) return false;
|
|
10253
|
+
const x = Math.floor(payload.x);
|
|
10254
|
+
const y = Math.floor(payload.y);
|
|
10255
|
+
const op = payload.op ?? "draw";
|
|
10256
|
+
const normalized = {
|
|
10257
|
+
...payload,
|
|
10258
|
+
x,
|
|
10259
|
+
y,
|
|
10260
|
+
w: payload.w == null ? void 0 : Math.floor(payload.w),
|
|
10261
|
+
h: payload.h == null ? void 0 : Math.floor(payload.h),
|
|
10262
|
+
op,
|
|
10263
|
+
order: nextGraphicsOrder++
|
|
10264
|
+
};
|
|
10265
|
+
if (!normalized.id.trim()) return false;
|
|
10266
|
+
if (!Number.isFinite(normalized.x) || !Number.isFinite(normalized.y)) return false;
|
|
10267
|
+
if (!canUseTerminalGraphicsProtocol(normalized.protocol, graphicsCapabilities)) return false;
|
|
10268
|
+
if (op === "draw") {
|
|
10269
|
+
const frame = validateTerminalGraphicFrame({
|
|
10270
|
+
id: normalized.id,
|
|
10271
|
+
protocol: normalized.protocol,
|
|
10272
|
+
sequence: normalized.sequence,
|
|
10273
|
+
fallbackText: normalized.fallbackText,
|
|
10274
|
+
width: normalized.w ?? 1,
|
|
10275
|
+
height: normalized.h ?? 1
|
|
10276
|
+
});
|
|
10277
|
+
if (!frame) return false;
|
|
10278
|
+
if (isDebugEnabled()) {
|
|
10279
|
+
const size = terminal.size();
|
|
10280
|
+
getDebugLog().render(`terminal graphic queue draw request: id=${frame.id}, x=${normalized.x}, y=${normalized.y}, w=${frame.width}, h=${frame.height}, viewport=${size.cols}x${size.rows}`);
|
|
10281
|
+
}
|
|
10282
|
+
if (!anchoredGraphicRectInViewport({
|
|
10283
|
+
x: normalized.x,
|
|
10284
|
+
y: normalized.y,
|
|
10285
|
+
w: frame.width,
|
|
10286
|
+
h: frame.height
|
|
10287
|
+
}, terminal.size())) {
|
|
10288
|
+
if (isDebugEnabled()) {
|
|
10289
|
+
const size = terminal.size();
|
|
10290
|
+
getDebugLog().render(`terminal graphic queue draw rejected offscreen: id=${frame.id}, x=${normalized.x}, y=${normalized.y}, w=${frame.width}, h=${frame.height}, viewport=${size.cols}x${size.rows}`);
|
|
10291
|
+
}
|
|
10292
|
+
queueTerminalGraphicClear(frame.id);
|
|
10293
|
+
return false;
|
|
10294
|
+
}
|
|
10295
|
+
const clearSequence = normalized.clearSequence && isSafeTerminalGraphicsSequence(normalized.clearSequence, normalized.protocol, "clear") ? normalized.clearSequence : void 0;
|
|
10296
|
+
const resizeSequence = normalized.resizeSequence && isSafeTerminalGraphicsSequence(normalized.resizeSequence, normalized.protocol, "draw") ? normalized.resizeSequence : void 0;
|
|
10297
|
+
const signature = terminalGraphicsPayloadSignature({
|
|
10298
|
+
...normalized,
|
|
10299
|
+
id: frame.id,
|
|
10300
|
+
w: frame.width,
|
|
10301
|
+
h: frame.height,
|
|
10302
|
+
sequence: frame.sequence,
|
|
10303
|
+
resizeSequence,
|
|
10304
|
+
clearSequence
|
|
10305
|
+
});
|
|
10306
|
+
const forceTerminalResizeRedraw = terminalResizeDirtyGraphics.has(frame.id);
|
|
10307
|
+
const removedPendingGraphicClear = pendingGraphics.delete(`${frame.id}:clear`);
|
|
10308
|
+
const removedPendingClear = pendingGraphicClears.delete(frame.id);
|
|
10309
|
+
const canceledPendingClear = removedPendingGraphicClear || removedPendingClear;
|
|
10310
|
+
if (!forceTerminalResizeRedraw && !normalized.forceDraw && !canceledPendingClear && (pendingGraphicSignatures.get(frame.id) === signature || activeGraphicSignatures.get(frame.id) === signature)) {
|
|
10311
|
+
recordTerminalGraphicTrace({
|
|
10312
|
+
type: "queue-dedupe",
|
|
10313
|
+
id: frame.id,
|
|
10314
|
+
protocol: normalized.protocol
|
|
10315
|
+
});
|
|
10316
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic queue draw dedupe: id=${frame.id}, x=${normalized.x}, y=${normalized.y}, w=${frame.width}, h=${frame.height}`);
|
|
10317
|
+
return true;
|
|
10318
|
+
}
|
|
10319
|
+
if (!forceTerminalResizeRedraw && !normalized.forceDraw && canceledPendingClear && activeGraphicSignatures.get(frame.id) === signature) {
|
|
10320
|
+
recordTerminalGraphicTrace({
|
|
10321
|
+
type: "queue-dedupe",
|
|
10322
|
+
id: frame.id,
|
|
10323
|
+
protocol: normalized.protocol
|
|
10324
|
+
});
|
|
10325
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic queue draw canceled clear: id=${frame.id}, x=${normalized.x}, y=${normalized.y}, w=${frame.width}, h=${frame.height}`);
|
|
10326
|
+
return true;
|
|
10327
|
+
}
|
|
10328
|
+
const retained = retainedGraphics.get(frame.id);
|
|
10329
|
+
const retainedCanReplacePlacement = retained && resizeSequence && canReplaceKittyPlacementWithoutClear(retained.active, {
|
|
10330
|
+
...normalized,
|
|
10331
|
+
id: frame.id,
|
|
10332
|
+
w: frame.width,
|
|
10333
|
+
h: frame.height,
|
|
10334
|
+
sequence: resizeSequence,
|
|
10335
|
+
resizeSequence,
|
|
10336
|
+
clearSequence,
|
|
10337
|
+
fallbackText: frame.fallbackText,
|
|
10338
|
+
resizeRedraw: true,
|
|
10339
|
+
placementMoveWithoutClear: true
|
|
10340
|
+
});
|
|
10341
|
+
if (!canceledPendingClear && retained && resizeSequence && (retained.signature === signature || retainedCanReplacePlacement)) {
|
|
10342
|
+
activeGraphics.set(frame.id, retained.active);
|
|
10343
|
+
activeGraphicSignatures.set(frame.id, retained.signature);
|
|
10344
|
+
retainedGraphics.delete(frame.id);
|
|
10345
|
+
pendingGraphics.set(`${frame.id}:draw`, {
|
|
10346
|
+
...normalized,
|
|
10347
|
+
id: frame.id,
|
|
10348
|
+
w: frame.width,
|
|
10349
|
+
h: frame.height,
|
|
10350
|
+
sequence: resizeSequence,
|
|
10351
|
+
resizeSequence,
|
|
10352
|
+
clearSequence,
|
|
10353
|
+
fallbackText: frame.fallbackText,
|
|
10354
|
+
resizeRedraw: true,
|
|
10355
|
+
placementMoveWithoutClear: true,
|
|
10356
|
+
terminalResizeRedraw: forceTerminalResizeRedraw
|
|
10357
|
+
});
|
|
10358
|
+
pendingGraphicSignatures.set(frame.id, signature);
|
|
10359
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic retained resize redraw: id=${frame.id}, x=${retained.active.x}, y=${retained.active.y}, w=${retained.active.w}, h=${retained.active.h}, bytes=${resizeSequence.length}`);
|
|
10360
|
+
recordTerminalGraphicTrace({
|
|
10361
|
+
type: "queue",
|
|
10362
|
+
id: frame.id,
|
|
10363
|
+
protocol: normalized.protocol,
|
|
10364
|
+
bytes: resizeSequence.length
|
|
10365
|
+
});
|
|
10366
|
+
requestTerminalGraphicsFlush(Boolean(normalized.deferFlush));
|
|
10367
|
+
return true;
|
|
10368
|
+
}
|
|
10369
|
+
retainedGraphics.delete(frame.id);
|
|
10370
|
+
pendingGraphics.set(`${frame.id}:draw`, {
|
|
10371
|
+
...normalized,
|
|
10372
|
+
id: frame.id,
|
|
10373
|
+
w: frame.width,
|
|
10374
|
+
h: frame.height,
|
|
10375
|
+
sequence: frame.sequence,
|
|
10376
|
+
resizeSequence,
|
|
10377
|
+
clearSequence,
|
|
10378
|
+
fallbackText: frame.fallbackText,
|
|
10379
|
+
terminalResizeRedraw: forceTerminalResizeRedraw
|
|
10380
|
+
});
|
|
10381
|
+
pendingGraphicSignatures.set(frame.id, signature);
|
|
10382
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic queue draw accepted: id=${frame.id}, x=${normalized.x}, y=${normalized.y}, w=${frame.width}, h=${frame.height}, bytes=${frame.sequence.length}`);
|
|
10383
|
+
recordTerminalGraphicTrace({
|
|
10384
|
+
type: "queue",
|
|
10385
|
+
id: frame.id,
|
|
10386
|
+
protocol: normalized.protocol,
|
|
10387
|
+
bytes: frame.sequence.length
|
|
10388
|
+
});
|
|
10389
|
+
requestTerminalGraphicsFlush(Boolean(normalized.deferFlush));
|
|
10390
|
+
return true;
|
|
10391
|
+
}
|
|
10392
|
+
if (!validateTerminalGraphicsPayload(normalized, graphicsCapabilities)) return false;
|
|
10393
|
+
pendingGraphics.delete(`${normalized.id}:draw`);
|
|
10394
|
+
pendingGraphicSignatures.delete(normalized.id);
|
|
10395
|
+
retainedGraphics.delete(normalized.id);
|
|
10396
|
+
pendingGraphics.set(`${normalized.id}:clear`, {
|
|
10397
|
+
...normalized,
|
|
10398
|
+
w: normalized.w,
|
|
10399
|
+
h: normalized.h
|
|
10400
|
+
});
|
|
10401
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic queue clear accepted: id=${normalized.id}, x=${normalized.x}, y=${normalized.y}, w=${normalized.w ?? 1}, h=${normalized.h ?? 1}`);
|
|
10402
|
+
recordTerminalGraphicTrace({
|
|
10403
|
+
type: "clear",
|
|
10404
|
+
id: normalized.id,
|
|
10405
|
+
protocol: normalized.protocol
|
|
10406
|
+
});
|
|
10407
|
+
requestTerminalGraphicsFlush(Boolean(normalized.deferFlush));
|
|
10408
|
+
return true;
|
|
10409
|
+
},
|
|
10410
|
+
clear(id) {
|
|
10411
|
+
return queueTerminalGraphicClear(id);
|
|
10412
|
+
}
|
|
10413
|
+
};
|
|
10414
|
+
const unregisterGraphicsOutput = registerTerminalGraphicsOutput(terminal, graphicsOutput);
|
|
8594
10415
|
const MIN_FRAME_MS = outputIsTTY ? 16 : 0;
|
|
10416
|
+
const ROWS_ONLY_RESIZE_REPAINT_DELAY_MS = 500;
|
|
8595
10417
|
function clampCellToViewport(cell, size) {
|
|
8596
10418
|
const maxX = Math.max(0, Math.floor(size.cols) - 1);
|
|
8597
10419
|
const maxY = Math.max(0, Math.floor(size.rows) - 1);
|
|
@@ -8604,6 +10426,92 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8604
10426
|
y
|
|
8605
10427
|
};
|
|
8606
10428
|
}
|
|
10429
|
+
function normalizeGraphicRect(rect) {
|
|
10430
|
+
const x0 = Math.floor(rect.x);
|
|
10431
|
+
const y0 = Math.floor(rect.y);
|
|
10432
|
+
const w0 = Math.floor(rect.w);
|
|
10433
|
+
const h0 = Math.floor(rect.h);
|
|
10434
|
+
if (!Number.isFinite(x0) || !Number.isFinite(y0) || !Number.isFinite(w0) || !Number.isFinite(h0)) return null;
|
|
10435
|
+
const size = normalizeTerminalGraphicSize(w0, h0);
|
|
10436
|
+
if (!size) return null;
|
|
10437
|
+
return {
|
|
10438
|
+
x: x0,
|
|
10439
|
+
y: y0,
|
|
10440
|
+
w: size.width,
|
|
10441
|
+
h: size.height
|
|
10442
|
+
};
|
|
10443
|
+
}
|
|
10444
|
+
function clipGraphicRectToViewport(rect, size) {
|
|
10445
|
+
const cols = Math.max(0, Math.floor(size.cols));
|
|
10446
|
+
const rows = Math.max(0, Math.floor(size.rows));
|
|
10447
|
+
if (cols <= 0 || rows <= 0) return null;
|
|
10448
|
+
const normalized = normalizeGraphicRect(rect);
|
|
10449
|
+
if (!normalized) return null;
|
|
10450
|
+
const x0 = normalized.x;
|
|
10451
|
+
const y0 = normalized.y;
|
|
10452
|
+
const w0 = normalized.w;
|
|
10453
|
+
const h0 = normalized.h;
|
|
10454
|
+
const left = Math.max(0, x0);
|
|
10455
|
+
const top = Math.max(0, y0);
|
|
10456
|
+
const right = Math.min(cols, x0 + w0);
|
|
10457
|
+
const bottom = Math.min(rows, y0 + h0);
|
|
10458
|
+
if (right <= left || bottom <= top) return null;
|
|
10459
|
+
return {
|
|
10460
|
+
x: left,
|
|
10461
|
+
y: top,
|
|
10462
|
+
w: right - left,
|
|
10463
|
+
h: bottom - top
|
|
10464
|
+
};
|
|
10465
|
+
}
|
|
10466
|
+
function anchoredGraphicRectInViewport(rect, size) {
|
|
10467
|
+
const cols = Math.max(0, Math.floor(size.cols));
|
|
10468
|
+
const rows = Math.max(0, Math.floor(size.rows));
|
|
10469
|
+
if (cols <= 0 || rows <= 0) return null;
|
|
10470
|
+
const normalized = normalizeGraphicRect(rect);
|
|
10471
|
+
if (!normalized) return null;
|
|
10472
|
+
return normalized.x >= 0 && normalized.y >= 0 && normalized.x < cols && normalized.y < rows ? normalized : null;
|
|
10473
|
+
}
|
|
10474
|
+
function clearGraphicRect(rect) {
|
|
10475
|
+
const blank = " ".repeat(Math.max(0, rect.w));
|
|
10476
|
+
let out$1 = "";
|
|
10477
|
+
for (let row = 0; row < rect.h; row++) out$1 += `\u001B[${rect.y + row + 1};${rect.x + 1}H${blank}`;
|
|
10478
|
+
return out$1;
|
|
10479
|
+
}
|
|
10480
|
+
function sameGraphicRect(a, b) {
|
|
10481
|
+
return Boolean(a && a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h);
|
|
10482
|
+
}
|
|
10483
|
+
function maybeWrapTerminalGraphic(sequence) {
|
|
10484
|
+
return wrapTerminalGraphicsForMultiplexer(sequence, graphicsCapabilities);
|
|
10485
|
+
}
|
|
10486
|
+
function kittyClearTargetsCurrentCell(sequence) {
|
|
10487
|
+
const prefix = "\x1B_G";
|
|
10488
|
+
const terminator = "\x1B\\";
|
|
10489
|
+
let index = 0;
|
|
10490
|
+
while (index < sequence.length) {
|
|
10491
|
+
if (!sequence.startsWith(prefix, index)) return false;
|
|
10492
|
+
const end = sequence.indexOf(terminator, index + prefix.length);
|
|
10493
|
+
if (end < 0) return false;
|
|
10494
|
+
const body = sequence.slice(index + prefix.length, end);
|
|
10495
|
+
const semicolon = body.indexOf(";");
|
|
10496
|
+
const controlsText = semicolon < 0 ? body : body.slice(0, semicolon);
|
|
10497
|
+
let action = "";
|
|
10498
|
+
let deleteMode = "";
|
|
10499
|
+
for (const part of controlsText.split(",")) {
|
|
10500
|
+
const eq = part.indexOf("=");
|
|
10501
|
+
if (eq <= 0) continue;
|
|
10502
|
+
const key = part.slice(0, eq);
|
|
10503
|
+
const value = part.slice(eq + 1);
|
|
10504
|
+
if (key === "a") action = value;
|
|
10505
|
+
else if (key === "d") deleteMode = value;
|
|
10506
|
+
}
|
|
10507
|
+
if (action === "d" && (deleteMode === "c" || deleteMode === "C")) return true;
|
|
10508
|
+
index = end + terminator.length;
|
|
10509
|
+
}
|
|
10510
|
+
return false;
|
|
10511
|
+
}
|
|
10512
|
+
function clearSequenceNeedsVisibleCell(sequence, protocol) {
|
|
10513
|
+
return protocol === "kitty" && kittyClearTargetsCurrentCell(sequence);
|
|
10514
|
+
}
|
|
8607
10515
|
function resolveColorMode() {
|
|
8608
10516
|
const opt = (options === null || options === void 0 ? void 0 : options.colorMode) ?? "auto";
|
|
8609
10517
|
if (opt !== "auto") return opt;
|
|
@@ -8755,6 +10663,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8755
10663
|
const MAX_CELL_TEXT_IDS = 131072;
|
|
8756
10664
|
let prevOverlayBlockedRows = [];
|
|
8757
10665
|
let prevOverlayPartialRows = [];
|
|
10666
|
+
let prevOverlayVisibleSpans = new Map();
|
|
8758
10667
|
const hrefIndex = new Map();
|
|
8759
10668
|
let nextHrefId = 1;
|
|
8760
10669
|
const MAX_HREF_IDS = 8192;
|
|
@@ -8779,6 +10688,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8779
10688
|
fpPrevValid = false;
|
|
8780
10689
|
prevOverlayBlockedRows = [];
|
|
8781
10690
|
prevOverlayPartialRows = [];
|
|
10691
|
+
prevOverlayVisibleSpans = new Map();
|
|
8782
10692
|
}
|
|
8783
10693
|
function cellFingerprintFromStyleKey(_ch, key) {
|
|
8784
10694
|
return key >>> 0;
|
|
@@ -9476,12 +11386,46 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9476
11386
|
lastFrameTime = Date.now();
|
|
9477
11387
|
const renderStart = performance.now();
|
|
9478
11388
|
const size = terminal.size();
|
|
11389
|
+
const rowsOnlyResizeBaseline = preserveNextRowsOnlyResizeBaseline && fpPrevValid && fpCols === size.cols ? {
|
|
11390
|
+
cols: fpCols,
|
|
11391
|
+
rows: fpRows,
|
|
11392
|
+
fp: prevFP.slice(),
|
|
11393
|
+
hrefIds: prevHrefIds.slice(),
|
|
11394
|
+
textIds: prevTextIds.slice()
|
|
11395
|
+
} : null;
|
|
11396
|
+
preserveNextRowsOnlyResizeBaseline = false;
|
|
11397
|
+
const pendingGraphicClearsToRender = new Set(pendingGraphicClears);
|
|
11398
|
+
let graphicsClearsToRender = Array.from(pendingGraphicClearsToRender);
|
|
11399
|
+
let graphicsEntriesToRender = Array.from(pendingGraphics.entries()).sort(([, a], [, b]) => {
|
|
11400
|
+
const opA = a.op === "clear" ? 0 : 1;
|
|
11401
|
+
const opB = b.op === "clear" ? 0 : 1;
|
|
11402
|
+
return opA - opB || a.order - b.order;
|
|
11403
|
+
});
|
|
11404
|
+
let graphicsToRender = graphicsEntriesToRender.map(([, payload]) => payload);
|
|
11405
|
+
const allowGraphicsOnlyWithoutBaseline = allowNextGraphicsOnlyRenderWithoutBaseline && (dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) === 0 && !(scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length) && (graphicsClearsToRender.length > 0 || graphicsToRender.length > 0);
|
|
11406
|
+
allowNextGraphicsOnlyRenderWithoutBaseline = false;
|
|
11407
|
+
if (isDebugEnabled()) getDebugLog().render(`doRender state: size=${size.cols}x${size.rows}, dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}, scrollOps=${(scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length) ?? 0}, rowsOnlyBaseline=${rowsOnlyResizeBaseline ? "true" : "false"}, allowGraphicsOnlyWithoutBaseline=${allowGraphicsOnlyWithoutBaseline ? "true" : "false"}, activeGraphics=${activeGraphics.size}, pendingGraphics=${graphicsToRender.length}, pendingGraphicClears=${graphicsClearsToRender.length}`);
|
|
11408
|
+
let terminalGraphicsBlockScrollRegions = false;
|
|
9479
11409
|
ensureRowEscapes(Math.max(size.rows, lastRenderedRows));
|
|
9480
11410
|
ensureFingerprints(size.cols, size.rows);
|
|
9481
11411
|
const bgSeq = openBg(defaultBg);
|
|
9482
11412
|
const bgOnlyStyle = { bg: defaultBg };
|
|
9483
11413
|
const bgKey = styleKeyFromParts({ bg: defaultBg });
|
|
9484
11414
|
const blankFP = cellFingerprintFromStyleKey(" ", bgKey);
|
|
11415
|
+
if (rowsOnlyResizeBaseline && rowsOnlyResizeBaseline.cols === size.cols) {
|
|
11416
|
+
prevFP.fill(blankFP);
|
|
11417
|
+
prevHrefIds.fill(0);
|
|
11418
|
+
prevTextIds.fill(blankTextId);
|
|
11419
|
+
const rowsToCopy = Math.min(size.rows, rowsOnlyResizeBaseline.rows);
|
|
11420
|
+
for (let y = 0; y < rowsToCopy; y++) {
|
|
11421
|
+
const start = y * size.cols;
|
|
11422
|
+
const end = start + size.cols;
|
|
11423
|
+
prevFP.set(rowsOnlyResizeBaseline.fp.subarray(start, end), start);
|
|
11424
|
+
prevHrefIds.set(rowsOnlyResizeBaseline.hrefIds.subarray(start, end), start);
|
|
11425
|
+
prevTextIds.set(rowsOnlyResizeBaseline.textIds.subarray(start, end), start);
|
|
11426
|
+
}
|
|
11427
|
+
fpPrevValid = true;
|
|
11428
|
+
}
|
|
9485
11429
|
let dirtySorted = true;
|
|
9486
11430
|
const forceFullRender = hrefIndexResetRequiresBaseline || fingerprintInternResetRequiresBaseline;
|
|
9487
11431
|
if (forceFullRender) {
|
|
@@ -9507,7 +11451,171 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9507
11451
|
if (!outOps.length) return null;
|
|
9508
11452
|
return outOps;
|
|
9509
11453
|
})();
|
|
11454
|
+
const terminalGraphicsAffectedRows = new Set();
|
|
11455
|
+
const terminalGraphicTextPreserveSpans = new Map();
|
|
11456
|
+
const addTerminalGraphicRows = (rect) => {
|
|
11457
|
+
if (!rect) return;
|
|
11458
|
+
const visible = clipGraphicRectToViewport(rect, size);
|
|
11459
|
+
if (!visible) return;
|
|
11460
|
+
for (let y = visible.y; y < visible.y + visible.h; y++) terminalGraphicsAffectedRows.add(y);
|
|
11461
|
+
};
|
|
11462
|
+
const addTerminalGraphicTextPreserveSpans = (rect) => {
|
|
11463
|
+
if (!rect) return;
|
|
11464
|
+
const visible = clipGraphicRectToViewport(rect, size);
|
|
11465
|
+
if (!visible) return;
|
|
11466
|
+
const start = Math.max(0, Math.min(size.cols, visible.x));
|
|
11467
|
+
const end = Math.max(start, Math.min(size.cols, visible.x + visible.w));
|
|
11468
|
+
if (end <= start) return;
|
|
11469
|
+
for (let y = visible.y; y < visible.y + visible.h; y++) {
|
|
11470
|
+
const spans = terminalGraphicTextPreserveSpans.get(y);
|
|
11471
|
+
if (spans) spans.push({
|
|
11472
|
+
start,
|
|
11473
|
+
end
|
|
11474
|
+
});
|
|
11475
|
+
else terminalGraphicTextPreserveSpans.set(y, [{
|
|
11476
|
+
start,
|
|
11477
|
+
end
|
|
11478
|
+
}]);
|
|
11479
|
+
}
|
|
11480
|
+
};
|
|
11481
|
+
const payloadRect = (payload) => ({
|
|
11482
|
+
x: payload.x,
|
|
11483
|
+
y: payload.y,
|
|
11484
|
+
w: payload.w ?? 1,
|
|
11485
|
+
h: payload.h ?? 1
|
|
11486
|
+
});
|
|
11487
|
+
const intersectsScrollOperations = (rect) => {
|
|
11488
|
+
if (!rect || !(normalizedScrollOperations === null || normalizedScrollOperations === void 0 ? void 0 : normalizedScrollOperations.length)) return false;
|
|
11489
|
+
const top = rect.y;
|
|
11490
|
+
const bottom = rect.y + rect.h;
|
|
11491
|
+
for (const op of normalizedScrollOperations) if (top < op.endY && bottom > op.startY) return true;
|
|
11492
|
+
return false;
|
|
11493
|
+
};
|
|
11494
|
+
const graphicRectVisible = (rect) => Boolean(rect && clipGraphicRectToViewport(rect, size));
|
|
11495
|
+
const pendingGraphicIds = new Set(graphicsToRender.map((payload) => payload.id));
|
|
11496
|
+
const explicitGraphicClears = new Set(graphicsClearsToRender);
|
|
11497
|
+
if ((normalizedScrollOperations === null || normalizedScrollOperations === void 0 ? void 0 : normalizedScrollOperations.length) && activeGraphics.size > 0) for (const [id, active] of activeGraphics) {
|
|
11498
|
+
if (explicitGraphicClears.has(id) || pendingGraphicIds.has(id)) continue;
|
|
11499
|
+
if (!intersectsScrollOperations(active)) continue;
|
|
11500
|
+
const signature = activeGraphicSignatures.get(id);
|
|
11501
|
+
graphicsToRender.push({
|
|
11502
|
+
id,
|
|
11503
|
+
x: active.x,
|
|
11504
|
+
y: active.y,
|
|
11505
|
+
w: active.w,
|
|
11506
|
+
h: active.h,
|
|
11507
|
+
protocol: active.protocol,
|
|
11508
|
+
sequence: active.sequence,
|
|
11509
|
+
resizeSequence: active.resizeSequence,
|
|
11510
|
+
clearSequence: active.clearSequence,
|
|
11511
|
+
op: "draw",
|
|
11512
|
+
order: nextGraphicsOrder++
|
|
11513
|
+
});
|
|
11514
|
+
if (signature) pendingGraphicSignatures.set(id, signature);
|
|
11515
|
+
pendingGraphicIds.add(id);
|
|
11516
|
+
}
|
|
11517
|
+
for (const [id, active] of activeGraphics) {
|
|
11518
|
+
if (explicitGraphicClears.has(id)) continue;
|
|
11519
|
+
if (pendingGraphicIds.has(id)) continue;
|
|
11520
|
+
if (intersectsScrollOperations(active)) continue;
|
|
11521
|
+
addTerminalGraphicTextPreserveSpans(active);
|
|
11522
|
+
}
|
|
11523
|
+
if ((normalizedScrollOperations === null || normalizedScrollOperations === void 0 ? void 0 : normalizedScrollOperations.length) && activeGraphics.size > 0) for (const active of activeGraphics.values()) {
|
|
11524
|
+
if (!intersectsScrollOperations(active)) continue;
|
|
11525
|
+
terminalGraphicsBlockScrollRegions = true;
|
|
11526
|
+
addTerminalGraphicRows(active);
|
|
11527
|
+
}
|
|
11528
|
+
for (const id of graphicsClearsToRender) {
|
|
11529
|
+
const active = activeGraphics.get(id);
|
|
11530
|
+
addTerminalGraphicRows(active);
|
|
11531
|
+
if (intersectsScrollOperations(active)) terminalGraphicsBlockScrollRegions = true;
|
|
11532
|
+
}
|
|
11533
|
+
for (const payload of graphicsToRender) {
|
|
11534
|
+
const active = activeGraphics.get(payload.id);
|
|
11535
|
+
if (payload.op === "clear") {
|
|
11536
|
+
const rect = active ?? payloadRect(payload);
|
|
11537
|
+
addTerminalGraphicRows(rect);
|
|
11538
|
+
if (intersectsScrollOperations(rect)) terminalGraphicsBlockScrollRegions = true;
|
|
11539
|
+
continue;
|
|
11540
|
+
}
|
|
11541
|
+
const next = payloadRect(payload);
|
|
11542
|
+
if (!payload.allowTextOverlay) addTerminalGraphicTextPreserveSpans(next);
|
|
11543
|
+
addTerminalGraphicRows(active);
|
|
11544
|
+
addTerminalGraphicRows(next);
|
|
11545
|
+
if (intersectsScrollOperations(active) || intersectsScrollOperations(next)) terminalGraphicsBlockScrollRegions = true;
|
|
11546
|
+
}
|
|
11547
|
+
if (!terminalGraphicsBlockScrollRegions && (Array.from(activeGraphics.values()).some(graphicRectVisible) || graphicsClearsToRender.some((id) => graphicRectVisible(activeGraphics.get(id))) || graphicsToRender.some((payload) => payload.op === "clear" ? graphicRectVisible(activeGraphics.get(payload.id) ?? payloadRect(payload)) : graphicRectVisible(anchoredGraphicRectInViewport({
|
|
11548
|
+
x: payload.x,
|
|
11549
|
+
y: payload.y,
|
|
11550
|
+
w: payload.w ?? 1,
|
|
11551
|
+
h: payload.h ?? 1
|
|
11552
|
+
}, size))))) terminalGraphicsBlockScrollRegions = true;
|
|
11553
|
+
let forceDirtyRowsRepaintForFrame = forceDirtyRowsRepaint;
|
|
11554
|
+
const forceTerminalGraphicsRowRepaint = (y) => forceDirtyRowsRepaintForFrame || terminalGraphicsAffectedRows.has(y) || terminalGraphicTextPreserveSpans.has(y);
|
|
11555
|
+
for (const [y, spans] of terminalGraphicTextPreserveSpans) {
|
|
11556
|
+
spans.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
11557
|
+
const merged = [];
|
|
11558
|
+
for (const span of spans) {
|
|
11559
|
+
const previous = merged[merged.length - 1];
|
|
11560
|
+
if (previous && span.start <= previous.end) previous.end = Math.max(previous.end, span.end);
|
|
11561
|
+
else merged.push({ ...span });
|
|
11562
|
+
}
|
|
11563
|
+
terminalGraphicTextPreserveSpans.set(y, merged);
|
|
11564
|
+
}
|
|
11565
|
+
const mergeSpans = (spans) => {
|
|
11566
|
+
if (!spans.length) return [];
|
|
11567
|
+
const sorted = [...spans].sort((a, b) => a.start - b.start || a.end - b.end);
|
|
11568
|
+
const merged = [];
|
|
11569
|
+
for (const span of sorted) {
|
|
11570
|
+
const start = Math.max(0, Math.min(size.cols, span.start));
|
|
11571
|
+
const end = Math.max(start, Math.min(size.cols, span.end));
|
|
11572
|
+
if (end <= start) continue;
|
|
11573
|
+
const previous = merged[merged.length - 1];
|
|
11574
|
+
if (previous && start <= previous.end) previous.end = Math.max(previous.end, end);
|
|
11575
|
+
else merged.push({
|
|
11576
|
+
start,
|
|
11577
|
+
end
|
|
11578
|
+
});
|
|
11579
|
+
}
|
|
11580
|
+
return merged;
|
|
11581
|
+
};
|
|
11582
|
+
const overlayVisibleSpansForRows = (rows) => {
|
|
11583
|
+
const overlay = getPlaneTerminal(terminal, "overlay");
|
|
11584
|
+
const result = new Map();
|
|
11585
|
+
for (const y of rows) {
|
|
11586
|
+
if (y < 0 || y >= size.rows) continue;
|
|
11587
|
+
const row = overlay.getRow(y);
|
|
11588
|
+
const spans = [];
|
|
11589
|
+
let start = null;
|
|
11590
|
+
let end = 0;
|
|
11591
|
+
for (let x = 0; x < size.cols; x++) {
|
|
11592
|
+
const cell = row[x];
|
|
11593
|
+
const visible = cell != null && !cell.continuation && (cell.ch !== " " || styleKey(cell.style) !== bgKey || renderedHref(cell.style.href) != null);
|
|
11594
|
+
if (visible) {
|
|
11595
|
+
if (start == null) start = x;
|
|
11596
|
+
end = Math.max(end, Math.min(size.cols, x + Math.max(1, cell.width ?? 1)));
|
|
11597
|
+
continue;
|
|
11598
|
+
}
|
|
11599
|
+
if (start != null && x >= end) {
|
|
11600
|
+
spans.push({
|
|
11601
|
+
start,
|
|
11602
|
+
end
|
|
11603
|
+
});
|
|
11604
|
+
start = null;
|
|
11605
|
+
}
|
|
11606
|
+
}
|
|
11607
|
+
if (start != null) spans.push({
|
|
11608
|
+
start,
|
|
11609
|
+
end: Math.max(end, start + 1)
|
|
11610
|
+
});
|
|
11611
|
+
if (spans.length) result.set(y, mergeSpans(spans));
|
|
11612
|
+
}
|
|
11613
|
+
return result;
|
|
11614
|
+
};
|
|
11615
|
+
const overlayCoverage = overlayPlaneCoverageRows(size.rows);
|
|
11616
|
+
const overlayVisibleSpans = overlayVisibleSpansForRows(overlayCoverage.blockedRows);
|
|
9510
11617
|
let rowsToRender = (() => {
|
|
11618
|
+
if (allowGraphicsOnlyWithoutBaseline) return [];
|
|
9511
11619
|
if (forceFullRender || !fpPrevValid) return null;
|
|
9512
11620
|
if (!dirtyRows) return null;
|
|
9513
11621
|
if (dirtyRows.length === 0) return [];
|
|
@@ -9529,7 +11637,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9529
11637
|
if (!sorted) outRows.sort((a, b) => a - b);
|
|
9530
11638
|
return outRows;
|
|
9531
11639
|
})();
|
|
9532
|
-
if ((rowsToRender === null || rowsToRender === void 0 ? void 0 : rowsToRender.length) === 0 && !normalizedScrollOperations && !getImeAnchor) {
|
|
11640
|
+
if ((rowsToRender === null || rowsToRender === void 0 ? void 0 : rowsToRender.length) === 0 && !normalizedScrollOperations && !getImeAnchor && graphicsClearsToRender.length === 0 && graphicsToRender.length === 0) {
|
|
9533
11641
|
if (isDebugEnabled()) getDebugLog().render(" No valid dirty rows; frame skipped");
|
|
9534
11642
|
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutNoOutput();
|
|
9535
11643
|
return;
|
|
@@ -9548,10 +11656,13 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9548
11656
|
currentHrefIds.set(prevHrefIds);
|
|
9549
11657
|
currentTextIds.set(prevTextIds);
|
|
9550
11658
|
}
|
|
11659
|
+
const frameHasTerminalGraphics = activeGraphics.size > 0 || graphicsClearsToRender.length > 0 || graphicsToRender.length > 0;
|
|
11660
|
+
const useFrameSyncOutput = useSyncOutput || isGhostty && frameHasTerminalGraphics;
|
|
9551
11661
|
const frameParts = [];
|
|
9552
|
-
frameParts.push(
|
|
9553
|
-
frameParts.push("\x1B[?7l");
|
|
11662
|
+
frameParts.push(useFrameSyncOutput ? SYNC_START : "");
|
|
11663
|
+
frameParts.push(allowGraphicsOnlyWithoutBaseline || keepLineWrapDisabled ? "" : "\x1B[?7l");
|
|
9554
11664
|
frameParts.push(SGR_RESET, bgSeq);
|
|
11665
|
+
if (hideCursor && !getImeAnchor) frameParts.push(CURSOR_HOME);
|
|
9555
11666
|
let lastRenderedY = -1;
|
|
9556
11667
|
let lastRenderWasFullRow = false;
|
|
9557
11668
|
let hasFrameOutput = false;
|
|
@@ -9566,6 +11677,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9566
11677
|
inverse: false,
|
|
9567
11678
|
href: null
|
|
9568
11679
|
};
|
|
11680
|
+
let overlayTouchedRowSet = null;
|
|
9569
11681
|
const closeActiveHrefBeforeCursorMove = () => {
|
|
9570
11682
|
if (!enableOsc8Links || !activeStyle.href) return;
|
|
9571
11683
|
frameParts.push(OSC8_CLOSE);
|
|
@@ -9668,6 +11780,65 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9668
11780
|
lastRenderedY = y;
|
|
9669
11781
|
lastRenderWasFullRow = spanStart === 0 && (spanEnd >= size.cols || shouldClearToEol);
|
|
9670
11782
|
};
|
|
11783
|
+
const overlayBypassSpansForRow = (y) => {
|
|
11784
|
+
const current = overlayVisibleSpans.get(y) ?? [];
|
|
11785
|
+
const previous = prevOverlayVisibleSpans.get(y) ?? [];
|
|
11786
|
+
return current.length || previous.length ? mergeSpans([...current, ...previous]) : [];
|
|
11787
|
+
};
|
|
11788
|
+
const subtractSpans = (spans, bypass) => {
|
|
11789
|
+
if (!bypass.length) return [...spans];
|
|
11790
|
+
const result = [];
|
|
11791
|
+
for (const span of spans) {
|
|
11792
|
+
let cursor = span.start;
|
|
11793
|
+
for (const cut of bypass) {
|
|
11794
|
+
if (cut.end <= cursor) continue;
|
|
11795
|
+
if (cut.start >= span.end) break;
|
|
11796
|
+
if (cursor < cut.start) result.push({
|
|
11797
|
+
start: cursor,
|
|
11798
|
+
end: Math.min(cut.start, span.end)
|
|
11799
|
+
});
|
|
11800
|
+
cursor = Math.max(cursor, cut.end);
|
|
11801
|
+
if (cursor >= span.end) break;
|
|
11802
|
+
}
|
|
11803
|
+
if (cursor < span.end) result.push({
|
|
11804
|
+
start: cursor,
|
|
11805
|
+
end: span.end
|
|
11806
|
+
});
|
|
11807
|
+
}
|
|
11808
|
+
return result;
|
|
11809
|
+
};
|
|
11810
|
+
const preserveFingerprintSpans = (y, spans) => {
|
|
11811
|
+
if (!fpPrevValid || y < 0 || y >= fpRows || currentFP.length !== prevFP.length) return;
|
|
11812
|
+
const base = y * fpCols;
|
|
11813
|
+
for (const span of spans) {
|
|
11814
|
+
const start = Math.max(0, Math.min(fpCols, span.start));
|
|
11815
|
+
const end = Math.max(start, Math.min(fpCols, span.end));
|
|
11816
|
+
for (let x = start; x < end; x++) {
|
|
11817
|
+
currentFP[base + x] = prevFP[base + x];
|
|
11818
|
+
currentHrefIds[base + x] = prevHrefIds[base + x];
|
|
11819
|
+
currentTextIds[base + x] = prevTextIds[base + x];
|
|
11820
|
+
}
|
|
11821
|
+
}
|
|
11822
|
+
};
|
|
11823
|
+
const renderRowPreservingTerminalGraphics = (y, row) => {
|
|
11824
|
+
const spans = terminalGraphicTextPreserveSpans.get(y);
|
|
11825
|
+
if (!(spans === null || spans === void 0 ? void 0 : spans.length)) {
|
|
11826
|
+
renderRow(y, row);
|
|
11827
|
+
return;
|
|
11828
|
+
}
|
|
11829
|
+
const effectiveSpans = subtractSpans(spans, overlayBypassSpansForRow(y));
|
|
11830
|
+
if (!effectiveSpans.length) {
|
|
11831
|
+
renderRow(y, row);
|
|
11832
|
+
return;
|
|
11833
|
+
}
|
|
11834
|
+
let cursor = 0;
|
|
11835
|
+
for (const span of effectiveSpans) {
|
|
11836
|
+
if (cursor < span.start) renderRow(y, row, cursor, span.start, false);
|
|
11837
|
+
cursor = Math.max(cursor, span.end);
|
|
11838
|
+
}
|
|
11839
|
+
if (cursor < size.cols) renderRow(y, row, cursor, size.cols, false);
|
|
11840
|
+
preserveFingerprintSpans(y, effectiveSpans);
|
|
11841
|
+
};
|
|
9671
11842
|
const lastRenderableColumnInCurrentRow = (rowY, cols, blankFingerprint) => {
|
|
9672
11843
|
if (!fpCols || rowY < 0 || rowY >= fpRows) return -1;
|
|
9673
11844
|
const base = rowY * fpCols;
|
|
@@ -9732,16 +11903,15 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9732
11903
|
} else for (const span of spansToPaint) renderRow(rowY, row, span.startX, span.endXExclusive, false);
|
|
9733
11904
|
if (clearStartX != null && !paintTailInsteadOfEscK) renderRow(rowY, row, clearStartX, clearStartX, true);
|
|
9734
11905
|
};
|
|
9735
|
-
const overlayCoverage = overlayPlaneCoverageRows(size.rows);
|
|
9736
11906
|
const overlayRows = Array.from(new Set([...overlayCoverage.blockedRows, ...prevOverlayBlockedRows])).sort((a, b) => a - b);
|
|
9737
11907
|
const overlayRowSet = overlayRows.length ? new Set(overlayRows) : null;
|
|
9738
11908
|
const overlayPartialRows = Array.from(new Set([...overlayCoverage.partialRows, ...prevOverlayPartialRows])).sort((a, b) => a - b);
|
|
9739
11909
|
const overlayPartialRowSet = overlayPartialRows.length ? new Set(overlayPartialRows) : null;
|
|
9740
|
-
|
|
11910
|
+
overlayTouchedRowSet = (() => {
|
|
9741
11911
|
if (!overlayRowSet && !overlayPartialRowSet) return null;
|
|
9742
11912
|
return new Set([...overlayRowSet ? Array.from(overlayRowSet) : [], ...overlayPartialRowSet ? Array.from(overlayPartialRowSet) : []]);
|
|
9743
11913
|
})();
|
|
9744
|
-
let explicitScrollOperations = normalizedScrollOperations;
|
|
11914
|
+
let explicitScrollOperations = terminalGraphicsBlockScrollRegions ? null : normalizedScrollOperations;
|
|
9745
11915
|
let hiddenExplicitDirtyRows = null;
|
|
9746
11916
|
let allowInferredScrollRegions = true;
|
|
9747
11917
|
if (explicitScrollOperations && overlayRows.length) {
|
|
@@ -9756,6 +11926,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9756
11926
|
for (const op of explicitScrollOperations) for (let y = op.startY; y < op.endY; y++) expandedRows$1.add(y);
|
|
9757
11927
|
rowsToRender = Array.from(expandedRows$1).sort((a, b) => a - b);
|
|
9758
11928
|
dirtySorted = true;
|
|
11929
|
+
forceDirtyRowsRepaintForFrame = true;
|
|
9759
11930
|
explicitScrollOperations = null;
|
|
9760
11931
|
hiddenExplicitDirtyRows = null;
|
|
9761
11932
|
if (isDebugEnabled()) getDebugLog().render(preparedExplicit.blockedInterior ? " Explicit scroll ops split by interior overlay rows; falling back to region repaint" : " Explicit scroll ops could not be clipped safely; falling back to region repaint");
|
|
@@ -9770,10 +11941,18 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9770
11941
|
expandedRows.add(y);
|
|
9771
11942
|
}
|
|
9772
11943
|
};
|
|
11944
|
+
if (terminalGraphicsBlockScrollRegions && normalizedScrollOperations && rowsToRender) {
|
|
11945
|
+
includeRowsForPendingScrollOperations(normalizedScrollOperations);
|
|
11946
|
+
rowsToRender = Array.from(expandedRows).sort((a, b) => a - b);
|
|
11947
|
+
dirtySorted = true;
|
|
11948
|
+
forceDirtyRowsRepaintForFrame = true;
|
|
11949
|
+
if (isDebugEnabled()) getDebugLog().render(" Scroll regions disabled for frame with active/pending terminal graphics");
|
|
11950
|
+
}
|
|
9773
11951
|
if (explicitScrollOperations && rowsToRender && (!enableScrollRegions || !fpPrevValid)) {
|
|
9774
11952
|
includeRowsForPendingScrollOperations(explicitScrollOperations);
|
|
9775
11953
|
rowsToRender = Array.from(expandedRows).sort((a, b) => a - b);
|
|
9776
11954
|
dirtySorted = true;
|
|
11955
|
+
forceDirtyRowsRepaintForFrame = true;
|
|
9777
11956
|
explicitScrollOperations = null;
|
|
9778
11957
|
hiddenExplicitDirtyRows = null;
|
|
9779
11958
|
if (isDebugEnabled()) getDebugLog().render(enableScrollRegions ? " Explicit scroll ops fell back to region repaint because previous fingerprints are unavailable" : " Explicit scroll ops fell back to region repaint because scroll regions are disabled");
|
|
@@ -9781,7 +11960,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9781
11960
|
const denseDirtyRows = Boolean(rowsToRender && size.rows > 1 && rowsToRender.length >= size.rows * dirtyFullThreshold);
|
|
9782
11961
|
if (denseDirtyRows) rowsToRender = null;
|
|
9783
11962
|
let profiledRowCount = rowsToRender ? rowsToRender.length : size.rows;
|
|
9784
|
-
const useScrollRegions = enableScrollRegions && fpPrevValid && scrollRowsCandidate && scrollRowsCandidate.length >= 3 && !forceDirtyRowsRepaint && allowInferredScrollRegions;
|
|
11963
|
+
const useScrollRegions = !terminalGraphicsBlockScrollRegions && enableScrollRegions && fpPrevValid && scrollRowsCandidate && scrollRowsCandidate.length >= 3 && !forceDirtyRowsRepaint && allowInferredScrollRegions;
|
|
9785
11964
|
let scrollHandled = false;
|
|
9786
11965
|
if (enableScrollRegions && explicitScrollOperations && scrollRowsCandidate && fpPrevValid) {
|
|
9787
11966
|
if (currentFP.length === prevFP.length) {
|
|
@@ -9856,9 +12035,9 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9856
12035
|
for (const y of explicitDirtyRows) {
|
|
9857
12036
|
const row = terminal.getRow(y);
|
|
9858
12037
|
const overlayRow = overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y);
|
|
9859
|
-
if (
|
|
12038
|
+
if (forceTerminalGraphicsRowRepaint(y) || !shouldUseDirtySpans() || overlayRow) {
|
|
9860
12039
|
fingerprintRow(row, y, size.cols);
|
|
9861
|
-
|
|
12040
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9862
12041
|
paintedExplicitRows.push(y);
|
|
9863
12042
|
continue;
|
|
9864
12043
|
}
|
|
@@ -9935,12 +12114,12 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9935
12114
|
for (let y = shift.newRowStart; y < shift.newRowEnd; y++) {
|
|
9936
12115
|
const row = terminal.getRow(y);
|
|
9937
12116
|
fingerprintRow(row, y, size.cols);
|
|
9938
|
-
|
|
12117
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9939
12118
|
}
|
|
9940
12119
|
const extraDirtyRows = overlayRowSet ? shift.extraDirtyRows.filter((y) => !overlayRowSet.has(y) || Boolean(overlayPartialRowSet === null || overlayPartialRowSet === void 0 ? void 0 : overlayPartialRowSet.has(y))) : shift.extraDirtyRows;
|
|
9941
12120
|
for (const y of extraDirtyRows) {
|
|
9942
12121
|
const row = terminal.getRow(y);
|
|
9943
|
-
if (shouldUseDirtySpans()) {
|
|
12122
|
+
if (!forceTerminalGraphicsRowRepaint(y) && shouldUseDirtySpans()) {
|
|
9944
12123
|
const spans = resolveChangedSpansAgainstReference(row, y, size.cols, currentFP, currentHrefIds, currentTextIds);
|
|
9945
12124
|
if (!spans.length) {
|
|
9946
12125
|
fingerprintRow(row, y, size.cols);
|
|
@@ -9952,7 +12131,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9952
12131
|
continue;
|
|
9953
12132
|
}
|
|
9954
12133
|
fingerprintRow(row, y, size.cols);
|
|
9955
|
-
|
|
12134
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9956
12135
|
}
|
|
9957
12136
|
for (let y = shift.newRowStart; y < shift.newRowEnd; y++) fingerprintRow(terminal.getRow(y), y, size.cols);
|
|
9958
12137
|
const renderedRows = new Set();
|
|
@@ -9972,7 +12151,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9972
12151
|
for (let y = 0; y < size.rows; y++) {
|
|
9973
12152
|
const row = terminal.getRow(y);
|
|
9974
12153
|
fingerprintRow(row, y, size.cols);
|
|
9975
|
-
|
|
12154
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9976
12155
|
}
|
|
9977
12156
|
} else {
|
|
9978
12157
|
const overlayDirtyRows = overlayTouchedRowSet ? rowsToRender.filter((y) => overlayTouchedRowSet.has(y)) : [];
|
|
@@ -9980,8 +12159,8 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9980
12159
|
for (const y of rowsToRender) {
|
|
9981
12160
|
const row = terminal.getRow(y);
|
|
9982
12161
|
fingerprintRow(row, y, size.cols);
|
|
9983
|
-
if (
|
|
9984
|
-
|
|
12162
|
+
if (forceTerminalGraphicsRowRepaint(y) || !shouldUseDirtySpans()) {
|
|
12163
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9985
12164
|
continue;
|
|
9986
12165
|
}
|
|
9987
12166
|
const spans = resolveChangedSpans(row, y, size.cols, (dirtyRowSnapshots === null || dirtyRowSnapshots === void 0 ? void 0 : dirtyRowSnapshots.get(y)) ?? null);
|
|
@@ -9990,7 +12169,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9990
12169
|
renderDirtySpans(y, row, spans, rewriteTail);
|
|
9991
12170
|
}
|
|
9992
12171
|
}
|
|
9993
|
-
if (!rowsToRender && lastRenderedRows > size.rows) {
|
|
12172
|
+
if (!rowsToRender && lastRenderedRows > size.rows && !rowsOnlyResizeBaseline) {
|
|
9994
12173
|
const extraRows = lastRenderedRows - size.rows;
|
|
9995
12174
|
if (activeStyleKey !== bgKey) {
|
|
9996
12175
|
frameParts.push(SGR_RESET, bgSeq);
|
|
@@ -10001,7 +12180,8 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10001
12180
|
frameParts.push(rowClearToEol[size.rows + i]);
|
|
10002
12181
|
}
|
|
10003
12182
|
}
|
|
10004
|
-
const nextLastRenderedRows = !rowsToRender ? size.rows : lastRenderedRows;
|
|
12183
|
+
const nextLastRenderedRows = !rowsToRender || rowsToRender.length === 0 ? size.rows : lastRenderedRows;
|
|
12184
|
+
const graphicsOnlyFrame = Boolean(rowsToRender && rowsToRender.length === 0) && !scrollHandled && (graphicsClearsToRender.length > 0 || graphicsToRender.length > 0);
|
|
10005
12185
|
const commitRenderBaseline = () => {
|
|
10006
12186
|
lastRenderedRows = nextLastRenderedRows;
|
|
10007
12187
|
const tmpFP = prevFP;
|
|
@@ -10013,10 +12193,258 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10013
12193
|
const tmpTextIds = prevTextIds;
|
|
10014
12194
|
prevTextIds = currentTextIds;
|
|
10015
12195
|
currentTextIds = tmpTextIds;
|
|
10016
|
-
fpPrevValid = !hrefIndexResetRequiresBaseline && !fingerprintInternResetRequiresBaseline;
|
|
12196
|
+
fpPrevValid = graphicsOnlyFrame ? fpPrevValid : !hrefIndexResetRequiresBaseline && !fingerprintInternResetRequiresBaseline;
|
|
10017
12197
|
prevOverlayBlockedRows = overlayCoverage.blockedRows;
|
|
10018
12198
|
prevOverlayPartialRows = overlayCoverage.partialRows;
|
|
12199
|
+
prevOverlayVisibleSpans = overlayVisibleSpans;
|
|
12200
|
+
};
|
|
12201
|
+
if (graphicsOnlyFrame && fpPrevValid && currentFP.length === prevFP.length) {
|
|
12202
|
+
currentFP.set(prevFP);
|
|
12203
|
+
currentHrefIds.set(prevHrefIds);
|
|
12204
|
+
currentTextIds.set(prevTextIds);
|
|
12205
|
+
}
|
|
12206
|
+
let renderedRowsLookup;
|
|
12207
|
+
const rowWasPaintedByTextRenderer = (y) => {
|
|
12208
|
+
if (scrollHandled) return true;
|
|
12209
|
+
if (!rowsToRender) return true;
|
|
12210
|
+
renderedRowsLookup ??= new Set(rowsToRender);
|
|
12211
|
+
return renderedRowsLookup.has(y);
|
|
10019
12212
|
};
|
|
12213
|
+
const clearGraphicRectForRowsNotPainted = (rect) => {
|
|
12214
|
+
if (scrollHandled) return "";
|
|
12215
|
+
const erase = `\u001B[${Math.max(0, rect.w)}X`;
|
|
12216
|
+
const clearStyle = bgSeq;
|
|
12217
|
+
let out$1 = "";
|
|
12218
|
+
for (let row = 0; row < rect.h; row++) {
|
|
12219
|
+
const y = rect.y + row;
|
|
12220
|
+
const spans = terminalGraphicTextPreserveSpans.get(y);
|
|
12221
|
+
const preservedGraphicSpan = !(overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y)) && Boolean(spans === null || spans === void 0 ? void 0 : spans.some((span) => span.start < rect.x + rect.w && span.end > rect.x));
|
|
12222
|
+
if ((!rowsToRender || rowWasPaintedByTextRenderer(y)) && !preservedGraphicSpan) continue;
|
|
12223
|
+
out$1 += `\u001B[${y + 1};${rect.x + 1}H${clearStyle}${erase}${SGR_RESET}`;
|
|
12224
|
+
}
|
|
12225
|
+
return out$1;
|
|
12226
|
+
};
|
|
12227
|
+
const clearGraphicRowBackgroundForRowsNotPainted = (rect) => {
|
|
12228
|
+
if (scrollHandled) return "";
|
|
12229
|
+
const clearStyle = bgSeq;
|
|
12230
|
+
let out$1 = "";
|
|
12231
|
+
const leftW = Math.max(0, Math.min(size.cols, rect.x));
|
|
12232
|
+
const rightX = Math.max(0, Math.min(size.cols, rect.x + rect.w));
|
|
12233
|
+
const rightW = Math.max(0, size.cols - rightX);
|
|
12234
|
+
if (leftW <= 0 && rightW <= 0) return "";
|
|
12235
|
+
for (let row = 0; row < rect.h; row++) {
|
|
12236
|
+
const y = rect.y + row;
|
|
12237
|
+
if (!rowsToRender || rowWasPaintedByTextRenderer(y)) continue;
|
|
12238
|
+
if (leftW > 0) out$1 += `\u001B[${y + 1};1H${clearStyle}\u001B[${leftW}X${SGR_RESET}`;
|
|
12239
|
+
if (rightW > 0) out$1 += `\u001B[${y + 1};${rightX + 1}H${clearStyle}\u001B[${rightW}X${SGR_RESET}`;
|
|
12240
|
+
}
|
|
12241
|
+
return out$1;
|
|
12242
|
+
};
|
|
12243
|
+
let commitTerminalGraphicsState = null;
|
|
12244
|
+
let restoreTerminalGraphicsAfterWriteFailure = null;
|
|
12245
|
+
let terminalGraphicsMetrics = null;
|
|
12246
|
+
const mergeGraphicsQueuedDuringPaint = () => {
|
|
12247
|
+
const seenEntries = new Set(graphicsEntriesToRender.map(([key]) => key));
|
|
12248
|
+
let changed = false;
|
|
12249
|
+
for (const entry of pendingGraphics.entries()) {
|
|
12250
|
+
if (seenEntries.has(entry[0])) continue;
|
|
12251
|
+
graphicsEntriesToRender.push(entry);
|
|
12252
|
+
changed = true;
|
|
12253
|
+
}
|
|
12254
|
+
for (const id of pendingGraphicClears) {
|
|
12255
|
+
if (pendingGraphicClearsToRender.has(id)) continue;
|
|
12256
|
+
pendingGraphicClearsToRender.add(id);
|
|
12257
|
+
graphicsClearsToRender.push(id);
|
|
12258
|
+
}
|
|
12259
|
+
if (!changed) return;
|
|
12260
|
+
graphicsEntriesToRender = graphicsEntriesToRender.sort(([, a], [, b]) => {
|
|
12261
|
+
const opA = a.op === "clear" ? 0 : 1;
|
|
12262
|
+
const opB = b.op === "clear" ? 0 : 1;
|
|
12263
|
+
return opA - opB || a.order - b.order;
|
|
12264
|
+
});
|
|
12265
|
+
graphicsToRender = graphicsEntriesToRender.map(([, payload]) => payload);
|
|
12266
|
+
};
|
|
12267
|
+
mergeGraphicsQueuedDuringPaint();
|
|
12268
|
+
if (graphicsClearsToRender.length > 0 || graphicsToRender.length > 0) {
|
|
12269
|
+
const nextActiveGraphics = new Map(activeGraphics);
|
|
12270
|
+
const nextActiveGraphicSignatures = new Map(activeGraphicSignatures);
|
|
12271
|
+
const nextPendingGraphicSignatures = new Map(pendingGraphicSignatures);
|
|
12272
|
+
let terminalGraphicsDraws = 0;
|
|
12273
|
+
let terminalGraphicsClears = 0;
|
|
12274
|
+
let terminalGraphicsBytes = 0;
|
|
12275
|
+
const countGraphicsBytes = (value) => {
|
|
12276
|
+
terminalGraphicsBytes += Buffer.byteLength(value, "utf8");
|
|
12277
|
+
return value;
|
|
12278
|
+
};
|
|
12279
|
+
const appendTerminalGraphicSequenceAt = (sequence, rect, fallbackCell, skipWithoutRect = false) => {
|
|
12280
|
+
if (!rect && skipWithoutRect) return false;
|
|
12281
|
+
const cell = rect ? {
|
|
12282
|
+
x: rect.x,
|
|
12283
|
+
y: rect.y
|
|
12284
|
+
} : clampCellToViewport(fallbackCell, size);
|
|
12285
|
+
frameParts.push(countGraphicsBytes(`\u001B[${cell.y + 1};${cell.x + 1}H`), countGraphicsBytes(maybeWrapTerminalGraphic(sequence)), countGraphicsBytes(SGR_RESET));
|
|
12286
|
+
return true;
|
|
12287
|
+
};
|
|
12288
|
+
const appendActiveGraphicProtocolClear = (active, rect) => {
|
|
12289
|
+
if (!active.clearSequence) return false;
|
|
12290
|
+
return appendTerminalGraphicSequenceAt(active.clearSequence, rect, {
|
|
12291
|
+
cellX: active.x,
|
|
12292
|
+
cellY: active.y
|
|
12293
|
+
}, clearSequenceNeedsVisibleCell(active.clearSequence, active.protocol));
|
|
12294
|
+
};
|
|
12295
|
+
hasFrameOutput = true;
|
|
12296
|
+
if (enableOsc8Links && activeStyle.href) frameParts.push(OSC8_CLOSE);
|
|
12297
|
+
if (allowGraphicsOnlyWithoutBaseline) frameParts.push(CURSOR_SAVE);
|
|
12298
|
+
activeStyle = {
|
|
12299
|
+
fg: null,
|
|
12300
|
+
bg: defaultBg,
|
|
12301
|
+
bold: false,
|
|
12302
|
+
dim: false,
|
|
12303
|
+
italic: false,
|
|
12304
|
+
underline: false,
|
|
12305
|
+
inverse: false,
|
|
12306
|
+
href: null
|
|
12307
|
+
};
|
|
12308
|
+
activeStyleKey = null;
|
|
12309
|
+
frameParts.push(countGraphicsBytes(SGR_RESET));
|
|
12310
|
+
for (const id of graphicsClearsToRender) {
|
|
12311
|
+
const active = nextActiveGraphics.get(id);
|
|
12312
|
+
if (!active) continue;
|
|
12313
|
+
const visibleRect = clipGraphicRectToViewport(active, size);
|
|
12314
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic render active clear: id=${id}, x=${active.x}, y=${active.y}, w=${active.w}, h=${active.h}, visible=${visibleRect ? `${visibleRect.x},${visibleRect.y},${visibleRect.w},${visibleRect.h}` : "none"}`);
|
|
12315
|
+
let wroteClear = false;
|
|
12316
|
+
if (visibleRect) {
|
|
12317
|
+
const clearRect$1 = clearGraphicRectForRowsNotPainted(visibleRect);
|
|
12318
|
+
if (clearRect$1) {
|
|
12319
|
+
frameParts.push(countGraphicsBytes(clearRect$1));
|
|
12320
|
+
wroteClear = true;
|
|
12321
|
+
}
|
|
12322
|
+
}
|
|
12323
|
+
wroteClear = appendActiveGraphicProtocolClear(active, visibleRect) || wroteClear;
|
|
12324
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
12325
|
+
retainedGraphics.delete(id);
|
|
12326
|
+
terminalResizeDirtyGraphics.delete(id);
|
|
12327
|
+
nextActiveGraphics.delete(id);
|
|
12328
|
+
nextActiveGraphicSignatures.delete(id);
|
|
12329
|
+
nextPendingGraphicSignatures.delete(id);
|
|
12330
|
+
}
|
|
12331
|
+
for (const payload of graphicsToRender) {
|
|
12332
|
+
if (payload.op === "clear") {
|
|
12333
|
+
const active = nextActiveGraphics.get(payload.id);
|
|
12334
|
+
const rect$1 = clipGraphicRectToViewport({
|
|
12335
|
+
x: (active === null || active === void 0 ? void 0 : active.x) ?? payload.x,
|
|
12336
|
+
y: (active === null || active === void 0 ? void 0 : active.y) ?? payload.y,
|
|
12337
|
+
w: (active === null || active === void 0 ? void 0 : active.w) ?? payload.w ?? 1,
|
|
12338
|
+
h: (active === null || active === void 0 ? void 0 : active.h) ?? payload.h ?? 1
|
|
12339
|
+
}, size);
|
|
12340
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic render payload clear: id=${payload.id}, x=${(active === null || active === void 0 ? void 0 : active.x) ?? payload.x}, y=${(active === null || active === void 0 ? void 0 : active.y) ?? payload.y}, w=${(active === null || active === void 0 ? void 0 : active.w) ?? payload.w ?? 1}, h=${(active === null || active === void 0 ? void 0 : active.h) ?? payload.h ?? 1}, visible=${rect$1 ? `${rect$1.x},${rect$1.y},${rect$1.w},${rect$1.h}` : "none"}`);
|
|
12341
|
+
const clearRect$2 = rect$1 ? clearGraphicRectForRowsNotPainted(rect$1) : "";
|
|
12342
|
+
let wroteClear = false;
|
|
12343
|
+
if (clearRect$2) {
|
|
12344
|
+
frameParts.push(countGraphicsBytes(clearRect$2));
|
|
12345
|
+
wroteClear = true;
|
|
12346
|
+
}
|
|
12347
|
+
wroteClear = appendTerminalGraphicSequenceAt(payload.sequence, rect$1, {
|
|
12348
|
+
cellX: (active === null || active === void 0 ? void 0 : active.x) ?? payload.x,
|
|
12349
|
+
cellY: (active === null || active === void 0 ? void 0 : active.y) ?? payload.y
|
|
12350
|
+
}, clearSequenceNeedsVisibleCell(payload.sequence, payload.protocol)) || wroteClear;
|
|
12351
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
12352
|
+
if (active && payload.retainOnClear) retainTerminalGraphic(payload.id, active, nextActiveGraphicSignatures.get(payload.id));
|
|
12353
|
+
else retainedGraphics.delete(payload.id);
|
|
12354
|
+
terminalResizeDirtyGraphics.delete(payload.id);
|
|
12355
|
+
nextActiveGraphics.delete(payload.id);
|
|
12356
|
+
nextActiveGraphicSignatures.delete(payload.id);
|
|
12357
|
+
nextPendingGraphicSignatures.delete(payload.id);
|
|
12358
|
+
continue;
|
|
12359
|
+
}
|
|
12360
|
+
const previous = nextActiveGraphics.get(payload.id);
|
|
12361
|
+
const rect = anchoredGraphicRectInViewport({
|
|
12362
|
+
x: payload.x,
|
|
12363
|
+
y: payload.y,
|
|
12364
|
+
w: payload.w ?? 1,
|
|
12365
|
+
h: payload.h ?? 1
|
|
12366
|
+
}, size);
|
|
12367
|
+
if (!rect) {
|
|
12368
|
+
if (previous) {
|
|
12369
|
+
const visiblePrevious = clipGraphicRectToViewport(previous, size);
|
|
12370
|
+
let wroteClear = false;
|
|
12371
|
+
if (visiblePrevious) {
|
|
12372
|
+
const clearPrevious = clearGraphicRectForRowsNotPainted(visiblePrevious);
|
|
12373
|
+
if (clearPrevious) {
|
|
12374
|
+
frameParts.push(countGraphicsBytes(clearPrevious));
|
|
12375
|
+
wroteClear = true;
|
|
12376
|
+
}
|
|
12377
|
+
}
|
|
12378
|
+
wroteClear = appendActiveGraphicProtocolClear(previous, visiblePrevious) || wroteClear;
|
|
12379
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
12380
|
+
retainTerminalGraphic(payload.id, previous, nextActiveGraphicSignatures.get(payload.id), { autoRedrawOnResize: true });
|
|
12381
|
+
nextActiveGraphics.delete(payload.id);
|
|
12382
|
+
nextActiveGraphicSignatures.delete(payload.id);
|
|
12383
|
+
}
|
|
12384
|
+
terminalResizeDirtyGraphics.delete(payload.id);
|
|
12385
|
+
nextPendingGraphicSignatures.delete(payload.id);
|
|
12386
|
+
continue;
|
|
12387
|
+
}
|
|
12388
|
+
const previousSignature = previous ? nextActiveGraphicSignatures.get(payload.id) : void 0;
|
|
12389
|
+
const nextSignature = nextPendingGraphicSignatures.get(payload.id) ?? terminalGraphicsPayloadSignature(payload);
|
|
12390
|
+
const canReplacePlacement = previous != null && payload.resizeRedraw && canReplaceKittyPlacementWithoutClear(previous, payload);
|
|
12391
|
+
const resizeRedrawNeedsClear = previous && (payload.resizeRedraw || payload.terminalResizeRedraw) && Boolean(previous.clearSequence) && !canReplacePlacement;
|
|
12392
|
+
if (previous && (!canReplacePlacement && (previousSignature !== nextSignature || !sameGraphicRect(previous, rect)) || resizeRedrawNeedsClear)) {
|
|
12393
|
+
const visiblePrevious = clipGraphicRectToViewport(previous, size);
|
|
12394
|
+
let wroteClear = false;
|
|
12395
|
+
if (visiblePrevious) {
|
|
12396
|
+
const clearPrevious = clearGraphicRectForRowsNotPainted(visiblePrevious);
|
|
12397
|
+
if (clearPrevious) {
|
|
12398
|
+
frameParts.push(countGraphicsBytes(clearPrevious));
|
|
12399
|
+
wroteClear = true;
|
|
12400
|
+
}
|
|
12401
|
+
}
|
|
12402
|
+
wroteClear = appendActiveGraphicProtocolClear(previous, visiblePrevious) || wroteClear;
|
|
12403
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
12404
|
+
}
|
|
12405
|
+
const visibleRect = clipGraphicRectToViewport(rect, size);
|
|
12406
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic render draw: id=${payload.id}, x=${rect.x}, y=${rect.y}, w=${rect.w}, h=${rect.h}, visible=${visibleRect ? `${visibleRect.x},${visibleRect.y},${visibleRect.w},${visibleRect.h}` : "none"}, resizeRedraw=${payload.resizeRedraw || payload.terminalResizeRedraw ? "true" : "false"}, previous=${previous ? `${previous.x},${previous.y},${previous.w},${previous.h}` : "none"}`);
|
|
12407
|
+
const clearRect$1 = visibleRect ? clearGraphicRectForRowsNotPainted(visibleRect) : "";
|
|
12408
|
+
const clearRowBackground = visibleRect ? clearGraphicRowBackgroundForRowsNotPainted(visibleRect) : "";
|
|
12409
|
+
const cursor = `\u001B[${rect.y + 1};${rect.x + 1}H`;
|
|
12410
|
+
const sequencePayload = (canReplacePlacement || payload.terminalResizeRedraw) && payload.resizeSequence ? payload.resizeSequence : payload.sequence;
|
|
12411
|
+
const sequence = maybeWrapTerminalGraphic(sequencePayload);
|
|
12412
|
+
frameParts.push(countGraphicsBytes(cursor), countGraphicsBytes(sequence), countGraphicsBytes(SGR_RESET), clearRowBackground ? countGraphicsBytes(clearRowBackground) : "", clearRect$1 ? countGraphicsBytes(clearRect$1) : "");
|
|
12413
|
+
terminalGraphicsDraws++;
|
|
12414
|
+
nextActiveGraphics.set(payload.id, {
|
|
12415
|
+
...rect,
|
|
12416
|
+
protocol: payload.protocol,
|
|
12417
|
+
sequence: payload.sequence,
|
|
12418
|
+
resizeSequence: payload.resizeSequence ?? (previous === null || previous === void 0 ? void 0 : previous.resizeSequence),
|
|
12419
|
+
clearSequence: payload.clearSequence
|
|
12420
|
+
});
|
|
12421
|
+
nextActiveGraphicSignatures.set(payload.id, nextSignature);
|
|
12422
|
+
nextPendingGraphicSignatures.delete(payload.id);
|
|
12423
|
+
terminalResizeDirtyGraphics.delete(payload.id);
|
|
12424
|
+
}
|
|
12425
|
+
if (allowGraphicsOnlyWithoutBaseline) frameParts.push(CURSOR_RESTORE);
|
|
12426
|
+
restoreTerminalGraphicsAfterWriteFailure = () => {
|
|
12427
|
+
for (const id of graphicsClearsToRender) pendingGraphicClears.add(id);
|
|
12428
|
+
for (const [key, payload] of graphicsEntriesToRender) pendingGraphics.set(key, payload);
|
|
12429
|
+
};
|
|
12430
|
+
commitTerminalGraphicsState = () => {
|
|
12431
|
+
for (const id of pendingGraphicClearsToRender) pendingGraphicClears.delete(id);
|
|
12432
|
+
for (const [key, payload] of graphicsEntriesToRender) if (pendingGraphics.get(key) === payload) pendingGraphics.delete(key);
|
|
12433
|
+
activeGraphics.clear();
|
|
12434
|
+
for (const [id, active] of nextActiveGraphics) activeGraphics.set(id, active);
|
|
12435
|
+
activeGraphicSignatures.clear();
|
|
12436
|
+
for (const [id, signature] of nextActiveGraphicSignatures) activeGraphicSignatures.set(id, signature);
|
|
12437
|
+
pendingGraphicSignatures.clear();
|
|
12438
|
+
for (const [id, signature] of nextPendingGraphicSignatures) pendingGraphicSignatures.set(id, signature);
|
|
12439
|
+
};
|
|
12440
|
+
terminalGraphicsMetrics = {
|
|
12441
|
+
draws: terminalGraphicsDraws,
|
|
12442
|
+
clears: terminalGraphicsClears,
|
|
12443
|
+
bytes: terminalGraphicsBytes,
|
|
12444
|
+
active: nextActiveGraphics.size
|
|
12445
|
+
};
|
|
12446
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphics frame: draws=${terminalGraphicsDraws}, clears=${terminalGraphicsClears}, bytes=${terminalGraphicsBytes}, activeNext=${nextActiveGraphics.size}`);
|
|
12447
|
+
}
|
|
10020
12448
|
let emittedCursorPos = null;
|
|
10021
12449
|
if (getImeAnchor) {
|
|
10022
12450
|
const anchor = getImeAnchor();
|
|
@@ -10041,8 +12469,9 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10041
12469
|
}
|
|
10042
12470
|
if (enableOsc8Links && activeStyle.href) frameParts.push(OSC8_CLOSE);
|
|
10043
12471
|
frameParts.push(SGR_RESET);
|
|
10044
|
-
frameParts.push(
|
|
10045
|
-
frameParts.push(
|
|
12472
|
+
if (hideCursor && !getImeAnchor) frameParts.push(CURSOR_HOME);
|
|
12473
|
+
frameParts.push(allowGraphicsOnlyWithoutBaseline || keepLineWrapDisabled ? "" : "\x1B[?7h");
|
|
12474
|
+
frameParts.push(useFrameSyncOutput ? SYNC_END : "");
|
|
10046
12475
|
const frame = frameParts.join("");
|
|
10047
12476
|
const frameBytes = Buffer.byteLength(frame, "utf8");
|
|
10048
12477
|
if (profiler) profiler.recordRender({
|
|
@@ -10103,10 +12532,11 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10103
12532
|
const resetCount = countResets(frame);
|
|
10104
12533
|
const buildTime = (performance.now() - renderStart).toFixed(2);
|
|
10105
12534
|
getDebugLog().render(` Frame built: ${frameSize} bytes, ${cursorSeqCount} cursor sequences, ${resetCount} resets, ${buildTime}ms`);
|
|
10106
|
-
getDebugLog().render(` Terminal: ${isGhostty ? "GHOSTTY" : "other"}, useSyncOutput: ${useSyncOutput}`);
|
|
12535
|
+
getDebugLog().render(` Terminal: ${isGhostty ? "GHOSTTY" : "other"}, useSyncOutput: ${useSyncOutput}, useFrameSyncOutput: ${useFrameSyncOutput}`);
|
|
10107
12536
|
}
|
|
10108
12537
|
const writeStart = performance.now();
|
|
10109
12538
|
const resolveWriteMode = (frameSizeBytes) => {
|
|
12539
|
+
if (frameHasTerminalGraphics && frameSizeBytes <= syncMaxBytes) return canUseSyncStdout ? "sync" : "stream";
|
|
10110
12540
|
if (isGhostty) return "chunked";
|
|
10111
12541
|
const preferChunked = frameSizeBytes >= chunkThresholdBytes || writeEmaMs >= 24;
|
|
10112
12542
|
if (preferChunked) return "chunked";
|
|
@@ -10136,12 +12566,15 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10136
12566
|
getDebugLog().render(` Write completed in ${writeTime}ms`);
|
|
10137
12567
|
}
|
|
10138
12568
|
} catch (writeError) {
|
|
12569
|
+
restoreTerminalGraphicsAfterWriteFailure === null || restoreTerminalGraphicsAfterWriteFailure === void 0 || restoreTerminalGraphicsAfterWriteFailure();
|
|
10139
12570
|
if (isDebugEnabled()) getDebugLog().error(`Write ERROR:`, writeError);
|
|
10140
12571
|
try {
|
|
10141
|
-
out.write(`\u001B[?7h${
|
|
12572
|
+
out.write(`\u001B[?7h${useFrameSyncOutput ? SYNC_END : ""}`);
|
|
10142
12573
|
} catch {}
|
|
10143
12574
|
throw writeError;
|
|
10144
12575
|
}
|
|
12576
|
+
commitTerminalGraphicsState === null || commitTerminalGraphicsState === void 0 || commitTerminalGraphicsState();
|
|
12577
|
+
if (terminalGraphicsMetrics) recordStdoutTerminalGraphics(terminalGraphicsMetrics);
|
|
10145
12578
|
commitRenderBaseline();
|
|
10146
12579
|
{
|
|
10147
12580
|
const writeMs = performance.now() - writeStart;
|
|
@@ -10149,6 +12582,9 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10149
12582
|
if (emittedCursorPos) {
|
|
10150
12583
|
lastCursorX = emittedCursorPos.x;
|
|
10151
12584
|
lastCursorY = emittedCursorPos.y;
|
|
12585
|
+
} else if (hideCursor && !getImeAnchor) {
|
|
12586
|
+
lastCursorX = 0;
|
|
12587
|
+
lastCursorY = 0;
|
|
10152
12588
|
} else {
|
|
10153
12589
|
lastCursorX = null;
|
|
10154
12590
|
lastCursorY = null;
|
|
@@ -10315,6 +12751,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10315
12751
|
*/
|
|
10316
12752
|
function render(dirtyRows, sync, scrollOperations) {
|
|
10317
12753
|
if (disposed) return;
|
|
12754
|
+
if (dirtyRows == null || sync) deferGraphicsFlushUntilResizeCommit = false;
|
|
10318
12755
|
if (isDebugEnabled()) getDebugLog().render(`render() called: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}, pending=${pendingRender}, elapsed=${Date.now() - lastFrameTime}ms`);
|
|
10319
12756
|
if (dirtyRows == null) {
|
|
10320
12757
|
accumulatedAllRows = true;
|
|
@@ -10326,7 +12763,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10326
12763
|
accumulatedScrollOperations = null;
|
|
10327
12764
|
} else if (dirtyRows.length === 0) {
|
|
10328
12765
|
if (scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length) mergeScrollOperations(scrollOperations);
|
|
10329
|
-
else if (!accumulatedAllRows && accumulatedDirtyCount === 0 && !getImeAnchor) {
|
|
12766
|
+
else if (!accumulatedAllRows && accumulatedDirtyCount === 0 && !getImeAnchor && !hasPendingTerminalGraphics()) {
|
|
10330
12767
|
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(0);
|
|
10331
12768
|
return;
|
|
10332
12769
|
}
|
|
@@ -10345,8 +12782,8 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10345
12782
|
}
|
|
10346
12783
|
}
|
|
10347
12784
|
}
|
|
10348
|
-
const now$
|
|
10349
|
-
const elapsed = now$
|
|
12785
|
+
const now$3 = Date.now();
|
|
12786
|
+
const elapsed = now$3 - lastFrameTime;
|
|
10350
12787
|
const queuedDelayMs = Math.max(0, MIN_FRAME_MS - elapsed);
|
|
10351
12788
|
if (pendingRender && !sync) {
|
|
10352
12789
|
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(queuedDelayMs);
|
|
@@ -10436,13 +12873,94 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10436
12873
|
} catch {}
|
|
10437
12874
|
}
|
|
10438
12875
|
installFingerprintFn();
|
|
12876
|
+
let suppressNextResizeCommitRender = false;
|
|
12877
|
+
function consumeResizeDirtyState() {
|
|
12878
|
+
suppressNextResizeCommitRender = true;
|
|
12879
|
+
try {
|
|
12880
|
+
terminal.commit({ sync: true });
|
|
12881
|
+
} finally {
|
|
12882
|
+
suppressNextResizeCommitRender = false;
|
|
12883
|
+
}
|
|
12884
|
+
}
|
|
12885
|
+
function clearRowsOnlyResizeRepaintTimer() {
|
|
12886
|
+
if (!rowsOnlyResizeRepaintTimer) return;
|
|
12887
|
+
clearTimeout(rowsOnlyResizeRepaintTimer);
|
|
12888
|
+
rowsOnlyResizeRepaintTimer = null;
|
|
12889
|
+
}
|
|
12890
|
+
function repaintRowsAfterRowsOnlyResize() {
|
|
12891
|
+
if (disposed) return;
|
|
12892
|
+
const { rows } = terminal.size();
|
|
12893
|
+
if (rows <= 0) return;
|
|
12894
|
+
if (isDebugEnabled()) getDebugLog().render(`rows-only resize repaint: rows=${rows}`);
|
|
12895
|
+
preserveNextRowsOnlyResizeBaseline = true;
|
|
12896
|
+
const dirtyRows = Array.from({ length: rows }, (_, y) => y);
|
|
12897
|
+
accumulatedDirtyRowsRequireRepaint = true;
|
|
12898
|
+
deferGraphicsFlushUntilResizeCommit = false;
|
|
12899
|
+
allowNextGraphicsOnlyRenderWithoutBaseline = false;
|
|
12900
|
+
render(dirtyRows, true);
|
|
12901
|
+
}
|
|
12902
|
+
function scheduleRowsOnlyResizeRepaint() {
|
|
12903
|
+
clearRowsOnlyResizeRepaintTimer();
|
|
12904
|
+
if (isDebugEnabled()) getDebugLog().render(`rows-only resize repaint scheduled: delay=${ROWS_ONLY_RESIZE_REPAINT_DELAY_MS}ms`);
|
|
12905
|
+
rowsOnlyResizeRepaintTimer = setTimeout(() => {
|
|
12906
|
+
rowsOnlyResizeRepaintTimer = null;
|
|
12907
|
+
repaintRowsAfterRowsOnlyResize();
|
|
12908
|
+
}, ROWS_ONLY_RESIZE_REPAINT_DELAY_MS);
|
|
12909
|
+
}
|
|
10439
12910
|
if (altScreen && outputIsTTY) out.write("\x1B[?1049h");
|
|
12911
|
+
if (keepLineWrapDisabled) out.write("\x1B[?7l");
|
|
10440
12912
|
if (hideCursor) out.write("\x1B[?25l");
|
|
10441
12913
|
if (clear) out.write(`${SGR_RESET}${openBg(defaultBg)}\u001B[2J\u001B[H${SGR_RESET}`);
|
|
10442
12914
|
const off = terminal.on("commit", ({ dirtyRows, scrollOperations, sync }) => {
|
|
12915
|
+
if (suppressNextResizeCommitRender) return;
|
|
12916
|
+
const deferRowsOnlyResizeCommit = rowsOnlyResizeRepaintTimer && (dirtyRows == null || dirtyRows.length >= terminal.size().rows);
|
|
12917
|
+
if (deferRowsOnlyResizeCommit) {
|
|
12918
|
+
if (isDebugEnabled()) getDebugLog().render(`rows-only resize commit deferred: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}${sync ? " (sync)" : ""}`);
|
|
12919
|
+
scheduleRowsOnlyResizeRepaint();
|
|
12920
|
+
return;
|
|
12921
|
+
}
|
|
10443
12922
|
if (isDebugEnabled()) getDebugLog().render(`Commit event: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}, rows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.join(",")) ?? "all"}${(scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length) ? `, scrollOps=${scrollOperations.map((op) => `${op.startY}-${op.endY - 1}:${op.delta}`).join("|")}` : ""}${sync ? " (sync)" : ""}`);
|
|
10444
12923
|
render(dirtyRows, sync, scrollOperations);
|
|
10445
12924
|
});
|
|
12925
|
+
let terminalResizeCols = terminal.size().cols;
|
|
12926
|
+
let terminalResizeRows = terminal.size().rows;
|
|
12927
|
+
const offTerminalResize = terminal.on("resize", ({ cols, rows }) => {
|
|
12928
|
+
const colsChanged = cols !== terminalResizeCols;
|
|
12929
|
+
const rowsChanged = rows !== terminalResizeRows;
|
|
12930
|
+
const rowsIncreased = rows > terminalResizeRows;
|
|
12931
|
+
terminalResizeCols = cols;
|
|
12932
|
+
terminalResizeRows = rows;
|
|
12933
|
+
if (!colsChanged && !rowsChanged) return;
|
|
12934
|
+
if (pendingRender) {
|
|
12935
|
+
pendingRender = false;
|
|
12936
|
+
if (renderTimer) {
|
|
12937
|
+
clearTimeout(renderTimer);
|
|
12938
|
+
renderTimer = null;
|
|
12939
|
+
}
|
|
12940
|
+
if (isDebugEnabled()) getDebugLog().render("pending stdout render canceled until resize commit");
|
|
12941
|
+
}
|
|
12942
|
+
queueTerminalGraphicsForResizeRedraw({
|
|
12943
|
+
cols,
|
|
12944
|
+
rows
|
|
12945
|
+
});
|
|
12946
|
+
if (!colsChanged) {
|
|
12947
|
+
consumeResizeDirtyState();
|
|
12948
|
+
preserveNextRowsOnlyResizeBaseline = true;
|
|
12949
|
+
if (rowsIncreased) {
|
|
12950
|
+
clearRowsOnlyResizeRepaintTimer();
|
|
12951
|
+
repaintRowsAfterRowsOnlyResize();
|
|
12952
|
+
return;
|
|
12953
|
+
}
|
|
12954
|
+
scheduleRowsOnlyResizeRepaint();
|
|
12955
|
+
if (hasPendingTerminalGraphics()) {
|
|
12956
|
+
deferGraphicsFlushUntilResizeCommit = false;
|
|
12957
|
+
allowNextGraphicsOnlyRenderWithoutBaseline = true;
|
|
12958
|
+
render([], true);
|
|
12959
|
+
}
|
|
12960
|
+
return;
|
|
12961
|
+
}
|
|
12962
|
+
clearRowsOnlyResizeRepaintTimer();
|
|
12963
|
+
});
|
|
10446
12964
|
const resizeSource = (options === null || options === void 0 ? void 0 : options.output) ?? process.stdout;
|
|
10447
12965
|
const canTrackResize = Boolean(trackResize && outputIsTTY && typeof (resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.on) === "function");
|
|
10448
12966
|
const onResize = () => {
|
|
@@ -10450,9 +12968,13 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10450
12968
|
const rows = Number(resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.rows);
|
|
10451
12969
|
if (!Number.isFinite(cols) || !Number.isFinite(rows)) return;
|
|
10452
12970
|
const size = terminal.size();
|
|
12971
|
+
if (isDebugEnabled()) getDebugLog().render(`stdout resize event: output=${cols}x${rows}, terminal=${size.cols}x${size.rows}, trackResize=${trackResize ? "true" : "false"}`);
|
|
10453
12972
|
if (cols === size.cols && rows === size.rows) return;
|
|
12973
|
+
const colsChanged = cols !== size.cols;
|
|
12974
|
+
const rowsChanged = rows !== size.rows;
|
|
10454
12975
|
terminal.resize(cols, rows);
|
|
10455
|
-
|
|
12976
|
+
consumeResizeDirtyState();
|
|
12977
|
+
if (isDebugEnabled()) getDebugLog().render(`stdout resize consumed: target=${cols}x${rows}, colsChanged=${colsChanged ? "true" : "false"}, rowsChanged=${rowsChanged ? "true" : "false"}`);
|
|
10456
12978
|
};
|
|
10457
12979
|
if (canTrackResize) try {
|
|
10458
12980
|
resizeSource.on("resize", onResize);
|
|
@@ -10482,17 +13004,72 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10482
13004
|
function dispose() {
|
|
10483
13005
|
if (disposed) return;
|
|
10484
13006
|
disposed = true;
|
|
13007
|
+
let disposeError = null;
|
|
10485
13008
|
if (renderTimer) {
|
|
10486
13009
|
clearTimeout(renderTimer);
|
|
10487
13010
|
renderTimer = null;
|
|
10488
13011
|
}
|
|
13012
|
+
if (terminalGraphicsFlushTimer) {
|
|
13013
|
+
clearTimeout(terminalGraphicsFlushTimer);
|
|
13014
|
+
terminalGraphicsFlushTimer = null;
|
|
13015
|
+
}
|
|
13016
|
+
clearRowsOnlyResizeRepaintTimer();
|
|
10489
13017
|
accumulatedAllRows = false;
|
|
10490
13018
|
accumulatedDirtyBits = null;
|
|
10491
13019
|
accumulatedDirtyCount = 0;
|
|
10492
13020
|
accumulatedDirtyMin = Number.POSITIVE_INFINITY;
|
|
10493
13021
|
accumulatedDirtyMax = -1;
|
|
10494
13022
|
accumulatedDirtyRowsRequireRepaint = false;
|
|
13023
|
+
pendingGraphics.clear();
|
|
13024
|
+
pendingGraphicClears.clear();
|
|
13025
|
+
pendingGraphicSignatures.clear();
|
|
13026
|
+
retainedGraphics.clear();
|
|
13027
|
+
terminalResizeDirtyGraphics.clear();
|
|
13028
|
+
try {
|
|
13029
|
+
if (activeGraphics.size > 0) {
|
|
13030
|
+
const size = terminal.size();
|
|
13031
|
+
const clearParts = [];
|
|
13032
|
+
let terminalGraphicsClears = 0;
|
|
13033
|
+
for (const active of activeGraphics.values()) {
|
|
13034
|
+
const visibleRect = clipGraphicRectToViewport(active, size);
|
|
13035
|
+
let wroteClear = false;
|
|
13036
|
+
if (visibleRect) {
|
|
13037
|
+
clearParts.push(clearGraphicRect(visibleRect));
|
|
13038
|
+
wroteClear = true;
|
|
13039
|
+
}
|
|
13040
|
+
if (active.clearSequence && (visibleRect || !clearSequenceNeedsVisibleCell(active.clearSequence, active.protocol))) {
|
|
13041
|
+
const cell = visibleRect ? {
|
|
13042
|
+
x: visibleRect.x,
|
|
13043
|
+
y: visibleRect.y
|
|
13044
|
+
} : clampCellToViewport({
|
|
13045
|
+
cellX: active.x,
|
|
13046
|
+
cellY: active.y
|
|
13047
|
+
}, size);
|
|
13048
|
+
clearParts.push(`\u001B[${cell.y + 1};${cell.x + 1}H`, maybeWrapTerminalGraphic(active.clearSequence));
|
|
13049
|
+
wroteClear = true;
|
|
13050
|
+
}
|
|
13051
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
13052
|
+
}
|
|
13053
|
+
activeGraphics.clear();
|
|
13054
|
+
activeGraphicSignatures.clear();
|
|
13055
|
+
if (clearParts.length > 0) {
|
|
13056
|
+
const frame = `${SGR_RESET}${clearParts.join("")}${SGR_RESET}`;
|
|
13057
|
+
out.write(frame);
|
|
13058
|
+
recordStdoutTerminalGraphics({
|
|
13059
|
+
clears: terminalGraphicsClears,
|
|
13060
|
+
bytes: Buffer.byteLength(frame, "utf8"),
|
|
13061
|
+
active: 0
|
|
13062
|
+
});
|
|
13063
|
+
} else recordStdoutTerminalGraphics({ active: 0 });
|
|
13064
|
+
}
|
|
13065
|
+
} catch {
|
|
13066
|
+
activeGraphics.clear();
|
|
13067
|
+
activeGraphicSignatures.clear();
|
|
13068
|
+
recordStdoutTerminalGraphics({ active: 0 });
|
|
13069
|
+
}
|
|
13070
|
+
unregisterGraphicsOutput();
|
|
10495
13071
|
off();
|
|
13072
|
+
offTerminalResize();
|
|
10496
13073
|
releaseFingerprintFn();
|
|
10497
13074
|
if (canTrackResize && typeof (resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.off) === "function") try {
|
|
10498
13075
|
resizeSource.off("resize", onResize);
|
|
@@ -10500,9 +13077,15 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10500
13077
|
else if (canTrackResize && typeof (resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.removeListener) === "function") try {
|
|
10501
13078
|
resizeSource.removeListener("resize", onResize);
|
|
10502
13079
|
} catch {}
|
|
10503
|
-
|
|
10504
|
-
|
|
13080
|
+
try {
|
|
13081
|
+
if (keepLineWrapDisabled) out.write("\x1B[?7h");
|
|
13082
|
+
if (hideCursor) out.write("\x1B[?25h");
|
|
13083
|
+
if (altScreen && outputIsTTY) out.write("\x1B[?1049l");
|
|
13084
|
+
} catch (err) {
|
|
13085
|
+
if (disposeError == null) disposeError = err;
|
|
13086
|
+
}
|
|
10505
13087
|
profiler === null || profiler === void 0 || profiler.dispose();
|
|
13088
|
+
if (disposeError) throw disposeError;
|
|
10506
13089
|
}
|
|
10507
13090
|
const updateTheme = (next) => {
|
|
10508
13091
|
if (disposed) return;
|
|
@@ -10517,10 +13100,12 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10517
13100
|
fpPrevValid = false;
|
|
10518
13101
|
prevOverlayBlockedRows = [];
|
|
10519
13102
|
prevOverlayPartialRows = [];
|
|
13103
|
+
prevOverlayVisibleSpans = new Map();
|
|
10520
13104
|
render();
|
|
10521
13105
|
};
|
|
10522
13106
|
return {
|
|
10523
13107
|
capabilities: STDOUT_RENDERER_CAPABILITIES,
|
|
13108
|
+
graphicsCapabilities,
|
|
10524
13109
|
render,
|
|
10525
13110
|
dispose,
|
|
10526
13111
|
setCursor,
|
|
@@ -10554,4 +13139,4 @@ function createNodeMentionPathProvider() {
|
|
|
10554
13139
|
}
|
|
10555
13140
|
|
|
10556
13141
|
//#endregion
|
|
10557
|
-
export { HEADLESS_RENDERER_CAPABILITIES, STDOUT_RENDERER_CAPABILITIES, createCliEventManager, createDefaultTInputHostAdapter, createNodeMentionPathProvider, createNodePathPickerProvider, createOsc52ClipboardProvider, createStdinDriver, createStdoutRenderer, createTInputHostPlugin, createTerminalApp, defaultTInputHostPlugin, getCliLatencyProfiler, getStdoutRendererMetrics, installNodeFileWriters, installTerminalCleanup, readEventLog, resetNodeFileWriters, resolveUserPath, sanitizeTerminalHref, suggestPaths, writeEventLog, writeSnapshot };
|
|
13142
|
+
export { HEADLESS_RENDERER_CAPABILITIES, STDOUT_RENDERER_CAPABILITIES, createCliEventManager, createDefaultTInputHostAdapter, createIterm2InlineImageSequence, createKittyDeleteGraphicsSequence, createKittyGraphicsSequence, createNodeMentionPathProvider, createNodePathPickerProvider, createOsc52ClipboardProvider, createStdinDriver, createStdoutRenderer, createTInputHostPlugin, createTerminalApp, createTerminalGraphicRenderQueue, defaultTInputHostPlugin, detectTerminalGraphicsCapabilities, getCliLatencyProfiler, getStdoutRendererMetrics, installNodeFileWriters, installTerminalCleanup, readEventLog, resetNodeFileWriters, resolveUserPath, sanitizeTerminalHref, suggestPaths, writeEventLog, writeSnapshot };
|