@simon_he/vue-tui 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -26
- package/dist/TMermaidText-frVr8Ysb.js +885 -0
- package/dist/{TSelect-DR0FomSu.js → TSelect-tJ87rKPM.js} +59 -242
- package/dist/{TTree-kzhlB5P0.js → TTree-CGdE-CYu.js} +138 -102
- 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 +31188 -24907
- package/dist/agent.d.cts +11 -1
- package/dist/agent.d.ts +11 -1
- package/dist/agent.js +516 -11
- package/dist/{block-source-CKUOnkgT.js → block-source-CrlmaBM5.js} +1039 -66
- package/dist/cli/input.d.ts +8 -0
- package/dist/cli/stdin-buffer.d.ts +1 -1
- package/dist/cli/video/ffmpeg-frame-source.d.ts +10 -0
- package/dist/cli/video/png-frame-parser.d.ts +4 -0
- package/dist/cli/video/raw-frame-parser.d.ts +1 -0
- package/dist/cli/video/yt-dlp-frame-source.d.ts +11 -0
- package/dist/cli.cjs +5146 -6767
- package/dist/cli.d.cts +5 -1
- package/dist/cli.d.ts +5 -1
- package/dist/cli.js +2869 -154
- 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 +4 -5
- package/dist/create-terminal-app.d.ts +24 -1
- package/dist/debug-logger-CmsGI4of.js +74 -0
- package/dist/{dom-renderer-BniJSQyX.js → dom-renderer-DXx8fWzD.js} +2 -3
- package/dist/experimental/3d/bun/contributor-avatar-atlas.d.ts +12 -0
- package/dist/experimental/3d/bun/png.d.ts +1 -0
- package/dist/experimental/3d/bun/terminal-badge-scene.d.ts +11 -0
- package/dist/experimental/3d/bun/terminal-badge.wgsl.d.ts +1 -0
- package/dist/experimental/3d/bun/webgpu-renderer.d.ts +26 -0
- package/dist/experimental/3d/bun.cjs +7271 -0
- package/dist/experimental/3d/bun.d.cts +4 -0
- package/dist/experimental/3d/bun.d.ts +4 -0
- package/dist/experimental/3d/bun.js +7390 -0
- package/dist/experimental/video/node.cjs +497 -0
- package/dist/experimental/video/node.d.cts +4 -0
- package/dist/experimental/video/node.d.ts +4 -0
- package/dist/experimental/video/node.js +610 -0
- package/dist/experimental.cjs +6876 -6192
- package/dist/experimental.d.cts +7 -0
- package/dist/experimental.d.ts +7 -0
- package/dist/experimental.js +3005 -9
- package/dist/frame-perf-CHpWhbC4.js +111 -0
- package/dist/{create-terminal-DBFNYr8f.js → hyperlink-_1FAj7Wq.js} +440 -13
- package/dist/index.cjs +5017 -10339
- package/dist/index.js +14 -13
- package/dist/{linkify-D_gzn9Xq.js → linkify-D68T7rdW.js} +193 -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-BNhM1jAZ.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/{wheel-scroll-vBRaQ7p-.js → rect-DUpeDfBg.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 +147 -0
- package/dist/renderer-dom.cjs +364 -903
- package/dist/renderer-dom.js +4 -5
- package/dist/runtime/index.d.ts +2 -0
- package/dist/{runtime-rfcZCyJq.js → runtime-Byf8XXOT.js} +28 -15
- package/dist/runtime.cjs +427 -889
- package/dist/runtime.js +2 -2
- package/dist/terminal-graphics-Bbe83wSr.js +597 -0
- package/dist/{terminal-selection-DBinO6p5.js → terminal-selection-4W1SJj4c.js} +4 -1
- package/dist/{tlog-theme-CvLFNMwk.js → tlog-theme-Bul2Na3u.js} +1237 -12
- package/dist/{trace-CjzYeIxN.js → trace-Bh8WnoMo.js} +5 -0
- package/dist/vue/agent/create-png-terminal-graphic-renderer.d.ts +19 -0
- package/dist/vue/components/T3DViewport.d.ts +473 -0
- package/dist/vue/components/TAgentTerminalGraphic.d.ts +494 -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/TVideo.d.ts +291 -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/video/types.d.ts +39 -0
- package/dist/vue.cjs +7207 -12437
- package/dist/vue.js +704 -38
- package/dist/wheel-scroll-DASkEZr-.js +106 -0
- package/dist/{hyperlink-Bn02UXJb.js → width-GqllnV8C.js} +166 -111
- package/package.json +119 -14
- package/dist/frame-perf-C6Xfg85O.js +0 -24
- package/dist/sgr-BmzxEjAO.js +0 -304
- /package/dist/{ansi-palette-CNXqFciC.js → ansi-palette-CH6jc2Z7.js} +0 -0
- /package/dist/{path-suggest-BNqcuE3-.js → path-suggest-Dndu4dTi.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
|
}
|
|
@@ -2355,10 +2382,8 @@ function createStdinDriver(options) {
|
|
|
2355
2382
|
if (stdout.isTTY) {
|
|
2356
2383
|
let restore = "\x1B[?2004l\x1B[?1004l";
|
|
2357
2384
|
if (keyboardProtocolSequences) restore += keyboardProtocolSequences.disable;
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
restore += enableMouseMotion ? "\x1B[?1000l\x1B[?1003l\x1B[?1006l" : "\x1B[?1000l\x1B[?1002l\x1B[?1006l";
|
|
2361
|
-
}
|
|
2385
|
+
restore += "\x1B[?1007l";
|
|
2386
|
+
restore += enableMouseMotion ? "\x1B[?1000l\x1B[?1003l\x1B[?1006l" : "\x1B[?1000l\x1B[?1002l\x1B[?1006l";
|
|
2362
2387
|
writeTTYSyncOrStream(stdout, restore);
|
|
2363
2388
|
}
|
|
2364
2389
|
};
|
|
@@ -2370,7 +2395,21 @@ function createStdinDriver(options) {
|
|
|
2370
2395
|
signalPolicy: typeof autoCleanup === "object" ? cleanupOptions.signalPolicy ?? "reraise" : "reraise"
|
|
2371
2396
|
});
|
|
2372
2397
|
}
|
|
2373
|
-
|
|
2398
|
+
const setMouseCapture = (enabled) => {
|
|
2399
|
+
if (disposed || !stdout.isTTY) return;
|
|
2400
|
+
if (enabled) {
|
|
2401
|
+
stdout.write("\x1B[?1007h");
|
|
2402
|
+
if (enableMouseMotion) stdout.write("\x1B[?1000h\x1B[?1003h\x1B[?1006h");
|
|
2403
|
+
else stdout.write("\x1B[?1000h\x1B[?1002h\x1B[?1006h");
|
|
2404
|
+
} else {
|
|
2405
|
+
stdout.write("\x1B[?1007l");
|
|
2406
|
+
stdout.write(enableMouseMotion ? "\x1B[?1000l\x1B[?1003l\x1B[?1006l" : "\x1B[?1000l\x1B[?1002l\x1B[?1006l");
|
|
2407
|
+
}
|
|
2408
|
+
};
|
|
2409
|
+
return {
|
|
2410
|
+
dispose,
|
|
2411
|
+
setMouseCapture
|
|
2412
|
+
};
|
|
2374
2413
|
}
|
|
2375
2414
|
|
|
2376
2415
|
//#endregion
|
|
@@ -2649,7 +2688,7 @@ function segmentedGraphemes(text) {
|
|
|
2649
2688
|
|
|
2650
2689
|
//#endregion
|
|
2651
2690
|
//#region src/core/ansi/sgr.ts
|
|
2652
|
-
const ESC$
|
|
2691
|
+
const ESC$2 = "\x1B";
|
|
2653
2692
|
function ansi16ToColorName(code) {
|
|
2654
2693
|
switch (code) {
|
|
2655
2694
|
case 30: return "black";
|
|
@@ -2922,7 +2961,7 @@ function parseAnsiSgr(input, baseStyle = {}) {
|
|
|
2922
2961
|
let style = { ...baseStyle };
|
|
2923
2962
|
let lastIndex = 0;
|
|
2924
2963
|
for (let i = 0; i < input.length; i++) {
|
|
2925
|
-
if (input[i] !== ESC$
|
|
2964
|
+
if (input[i] !== ESC$2 || input[i + 1] !== "[") continue;
|
|
2926
2965
|
let j = i + 2;
|
|
2927
2966
|
while (j < input.length) {
|
|
2928
2967
|
const c = input.charCodeAt(j);
|
|
@@ -2951,17 +2990,131 @@ function parseAnsiSgr(input, baseStyle = {}) {
|
|
|
2951
2990
|
}
|
|
2952
2991
|
|
|
2953
2992
|
//#endregion
|
|
2954
|
-
//#region src/core/buffer/
|
|
2993
|
+
//#region src/core/buffer/eaw-ranges-unicode-17.ts
|
|
2955
2994
|
const fullWidthRanges = [
|
|
2956
2995
|
[4352, 4447],
|
|
2996
|
+
[8986, 8987],
|
|
2957
2997
|
[9001, 9002],
|
|
2958
|
-
[
|
|
2998
|
+
[9193, 9196],
|
|
2999
|
+
[9200, 9200],
|
|
3000
|
+
[9203, 9203],
|
|
3001
|
+
[9725, 9726],
|
|
3002
|
+
[9748, 9749],
|
|
3003
|
+
[9776, 9783],
|
|
3004
|
+
[9800, 9811],
|
|
3005
|
+
[9855, 9855],
|
|
3006
|
+
[9866, 9871],
|
|
3007
|
+
[9875, 9875],
|
|
3008
|
+
[9889, 9889],
|
|
3009
|
+
[9898, 9899],
|
|
3010
|
+
[9917, 9918],
|
|
3011
|
+
[9924, 9925],
|
|
3012
|
+
[9934, 9934],
|
|
3013
|
+
[9940, 9940],
|
|
3014
|
+
[9962, 9962],
|
|
3015
|
+
[9970, 9971],
|
|
3016
|
+
[9973, 9973],
|
|
3017
|
+
[9978, 9978],
|
|
3018
|
+
[9981, 9981],
|
|
3019
|
+
[9989, 9989],
|
|
3020
|
+
[9994, 9995],
|
|
3021
|
+
[10024, 10024],
|
|
3022
|
+
[10060, 10060],
|
|
3023
|
+
[10062, 10062],
|
|
3024
|
+
[10067, 10069],
|
|
3025
|
+
[10071, 10071],
|
|
3026
|
+
[10133, 10135],
|
|
3027
|
+
[10160, 10160],
|
|
3028
|
+
[10175, 10175],
|
|
3029
|
+
[11035, 11036],
|
|
3030
|
+
[11088, 11088],
|
|
3031
|
+
[11093, 11093],
|
|
3032
|
+
[11904, 11929],
|
|
3033
|
+
[11931, 12019],
|
|
3034
|
+
[12032, 12245],
|
|
3035
|
+
[12272, 12350],
|
|
3036
|
+
[12353, 12438],
|
|
3037
|
+
[12441, 12543],
|
|
3038
|
+
[12549, 12591],
|
|
3039
|
+
[12593, 12686],
|
|
3040
|
+
[12688, 12773],
|
|
3041
|
+
[12783, 12830],
|
|
3042
|
+
[12832, 12871],
|
|
3043
|
+
[12880, 42124],
|
|
3044
|
+
[42128, 42182],
|
|
3045
|
+
[43360, 43388],
|
|
2959
3046
|
[44032, 55203],
|
|
2960
3047
|
[63744, 64255],
|
|
2961
3048
|
[65040, 65049],
|
|
2962
|
-
[65072,
|
|
2963
|
-
[
|
|
2964
|
-
[
|
|
3049
|
+
[65072, 65106],
|
|
3050
|
+
[65108, 65126],
|
|
3051
|
+
[65128, 65131],
|
|
3052
|
+
[65281, 65376],
|
|
3053
|
+
[65504, 65510],
|
|
3054
|
+
[94176, 94180],
|
|
3055
|
+
[94192, 94198],
|
|
3056
|
+
[94208, 101589],
|
|
3057
|
+
[101631, 101662],
|
|
3058
|
+
[101760, 101874],
|
|
3059
|
+
[110576, 110579],
|
|
3060
|
+
[110581, 110587],
|
|
3061
|
+
[110589, 110590],
|
|
3062
|
+
[110592, 110882],
|
|
3063
|
+
[110898, 110898],
|
|
3064
|
+
[110928, 110930],
|
|
3065
|
+
[110933, 110933],
|
|
3066
|
+
[110948, 110951],
|
|
3067
|
+
[110960, 111355],
|
|
3068
|
+
[119552, 119638],
|
|
3069
|
+
[119648, 119670],
|
|
3070
|
+
[126980, 126980],
|
|
3071
|
+
[127183, 127183],
|
|
3072
|
+
[127374, 127374],
|
|
3073
|
+
[127377, 127386],
|
|
3074
|
+
[127488, 127490],
|
|
3075
|
+
[127504, 127547],
|
|
3076
|
+
[127552, 127560],
|
|
3077
|
+
[127568, 127569],
|
|
3078
|
+
[127584, 127589],
|
|
3079
|
+
[127744, 127776],
|
|
3080
|
+
[127789, 127797],
|
|
3081
|
+
[127799, 127868],
|
|
3082
|
+
[127870, 127891],
|
|
3083
|
+
[127904, 127946],
|
|
3084
|
+
[127951, 127955],
|
|
3085
|
+
[127968, 127984],
|
|
3086
|
+
[127988, 127988],
|
|
3087
|
+
[127992, 128062],
|
|
3088
|
+
[128064, 128064],
|
|
3089
|
+
[128066, 128252],
|
|
3090
|
+
[128255, 128317],
|
|
3091
|
+
[128331, 128334],
|
|
3092
|
+
[128336, 128359],
|
|
3093
|
+
[128378, 128378],
|
|
3094
|
+
[128405, 128406],
|
|
3095
|
+
[128420, 128420],
|
|
3096
|
+
[128507, 128591],
|
|
3097
|
+
[128640, 128709],
|
|
3098
|
+
[128716, 128716],
|
|
3099
|
+
[128720, 128722],
|
|
3100
|
+
[128725, 128728],
|
|
3101
|
+
[128732, 128735],
|
|
3102
|
+
[128747, 128748],
|
|
3103
|
+
[128756, 128764],
|
|
3104
|
+
[128992, 129003],
|
|
3105
|
+
[129008, 129008],
|
|
3106
|
+
[129292, 129338],
|
|
3107
|
+
[129340, 129349],
|
|
3108
|
+
[129351, 129535],
|
|
3109
|
+
[129648, 129660],
|
|
3110
|
+
[129664, 129674],
|
|
3111
|
+
[129678, 129734],
|
|
3112
|
+
[129736, 129736],
|
|
3113
|
+
[129741, 129756],
|
|
3114
|
+
[129759, 129770],
|
|
3115
|
+
[129775, 129784],
|
|
3116
|
+
[131072, 196605],
|
|
3117
|
+
[196608, 262141]
|
|
2965
3118
|
];
|
|
2966
3119
|
const ambiguousWidthRanges = [
|
|
2967
3120
|
[161, 161],
|
|
@@ -3017,6 +3170,7 @@ const ambiguousWidthRanges = [
|
|
|
3017
3170
|
[728, 731],
|
|
3018
3171
|
[733, 733],
|
|
3019
3172
|
[735, 735],
|
|
3173
|
+
[768, 879],
|
|
3020
3174
|
[913, 929],
|
|
3021
3175
|
[931, 937],
|
|
3022
3176
|
[945, 961],
|
|
@@ -3024,7 +3178,8 @@ const ambiguousWidthRanges = [
|
|
|
3024
3178
|
[1025, 1025],
|
|
3025
3179
|
[1040, 1103],
|
|
3026
3180
|
[1105, 1105],
|
|
3027
|
-
[8208,
|
|
3181
|
+
[8208, 8208],
|
|
3182
|
+
[8211, 8214],
|
|
3028
3183
|
[8216, 8217],
|
|
3029
3184
|
[8220, 8221],
|
|
3030
3185
|
[8224, 8226],
|
|
@@ -3086,7 +3241,8 @@ const ambiguousWidthRanges = [
|
|
|
3086
3241
|
[8895, 8895],
|
|
3087
3242
|
[8978, 8978],
|
|
3088
3243
|
[9312, 9449],
|
|
3089
|
-
[9451,
|
|
3244
|
+
[9451, 9547],
|
|
3245
|
+
[9552, 9587],
|
|
3090
3246
|
[9600, 9615],
|
|
3091
3247
|
[9618, 9621],
|
|
3092
3248
|
[9632, 9633],
|
|
@@ -3112,14 +3268,40 @@ const ambiguousWidthRanges = [
|
|
|
3112
3268
|
[9831, 9834],
|
|
3113
3269
|
[9836, 9837],
|
|
3114
3270
|
[9839, 9839],
|
|
3271
|
+
[9886, 9887],
|
|
3272
|
+
[9919, 9919],
|
|
3273
|
+
[9926, 9933],
|
|
3274
|
+
[9935, 9939],
|
|
3275
|
+
[9941, 9953],
|
|
3276
|
+
[9955, 9955],
|
|
3277
|
+
[9960, 9961],
|
|
3278
|
+
[9963, 9969],
|
|
3279
|
+
[9972, 9972],
|
|
3280
|
+
[9974, 9977],
|
|
3281
|
+
[9979, 9980],
|
|
3282
|
+
[9982, 9983],
|
|
3115
3283
|
[10045, 10045],
|
|
3116
3284
|
[10102, 10111],
|
|
3117
|
-
[11094,
|
|
3285
|
+
[11094, 11097],
|
|
3286
|
+
[12872, 12879],
|
|
3118
3287
|
[57344, 63743],
|
|
3119
|
-
[
|
|
3288
|
+
[65024, 65039],
|
|
3289
|
+
[65533, 65533],
|
|
3290
|
+
[127232, 127242],
|
|
3291
|
+
[127248, 127277],
|
|
3292
|
+
[127280, 127337],
|
|
3293
|
+
[127344, 127373],
|
|
3294
|
+
[127375, 127376],
|
|
3295
|
+
[127387, 127404],
|
|
3296
|
+
[917760, 917999],
|
|
3297
|
+
[983040, 1048573],
|
|
3298
|
+
[1048576, 1114109]
|
|
3120
3299
|
];
|
|
3300
|
+
|
|
3301
|
+
//#endregion
|
|
3302
|
+
//#region src/core/buffer/width.ts
|
|
3121
3303
|
function isFullWidthCodePoint(codePoint) {
|
|
3122
|
-
if (codePoint < 4352
|
|
3304
|
+
if (codePoint < 4352) return false;
|
|
3123
3305
|
for (const [start, end] of fullWidthRanges) {
|
|
3124
3306
|
if (codePoint < start) return false;
|
|
3125
3307
|
if (codePoint <= end) return true;
|
|
@@ -3127,13 +3309,22 @@ function isFullWidthCodePoint(codePoint) {
|
|
|
3127
3309
|
return false;
|
|
3128
3310
|
}
|
|
3129
3311
|
function isAmbiguousWidthCodePoint(codePoint) {
|
|
3130
|
-
|
|
3312
|
+
const first = ambiguousWidthRanges[0];
|
|
3313
|
+
const last = ambiguousWidthRanges[ambiguousWidthRanges.length - 1];
|
|
3314
|
+
if (!first || !last) return false;
|
|
3315
|
+
if (codePoint < first[0] || codePoint > last[1]) return false;
|
|
3131
3316
|
for (const [start, end] of ambiguousWidthRanges) {
|
|
3132
3317
|
if (codePoint < start) return false;
|
|
3133
3318
|
if (codePoint <= end) return true;
|
|
3134
3319
|
}
|
|
3135
3320
|
return false;
|
|
3136
3321
|
}
|
|
3322
|
+
function isVariationSelectorCodePoint(codePoint) {
|
|
3323
|
+
return codePoint >= 65024 && codePoint <= 65039 || codePoint >= 917760 && codePoint <= 917999;
|
|
3324
|
+
}
|
|
3325
|
+
function isCombiningMarkCodePoint(codePoint) {
|
|
3326
|
+
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;
|
|
3327
|
+
}
|
|
3137
3328
|
function isEmojiLike(codePoint) {
|
|
3138
3329
|
return codePoint >= 127744 && codePoint <= 129791 || codePoint >= 127462 && codePoint <= 127487;
|
|
3139
3330
|
}
|
|
@@ -3168,6 +3359,8 @@ function charCellWidth(text, provider = "default") {
|
|
|
3168
3359
|
const codePoint = text.codePointAt(0);
|
|
3169
3360
|
if (codePoint == null) return 1;
|
|
3170
3361
|
const hasVs16 = text.includes("️");
|
|
3362
|
+
if (isVariationSelectorCodePoint(codePoint) || isCombiningMarkCodePoint(codePoint)) return 1;
|
|
3363
|
+
if (codePoint >= 9472 && codePoint <= 9599) return 1;
|
|
3171
3364
|
if (isFullWidthCodePoint(codePoint)) return 2;
|
|
3172
3365
|
if (provider === "cjk" && isAmbiguousWidthCodePoint(codePoint)) return 2;
|
|
3173
3366
|
if (isEmojiLike(codePoint)) return 2;
|
|
@@ -3601,9 +3794,12 @@ function resizeBuffer(buffer, cols, rows) {
|
|
|
3601
3794
|
const nextCols = Math.max(0, Math.floor(cols));
|
|
3602
3795
|
const nextRows = Math.max(0, Math.floor(rows));
|
|
3603
3796
|
if (nextCols === buffer.cols && nextRows === buffer.rows) return;
|
|
3797
|
+
const prevRows = buffer.rows;
|
|
3798
|
+
const prevDirtyAll = buffer.dirtyAll;
|
|
3799
|
+
const prevDirtyBits = buffer.dirtyBits;
|
|
3604
3800
|
const blank = createBlankCell();
|
|
3605
3801
|
const nextGrid = Array.from({ length: nextRows }, () => Array.from({ length: nextCols }, () => blank));
|
|
3606
|
-
const copyRows = Math.min(
|
|
3802
|
+
const copyRows = Math.min(prevRows, nextRows);
|
|
3607
3803
|
const copyCols = Math.min(buffer.cols, nextCols);
|
|
3608
3804
|
for (let y = 0; y < copyRows; y++) {
|
|
3609
3805
|
const src = getBufferRow(buffer, y);
|
|
@@ -3629,10 +3825,21 @@ function resizeBuffer(buffer, cols, rows) {
|
|
|
3629
3825
|
buffer.cols = nextCols;
|
|
3630
3826
|
buffer.rows = nextRows;
|
|
3631
3827
|
buffer.dirtyBits = new Uint8Array(nextRows);
|
|
3632
|
-
buffer.dirtyCount =
|
|
3633
|
-
buffer.dirtyMin =
|
|
3634
|
-
buffer.dirtyMax =
|
|
3635
|
-
buffer.dirtyAll = nextRows > 0;
|
|
3828
|
+
buffer.dirtyCount = 0;
|
|
3829
|
+
buffer.dirtyMin = Number.POSITIVE_INFINITY;
|
|
3830
|
+
buffer.dirtyMax = -1;
|
|
3831
|
+
buffer.dirtyAll = prevDirtyAll && nextRows > 0;
|
|
3832
|
+
if (buffer.dirtyAll) {
|
|
3833
|
+
buffer.dirtyCount = nextRows;
|
|
3834
|
+
buffer.dirtyMin = 0;
|
|
3835
|
+
buffer.dirtyMax = nextRows - 1;
|
|
3836
|
+
} else for (let y = 0; y < copyRows; y++) {
|
|
3837
|
+
if (prevDirtyBits[y] !== 1) continue;
|
|
3838
|
+
buffer.dirtyBits[y] = 1;
|
|
3839
|
+
buffer.dirtyCount++;
|
|
3840
|
+
if (y < buffer.dirtyMin) buffer.dirtyMin = y;
|
|
3841
|
+
if (y > buffer.dirtyMax) buffer.dirtyMax = y;
|
|
3842
|
+
}
|
|
3636
3843
|
buffer.cursorX = clamp(buffer.cursorX, 0, Math.max(0, nextCols));
|
|
3637
3844
|
buffer.cursorY = clamp(buffer.cursorY, 0, Math.max(0, nextRows - 1));
|
|
3638
3845
|
if (buffer.fingerprintFn) {
|
|
@@ -3705,6 +3912,10 @@ function mergePlanes(prev, next) {
|
|
|
3705
3912
|
return Array.from(merged);
|
|
3706
3913
|
}
|
|
3707
3914
|
const TERMINAL_PLANE_INTERNALS = Symbol.for("@simon_he/vue-tui:v1:terminal-plane-internals");
|
|
3915
|
+
const TERMINAL_ROOT = Symbol.for("@simon_he/vue-tui:v1:terminal-root");
|
|
3916
|
+
function getRootTerminal(terminal) {
|
|
3917
|
+
return terminal[TERMINAL_ROOT] ?? terminal;
|
|
3918
|
+
}
|
|
3708
3919
|
function createCoverage(cols, rows) {
|
|
3709
3920
|
return Array.from({ length: rows }, () => new Uint8Array(cols));
|
|
3710
3921
|
}
|
|
@@ -3789,6 +4000,8 @@ function markPlaneCoverageRange(state, x0, y0, x1, y1, value) {
|
|
|
3789
4000
|
}
|
|
3790
4001
|
}
|
|
3791
4002
|
function markPlaneCoverageForPut(state, x, y, ch, prevCell) {
|
|
4003
|
+
if (!Number.isSafeInteger(x) || !Number.isSafeInteger(y)) return;
|
|
4004
|
+
if (x < 0 || x >= state.buffer.cols || y < 0 || y >= state.buffer.rows) return;
|
|
3792
4005
|
const row = state.coverage[y];
|
|
3793
4006
|
if (!row) return;
|
|
3794
4007
|
if ((prevCell === null || prevCell === void 0 ? void 0 : prevCell.continuation) && x > 0) row[x - 1] = 1;
|
|
@@ -3912,10 +4125,14 @@ function createTerminal(opts) {
|
|
|
3912
4125
|
}
|
|
3913
4126
|
function putForPlane(plane, x, y, ch, style) {
|
|
3914
4127
|
const state = getPlaneState(plane);
|
|
3915
|
-
if (
|
|
3916
|
-
const
|
|
3917
|
-
|
|
3918
|
-
|
|
4128
|
+
if (typeof x !== "number" || typeof y !== "number") return;
|
|
4129
|
+
const cellX = Math.floor(x);
|
|
4130
|
+
const cellY = Math.floor(y);
|
|
4131
|
+
if (!Number.isFinite(cellX) || !Number.isFinite(cellY)) return;
|
|
4132
|
+
if (cellY < 0 || cellY >= state.buffer.rows || cellX < 0 || cellX >= state.buffer.cols) return;
|
|
4133
|
+
const prevCell = getBufferCell(state.buffer, cellX, cellY);
|
|
4134
|
+
putCell(state.buffer, cellX, cellY, ch, style);
|
|
4135
|
+
markPlaneCoverageForPut(state, cellX, cellY, ch, prevCell);
|
|
3919
4136
|
}
|
|
3920
4137
|
function writeAtForPlane(plane, text, x, y, style) {
|
|
3921
4138
|
const state = getPlaneState(plane);
|
|
@@ -4419,6 +4636,7 @@ function createTerminal(opts) {
|
|
|
4419
4636
|
return getRowFingerprints(state.buffer, yy);
|
|
4420
4637
|
}
|
|
4421
4638
|
};
|
|
4639
|
+
api[TERMINAL_ROOT] = base;
|
|
4422
4640
|
planeTerminals.set(plane, api);
|
|
4423
4641
|
return api;
|
|
4424
4642
|
}
|
|
@@ -4502,7 +4720,7 @@ function createTerminal(opts) {
|
|
|
4502
4720
|
const rows = collectAndClearDirtyRows(state.buffer);
|
|
4503
4721
|
if (rows === null) {
|
|
4504
4722
|
composeAllRows = true;
|
|
4505
|
-
|
|
4723
|
+
continue;
|
|
4506
4724
|
}
|
|
4507
4725
|
for (const y of rows) dirtyRows.add(y);
|
|
4508
4726
|
}
|
|
@@ -4624,6 +4842,7 @@ function createTerminal(opts) {
|
|
|
4624
4842
|
scrollRowsForPlane(plane, startY, endY, lines);
|
|
4625
4843
|
}
|
|
4626
4844
|
};
|
|
4845
|
+
base[TERMINAL_ROOT] = base;
|
|
4627
4846
|
return base;
|
|
4628
4847
|
}
|
|
4629
4848
|
|
|
@@ -4650,7 +4869,7 @@ function sameRect$1(a, b) {
|
|
|
4650
4869
|
function isVisible(node) {
|
|
4651
4870
|
return node.visible !== false;
|
|
4652
4871
|
}
|
|
4653
|
-
function now() {
|
|
4872
|
+
function now$1() {
|
|
4654
4873
|
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
4655
4874
|
}
|
|
4656
4875
|
function rectRowRange(rect) {
|
|
@@ -4830,7 +5049,7 @@ function createCliEventManager(options) {
|
|
|
4830
5049
|
bubbles: true,
|
|
4831
5050
|
cancelable: true,
|
|
4832
5051
|
defaultPrevented: false,
|
|
4833
|
-
timeStamp: typeof time === "number" ? time : now(),
|
|
5052
|
+
timeStamp: typeof time === "number" ? time : now$1(),
|
|
4834
5053
|
__stopped: false,
|
|
4835
5054
|
stopPropagation() {
|
|
4836
5055
|
this.__stopped = true;
|
|
@@ -5196,6 +5415,94 @@ const FRAME_PERF_REASON_PRIORITY = {
|
|
|
5196
5415
|
scroll: 6,
|
|
5197
5416
|
input: 7
|
|
5198
5417
|
};
|
|
5418
|
+
const EMPTY_METRIC_STATS = Object.freeze({
|
|
5419
|
+
avg: 0,
|
|
5420
|
+
max: 0,
|
|
5421
|
+
min: 0
|
|
5422
|
+
});
|
|
5423
|
+
function metricStats(values) {
|
|
5424
|
+
if (!values.length) return EMPTY_METRIC_STATS;
|
|
5425
|
+
let sum = 0;
|
|
5426
|
+
let max = Number.NEGATIVE_INFINITY;
|
|
5427
|
+
let min = Number.POSITIVE_INFINITY;
|
|
5428
|
+
for (const value of values) {
|
|
5429
|
+
sum += value;
|
|
5430
|
+
if (value > max) max = value;
|
|
5431
|
+
if (value < min) min = value;
|
|
5432
|
+
}
|
|
5433
|
+
return {
|
|
5434
|
+
avg: sum / values.length,
|
|
5435
|
+
max,
|
|
5436
|
+
min
|
|
5437
|
+
};
|
|
5438
|
+
}
|
|
5439
|
+
function summarizeFramePerf(samples) {
|
|
5440
|
+
const durationMs = [];
|
|
5441
|
+
const renderManagerMs = [];
|
|
5442
|
+
const commitMs = [];
|
|
5443
|
+
const domFlushMs = [];
|
|
5444
|
+
const stdoutFlushMs = [];
|
|
5445
|
+
const dirtyRows = [];
|
|
5446
|
+
const scannedNodes = [];
|
|
5447
|
+
const paintedNodes = [];
|
|
5448
|
+
const reasons = {};
|
|
5449
|
+
const activePlanes = {};
|
|
5450
|
+
let fullDirtyFrames = 0;
|
|
5451
|
+
let coalescedInvalidates = 0;
|
|
5452
|
+
let coalescedFrameTasks = 0;
|
|
5453
|
+
let droppedUpdates = 0;
|
|
5454
|
+
let maxQueueDepth = 0;
|
|
5455
|
+
let rowBucketFallbacks = 0;
|
|
5456
|
+
for (const sample of samples) {
|
|
5457
|
+
var _sample$rowBucketFall;
|
|
5458
|
+
durationMs.push(sample.durationMs);
|
|
5459
|
+
renderManagerMs.push(sample.renderManagerMs);
|
|
5460
|
+
commitMs.push(sample.commitMs);
|
|
5461
|
+
scannedNodes.push(sample.scannedNodes);
|
|
5462
|
+
paintedNodes.push(sample.paintedNodes);
|
|
5463
|
+
if (sample.domFlushMs != null) domFlushMs.push(sample.domFlushMs);
|
|
5464
|
+
if (sample.stdoutFlushMs != null) stdoutFlushMs.push(sample.stdoutFlushMs);
|
|
5465
|
+
if (sample.dirtyRows == null) fullDirtyFrames++;
|
|
5466
|
+
else dirtyRows.push(sample.dirtyRows);
|
|
5467
|
+
reasons[sample.reason] = (reasons[sample.reason] ?? 0) + 1;
|
|
5468
|
+
const planes = sample.activePlanes;
|
|
5469
|
+
if (!planes) activePlanes.all = (activePlanes.all ?? 0) + 1;
|
|
5470
|
+
else for (const plane of planes) activePlanes[plane] = (activePlanes[plane] ?? 0) + 1;
|
|
5471
|
+
coalescedInvalidates += sample.coalescedInvalidates;
|
|
5472
|
+
coalescedFrameTasks += sample.coalescedFrameTasks;
|
|
5473
|
+
droppedUpdates += sample.droppedUpdates;
|
|
5474
|
+
if (sample.queueDepth > maxQueueDepth) maxQueueDepth = sample.queueDepth;
|
|
5475
|
+
rowBucketFallbacks += ((_sample$rowBucketFall = sample.rowBucketFallbacks) === null || _sample$rowBucketFall === void 0 ? void 0 : _sample$rowBucketFall.length) ?? 0;
|
|
5476
|
+
}
|
|
5477
|
+
const first = samples[0] ?? null;
|
|
5478
|
+
const latest = samples[samples.length - 1] ?? null;
|
|
5479
|
+
return {
|
|
5480
|
+
frames: samples.length,
|
|
5481
|
+
firstFrameId: (first === null || first === void 0 ? void 0 : first.frameId) ?? null,
|
|
5482
|
+
latestFrameId: (latest === null || latest === void 0 ? void 0 : latest.frameId) ?? null,
|
|
5483
|
+
windowMs: first && latest ? Math.max(0, latest.startedAt - first.startedAt) : 0,
|
|
5484
|
+
durationMs: metricStats(durationMs),
|
|
5485
|
+
renderManagerMs: metricStats(renderManagerMs),
|
|
5486
|
+
commitMs: metricStats(commitMs),
|
|
5487
|
+
domFlushMs: metricStats(domFlushMs),
|
|
5488
|
+
stdoutFlushMs: metricStats(stdoutFlushMs),
|
|
5489
|
+
dirtyRows: {
|
|
5490
|
+
avg: dirtyRows.length ? dirtyRows.reduce((sum, value) => sum + value, 0) / dirtyRows.length : 0,
|
|
5491
|
+
max: dirtyRows.length ? Math.max(...dirtyRows) : 0,
|
|
5492
|
+
sampledFrames: dirtyRows.length,
|
|
5493
|
+
fullFrames: fullDirtyFrames
|
|
5494
|
+
},
|
|
5495
|
+
scannedNodes: metricStats(scannedNodes),
|
|
5496
|
+
paintedNodes: metricStats(paintedNodes),
|
|
5497
|
+
coalescedInvalidates,
|
|
5498
|
+
coalescedFrameTasks,
|
|
5499
|
+
droppedUpdates,
|
|
5500
|
+
maxQueueDepth,
|
|
5501
|
+
rowBucketFallbacks,
|
|
5502
|
+
reasons,
|
|
5503
|
+
activePlanes
|
|
5504
|
+
};
|
|
5505
|
+
}
|
|
5199
5506
|
function framePerfNow() {
|
|
5200
5507
|
const p = globalThis.performance;
|
|
5201
5508
|
if (p && typeof p.now === "function") return p.now();
|
|
@@ -5336,6 +5643,9 @@ function createFramePerfStore(limit = 120, opts) {
|
|
|
5336
5643
|
function list() {
|
|
5337
5644
|
return samples.slice();
|
|
5338
5645
|
}
|
|
5646
|
+
function summary() {
|
|
5647
|
+
return summarizeFramePerf(samples);
|
|
5648
|
+
}
|
|
5339
5649
|
function clear() {
|
|
5340
5650
|
samples.length = 0;
|
|
5341
5651
|
}
|
|
@@ -5348,6 +5658,7 @@ function createFramePerfStore(limit = 120, opts) {
|
|
|
5348
5658
|
addSink,
|
|
5349
5659
|
latest,
|
|
5350
5660
|
list,
|
|
5661
|
+
summary,
|
|
5351
5662
|
clear
|
|
5352
5663
|
};
|
|
5353
5664
|
}
|
|
@@ -5463,6 +5774,9 @@ function clampPointToRect(point, rect) {
|
|
|
5463
5774
|
y: Math.max(rect.y, Math.min(rect.y + Math.max(0, rect.h - 1), Math.floor(point.y)))
|
|
5464
5775
|
};
|
|
5465
5776
|
}
|
|
5777
|
+
function clipboardCanWrite$1(api) {
|
|
5778
|
+
return api.canWrite ?? api.supported;
|
|
5779
|
+
}
|
|
5466
5780
|
function createTerminalSelectionController(options) {
|
|
5467
5781
|
const state = shallowRef(EMPTY_STATE);
|
|
5468
5782
|
let range = null;
|
|
@@ -5664,7 +5978,7 @@ function createTerminalSelectionController(options) {
|
|
|
5664
5978
|
const text = state.value.text || selectedText();
|
|
5665
5979
|
if (!text) return false;
|
|
5666
5980
|
setResolvedText(text);
|
|
5667
|
-
if (!options.clipboard
|
|
5981
|
+
if (!clipboardCanWrite$1(options.clipboard)) {
|
|
5668
5982
|
var _options$onCopy;
|
|
5669
5983
|
(_options$onCopy = options.onCopy) === null || _options$onCopy === void 0 || _options$onCopy.call(options, copyPayload(text, false, new Error("Clipboard unavailable")));
|
|
5670
5984
|
return false;
|
|
@@ -5769,16 +6083,19 @@ function createOsc52ClipboardProvider(options = {}) {
|
|
|
5769
6083
|
var _stdout$write;
|
|
5770
6084
|
stdout === null || stdout === void 0 || (_stdout$write = stdout.write) === null || _stdout$write === void 0 || _stdout$write.call(stdout, sequence);
|
|
5771
6085
|
});
|
|
5772
|
-
const
|
|
6086
|
+
const canWrite = options.supported ?? Boolean(options.write || (stdout === null || stdout === void 0 ? void 0 : stdout.write) && stdout.isTTY);
|
|
6087
|
+
const canRead = typeof options.readText === "function";
|
|
5773
6088
|
const target = normalizeOsc52Target(options.target);
|
|
5774
6089
|
return {
|
|
5775
|
-
supported,
|
|
6090
|
+
supported: canWrite,
|
|
6091
|
+
canRead,
|
|
6092
|
+
canWrite,
|
|
5776
6093
|
async readText() {
|
|
5777
|
-
if (!
|
|
6094
|
+
if (!canRead) throw new Error("Clipboard read not available in this runtime");
|
|
5778
6095
|
return options.readText();
|
|
5779
6096
|
},
|
|
5780
6097
|
async writeText(text) {
|
|
5781
|
-
if (!
|
|
6098
|
+
if (!canWrite) throw new Error("Clipboard not available in this runtime");
|
|
5782
6099
|
const bytes = encodeTextBytes(text);
|
|
5783
6100
|
const maxBytes = resolveMaxBytes(options.maxBytes, 100 * 1024);
|
|
5784
6101
|
if (bytes.byteLength > maxBytes) throw new Error(`OSC52 clipboard payload too large: ${bytes.byteLength} bytes`);
|
|
@@ -6133,6 +6450,120 @@ function normalizeTerminalLinkOpener(opener) {
|
|
|
6133
6450
|
return opener;
|
|
6134
6451
|
}
|
|
6135
6452
|
|
|
6453
|
+
//#endregion
|
|
6454
|
+
//#region src/renderer/terminal-graphics-trace.ts
|
|
6455
|
+
const metrics$1 = {
|
|
6456
|
+
requests: 0,
|
|
6457
|
+
skippedHidden: 0,
|
|
6458
|
+
skippedScrolling: 0,
|
|
6459
|
+
cacheHits: 0,
|
|
6460
|
+
cacheMisses: 0,
|
|
6461
|
+
cacheStores: 0,
|
|
6462
|
+
rendererRuns: 0,
|
|
6463
|
+
rendererAborts: 0,
|
|
6464
|
+
rendererErrors: 0,
|
|
6465
|
+
queued: 0,
|
|
6466
|
+
queueWaits: 0,
|
|
6467
|
+
queueDeduped: 0,
|
|
6468
|
+
cleared: 0,
|
|
6469
|
+
bytesQueued: 0,
|
|
6470
|
+
totalRendererMs: 0,
|
|
6471
|
+
totalValidateMs: 0,
|
|
6472
|
+
totalQueueWaitMs: 0,
|
|
6473
|
+
maxQueueWaitMs: 0,
|
|
6474
|
+
maxActiveRenders: 0,
|
|
6475
|
+
maxWaitingRenders: 0,
|
|
6476
|
+
maxCacheEntries: 0,
|
|
6477
|
+
maxCacheBytes: 0,
|
|
6478
|
+
scrollStarts: 0,
|
|
6479
|
+
scrollMarks: 0,
|
|
6480
|
+
scrollIdles: 0,
|
|
6481
|
+
totalScrollMs: 0,
|
|
6482
|
+
maxScrollMs: 0
|
|
6483
|
+
};
|
|
6484
|
+
const subscribers = new Set();
|
|
6485
|
+
function nowTerminalGraphicTraceTime() {
|
|
6486
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
6487
|
+
}
|
|
6488
|
+
function recordTerminalGraphicTrace(event) {
|
|
6489
|
+
const normalized = {
|
|
6490
|
+
...event,
|
|
6491
|
+
timestamp: event.timestamp ?? nowTerminalGraphicTraceTime()
|
|
6492
|
+
};
|
|
6493
|
+
switch (normalized.type) {
|
|
6494
|
+
case "request":
|
|
6495
|
+
metrics$1.requests++;
|
|
6496
|
+
break;
|
|
6497
|
+
case "skip-hidden":
|
|
6498
|
+
metrics$1.skippedHidden++;
|
|
6499
|
+
break;
|
|
6500
|
+
case "skip-scrolling":
|
|
6501
|
+
metrics$1.skippedScrolling++;
|
|
6502
|
+
break;
|
|
6503
|
+
case "cache-hit":
|
|
6504
|
+
metrics$1.cacheHits++;
|
|
6505
|
+
break;
|
|
6506
|
+
case "cache-miss":
|
|
6507
|
+
metrics$1.cacheMisses++;
|
|
6508
|
+
break;
|
|
6509
|
+
case "cache-store":
|
|
6510
|
+
metrics$1.cacheStores++;
|
|
6511
|
+
break;
|
|
6512
|
+
case "renderer-start":
|
|
6513
|
+
metrics$1.rendererRuns++;
|
|
6514
|
+
break;
|
|
6515
|
+
case "renderer-end":
|
|
6516
|
+
metrics$1.totalRendererMs += normalized.durationMs ?? 0;
|
|
6517
|
+
break;
|
|
6518
|
+
case "renderer-abort":
|
|
6519
|
+
metrics$1.rendererAborts++;
|
|
6520
|
+
break;
|
|
6521
|
+
case "renderer-error":
|
|
6522
|
+
metrics$1.rendererErrors++;
|
|
6523
|
+
break;
|
|
6524
|
+
case "validate-end":
|
|
6525
|
+
metrics$1.totalValidateMs += normalized.durationMs ?? 0;
|
|
6526
|
+
break;
|
|
6527
|
+
case "queue":
|
|
6528
|
+
metrics$1.queued++;
|
|
6529
|
+
metrics$1.bytesQueued += normalized.bytes ?? 0;
|
|
6530
|
+
break;
|
|
6531
|
+
case "queue-wait": {
|
|
6532
|
+
const durationMs = normalized.durationMs ?? 0;
|
|
6533
|
+
metrics$1.queueWaits++;
|
|
6534
|
+
metrics$1.totalQueueWaitMs += durationMs;
|
|
6535
|
+
metrics$1.maxQueueWaitMs = Math.max(metrics$1.maxQueueWaitMs, durationMs);
|
|
6536
|
+
break;
|
|
6537
|
+
}
|
|
6538
|
+
case "queue-dedupe":
|
|
6539
|
+
metrics$1.queueDeduped++;
|
|
6540
|
+
break;
|
|
6541
|
+
case "clear":
|
|
6542
|
+
metrics$1.cleared++;
|
|
6543
|
+
break;
|
|
6544
|
+
case "scroll-start":
|
|
6545
|
+
metrics$1.scrollStarts++;
|
|
6546
|
+
break;
|
|
6547
|
+
case "scroll-mark":
|
|
6548
|
+
metrics$1.scrollMarks++;
|
|
6549
|
+
break;
|
|
6550
|
+
case "scroll-idle": {
|
|
6551
|
+
const durationMs = normalized.durationMs ?? 0;
|
|
6552
|
+
metrics$1.scrollIdles++;
|
|
6553
|
+
metrics$1.totalScrollMs += durationMs;
|
|
6554
|
+
metrics$1.maxScrollMs = Math.max(metrics$1.maxScrollMs, durationMs);
|
|
6555
|
+
break;
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6558
|
+
if (normalized.active != null && Number.isFinite(normalized.active)) metrics$1.maxActiveRenders = Math.max(metrics$1.maxActiveRenders, Math.max(0, normalized.active));
|
|
6559
|
+
if (normalized.waiting != null && Number.isFinite(normalized.waiting)) metrics$1.maxWaitingRenders = Math.max(metrics$1.maxWaitingRenders, Math.max(0, normalized.waiting));
|
|
6560
|
+
if (normalized.cacheEntries != null && Number.isFinite(normalized.cacheEntries)) metrics$1.maxCacheEntries = Math.max(metrics$1.maxCacheEntries, Math.max(0, normalized.cacheEntries));
|
|
6561
|
+
if (normalized.cacheBytes != null && Number.isFinite(normalized.cacheBytes)) metrics$1.maxCacheBytes = Math.max(metrics$1.maxCacheBytes, Math.max(0, normalized.cacheBytes));
|
|
6562
|
+
for (const subscriber of subscribers) try {
|
|
6563
|
+
subscriber(normalized);
|
|
6564
|
+
} catch {}
|
|
6565
|
+
}
|
|
6566
|
+
|
|
6136
6567
|
//#endregion
|
|
6137
6568
|
//#region src/vue/context.ts
|
|
6138
6569
|
const TerminalContextKey = injectionKey("TerminalContext");
|
|
@@ -6143,6 +6574,7 @@ const RenderPlaneContextKey = injectionKey("RenderPlane");
|
|
|
6143
6574
|
const ImeAnchorContextKey = injectionKey("ImeAnchor");
|
|
6144
6575
|
const TInputPluginsContextKey = injectionKey("TInputPlugins");
|
|
6145
6576
|
const TPathPickerProviderContextKey = injectionKey("TPathPickerProvider");
|
|
6577
|
+
const TerminalGraphicsActivityKey = injectionKey("TerminalGraphicsActivity");
|
|
6146
6578
|
const DialogContextKey = injectionKey("DialogContext");
|
|
6147
6579
|
|
|
6148
6580
|
//#endregion
|
|
@@ -6293,6 +6725,10 @@ function sameRect(a, b) {
|
|
|
6293
6725
|
if (!a || !b) return false;
|
|
6294
6726
|
return a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;
|
|
6295
6727
|
}
|
|
6728
|
+
function rectsIntersect(a, b) {
|
|
6729
|
+
if (isEmptyRect(a) || isEmptyRect(b)) return false;
|
|
6730
|
+
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;
|
|
6731
|
+
}
|
|
6296
6732
|
function createRenderManager(terminal, options = {}) {
|
|
6297
6733
|
const widthProvider = options.widthProvider ?? "default";
|
|
6298
6734
|
const withRenderTextPass = (fn) => withTextRenderPass(fn, widthProvider);
|
|
@@ -6300,6 +6736,7 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6300
6736
|
const nodes = new Map();
|
|
6301
6737
|
const planeDirtyStates = new Map();
|
|
6302
6738
|
const initialSize = terminal.size();
|
|
6739
|
+
let terminalCols = initialSize.cols;
|
|
6303
6740
|
let terminalRows = initialSize.rows;
|
|
6304
6741
|
let allRows = Array.from({ length: terminalRows }, (_, index) => index);
|
|
6305
6742
|
let sortedNodes = [];
|
|
@@ -6320,19 +6757,37 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6320
6757
|
let disposed = false;
|
|
6321
6758
|
const stackPathCache = new WeakMap();
|
|
6322
6759
|
const profiler = createTuiProfiler("render-manager", options.profiler);
|
|
6323
|
-
const offResize = terminal.on("resize", ({ rows }) => {
|
|
6760
|
+
const offResize = terminal.on("resize", ({ cols, rows }) => {
|
|
6324
6761
|
if (disposed) return;
|
|
6762
|
+
const colsChanged = cols !== terminalCols;
|
|
6763
|
+
const prevRows = terminalRows;
|
|
6764
|
+
terminalCols = cols;
|
|
6325
6765
|
terminalRows = rows;
|
|
6326
6766
|
allRows = Array.from({ length: terminalRows }, (_, index) => index);
|
|
6327
6767
|
for (const state of planeDirtyStates.values()) {
|
|
6328
|
-
|
|
6768
|
+
const prevBits = state.dirtyRowBits;
|
|
6329
6769
|
state.dirtyRowBits = new Uint8Array(terminalRows);
|
|
6330
6770
|
state.dirtyRowCount = 0;
|
|
6331
6771
|
state.dirtyMinY = Number.POSITIVE_INFINITY;
|
|
6332
6772
|
state.dirtyMaxY = -1;
|
|
6773
|
+
const limit = Math.min(terminalRows, prevBits.length);
|
|
6774
|
+
for (let y = 0; y < limit; y++) {
|
|
6775
|
+
if (prevBits[y] !== 1) continue;
|
|
6776
|
+
state.dirtyRowBits[y] = 1;
|
|
6777
|
+
state.dirtyRowCount++;
|
|
6778
|
+
if (y < state.dirtyMinY) state.dirtyMinY = y;
|
|
6779
|
+
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6780
|
+
}
|
|
6781
|
+
for (let y = prevRows; y < terminalRows; y++) {
|
|
6782
|
+
if (state.dirtyRowBits[y] === 1) continue;
|
|
6783
|
+
state.dirtyRowBits[y] = 1;
|
|
6784
|
+
state.dirtyRowCount++;
|
|
6785
|
+
if (y < state.dirtyMinY) state.dirtyMinY = y;
|
|
6786
|
+
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6787
|
+
}
|
|
6333
6788
|
}
|
|
6334
6789
|
rebuildRowBuckets();
|
|
6335
|
-
clearTextCaches();
|
|
6790
|
+
if (colsChanged) clearTextCaches();
|
|
6336
6791
|
});
|
|
6337
6792
|
const rootStack = Object.freeze({
|
|
6338
6793
|
id: `s${nextStackId++}`,
|
|
@@ -6531,6 +6986,33 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6531
6986
|
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6532
6987
|
}
|
|
6533
6988
|
}
|
|
6989
|
+
function markLowerPlanesForRect(plane, rect) {
|
|
6990
|
+
const planeIndex = TERMINAL_RENDER_PLANES.indexOf(plane);
|
|
6991
|
+
if (planeIndex <= 0) return;
|
|
6992
|
+
for (let i = 0; i < planeIndex; i++) markRect(TERMINAL_RENDER_PLANES[i], rect);
|
|
6993
|
+
}
|
|
6994
|
+
function markRowRange(plane, startY, endY) {
|
|
6995
|
+
const state = getDirtyState(plane);
|
|
6996
|
+
const start = Math.max(0, Math.min(terminalRows, Math.floor(startY)));
|
|
6997
|
+
const end = Math.max(start, Math.min(terminalRows, Math.floor(endY)));
|
|
6998
|
+
for (let y = start; y < end; y++) {
|
|
6999
|
+
if (state.dirtyRowBits[y] === 1) continue;
|
|
7000
|
+
state.dirtyRowBits[y] = 1;
|
|
7001
|
+
state.dirtyRowCount++;
|
|
7002
|
+
if (y < state.dirtyMinY) state.dirtyMinY = y;
|
|
7003
|
+
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
7004
|
+
}
|
|
7005
|
+
}
|
|
7006
|
+
function markRectHeightDelta(plane, prev, next) {
|
|
7007
|
+
if (!prev || !next) return false;
|
|
7008
|
+
if (prev.x !== next.x || prev.y !== next.y || prev.w !== next.w) return false;
|
|
7009
|
+
const prevBounds = rectToYBounds(prev);
|
|
7010
|
+
const nextBounds = rectToYBounds(next);
|
|
7011
|
+
if (prevBounds.y0 !== nextBounds.y0) return false;
|
|
7012
|
+
if (nextBounds.y1 > prevBounds.y1) markRowRange(plane, prevBounds.y1, nextBounds.y1);
|
|
7013
|
+
else if (prevBounds.y1 > nextBounds.y1) markRowRange(plane, nextBounds.y1, prevBounds.y1);
|
|
7014
|
+
return true;
|
|
7015
|
+
}
|
|
6534
7016
|
function markRowsForNode(node, rows) {
|
|
6535
7017
|
if (!rows.length) return false;
|
|
6536
7018
|
warnIfRowsLookLocal(node, rows);
|
|
@@ -6578,6 +7060,7 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6578
7060
|
nodes.set(id, full);
|
|
6579
7061
|
addToRowBuckets(full);
|
|
6580
7062
|
markRect(full.plane, full.rect);
|
|
7063
|
+
markLowerPlanesForRect(full.plane, full.rect);
|
|
6581
7064
|
sortedDirty = true;
|
|
6582
7065
|
return full;
|
|
6583
7066
|
}
|
|
@@ -6589,6 +7072,7 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6589
7072
|
const nextPlane = next.plane ?? prev.plane;
|
|
6590
7073
|
const planeChanged = nextPlane !== prev.plane;
|
|
6591
7074
|
const hasRect = Object.prototype.hasOwnProperty.call(next, "rect");
|
|
7075
|
+
const paintChanged = Object.prototype.hasOwnProperty.call(next, "paint");
|
|
6592
7076
|
const nextRect = hasRect ? next.rect ?? null : prev.rect;
|
|
6593
7077
|
const rectChanged = !sameRect(prev.rect, nextRect);
|
|
6594
7078
|
const bucketChanged = planeChanged || rectChanged;
|
|
@@ -6596,10 +7080,12 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6596
7080
|
const dirtyRowsHint = next.dirtyRowsHint;
|
|
6597
7081
|
const canUseDirtyRowsHint = !sortChanged && !rectChanged && nextPlane === prev.plane && dirtyRowsHint != null && dirtyRowsHint.length > 0;
|
|
6598
7082
|
if (canUseDirtyRowsHint) markRowsForNode(prev, dirtyRowsHint);
|
|
6599
|
-
else {
|
|
7083
|
+
else if (rectChanged && !paintChanged && !sortChanged && !planeChanged && markRectHeightDelta(prev.plane, prev.rect, nextRect)) {} else {
|
|
6600
7084
|
markRect(prev.plane, prev.rect);
|
|
6601
7085
|
markRect(nextPlane, nextRect);
|
|
6602
7086
|
}
|
|
7087
|
+
markLowerPlanesForRect(prev.plane, prev.rect);
|
|
7088
|
+
markLowerPlanesForRect(nextPlane, nextRect);
|
|
6603
7089
|
if (bucketChanged) removeFromRowBuckets(prev);
|
|
6604
7090
|
const full = Object.freeze({
|
|
6605
7091
|
...prev,
|
|
@@ -6629,11 +7115,41 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6629
7115
|
if (!node) return false;
|
|
6630
7116
|
return markRowsForNode(node, rows);
|
|
6631
7117
|
}
|
|
7118
|
+
function isRectCoveredByHigherNode(id, rect, options$1 = {}) {
|
|
7119
|
+
return higherNodeCoverageRects(id, rect, options$1).length > 0;
|
|
7120
|
+
}
|
|
7121
|
+
function higherNodeCoverageRects(id, rect, options$1 = {}) {
|
|
7122
|
+
if (disposed || isEmptyRect(rect)) return [];
|
|
7123
|
+
const owner = nodes.get(id);
|
|
7124
|
+
if (!owner) return [];
|
|
7125
|
+
const ownerPlaneIndex = TERMINAL_RENDER_PLANES.indexOf(owner.plane);
|
|
7126
|
+
if (ownerPlaneIndex < 0) return [];
|
|
7127
|
+
const out = [];
|
|
7128
|
+
for (const candidate of nodes.values()) {
|
|
7129
|
+
if (candidate.id === id || !candidate.rect || isEmptyRect(candidate.rect)) continue;
|
|
7130
|
+
if (!rectsIntersect(rect, candidate.rect)) continue;
|
|
7131
|
+
const candidatePlaneIndex = TERMINAL_RENDER_PLANES.indexOf(candidate.plane);
|
|
7132
|
+
const covered = candidatePlaneIndex > ownerPlaneIndex || !options$1.ignoreSamePlane && candidatePlaneIndex === ownerPlaneIndex && compareNodes(owner, candidate) < 0;
|
|
7133
|
+
if (!covered) continue;
|
|
7134
|
+
const x0 = Math.max(rect.x, candidate.rect.x);
|
|
7135
|
+
const y0 = Math.max(rect.y, candidate.rect.y);
|
|
7136
|
+
const x1 = Math.min(rect.x + rect.w, candidate.rect.x + candidate.rect.w);
|
|
7137
|
+
const y1 = Math.min(rect.y + rect.h, candidate.rect.y + candidate.rect.h);
|
|
7138
|
+
if (x1 > x0 && y1 > y0) out.push({
|
|
7139
|
+
x: x0,
|
|
7140
|
+
y: y0,
|
|
7141
|
+
w: x1 - x0,
|
|
7142
|
+
h: y1 - y0
|
|
7143
|
+
});
|
|
7144
|
+
}
|
|
7145
|
+
return out;
|
|
7146
|
+
}
|
|
6632
7147
|
function unregister(id) {
|
|
6633
7148
|
if (disposed) return;
|
|
6634
7149
|
const prev = nodes.get(id);
|
|
6635
7150
|
if (prev) {
|
|
6636
7151
|
markRect(prev.plane, prev.rect);
|
|
7152
|
+
markLowerPlanesForRect(prev.plane, prev.rect);
|
|
6637
7153
|
removeFromRowBuckets(prev);
|
|
6638
7154
|
warnedLocalDirtyRows.delete(id);
|
|
6639
7155
|
}
|
|
@@ -6849,6 +7365,8 @@ function createRenderManager(terminal, options = {}) {
|
|
|
6849
7365
|
register,
|
|
6850
7366
|
update,
|
|
6851
7367
|
markDirtyRows,
|
|
7368
|
+
isRectCoveredByHigherNode,
|
|
7369
|
+
higherNodeCoverageRects,
|
|
6852
7370
|
unregister,
|
|
6853
7371
|
render,
|
|
6854
7372
|
dispose() {
|
|
@@ -7247,6 +7765,8 @@ function resolveSelectionConfig(config) {
|
|
|
7247
7765
|
}
|
|
7248
7766
|
const unsupportedClipboard = {
|
|
7249
7767
|
supported: false,
|
|
7768
|
+
canRead: false,
|
|
7769
|
+
canWrite: false,
|
|
7250
7770
|
async readText() {
|
|
7251
7771
|
return "";
|
|
7252
7772
|
},
|
|
@@ -7254,6 +7774,12 @@ const unsupportedClipboard = {
|
|
|
7254
7774
|
throw new Error("Clipboard unavailable");
|
|
7255
7775
|
}
|
|
7256
7776
|
};
|
|
7777
|
+
function clipboardCanRead(api) {
|
|
7778
|
+
return api.canRead ?? api.supported;
|
|
7779
|
+
}
|
|
7780
|
+
function clipboardCanWrite(api) {
|
|
7781
|
+
return api.canWrite ?? api.supported;
|
|
7782
|
+
}
|
|
7257
7783
|
function isPlainObject(v) {
|
|
7258
7784
|
if (!v || typeof v !== "object") return false;
|
|
7259
7785
|
const proto = Object.getPrototypeOf(v);
|
|
@@ -7285,10 +7811,12 @@ function shallowEqualRecord(a, b) {
|
|
|
7285
7811
|
function createTerminalApp(options) {
|
|
7286
7812
|
const env = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
7287
7813
|
if (shouldInstallFileWriters(env)) installNodeFileWriters();
|
|
7814
|
+
const debugEnabled = isDebugEnabled();
|
|
7815
|
+
const debugLog$1 = createDebugLogger(debugEnabled);
|
|
7288
7816
|
const widthProvider = options.widthProvider ?? "default";
|
|
7289
7817
|
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());
|
|
7818
|
+
const profileLogPath = envString$1(env, "VUE_TUI_PROFILE_LOG_PATH", "DIMCODE_PROFILE_TUI_LOG_PATH");
|
|
7819
|
+
const framePerfLogPath = envString$1(env, "VUE_TUI_FRAME_PERF_LOG_PATH", "DIMCODE_TUI_PERF_LOG") || (profileLogPath.endsWith(".jsonl") ? profileLogPath : defaultVueTuiFramePerfLogPath());
|
|
7292
7820
|
const framePerfSink = profileEnabled ? createJsonlPerfSink({
|
|
7293
7821
|
file: framePerfLogPath,
|
|
7294
7822
|
fileWriter: nodeProfilerFileWriter,
|
|
@@ -7339,6 +7867,10 @@ function createTerminalApp(options) {
|
|
|
7339
7867
|
}
|
|
7340
7868
|
});
|
|
7341
7869
|
const offCommit = terminal.on("commit", ({ dirtyRows, planes, sync }) => {
|
|
7870
|
+
if (debugEnabled) {
|
|
7871
|
+
const size = terminal.size();
|
|
7872
|
+
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" : ""}`);
|
|
7873
|
+
}
|
|
7342
7874
|
latency === null || latency === void 0 || latency.recordCommit({
|
|
7343
7875
|
dirtyRows,
|
|
7344
7876
|
planes,
|
|
@@ -7431,6 +7963,10 @@ function createTerminalApp(options) {
|
|
|
7431
7963
|
scheduled = false;
|
|
7432
7964
|
flushing = true;
|
|
7433
7965
|
const activePlanes = takeActivePlanes();
|
|
7966
|
+
if (debugEnabled) {
|
|
7967
|
+
const size = terminal.size();
|
|
7968
|
+
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}`);
|
|
7969
|
+
}
|
|
7434
7970
|
latency === null || latency === void 0 || latency.recordFlushStart({
|
|
7435
7971
|
sync,
|
|
7436
7972
|
activePlanes
|
|
@@ -7556,6 +8092,10 @@ function createTerminalApp(options) {
|
|
|
7556
8092
|
function invalidate(options$1) {
|
|
7557
8093
|
if (disposed) return;
|
|
7558
8094
|
const priority = (options$1 === null || options$1 === void 0 ? void 0 : options$1.priority) ?? "normal";
|
|
8095
|
+
if (debugEnabled) {
|
|
8096
|
+
const size = terminal.size();
|
|
8097
|
+
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()}`);
|
|
8098
|
+
}
|
|
7559
8099
|
noteFrameReason(options$1 === null || options$1 === void 0 ? void 0 : options$1.reason);
|
|
7560
8100
|
latency === null || latency === void 0 || latency.recordSchedulerInvalidate({
|
|
7561
8101
|
priority,
|
|
@@ -7640,6 +8180,7 @@ function createTerminalApp(options) {
|
|
|
7640
8180
|
invalidate({ plane: portal.plane });
|
|
7641
8181
|
return handle;
|
|
7642
8182
|
} };
|
|
8183
|
+
const clipboard = options.clipboard ?? unsupportedClipboard;
|
|
7643
8184
|
const rootLayout = shallowReactive({
|
|
7644
8185
|
originX: 0,
|
|
7645
8186
|
originY: 0,
|
|
@@ -7652,6 +8193,7 @@ function createTerminalApp(options) {
|
|
|
7652
8193
|
});
|
|
7653
8194
|
const selectionTextProviders = new Map();
|
|
7654
8195
|
const selectionCopyHandlers = new Set();
|
|
8196
|
+
const selectionConfig = shallowRef(options.selection ?? false);
|
|
7655
8197
|
const selectionContext = {
|
|
7656
8198
|
registerTextProvider(provider) {
|
|
7657
8199
|
selectionTextProviders.set(provider.id, provider);
|
|
@@ -7670,6 +8212,10 @@ function createTerminalApp(options) {
|
|
|
7670
8212
|
},
|
|
7671
8213
|
clear() {
|
|
7672
8214
|
selection.clear();
|
|
8215
|
+
},
|
|
8216
|
+
setConfig(config) {
|
|
8217
|
+
selectionConfig.value = config;
|
|
8218
|
+
selection.refresh();
|
|
7673
8219
|
}
|
|
7674
8220
|
};
|
|
7675
8221
|
const selectionOverlay = getPlaneTerminal(terminal, "overlay");
|
|
@@ -7679,14 +8225,15 @@ function createTerminalApp(options) {
|
|
|
7679
8225
|
"chrome"
|
|
7680
8226
|
];
|
|
7681
8227
|
let selectionRenderNodeId = null;
|
|
8228
|
+
const selectionRenderRect = () => null;
|
|
7682
8229
|
const selection = createTerminalSelectionController({
|
|
7683
8230
|
terminal,
|
|
7684
8231
|
overlayTerminal: selectionOverlay,
|
|
7685
|
-
clipboard
|
|
8232
|
+
clipboard,
|
|
7686
8233
|
getRow: (y) => readTerminalRowForPlanes(terminal, y, selectionReadPlanes),
|
|
7687
8234
|
getTextProviders: () => Array.from(selectionTextProviders.values()),
|
|
7688
8235
|
getOptions: () => {
|
|
7689
|
-
const config = resolveSelectionConfig(
|
|
8236
|
+
const config = resolveSelectionConfig(selectionConfig.value);
|
|
7690
8237
|
return {
|
|
7691
8238
|
autoCopy: config.autoCopy,
|
|
7692
8239
|
copyOnMouseUp: config.copyOnMouseUp,
|
|
@@ -7728,12 +8275,7 @@ function createTerminalApp(options) {
|
|
|
7728
8275
|
stack: render.rootStack,
|
|
7729
8276
|
plane: "overlay",
|
|
7730
8277
|
zIndex: -1e4,
|
|
7731
|
-
rect:
|
|
7732
|
-
x: 0,
|
|
7733
|
-
y: 0,
|
|
7734
|
-
w: options.cols,
|
|
7735
|
-
h: options.rows
|
|
7736
|
-
},
|
|
8278
|
+
rect: selectionRenderRect(),
|
|
7737
8279
|
paint: selection.paint
|
|
7738
8280
|
});
|
|
7739
8281
|
selectionRenderNodeId = selectionRenderNode.id;
|
|
@@ -7848,19 +8390,17 @@ function createTerminalApp(options) {
|
|
|
7848
8390
|
...createDefaultTInputHostAdapter(),
|
|
7849
8391
|
isTerminalLike: true,
|
|
7850
8392
|
async readClipboardText() {
|
|
7851
|
-
|
|
7852
|
-
if (!((_options$clipboard = options.clipboard) === null || _options$clipboard === void 0 ? void 0 : _options$clipboard.supported)) return "";
|
|
8393
|
+
if (!clipboardCanRead(clipboard)) return "";
|
|
7853
8394
|
try {
|
|
7854
|
-
return await
|
|
8395
|
+
return await clipboard.readText();
|
|
7855
8396
|
} catch {
|
|
7856
8397
|
return "";
|
|
7857
8398
|
}
|
|
7858
8399
|
},
|
|
7859
8400
|
async writeClipboardText(text) {
|
|
7860
|
-
|
|
7861
|
-
if (!text || !((_options$clipboard2 = options.clipboard) === null || _options$clipboard2 === void 0 ? void 0 : _options$clipboard2.supported)) return false;
|
|
8401
|
+
if (!text || !clipboardCanWrite(clipboard)) return false;
|
|
7862
8402
|
try {
|
|
7863
|
-
await
|
|
8403
|
+
await clipboard.writeText(text);
|
|
7864
8404
|
return true;
|
|
7865
8405
|
} catch {
|
|
7866
8406
|
return false;
|
|
@@ -7869,6 +8409,7 @@ function createTerminalApp(options) {
|
|
|
7869
8409
|
}))] : [defaultTInputHostPlugin]);
|
|
7870
8410
|
const linkOpener = ref(normalizeTerminalLinkOpener(options.linkOpener));
|
|
7871
8411
|
const offResize = terminal.on("resize", ({ cols, rows }) => {
|
|
8412
|
+
if (debugEnabled) debugLog$1.render(`app resize event: size=${cols}x${rows}, scheduled=${scheduled}, flushing=${flushing}, queueDepth=${queueDepth()}`);
|
|
7872
8413
|
rootLayout.clipRect = {
|
|
7873
8414
|
x: 0,
|
|
7874
8415
|
y: 0,
|
|
@@ -7876,12 +8417,7 @@ function createTerminalApp(options) {
|
|
|
7876
8417
|
h: rows
|
|
7877
8418
|
};
|
|
7878
8419
|
selection.clear();
|
|
7879
|
-
if (selectionRenderNodeId) render.update(selectionRenderNodeId, { rect:
|
|
7880
|
-
x: 0,
|
|
7881
|
-
y: 0,
|
|
7882
|
-
w: cols,
|
|
7883
|
-
h: rows
|
|
7884
|
-
} });
|
|
8420
|
+
if (selectionRenderNodeId) render.update(selectionRenderNodeId, { rect: selectionRenderRect() });
|
|
7885
8421
|
invalidate({ reason: "resize" });
|
|
7886
8422
|
});
|
|
7887
8423
|
schedulerApi = {
|
|
@@ -7902,6 +8438,7 @@ function createTerminalApp(options) {
|
|
|
7902
8438
|
events: shallowRef(events),
|
|
7903
8439
|
scheduler: schedulerApi,
|
|
7904
8440
|
runtime,
|
|
8441
|
+
clipboard,
|
|
7905
8442
|
observability: {
|
|
7906
8443
|
trace,
|
|
7907
8444
|
framePerf
|
|
@@ -7941,6 +8478,8 @@ function createTerminalApp(options) {
|
|
|
7941
8478
|
events,
|
|
7942
8479
|
scheduler: ctx.scheduler,
|
|
7943
8480
|
defaultStyle: ctx.defaultStyle,
|
|
8481
|
+
clipboard,
|
|
8482
|
+
selection: selectionContext,
|
|
7944
8483
|
getImeAnchor() {
|
|
7945
8484
|
return imeAnchor.value;
|
|
7946
8485
|
},
|
|
@@ -7975,7 +8514,11 @@ const metrics = {
|
|
|
7975
8514
|
writeEmaMs: 0,
|
|
7976
8515
|
writeMode: "stream",
|
|
7977
8516
|
fps: 0,
|
|
7978
|
-
bytesPerSec: 0
|
|
8517
|
+
bytesPerSec: 0,
|
|
8518
|
+
terminalGraphicsDraws: 0,
|
|
8519
|
+
terminalGraphicsClears: 0,
|
|
8520
|
+
terminalGraphicsBytes: 0,
|
|
8521
|
+
terminalGraphicsActive: 0
|
|
7979
8522
|
};
|
|
7980
8523
|
let bucketStart = 0;
|
|
7981
8524
|
let bucketFrames = 0;
|
|
@@ -8009,6 +8552,291 @@ function recordStdoutFrame(info) {
|
|
|
8009
8552
|
bucketBytes = 0;
|
|
8010
8553
|
}
|
|
8011
8554
|
}
|
|
8555
|
+
function recordStdoutTerminalGraphics(info) {
|
|
8556
|
+
metrics.terminalGraphicsDraws += Math.max(0, Math.floor(Number(info.draws) || 0));
|
|
8557
|
+
metrics.terminalGraphicsClears += Math.max(0, Math.floor(Number(info.clears) || 0));
|
|
8558
|
+
metrics.terminalGraphicsBytes += Math.max(0, Math.floor(Number(info.bytes) || 0));
|
|
8559
|
+
metrics.terminalGraphicsActive = Math.max(0, Math.floor(Number(info.active) || 0));
|
|
8560
|
+
}
|
|
8561
|
+
|
|
8562
|
+
//#endregion
|
|
8563
|
+
//#region src/renderer/terminal-graphic-render-queue.ts
|
|
8564
|
+
const CACHE_MISS = Symbol("terminal-graphic-cache-miss");
|
|
8565
|
+
function now() {
|
|
8566
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
8567
|
+
}
|
|
8568
|
+
function createAbortError() {
|
|
8569
|
+
const error = new Error("Terminal graphic render aborted");
|
|
8570
|
+
error.name = "AbortError";
|
|
8571
|
+
return error;
|
|
8572
|
+
}
|
|
8573
|
+
function positiveFiniteInt(value, fallback) {
|
|
8574
|
+
const n = Number(value);
|
|
8575
|
+
if (!Number.isFinite(n)) return fallback;
|
|
8576
|
+
const int = Math.floor(n);
|
|
8577
|
+
return int > 0 ? int : fallback;
|
|
8578
|
+
}
|
|
8579
|
+
function throwIfAborted(signal) {
|
|
8580
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) throw createAbortError();
|
|
8581
|
+
}
|
|
8582
|
+
function raceAbort(promise, signal) {
|
|
8583
|
+
if (!signal) return promise;
|
|
8584
|
+
if (signal.aborted) return Promise.reject(createAbortError());
|
|
8585
|
+
return new Promise((resolve, reject) => {
|
|
8586
|
+
const onAbort = () => reject(createAbortError());
|
|
8587
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
8588
|
+
promise.then((value) => {
|
|
8589
|
+
signal.removeEventListener("abort", onAbort);
|
|
8590
|
+
resolve(value);
|
|
8591
|
+
}, (error) => {
|
|
8592
|
+
signal.removeEventListener("abort", onAbort);
|
|
8593
|
+
reject(error);
|
|
8594
|
+
});
|
|
8595
|
+
});
|
|
8596
|
+
}
|
|
8597
|
+
function createTerminalGraphicRenderQueue(options = {}) {
|
|
8598
|
+
const maxConcurrency = positiveFiniteInt(options.maxConcurrency, 2);
|
|
8599
|
+
const maxEntries = positiveFiniteInt(options.maxEntries, 128);
|
|
8600
|
+
const maxBytes = positiveFiniteInt(options.maxBytes, 32 * 1024 * 1024);
|
|
8601
|
+
const ttlMs = positiveFiniteInt(options.ttlMs, 5 * 6e4);
|
|
8602
|
+
const dedupeInflight = options.dedupeInflight ?? false;
|
|
8603
|
+
let active = 0;
|
|
8604
|
+
let cacheBytes = 0;
|
|
8605
|
+
let generation = 0;
|
|
8606
|
+
const waiters = [];
|
|
8607
|
+
const cache = new Map();
|
|
8608
|
+
const inflight = new Map();
|
|
8609
|
+
function traceQueueState(event) {
|
|
8610
|
+
recordTerminalGraphicTrace({
|
|
8611
|
+
...event,
|
|
8612
|
+
active,
|
|
8613
|
+
waiting: waiters.length,
|
|
8614
|
+
cacheEntries: cache.size,
|
|
8615
|
+
cacheBytes
|
|
8616
|
+
});
|
|
8617
|
+
}
|
|
8618
|
+
function evictUntilBudget() {
|
|
8619
|
+
while (cache.size > maxEntries || cacheBytes > maxBytes) {
|
|
8620
|
+
const oldestKey = cache.keys().next().value;
|
|
8621
|
+
if (!oldestKey) break;
|
|
8622
|
+
const entry = cache.get(oldestKey);
|
|
8623
|
+
cache.delete(oldestKey);
|
|
8624
|
+
if (entry) {
|
|
8625
|
+
var _options$onMetric;
|
|
8626
|
+
cacheBytes -= entry.bytes;
|
|
8627
|
+
(_options$onMetric = options.onMetric) === null || _options$onMetric === void 0 || _options$onMetric.call(options, {
|
|
8628
|
+
type: "evict",
|
|
8629
|
+
key: oldestKey,
|
|
8630
|
+
bytes: entry.bytes
|
|
8631
|
+
});
|
|
8632
|
+
}
|
|
8633
|
+
}
|
|
8634
|
+
}
|
|
8635
|
+
function setCache(key, value, bytes) {
|
|
8636
|
+
var _options$onMetric2;
|
|
8637
|
+
const prev = cache.get(key);
|
|
8638
|
+
if (prev) {
|
|
8639
|
+
cache.delete(key);
|
|
8640
|
+
cacheBytes -= prev.bytes;
|
|
8641
|
+
}
|
|
8642
|
+
if (bytes > maxBytes) return;
|
|
8643
|
+
cache.set(key, {
|
|
8644
|
+
value,
|
|
8645
|
+
bytes,
|
|
8646
|
+
expiresAt: Date.now() + ttlMs
|
|
8647
|
+
});
|
|
8648
|
+
cacheBytes += bytes;
|
|
8649
|
+
(_options$onMetric2 = options.onMetric) === null || _options$onMetric2 === void 0 || _options$onMetric2.call(options, {
|
|
8650
|
+
type: "cache-store",
|
|
8651
|
+
key,
|
|
8652
|
+
bytes
|
|
8653
|
+
});
|
|
8654
|
+
traceQueueState({
|
|
8655
|
+
type: "cache-store",
|
|
8656
|
+
id: key,
|
|
8657
|
+
key,
|
|
8658
|
+
bytes
|
|
8659
|
+
});
|
|
8660
|
+
evictUntilBudget();
|
|
8661
|
+
}
|
|
8662
|
+
function getCache(key) {
|
|
8663
|
+
var _options$onMetric3;
|
|
8664
|
+
const entry = cache.get(key);
|
|
8665
|
+
if (!entry) return CACHE_MISS;
|
|
8666
|
+
if (entry.expiresAt < Date.now()) {
|
|
8667
|
+
cache.delete(key);
|
|
8668
|
+
cacheBytes -= entry.bytes;
|
|
8669
|
+
return CACHE_MISS;
|
|
8670
|
+
}
|
|
8671
|
+
cache.delete(key);
|
|
8672
|
+
cache.set(key, entry);
|
|
8673
|
+
(_options$onMetric3 = options.onMetric) === null || _options$onMetric3 === void 0 || _options$onMetric3.call(options, {
|
|
8674
|
+
type: "cache-hit",
|
|
8675
|
+
key
|
|
8676
|
+
});
|
|
8677
|
+
traceQueueState({
|
|
8678
|
+
type: "cache-hit",
|
|
8679
|
+
id: key,
|
|
8680
|
+
key,
|
|
8681
|
+
bytes: entry.bytes
|
|
8682
|
+
});
|
|
8683
|
+
return entry.value;
|
|
8684
|
+
}
|
|
8685
|
+
function release() {
|
|
8686
|
+
active = Math.max(0, active - 1);
|
|
8687
|
+
pump();
|
|
8688
|
+
}
|
|
8689
|
+
function once(fn) {
|
|
8690
|
+
let called = false;
|
|
8691
|
+
return () => {
|
|
8692
|
+
if (called) return;
|
|
8693
|
+
called = true;
|
|
8694
|
+
fn();
|
|
8695
|
+
};
|
|
8696
|
+
}
|
|
8697
|
+
function observeActiveRenderAbort(key, signal) {
|
|
8698
|
+
if (!signal) return () => void 0;
|
|
8699
|
+
const onAbort = () => {
|
|
8700
|
+
var _options$onMetric4;
|
|
8701
|
+
(_options$onMetric4 = options.onMetric) === null || _options$onMetric4 === void 0 || _options$onMetric4.call(options, {
|
|
8702
|
+
type: "render-abort",
|
|
8703
|
+
key
|
|
8704
|
+
});
|
|
8705
|
+
traceQueueState({
|
|
8706
|
+
type: "renderer-abort",
|
|
8707
|
+
id: key,
|
|
8708
|
+
key
|
|
8709
|
+
});
|
|
8710
|
+
};
|
|
8711
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
8712
|
+
return () => signal.removeEventListener("abort", onAbort);
|
|
8713
|
+
}
|
|
8714
|
+
function pump() {
|
|
8715
|
+
while (active < maxConcurrency && waiters.length > 0) {
|
|
8716
|
+
const waiter = waiters.shift();
|
|
8717
|
+
active++;
|
|
8718
|
+
traceQueueState({
|
|
8719
|
+
type: "queue-depth",
|
|
8720
|
+
id: waiter.key,
|
|
8721
|
+
key: waiter.key
|
|
8722
|
+
});
|
|
8723
|
+
waiter.start();
|
|
8724
|
+
}
|
|
8725
|
+
}
|
|
8726
|
+
function acquire(key, signal) {
|
|
8727
|
+
throwIfAborted(signal);
|
|
8728
|
+
if (active < maxConcurrency) {
|
|
8729
|
+
active++;
|
|
8730
|
+
traceQueueState({
|
|
8731
|
+
type: "queue-depth",
|
|
8732
|
+
id: key,
|
|
8733
|
+
key
|
|
8734
|
+
});
|
|
8735
|
+
return Promise.resolve(release);
|
|
8736
|
+
}
|
|
8737
|
+
const waitStartedAt = now();
|
|
8738
|
+
return new Promise((resolve, reject) => {
|
|
8739
|
+
let onAbort = () => void 0;
|
|
8740
|
+
const cleanup = () => {
|
|
8741
|
+
signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
|
|
8742
|
+
};
|
|
8743
|
+
const waiter = {
|
|
8744
|
+
key,
|
|
8745
|
+
start: () => {
|
|
8746
|
+
var _options$onMetric5;
|
|
8747
|
+
cleanup();
|
|
8748
|
+
const waitMs = now() - waitStartedAt;
|
|
8749
|
+
(_options$onMetric5 = options.onMetric) === null || _options$onMetric5 === void 0 || _options$onMetric5.call(options, {
|
|
8750
|
+
type: "queue-wait",
|
|
8751
|
+
key,
|
|
8752
|
+
waitMs
|
|
8753
|
+
});
|
|
8754
|
+
traceQueueState({
|
|
8755
|
+
type: "queue-wait",
|
|
8756
|
+
id: key,
|
|
8757
|
+
key,
|
|
8758
|
+
durationMs: waitMs
|
|
8759
|
+
});
|
|
8760
|
+
resolve(release);
|
|
8761
|
+
},
|
|
8762
|
+
reject: (error) => {
|
|
8763
|
+
cleanup();
|
|
8764
|
+
reject(error);
|
|
8765
|
+
}
|
|
8766
|
+
};
|
|
8767
|
+
onAbort = () => {
|
|
8768
|
+
const index = waiters.indexOf(waiter);
|
|
8769
|
+
if (index >= 0) waiters.splice(index, 1);
|
|
8770
|
+
cleanup();
|
|
8771
|
+
reject(createAbortError());
|
|
8772
|
+
};
|
|
8773
|
+
signal === null || signal === void 0 || signal.addEventListener("abort", onAbort, { once: true });
|
|
8774
|
+
waiters.push(waiter);
|
|
8775
|
+
traceQueueState({
|
|
8776
|
+
type: "queue-depth",
|
|
8777
|
+
id: key,
|
|
8778
|
+
key
|
|
8779
|
+
});
|
|
8780
|
+
});
|
|
8781
|
+
}
|
|
8782
|
+
async function cached(key, signal, render, estimateBytes = () => 0, cachedOptions = {}) {
|
|
8783
|
+
throwIfAborted(signal);
|
|
8784
|
+
const cachedValue = getCache(key);
|
|
8785
|
+
if (cachedValue !== CACHE_MISS) return cachedValue;
|
|
8786
|
+
traceQueueState({
|
|
8787
|
+
type: "cache-miss",
|
|
8788
|
+
id: key,
|
|
8789
|
+
key
|
|
8790
|
+
});
|
|
8791
|
+
const shouldDedupeInflight = cachedOptions.dedupeInflight ?? dedupeInflight;
|
|
8792
|
+
const existing = shouldDedupeInflight ? inflight.get(key) : void 0;
|
|
8793
|
+
if (existing) return raceAbort(existing, signal);
|
|
8794
|
+
let promise;
|
|
8795
|
+
promise = (async () => {
|
|
8796
|
+
let releaseSlot = null;
|
|
8797
|
+
let removeAbortObserver = null;
|
|
8798
|
+
const renderGeneration = generation;
|
|
8799
|
+
try {
|
|
8800
|
+
releaseSlot = once(await acquire(key, signal));
|
|
8801
|
+
removeAbortObserver = observeActiveRenderAbort(key, signal);
|
|
8802
|
+
throwIfAborted(signal);
|
|
8803
|
+
const cachedAfterWait = getCache(key);
|
|
8804
|
+
if (cachedAfterWait !== CACHE_MISS) return cachedAfterWait;
|
|
8805
|
+
const value = await render();
|
|
8806
|
+
throwIfAborted(signal);
|
|
8807
|
+
const rawBytes = Math.floor(Number(estimateBytes(value)));
|
|
8808
|
+
const bytes = Number.isFinite(rawBytes) && rawBytes > 0 ? rawBytes : 0;
|
|
8809
|
+
if (renderGeneration === generation) setCache(key, value, bytes);
|
|
8810
|
+
return value;
|
|
8811
|
+
} finally {
|
|
8812
|
+
removeAbortObserver === null || removeAbortObserver === void 0 || removeAbortObserver();
|
|
8813
|
+
releaseSlot === null || releaseSlot === void 0 || releaseSlot();
|
|
8814
|
+
if (shouldDedupeInflight && inflight.get(key) === promise) inflight.delete(key);
|
|
8815
|
+
}
|
|
8816
|
+
})();
|
|
8817
|
+
if (shouldDedupeInflight) inflight.set(key, promise);
|
|
8818
|
+
return raceAbort(promise, signal);
|
|
8819
|
+
}
|
|
8820
|
+
return {
|
|
8821
|
+
cached,
|
|
8822
|
+
clear() {
|
|
8823
|
+
generation++;
|
|
8824
|
+
cache.clear();
|
|
8825
|
+
inflight.clear();
|
|
8826
|
+
const pending = waiters.splice(0);
|
|
8827
|
+
for (const waiter of pending) waiter.reject(createAbortError());
|
|
8828
|
+
cacheBytes = 0;
|
|
8829
|
+
},
|
|
8830
|
+
stats() {
|
|
8831
|
+
return {
|
|
8832
|
+
active,
|
|
8833
|
+
waiting: waiters.length,
|
|
8834
|
+
cacheEntries: cache.size,
|
|
8835
|
+
cacheBytes
|
|
8836
|
+
};
|
|
8837
|
+
}
|
|
8838
|
+
};
|
|
8839
|
+
}
|
|
8012
8840
|
|
|
8013
8841
|
//#endregion
|
|
8014
8842
|
//#region src/core/ansi-palette.ts
|
|
@@ -8172,13 +9000,13 @@ const ANSI16_COLOR_NAMES = Object.freeze([
|
|
|
8172
9000
|
"cyanBright",
|
|
8173
9001
|
"whiteBright"
|
|
8174
9002
|
]);
|
|
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`;
|
|
9003
|
+
const ESC$1 = "\x1B[";
|
|
9004
|
+
const SGR_RESET = `${ESC$1}0m`;
|
|
9005
|
+
const SGR_BOLD = `${ESC$1}1m`;
|
|
9006
|
+
const SGR_DIM = `${ESC$1}2m`;
|
|
9007
|
+
const SGR_ITALIC = `${ESC$1}3m`;
|
|
9008
|
+
const SGR_UNDERLINE = `${ESC$1}4m`;
|
|
9009
|
+
const SGR_INVERSE = `${ESC$1}7m`;
|
|
8182
9010
|
function toAnsi8ColorName(name) {
|
|
8183
9011
|
switch (name) {
|
|
8184
9012
|
case "black":
|
|
@@ -8238,32 +9066,32 @@ const ANSI16_BG_CODE = Object.freeze({
|
|
|
8238
9066
|
function ansi8FgOpen(name) {
|
|
8239
9067
|
const base = toAnsi8ColorName(name);
|
|
8240
9068
|
const idx = ANSI8_COLOR_NAMES.indexOf(base);
|
|
8241
|
-
return `${ESC}${30 + (idx < 0 ? 7 : idx)}m`;
|
|
9069
|
+
return `${ESC$1}${30 + (idx < 0 ? 7 : idx)}m`;
|
|
8242
9070
|
}
|
|
8243
9071
|
function ansi8BgOpen(name) {
|
|
8244
9072
|
const base = toAnsi8ColorName(name);
|
|
8245
9073
|
const idx = ANSI8_COLOR_NAMES.indexOf(base);
|
|
8246
|
-
return `${ESC}${40 + (idx < 0 ? 0 : idx)}m`;
|
|
9074
|
+
return `${ESC$1}${40 + (idx < 0 ? 0 : idx)}m`;
|
|
8247
9075
|
}
|
|
8248
9076
|
function ansi16FgOpen(name) {
|
|
8249
|
-
return `${ESC}${ANSI16_FG_CODE[name]}m`;
|
|
9077
|
+
return `${ESC$1}${ANSI16_FG_CODE[name]}m`;
|
|
8250
9078
|
}
|
|
8251
9079
|
function ansi16BgOpen(name) {
|
|
8252
|
-
return `${ESC}${ANSI16_BG_CODE[name]}m`;
|
|
9080
|
+
return `${ESC$1}${ANSI16_BG_CODE[name]}m`;
|
|
8253
9081
|
}
|
|
8254
9082
|
function ansi256FgOpen(index) {
|
|
8255
9083
|
const n = clampAnsiIndex(index);
|
|
8256
|
-
return `${ESC}38;5;${n}m`;
|
|
9084
|
+
return `${ESC$1}38;5;${n}m`;
|
|
8257
9085
|
}
|
|
8258
9086
|
function ansi256BgOpen(index) {
|
|
8259
9087
|
const n = clampAnsiIndex(index);
|
|
8260
|
-
return `${ESC}48;5;${n}m`;
|
|
9088
|
+
return `${ESC$1}48;5;${n}m`;
|
|
8261
9089
|
}
|
|
8262
9090
|
function truecolorFgOpen(rgb) {
|
|
8263
|
-
return `${ESC}38;2;${clampByte(rgb.r)};${clampByte(rgb.g)};${clampByte(rgb.b)}m`;
|
|
9091
|
+
return `${ESC$1}38;2;${clampByte(rgb.r)};${clampByte(rgb.g)};${clampByte(rgb.b)}m`;
|
|
8264
9092
|
}
|
|
8265
9093
|
function truecolorBgOpen(rgb) {
|
|
8266
|
-
return `${ESC}48;2;${clampByte(rgb.r)};${clampByte(rgb.g)};${clampByte(rgb.b)}m`;
|
|
9094
|
+
return `${ESC$1}48;2;${clampByte(rgb.r)};${clampByte(rgb.g)};${clampByte(rgb.b)}m`;
|
|
8267
9095
|
}
|
|
8268
9096
|
function ansi256ToRgb(index) {
|
|
8269
9097
|
const n = clampAnsiIndex(index);
|
|
@@ -8417,6 +9245,623 @@ function sanitizeTerminalHref(value, options = {}) {
|
|
|
8417
9245
|
return null;
|
|
8418
9246
|
}
|
|
8419
9247
|
|
|
9248
|
+
//#endregion
|
|
9249
|
+
//#region src/renderer/terminal-graphics.ts
|
|
9250
|
+
const TERMINAL_GRAPHICS_PROTOCOL_PRIORITY = [
|
|
9251
|
+
"kitty",
|
|
9252
|
+
"iterm2",
|
|
9253
|
+
"sixel"
|
|
9254
|
+
];
|
|
9255
|
+
const ESC = "\x1B";
|
|
9256
|
+
const BEL = "\x07";
|
|
9257
|
+
const ST = `${ESC}\\`;
|
|
9258
|
+
const ESC_RE = "\\u001B";
|
|
9259
|
+
const BEL_RE = "\\u0007";
|
|
9260
|
+
const CSI_RE = new RegExp(`${ESC_RE}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
9261
|
+
const OSC_RE = new RegExp(`${ESC_RE}\\][\\s\\S]*?(?:${BEL_RE}|${ESC_RE}\\\\)`, "g");
|
|
9262
|
+
const DCS_RE = new RegExp(`${ESC_RE}P[\\s\\S]*?${ESC_RE}\\\\`, "g");
|
|
9263
|
+
const APC_RE = new RegExp(`${ESC_RE}_[\\s\\S]*?${ESC_RE}\\\\`, "g");
|
|
9264
|
+
const C1_CSI_RE = new RegExp("\\u009B[0-?]*[ -/]*[@-~]", "g");
|
|
9265
|
+
const C1_OSC_RE = new RegExp(`\\u009D[\\s\\S]*?(?:${BEL_RE}|\\u009C)`, "g");
|
|
9266
|
+
const C1_DCS_RE = new RegExp("\\u0090[\\s\\S]*?\\u009C", "g");
|
|
9267
|
+
const C1_APC_RE = new RegExp("\\u009F[\\s\\S]*?\\u009C", "g");
|
|
9268
|
+
const MAX_TERMINAL_GRAPHICS_SEQUENCE_CHARS = 16 * 1024 * 1024;
|
|
9269
|
+
const MAX_TERMINAL_GRAPHICS_FALLBACK_CHARS = 16384;
|
|
9270
|
+
const MAX_TERMINAL_GRAPHIC_CELLS = 1e4;
|
|
9271
|
+
const TERMINAL_GRAPHICS_REGISTRY = Symbol.for("@simon_he/vue-tui:v1:terminal-graphics");
|
|
9272
|
+
const terminalGraphicsGlobal = globalThis;
|
|
9273
|
+
const terminalGraphicsRegistry = terminalGraphicsGlobal[TERMINAL_GRAPHICS_REGISTRY] ?? {
|
|
9274
|
+
outputs: new WeakMap(),
|
|
9275
|
+
outputVersions: new WeakMap(),
|
|
9276
|
+
outputListeners: new WeakMap()
|
|
9277
|
+
};
|
|
9278
|
+
terminalGraphicsGlobal[TERMINAL_GRAPHICS_REGISTRY] = terminalGraphicsRegistry;
|
|
9279
|
+
const terminalGraphicsOutputs = terminalGraphicsRegistry.outputs;
|
|
9280
|
+
const terminalGraphicsOutputVersions = terminalGraphicsRegistry.outputVersions;
|
|
9281
|
+
const terminalGraphicsOutputListeners = terminalGraphicsRegistry.outputListeners;
|
|
9282
|
+
function notifyTerminalGraphicsOutputChange(terminal) {
|
|
9283
|
+
const version = (terminalGraphicsOutputVersions.get(terminal) ?? 0) + 1;
|
|
9284
|
+
terminalGraphicsOutputVersions.set(terminal, version);
|
|
9285
|
+
const listeners = terminalGraphicsOutputListeners.get(terminal);
|
|
9286
|
+
if (!listeners) return;
|
|
9287
|
+
for (const listener of listeners) listener();
|
|
9288
|
+
}
|
|
9289
|
+
function registerTerminalGraphicsOutput(terminal, output) {
|
|
9290
|
+
const rootTerminal = getRootTerminal(terminal);
|
|
9291
|
+
terminalGraphicsOutputs.set(rootTerminal, output);
|
|
9292
|
+
notifyTerminalGraphicsOutputChange(rootTerminal);
|
|
9293
|
+
return () => {
|
|
9294
|
+
if (terminalGraphicsOutputs.get(rootTerminal) === output) {
|
|
9295
|
+
terminalGraphicsOutputs.delete(rootTerminal);
|
|
9296
|
+
notifyTerminalGraphicsOutputChange(rootTerminal);
|
|
9297
|
+
}
|
|
9298
|
+
};
|
|
9299
|
+
}
|
|
9300
|
+
function envString(env, key) {
|
|
9301
|
+
const value = env[key];
|
|
9302
|
+
return value == null ? void 0 : String(value);
|
|
9303
|
+
}
|
|
9304
|
+
function truthy(value) {
|
|
9305
|
+
if (value == null) return false;
|
|
9306
|
+
return /^(1|true|yes|on)$/i.test(String(value));
|
|
9307
|
+
}
|
|
9308
|
+
function readStdoutIsTTY() {
|
|
9309
|
+
var _maybeProcess$stdout;
|
|
9310
|
+
const maybeProcess = globalThis.process;
|
|
9311
|
+
return Boolean(maybeProcess === null || maybeProcess === void 0 || (_maybeProcess$stdout = maybeProcess.stdout) === null || _maybeProcess$stdout === void 0 ? void 0 : _maybeProcess$stdout.isTTY);
|
|
9312
|
+
}
|
|
9313
|
+
function readProcessEnv() {
|
|
9314
|
+
const maybeProcess = globalThis.process;
|
|
9315
|
+
return (maybeProcess === null || maybeProcess === void 0 ? void 0 : maybeProcess.env) ?? {};
|
|
9316
|
+
}
|
|
9317
|
+
function normalizeMode(value) {
|
|
9318
|
+
const raw = String(value ?? "auto").trim().toLowerCase();
|
|
9319
|
+
if (raw === "auto" || raw === "off" || raw === "none" || raw === "kitty" || raw === "iterm2" || raw === "sixel" || raw === "unicode") return raw === "off" ? "none" : raw;
|
|
9320
|
+
return "auto";
|
|
9321
|
+
}
|
|
9322
|
+
function isTerminalGraphicsProtocol(value) {
|
|
9323
|
+
return value === "kitty" || value === "iterm2" || value === "sixel";
|
|
9324
|
+
}
|
|
9325
|
+
function uniqueProtocols(protocols) {
|
|
9326
|
+
return [...new Set(protocols)];
|
|
9327
|
+
}
|
|
9328
|
+
function pickBestTerminalGraphicsProtocol(protocols) {
|
|
9329
|
+
const available = new Set(protocols);
|
|
9330
|
+
for (const protocol of TERMINAL_GRAPHICS_PROTOCOL_PRIORITY) if (available.has(protocol)) return protocol;
|
|
9331
|
+
return null;
|
|
9332
|
+
}
|
|
9333
|
+
function detectCandidates(env) {
|
|
9334
|
+
const candidates = [];
|
|
9335
|
+
const term = String(envString(env, "TERM") ?? "").toLowerCase();
|
|
9336
|
+
const termProgram = String(envString(env, "TERM_PROGRAM") ?? "").toLowerCase();
|
|
9337
|
+
const termProgramVersion = String(envString(env, "TERM_PROGRAM_VERSION") ?? "").toLowerCase();
|
|
9338
|
+
if (envString(env, "KITTY_WINDOW_ID") || envString(env, "GHOSTTY_RESOURCES_DIR") || /(?:^|-)kitty(?:-|$)/i.test(term) || term.includes("ghostty") || termProgram.includes("ghostty")) candidates.push("kitty");
|
|
9339
|
+
if (termProgram.includes("iterm") || termProgram.includes("wezterm") || envString(env, "WEZTERM_PANE") || envString(env, "WEZTERM_EXECUTABLE")) candidates.push("iterm2");
|
|
9340
|
+
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");
|
|
9341
|
+
return uniqueProtocols(candidates);
|
|
9342
|
+
}
|
|
9343
|
+
function capabilitiesFor(protocol, input) {
|
|
9344
|
+
const supported = protocol === "kitty" || protocol === "iterm2" || protocol === "sixel";
|
|
9345
|
+
const candidates = uniqueProtocols([...input.candidates ?? (supported ? [protocol] : [])]);
|
|
9346
|
+
return {
|
|
9347
|
+
supported,
|
|
9348
|
+
kitty: protocol === "kitty" || candidates.includes("kitty"),
|
|
9349
|
+
iterm2: protocol === "iterm2" || candidates.includes("iterm2"),
|
|
9350
|
+
sixel: protocol === "sixel" || candidates.includes("sixel"),
|
|
9351
|
+
preferredProtocol: supported ? protocol : null,
|
|
9352
|
+
protocol,
|
|
9353
|
+
candidates,
|
|
9354
|
+
stdoutIsTTY: input.stdoutIsTTY,
|
|
9355
|
+
insideTmux: input.insideTmux,
|
|
9356
|
+
insideScreen: input.insideScreen,
|
|
9357
|
+
insideZellij: input.insideZellij,
|
|
9358
|
+
multiplexer: input.multiplexer,
|
|
9359
|
+
passthrough: input.passthrough,
|
|
9360
|
+
forced: input.forced,
|
|
9361
|
+
reason: input.reason
|
|
9362
|
+
};
|
|
9363
|
+
}
|
|
9364
|
+
function detectTerminalGraphicsCapabilities(options = {}) {
|
|
9365
|
+
const env = options.env ?? readProcessEnv();
|
|
9366
|
+
const stdoutIsTTY = options.stdoutIsTTY ?? options.isTTY ?? readStdoutIsTTY();
|
|
9367
|
+
const term = String(envString(env, "TERM") ?? "").toLowerCase();
|
|
9368
|
+
const insideTmux = Boolean(envString(env, "TMUX")) || term.includes("tmux");
|
|
9369
|
+
const insideScreen = Boolean(envString(env, "STY")) || term.startsWith("screen");
|
|
9370
|
+
const insideZellij = Boolean(envString(env, "ZELLIJ") || envString(env, "ZELLIJ_SESSION_NAME")) || term.includes("zellij");
|
|
9371
|
+
const multiplexer = insideTmux ? "tmux" : insideScreen ? "screen" : insideZellij ? "zellij" : null;
|
|
9372
|
+
const passthroughRequested = options.passthrough ?? (truthy(envString(env, "VUE_TUI_TERMINAL_GRAPHICS_PASSTHROUGH")) || truthy(envString(env, "VUE_TUI_GRAPHICS_TMUX_PASSTHROUGH")));
|
|
9373
|
+
const passthroughSupported = !multiplexer || multiplexer === "tmux";
|
|
9374
|
+
const passthrough = passthroughRequested && passthroughSupported;
|
|
9375
|
+
const protocolOptionProvided = options.protocol != null;
|
|
9376
|
+
const mode = normalizeMode(options.protocol ?? envString(env, "VUE_TUI_TERMINAL_GRAPHICS") ?? envString(env, "VUE_TUI_GRAPHICS_PROTOCOL"));
|
|
9377
|
+
const forceFromOption = options.force === true;
|
|
9378
|
+
const force = options.force ?? truthy(envString(env, "VUE_TUI_GRAPHICS_FORCE"));
|
|
9379
|
+
const base = {
|
|
9380
|
+
stdoutIsTTY,
|
|
9381
|
+
insideTmux,
|
|
9382
|
+
insideScreen,
|
|
9383
|
+
insideZellij,
|
|
9384
|
+
multiplexer,
|
|
9385
|
+
passthrough,
|
|
9386
|
+
forced: force
|
|
9387
|
+
};
|
|
9388
|
+
if (mode === "none") return capabilitiesFor("none", {
|
|
9389
|
+
...base,
|
|
9390
|
+
reason: protocolOptionProvided ? "disabled-by-option" : "disabled-by-env"
|
|
9391
|
+
});
|
|
9392
|
+
if (!stdoutIsTTY && !force) return capabilitiesFor("unicode", {
|
|
9393
|
+
...base,
|
|
9394
|
+
reason: "stdout-is-not-tty"
|
|
9395
|
+
});
|
|
9396
|
+
if (truthy(envString(env, "CI")) && !force) return capabilitiesFor("unicode", {
|
|
9397
|
+
...base,
|
|
9398
|
+
reason: "ci"
|
|
9399
|
+
});
|
|
9400
|
+
if (multiplexer && passthroughRequested && !passthroughSupported && !force) return capabilitiesFor("unicode", {
|
|
9401
|
+
...base,
|
|
9402
|
+
reason: `${multiplexer}-passthrough-not-implemented`
|
|
9403
|
+
});
|
|
9404
|
+
if (multiplexer && !passthrough && !force) return capabilitiesFor("unicode", {
|
|
9405
|
+
...base,
|
|
9406
|
+
reason: `${multiplexer}-without-passthrough`
|
|
9407
|
+
});
|
|
9408
|
+
if (mode === "kitty" || mode === "iterm2" || mode === "sixel") return capabilitiesFor(mode, {
|
|
9409
|
+
...base,
|
|
9410
|
+
candidates: [mode],
|
|
9411
|
+
reason: force ? forceFromOption ? "forced-by-option" : "forced-by-env" : protocolOptionProvided ? "selected-by-option" : "selected-by-env"
|
|
9412
|
+
});
|
|
9413
|
+
if (mode === "unicode") return capabilitiesFor("unicode", {
|
|
9414
|
+
...base,
|
|
9415
|
+
reason: protocolOptionProvided ? "unicode-forced-by-option" : "unicode-forced-by-env"
|
|
9416
|
+
});
|
|
9417
|
+
const candidates = detectCandidates(env);
|
|
9418
|
+
const preferredProtocol = pickBestTerminalGraphicsProtocol(candidates);
|
|
9419
|
+
const protocol = preferredProtocol ?? "unicode";
|
|
9420
|
+
return capabilitiesFor(protocol, {
|
|
9421
|
+
...base,
|
|
9422
|
+
candidates,
|
|
9423
|
+
reason: protocol === "unicode" ? "no-supported-graphics-protocol-detected" : "auto-detected"
|
|
9424
|
+
});
|
|
9425
|
+
}
|
|
9426
|
+
function hashTerminalGraphicsString(input) {
|
|
9427
|
+
let hash = 2166136261;
|
|
9428
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
9429
|
+
hash ^= input.charCodeAt(index);
|
|
9430
|
+
hash = Math.imul(hash, 16777619);
|
|
9431
|
+
}
|
|
9432
|
+
return (hash >>> 0).toString(36);
|
|
9433
|
+
}
|
|
9434
|
+
function stableId(input) {
|
|
9435
|
+
return `tg_${hashTerminalGraphicsString(input)}`;
|
|
9436
|
+
}
|
|
9437
|
+
function positiveGraphicInt(value, max) {
|
|
9438
|
+
const n = Math.trunc(Number(value));
|
|
9439
|
+
if (!Number.isFinite(n) || n <= 0) return null;
|
|
9440
|
+
return Math.min(max, n);
|
|
9441
|
+
}
|
|
9442
|
+
function normalizeTerminalGraphicSize(width, height) {
|
|
9443
|
+
const w = positiveGraphicInt(width, MAX_TERMINAL_GRAPHIC_CELLS);
|
|
9444
|
+
const h$1 = positiveGraphicInt(height, MAX_TERMINAL_GRAPHIC_CELLS);
|
|
9445
|
+
if (w == null || h$1 == null) return null;
|
|
9446
|
+
if (w * h$1 > MAX_TERMINAL_GRAPHIC_CELLS) return null;
|
|
9447
|
+
return {
|
|
9448
|
+
width: w,
|
|
9449
|
+
height: h$1
|
|
9450
|
+
};
|
|
9451
|
+
}
|
|
9452
|
+
function withoutNestedEscapes(body) {
|
|
9453
|
+
return !body.includes(ESC) && !body.includes(BEL);
|
|
9454
|
+
}
|
|
9455
|
+
function isBase64ish(value) {
|
|
9456
|
+
return /^[A-Za-z0-9+/=]*$/.test(value);
|
|
9457
|
+
}
|
|
9458
|
+
function parseKittyControls(raw) {
|
|
9459
|
+
const out = new Map();
|
|
9460
|
+
if (!/^[A-Za-z0-9_,=+.\-:]*$/.test(raw)) return null;
|
|
9461
|
+
for (const part of raw.split(",")) {
|
|
9462
|
+
if (!part) continue;
|
|
9463
|
+
const eq = part.indexOf("=");
|
|
9464
|
+
if (eq <= 0) return null;
|
|
9465
|
+
const key = part.slice(0, eq);
|
|
9466
|
+
const value = part.slice(eq + 1);
|
|
9467
|
+
if (!/^[A-Za-z]$/.test(key)) return null;
|
|
9468
|
+
if (!/^[A-Za-z0-9+.\-:]*$/.test(value)) return null;
|
|
9469
|
+
out.set(key, value);
|
|
9470
|
+
}
|
|
9471
|
+
return out;
|
|
9472
|
+
}
|
|
9473
|
+
function parseKittyPackets(sequence) {
|
|
9474
|
+
const packets = [];
|
|
9475
|
+
let index = 0;
|
|
9476
|
+
while (index < sequence.length) {
|
|
9477
|
+
if (!sequence.startsWith(`${ESC}_G`, index)) return null;
|
|
9478
|
+
const end = sequence.indexOf(ST, index + 3);
|
|
9479
|
+
if (end < 0) return null;
|
|
9480
|
+
const body = sequence.slice(index + 3, end);
|
|
9481
|
+
if (!withoutNestedEscapes(body)) return null;
|
|
9482
|
+
const semicolon = body.indexOf(";");
|
|
9483
|
+
const rawControls = semicolon >= 0 ? body.slice(0, semicolon) : body;
|
|
9484
|
+
const payload = semicolon >= 0 ? body.slice(semicolon + 1) : "";
|
|
9485
|
+
const controls = parseKittyControls(rawControls);
|
|
9486
|
+
if (!controls) return null;
|
|
9487
|
+
if (payload && !isBase64ish(payload)) return null;
|
|
9488
|
+
packets.push({
|
|
9489
|
+
controls,
|
|
9490
|
+
payload
|
|
9491
|
+
});
|
|
9492
|
+
index = end + ST.length;
|
|
9493
|
+
}
|
|
9494
|
+
return packets.length ? packets : null;
|
|
9495
|
+
}
|
|
9496
|
+
const KITTY_DRAW_FIRST_CONTROL_KEYS = new Set([
|
|
9497
|
+
"a",
|
|
9498
|
+
"f",
|
|
9499
|
+
"q",
|
|
9500
|
+
"C",
|
|
9501
|
+
"i",
|
|
9502
|
+
"I",
|
|
9503
|
+
"p",
|
|
9504
|
+
"c",
|
|
9505
|
+
"r",
|
|
9506
|
+
"x",
|
|
9507
|
+
"y",
|
|
9508
|
+
"w",
|
|
9509
|
+
"h",
|
|
9510
|
+
"z",
|
|
9511
|
+
"m",
|
|
9512
|
+
"t"
|
|
9513
|
+
]);
|
|
9514
|
+
const KITTY_DRAW_CONTINUATION_CONTROL_KEYS = new Set([
|
|
9515
|
+
"a",
|
|
9516
|
+
"q",
|
|
9517
|
+
"m"
|
|
9518
|
+
]);
|
|
9519
|
+
const KITTY_CLEAR_CONTROL_KEYS = new Set([
|
|
9520
|
+
"a",
|
|
9521
|
+
"d",
|
|
9522
|
+
"i",
|
|
9523
|
+
"I",
|
|
9524
|
+
"p",
|
|
9525
|
+
"q"
|
|
9526
|
+
]);
|
|
9527
|
+
function kittyControlsUseOnly(controls, allowed) {
|
|
9528
|
+
for (const key of controls.keys()) if (!allowed.has(key)) return false;
|
|
9529
|
+
return true;
|
|
9530
|
+
}
|
|
9531
|
+
const KITTY_UINT32_MAX = 4294967295;
|
|
9532
|
+
const KITTY_INT32_MIN = -2147483648;
|
|
9533
|
+
const KITTY_INT32_MAX = 2147483647;
|
|
9534
|
+
function kittyControlIsUint32(controls, key, min = 0) {
|
|
9535
|
+
const value = controls.get(key);
|
|
9536
|
+
if (value == null) return true;
|
|
9537
|
+
if (!/^\d+$/.test(value)) return false;
|
|
9538
|
+
const n = Number(value);
|
|
9539
|
+
return Number.isSafeInteger(n) && n >= min && n <= KITTY_UINT32_MAX;
|
|
9540
|
+
}
|
|
9541
|
+
function kittyControlIsInt32(controls, key) {
|
|
9542
|
+
const value = controls.get(key);
|
|
9543
|
+
if (value == null) return true;
|
|
9544
|
+
if (!/^-?\d+$/.test(value)) return false;
|
|
9545
|
+
const n = Number(value);
|
|
9546
|
+
return Number.isSafeInteger(n) && n >= KITTY_INT32_MIN && n <= KITTY_INT32_MAX;
|
|
9547
|
+
}
|
|
9548
|
+
function kittyControlPositiveInt(controls, key, fallback) {
|
|
9549
|
+
const value = controls.get(key);
|
|
9550
|
+
if (value == null) return fallback;
|
|
9551
|
+
if (!/^\d+$/.test(value)) return null;
|
|
9552
|
+
const n = Number(value);
|
|
9553
|
+
return Number.isSafeInteger(n) && n >= 1 ? n : null;
|
|
9554
|
+
}
|
|
9555
|
+
function kittyControlIsTerminalGraphicCellsBounded(controls) {
|
|
9556
|
+
const columns = kittyControlPositiveInt(controls, "c", 1);
|
|
9557
|
+
const rows = kittyControlPositiveInt(controls, "r", 1);
|
|
9558
|
+
return columns != null && rows != null && columns * rows <= MAX_TERMINAL_GRAPHIC_CELLS;
|
|
9559
|
+
}
|
|
9560
|
+
function validateKittySharedSafeControls(controls) {
|
|
9561
|
+
const q = controls.get("q");
|
|
9562
|
+
if (q != null && !/^[0-2]$/.test(q)) return false;
|
|
9563
|
+
const cursorMove = controls.get("C");
|
|
9564
|
+
if (cursorMove != null && !/^[01]$/.test(cursorMove)) return false;
|
|
9565
|
+
for (const key of [
|
|
9566
|
+
"i",
|
|
9567
|
+
"I",
|
|
9568
|
+
"p"
|
|
9569
|
+
]) if (!kittyControlIsUint32(controls, key)) return false;
|
|
9570
|
+
for (const key of ["c", "r"]) if (!kittyControlIsUint32(controls, key, 1)) return false;
|
|
9571
|
+
if (!kittyControlIsTerminalGraphicCellsBounded(controls)) return false;
|
|
9572
|
+
for (const key of ["x", "y"]) if (!kittyControlIsUint32(controls, key)) return false;
|
|
9573
|
+
for (const key of ["w", "h"]) if (!kittyControlIsUint32(controls, key, 1)) return false;
|
|
9574
|
+
if (!kittyControlIsInt32(controls, "z")) return false;
|
|
9575
|
+
const transmissionMedium = controls.get("t");
|
|
9576
|
+
if (transmissionMedium != null && transmissionMedium !== "d") return false;
|
|
9577
|
+
return true;
|
|
9578
|
+
}
|
|
9579
|
+
function validateKittySequence(sequence, op = "draw") {
|
|
9580
|
+
const packets = parseKittyPackets(sequence);
|
|
9581
|
+
if (!packets) return false;
|
|
9582
|
+
if (op === "clear") {
|
|
9583
|
+
if (packets.length !== 1) return false;
|
|
9584
|
+
const packet = packets[0];
|
|
9585
|
+
if (!kittyControlsUseOnly(packet.controls, KITTY_CLEAR_CONTROL_KEYS)) return false;
|
|
9586
|
+
if (!validateKittySharedSafeControls(packet.controls)) return false;
|
|
9587
|
+
if (packet.payload) return false;
|
|
9588
|
+
if (packet.controls.get("a") !== "d") return false;
|
|
9589
|
+
const d = packet.controls.get("d");
|
|
9590
|
+
return d == null || /^[aAcCiI]$/.test(d);
|
|
9591
|
+
}
|
|
9592
|
+
const first = packets[0];
|
|
9593
|
+
if (!kittyControlsUseOnly(first.controls, KITTY_DRAW_FIRST_CONTROL_KEYS)) return false;
|
|
9594
|
+
if (!validateKittySharedSafeControls(first.controls)) return false;
|
|
9595
|
+
if (first.controls.get("a") === "p") {
|
|
9596
|
+
if (packets.length !== 1) return false;
|
|
9597
|
+
if (first.payload) return false;
|
|
9598
|
+
if (!first.controls.has("i") && !first.controls.has("I")) return false;
|
|
9599
|
+
return true;
|
|
9600
|
+
}
|
|
9601
|
+
if (first.controls.get("a") !== "T") return false;
|
|
9602
|
+
if (!first.payload) return false;
|
|
9603
|
+
const f = first.controls.get("f");
|
|
9604
|
+
if (f != null && f !== "24" && f !== "32" && f !== "100") return false;
|
|
9605
|
+
const firstMore = first.controls.get("m");
|
|
9606
|
+
if (firstMore != null && firstMore !== "0" && firstMore !== "1") return false;
|
|
9607
|
+
if (packets.length > 1 && firstMore !== "1") return false;
|
|
9608
|
+
for (let i = 1; i < packets.length; i++) {
|
|
9609
|
+
const packet = packets[i];
|
|
9610
|
+
if (!kittyControlsUseOnly(packet.controls, KITTY_DRAW_CONTINUATION_CONTROL_KEYS)) return false;
|
|
9611
|
+
if (!validateKittySharedSafeControls(packet.controls)) return false;
|
|
9612
|
+
const action = packet.controls.get("a");
|
|
9613
|
+
if (action != null && action !== "T") return false;
|
|
9614
|
+
const m = packet.controls.get("m");
|
|
9615
|
+
if (m !== "0" && m !== "1") return false;
|
|
9616
|
+
if (!packet.payload && !(i === packets.length - 1 && m === "0")) return false;
|
|
9617
|
+
}
|
|
9618
|
+
if (packets.length > 1 && packets[packets.length - 1].controls.get("m") === "1") return false;
|
|
9619
|
+
return true;
|
|
9620
|
+
}
|
|
9621
|
+
function validateIterm2Dimension(value) {
|
|
9622
|
+
return /^auto$/i.test(value) || /^(?:[1-9]\d{0,4})(?:px|%)?$/.test(value);
|
|
9623
|
+
}
|
|
9624
|
+
function validateIterm2Params(params) {
|
|
9625
|
+
const seen = new Set();
|
|
9626
|
+
let inline = false;
|
|
9627
|
+
for (const part of params.split(";").filter(Boolean)) {
|
|
9628
|
+
const eq = part.indexOf("=");
|
|
9629
|
+
if (eq <= 0) return false;
|
|
9630
|
+
const key = part.slice(0, eq);
|
|
9631
|
+
const value = part.slice(eq + 1);
|
|
9632
|
+
if (seen.has(key)) return false;
|
|
9633
|
+
seen.add(key);
|
|
9634
|
+
switch (key) {
|
|
9635
|
+
case "inline":
|
|
9636
|
+
if (value !== "1") return false;
|
|
9637
|
+
inline = true;
|
|
9638
|
+
break;
|
|
9639
|
+
case "width":
|
|
9640
|
+
case "height":
|
|
9641
|
+
if (!validateIterm2Dimension(value)) return false;
|
|
9642
|
+
break;
|
|
9643
|
+
case "preserveAspectRatio":
|
|
9644
|
+
case "doNotMoveCursor":
|
|
9645
|
+
if (!/^[01]$/.test(value)) return false;
|
|
9646
|
+
break;
|
|
9647
|
+
default: return false;
|
|
9648
|
+
}
|
|
9649
|
+
}
|
|
9650
|
+
return inline;
|
|
9651
|
+
}
|
|
9652
|
+
function validateIterm2Sequence(sequence, op = "draw") {
|
|
9653
|
+
if (op === "clear") return false;
|
|
9654
|
+
let index = 0;
|
|
9655
|
+
while (index < sequence.length) {
|
|
9656
|
+
const prefix = `${ESC}]1337;File=`;
|
|
9657
|
+
if (!sequence.startsWith(prefix, index)) return false;
|
|
9658
|
+
const belEnd = sequence.indexOf(BEL, index + prefix.length);
|
|
9659
|
+
const stEnd = sequence.indexOf(ST, index + prefix.length);
|
|
9660
|
+
const end = belEnd >= 0 && stEnd >= 0 ? Math.min(belEnd, stEnd) : belEnd >= 0 ? belEnd : stEnd;
|
|
9661
|
+
if (end < 0) return false;
|
|
9662
|
+
const body = sequence.slice(index + `${ESC}]1337;`.length, end);
|
|
9663
|
+
if (!body.startsWith("File=")) return false;
|
|
9664
|
+
if (!withoutNestedEscapes(body)) return false;
|
|
9665
|
+
const colon = body.indexOf(":");
|
|
9666
|
+
if (colon < 0) return false;
|
|
9667
|
+
const params = body.slice(5, colon);
|
|
9668
|
+
const payload = body.slice(colon + 1);
|
|
9669
|
+
if (!/^[A-Za-z0-9_=;,.%+\-:]*$/.test(params)) return false;
|
|
9670
|
+
if (!payload || !isBase64ish(payload)) return false;
|
|
9671
|
+
if (!validateIterm2Params(params)) return false;
|
|
9672
|
+
index = end + (end === stEnd ? ST.length : BEL.length);
|
|
9673
|
+
}
|
|
9674
|
+
return sequence.length > 0;
|
|
9675
|
+
}
|
|
9676
|
+
function validateSixelSequence(sequence, op = "draw") {
|
|
9677
|
+
if (op === "clear") return false;
|
|
9678
|
+
let index = 0;
|
|
9679
|
+
while (index < sequence.length) {
|
|
9680
|
+
if (!sequence.startsWith(`${ESC}P`, index)) return false;
|
|
9681
|
+
const end = sequence.indexOf(ST, index + 2);
|
|
9682
|
+
if (end < 0) return false;
|
|
9683
|
+
const body = sequence.slice(index + 2, end);
|
|
9684
|
+
if (!withoutNestedEscapes(body)) return false;
|
|
9685
|
+
for (let i = 0; i < body.length; i++) {
|
|
9686
|
+
const code = body.charCodeAt(i);
|
|
9687
|
+
if (code < 32 || code > 126) return false;
|
|
9688
|
+
}
|
|
9689
|
+
const q = body.indexOf("q");
|
|
9690
|
+
if (q < 0 || q > 32) return false;
|
|
9691
|
+
const introducer = body.slice(0, q);
|
|
9692
|
+
if (!/^[0-9;?]*$/.test(introducer)) return false;
|
|
9693
|
+
const data = body.slice(q + 1);
|
|
9694
|
+
if (!data.length) return false;
|
|
9695
|
+
index = end + ST.length;
|
|
9696
|
+
}
|
|
9697
|
+
return sequence.length > 0;
|
|
9698
|
+
}
|
|
9699
|
+
function stripTerminalControlChars(value) {
|
|
9700
|
+
let out = "";
|
|
9701
|
+
for (let index = 0; index < value.length; index++) {
|
|
9702
|
+
const code = value.charCodeAt(index);
|
|
9703
|
+
if (code <= 8 || code === 11 || code === 12 || code >= 14 && code <= 31 || code === 127 || code >= 128 && code <= 159) continue;
|
|
9704
|
+
out += value[index];
|
|
9705
|
+
}
|
|
9706
|
+
return out;
|
|
9707
|
+
}
|
|
9708
|
+
function sanitizeTerminalFallbackText(text) {
|
|
9709
|
+
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);
|
|
9710
|
+
}
|
|
9711
|
+
function validateTerminalGraphicFrame(frame) {
|
|
9712
|
+
const startedAt = nowTerminalGraphicTraceTime();
|
|
9713
|
+
const protocol = isTerminalGraphicsProtocol(frame.protocol) ? frame.protocol : void 0;
|
|
9714
|
+
const recordValidation = () => {
|
|
9715
|
+
recordTerminalGraphicTrace({
|
|
9716
|
+
type: "validate-end",
|
|
9717
|
+
id: frame.id ?? "",
|
|
9718
|
+
protocol,
|
|
9719
|
+
durationMs: nowTerminalGraphicTraceTime() - startedAt,
|
|
9720
|
+
bytes: typeof frame.sequence === "string" ? frame.sequence.length : void 0
|
|
9721
|
+
});
|
|
9722
|
+
};
|
|
9723
|
+
if (!protocol) {
|
|
9724
|
+
recordValidation();
|
|
9725
|
+
return null;
|
|
9726
|
+
}
|
|
9727
|
+
const sequence = String(frame.sequence ?? "");
|
|
9728
|
+
if (sequence.length <= 0 || sequence.length > MAX_TERMINAL_GRAPHICS_SEQUENCE_CHARS) {
|
|
9729
|
+
recordValidation();
|
|
9730
|
+
return null;
|
|
9731
|
+
}
|
|
9732
|
+
const size = normalizeTerminalGraphicSize(frame.width, frame.height);
|
|
9733
|
+
if (!size) {
|
|
9734
|
+
recordValidation();
|
|
9735
|
+
return null;
|
|
9736
|
+
}
|
|
9737
|
+
const ok = protocol === "kitty" ? validateKittySequence(sequence, "draw") : protocol === "iterm2" ? validateIterm2Sequence(sequence, "draw") : validateSixelSequence(sequence, "draw");
|
|
9738
|
+
if (!ok) {
|
|
9739
|
+
recordValidation();
|
|
9740
|
+
return null;
|
|
9741
|
+
}
|
|
9742
|
+
recordValidation();
|
|
9743
|
+
return {
|
|
9744
|
+
...frame,
|
|
9745
|
+
protocol,
|
|
9746
|
+
id: frame.id || stableId(`${protocol}:${sequence.slice(0, 4096)}`),
|
|
9747
|
+
sequence,
|
|
9748
|
+
fallbackText: sanitizeTerminalFallbackText(frame.fallbackText),
|
|
9749
|
+
width: size.width,
|
|
9750
|
+
height: size.height
|
|
9751
|
+
};
|
|
9752
|
+
}
|
|
9753
|
+
function isSafeTerminalGraphicsSequence(sequence, protocol, op = "draw") {
|
|
9754
|
+
if (!isTerminalGraphicsProtocol(protocol)) return false;
|
|
9755
|
+
if (!sequence || sequence.length > MAX_TERMINAL_GRAPHICS_SEQUENCE_CHARS) return false;
|
|
9756
|
+
return protocol === "kitty" ? validateKittySequence(sequence, op) : protocol === "iterm2" ? validateIterm2Sequence(sequence, op) : validateSixelSequence(sequence, op);
|
|
9757
|
+
}
|
|
9758
|
+
function validateTerminalGraphicsPayload(payload, capabilities) {
|
|
9759
|
+
if (!payload.id.trim()) return false;
|
|
9760
|
+
if (!Number.isFinite(payload.x) || !Number.isFinite(payload.y)) return false;
|
|
9761
|
+
if (!normalizeTerminalGraphicSize(payload.w ?? 1, payload.h ?? 1)) return false;
|
|
9762
|
+
if (!capabilities.supported) return false;
|
|
9763
|
+
if (!isTerminalGraphicsProtocol(payload.protocol)) return false;
|
|
9764
|
+
if (payload.protocol !== capabilities.preferredProtocol) return false;
|
|
9765
|
+
return isSafeTerminalGraphicsSequence(payload.sequence, payload.protocol, payload.op ?? "draw");
|
|
9766
|
+
}
|
|
9767
|
+
function uint32Control(key, value, min = 0) {
|
|
9768
|
+
if (value == null) return "";
|
|
9769
|
+
const n = Math.floor(value);
|
|
9770
|
+
return Number.isSafeInteger(n) && n >= min && n <= KITTY_UINT32_MAX ? `${key}=${n}` : "";
|
|
9771
|
+
}
|
|
9772
|
+
function int32Control(key, value) {
|
|
9773
|
+
if (value == null) return "";
|
|
9774
|
+
const n = Math.floor(value);
|
|
9775
|
+
return Number.isSafeInteger(n) && n >= KITTY_INT32_MIN && n <= KITTY_INT32_MAX ? `${key}=${n}` : "";
|
|
9776
|
+
}
|
|
9777
|
+
function sanitizeBase64(value) {
|
|
9778
|
+
const data = String(value ?? "").replace(/\s+/g, "");
|
|
9779
|
+
return isBase64ish(data) ? data : "";
|
|
9780
|
+
}
|
|
9781
|
+
function kittyGraphicCellControls(columns, rows) {
|
|
9782
|
+
if (columns == null && rows == null) return [];
|
|
9783
|
+
const size = normalizeTerminalGraphicSize(columns ?? 1, rows ?? 1);
|
|
9784
|
+
if (!size) return [];
|
|
9785
|
+
return [columns == null ? "" : `c=${size.width}`, rows == null ? "" : `r=${size.height}`];
|
|
9786
|
+
}
|
|
9787
|
+
function kittyGraphicSourceControls(sourceX, sourceY, sourceWidth, sourceHeight) {
|
|
9788
|
+
return [
|
|
9789
|
+
uint32Control("x", sourceX),
|
|
9790
|
+
uint32Control("y", sourceY),
|
|
9791
|
+
uint32Control("w", sourceWidth, 1),
|
|
9792
|
+
uint32Control("h", sourceHeight, 1)
|
|
9793
|
+
];
|
|
9794
|
+
}
|
|
9795
|
+
function chunkBase64(value, chunkSize) {
|
|
9796
|
+
const normalizedSize = Math.max(4, Math.floor(chunkSize / 4) * 4);
|
|
9797
|
+
const chunks = [];
|
|
9798
|
+
for (let index = 0; index < value.length; index += normalizedSize) chunks.push(value.slice(index, index + normalizedSize));
|
|
9799
|
+
return chunks.length ? chunks : [""];
|
|
9800
|
+
}
|
|
9801
|
+
function createKittyGraphicsSequence(base64Png, options = {}) {
|
|
9802
|
+
const data = sanitizeBase64(base64Png);
|
|
9803
|
+
if (!data) return "";
|
|
9804
|
+
const chunks = chunkBase64(data, options.chunkSize ?? 4096);
|
|
9805
|
+
const baseControls = [
|
|
9806
|
+
"a=T",
|
|
9807
|
+
"f=100",
|
|
9808
|
+
options.quiet === false ? "" : "q=2",
|
|
9809
|
+
options.noCursorMove === false ? "" : "C=1",
|
|
9810
|
+
uint32Control("i", options.imageId),
|
|
9811
|
+
uint32Control("I", options.imageNumber),
|
|
9812
|
+
uint32Control("p", options.placementId),
|
|
9813
|
+
...kittyGraphicCellControls(options.columns, options.rows),
|
|
9814
|
+
...kittyGraphicSourceControls(options.sourceX, options.sourceY, options.sourceWidth, options.sourceHeight),
|
|
9815
|
+
int32Control("z", options.zIndex)
|
|
9816
|
+
].filter(Boolean);
|
|
9817
|
+
return chunks.map((chunk, index) => {
|
|
9818
|
+
const last = index === chunks.length - 1;
|
|
9819
|
+
const controls = index === 0 ? [...baseControls, chunks.length > 1 ? `m=${last ? 0 : 1}` : ""] : [options.quiet === false ? "" : "q=2", `m=${last ? 0 : 1}`].filter(Boolean);
|
|
9820
|
+
return `${ESC}_G${controls.filter(Boolean).join(",")};${chunk}${ST}`;
|
|
9821
|
+
}).join("");
|
|
9822
|
+
}
|
|
9823
|
+
function createKittyDeleteGraphicsSequence(options = {}) {
|
|
9824
|
+
const controls = ["a=d"];
|
|
9825
|
+
if (options.allVisible) controls.push(`d=${options.freeImageData ? "A" : "a"}`);
|
|
9826
|
+
else if (options.imageId != null) {
|
|
9827
|
+
const imageId = uint32Control("i", options.imageId);
|
|
9828
|
+
const placementId = uint32Control("p", options.placementId);
|
|
9829
|
+
if (!imageId || options.placementId != null && !placementId) return "";
|
|
9830
|
+
controls.push(`d=${options.freeImageData ? "I" : "i"}`);
|
|
9831
|
+
controls.push(imageId);
|
|
9832
|
+
controls.push(placementId);
|
|
9833
|
+
} else if (options.currentCell) controls.push(`d=${options.freeImageData ? "C" : "c"}`);
|
|
9834
|
+
else return "";
|
|
9835
|
+
if (options.quiet !== false) controls.push("q=2");
|
|
9836
|
+
return `${ESC}_G${controls.filter(Boolean).join(",")}${ST}`;
|
|
9837
|
+
}
|
|
9838
|
+
function createIterm2InlineImageSequence(base64Data, options = {}) {
|
|
9839
|
+
const data = sanitizeBase64(base64Data);
|
|
9840
|
+
if (!data) return "";
|
|
9841
|
+
const params = [
|
|
9842
|
+
"inline=1",
|
|
9843
|
+
options.width != null ? `width=${formatItermDimension(options.width)}` : "",
|
|
9844
|
+
options.height != null ? `height=${formatItermDimension(options.height)}` : "",
|
|
9845
|
+
`preserveAspectRatio=${options.preserveAspectRatio === false ? 0 : 1}`,
|
|
9846
|
+
options.doNotMoveCursor === false ? "" : "doNotMoveCursor=1"
|
|
9847
|
+
].filter(Boolean);
|
|
9848
|
+
return `${ESC}]1337;File=${params.join(";")}:${data}${BEL}`;
|
|
9849
|
+
}
|
|
9850
|
+
function formatItermDimension(value) {
|
|
9851
|
+
if (typeof value === "number") {
|
|
9852
|
+
const n = Math.floor(value);
|
|
9853
|
+
if (!Number.isFinite(n)) return "auto";
|
|
9854
|
+
return String(Math.min(99999, Math.max(1, n)));
|
|
9855
|
+
}
|
|
9856
|
+
const raw = String(value ?? "").trim();
|
|
9857
|
+
return validateIterm2Dimension(raw) ? raw : "auto";
|
|
9858
|
+
}
|
|
9859
|
+
function wrapTerminalGraphicsForMultiplexer(sequence, capabilities) {
|
|
9860
|
+
if (!capabilities.passthrough) return sequence;
|
|
9861
|
+
if (capabilities.multiplexer === "tmux") return `${ESC}Ptmux;${sequence.split(ESC).join(`${ESC}${ESC}`)}${ST}`;
|
|
9862
|
+
return sequence;
|
|
9863
|
+
}
|
|
9864
|
+
|
|
8420
9865
|
//#endregion
|
|
8421
9866
|
//#region src/renderer/cli/stdout-renderer.ts
|
|
8422
9867
|
let debugLog = null;
|
|
@@ -8431,7 +9876,27 @@ const SYNC_START = "\x1B[?2026h";
|
|
|
8431
9876
|
const SYNC_END = "\x1B[?2026l";
|
|
8432
9877
|
const OSC8_OPEN = (href) => `\u001B]8;;${href}\u0007`;
|
|
8433
9878
|
const OSC8_CLOSE = "\x1B]8;;\x07";
|
|
9879
|
+
const CURSOR_SAVE = "\x1B7";
|
|
9880
|
+
const CURSOR_RESTORE = "\x1B8";
|
|
9881
|
+
const CURSOR_HOME = "\x1B[H";
|
|
8434
9882
|
const stdoutFingerprintOwners = new WeakMap();
|
|
9883
|
+
function isTerminalGraphicsCapabilities(value) {
|
|
9884
|
+
return typeof value === "object" && value !== null && "supported" in value && "protocol" in value && "preferredProtocol" in value && "candidates" in value;
|
|
9885
|
+
}
|
|
9886
|
+
function resolveTerminalGraphicsCapabilities(options, env, outputIsTTY) {
|
|
9887
|
+
const terminalGraphics = options === null || options === void 0 ? void 0 : options.terminalGraphics;
|
|
9888
|
+
if (terminalGraphics === false) return detectTerminalGraphicsCapabilities({
|
|
9889
|
+
env,
|
|
9890
|
+
isTTY: outputIsTTY,
|
|
9891
|
+
protocol: "none"
|
|
9892
|
+
});
|
|
9893
|
+
if (isTerminalGraphicsCapabilities(terminalGraphics)) return terminalGraphics;
|
|
9894
|
+
return detectTerminalGraphicsCapabilities({
|
|
9895
|
+
env,
|
|
9896
|
+
isTTY: outputIsTTY,
|
|
9897
|
+
...terminalGraphics ?? {}
|
|
9898
|
+
});
|
|
9899
|
+
}
|
|
8435
9900
|
function createStdoutRenderer(terminal, options) {
|
|
8436
9901
|
const env = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
8437
9902
|
if (shouldInstallFileWriters(env)) installNodeFileWriters();
|
|
@@ -8449,6 +9914,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8449
9914
|
const clear = (options === null || options === void 0 ? void 0 : options.clear) ?? true;
|
|
8450
9915
|
const hideCursor = (options === null || options === void 0 ? void 0 : options.hideCursor) ?? true;
|
|
8451
9916
|
const altScreen = (options === null || options === void 0 ? void 0 : options.altScreen) ?? outputIsTTY;
|
|
9917
|
+
const keepLineWrapDisabled = altScreen && outputIsTTY;
|
|
8452
9918
|
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
9919
|
let palette = (options === null || options === void 0 ? void 0 : options.palette) ?? null;
|
|
8454
9920
|
const trackResize = (options === null || options === void 0 ? void 0 : options.trackResize) ?? true;
|
|
@@ -8581,6 +10047,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8581
10047
|
let lastFrameTime = 0;
|
|
8582
10048
|
let pendingRender = false;
|
|
8583
10049
|
let renderTimer = null;
|
|
10050
|
+
let rowsOnlyResizeRepaintTimer = null;
|
|
8584
10051
|
let writeEmaMs = 0;
|
|
8585
10052
|
let lastCursorX = null;
|
|
8586
10053
|
let lastCursorY = null;
|
|
@@ -8591,7 +10058,505 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8591
10058
|
let accumulatedDirtyMax = -1;
|
|
8592
10059
|
let accumulatedDirtyRowsRequireRepaint = false;
|
|
8593
10060
|
let accumulatedScrollOperations = null;
|
|
10061
|
+
let allowNextGraphicsOnlyRenderWithoutBaseline = false;
|
|
10062
|
+
let preserveNextRowsOnlyResizeBaseline = false;
|
|
10063
|
+
let deferGraphicsFlushUntilResizeCommit = false;
|
|
10064
|
+
const graphicsCapabilities = resolveTerminalGraphicsCapabilities(options, env, outputIsTTY);
|
|
10065
|
+
const pendingGraphics = new Map();
|
|
10066
|
+
const pendingGraphicClears = new Set();
|
|
10067
|
+
const activeGraphics = new Map();
|
|
10068
|
+
const pendingGraphicSignatures = new Map();
|
|
10069
|
+
const activeGraphicSignatures = new Map();
|
|
10070
|
+
const retainedGraphics = new Map();
|
|
10071
|
+
const knownKittyImageIds = new Set();
|
|
10072
|
+
const terminalResizeDirtyGraphics = new Set();
|
|
10073
|
+
let nextGraphicsOrder = 0;
|
|
10074
|
+
let terminalGraphicsFlushTimer = null;
|
|
10075
|
+
const hasPendingTerminalGraphics = () => pendingGraphics.size > 0 || pendingGraphicClears.size > 0;
|
|
10076
|
+
function canUseTerminalGraphicsProtocol(protocol, capabilities) {
|
|
10077
|
+
return capabilities.supported && isTerminalGraphicsProtocol(protocol) && protocol === capabilities.preferredProtocol;
|
|
10078
|
+
}
|
|
10079
|
+
function requestTerminalGraphicsFlush(defer = false) {
|
|
10080
|
+
if (disposed) return;
|
|
10081
|
+
if (deferGraphicsFlushUntilResizeCommit) {
|
|
10082
|
+
if (isDebugEnabled()) getDebugLog().render("terminal graphics flush deferred until resize commit");
|
|
10083
|
+
return;
|
|
10084
|
+
}
|
|
10085
|
+
if (!defer) {
|
|
10086
|
+
render([], false);
|
|
10087
|
+
return;
|
|
10088
|
+
}
|
|
10089
|
+
if (terminalGraphicsFlushTimer) return;
|
|
10090
|
+
terminalGraphicsFlushTimer = setTimeout(() => {
|
|
10091
|
+
terminalGraphicsFlushTimer = null;
|
|
10092
|
+
if (!disposed) render([], false);
|
|
10093
|
+
}, 0);
|
|
10094
|
+
}
|
|
10095
|
+
function terminalGraphicsPayloadSignature(payload) {
|
|
10096
|
+
return [
|
|
10097
|
+
payload.id,
|
|
10098
|
+
payload.protocol,
|
|
10099
|
+
payload.x,
|
|
10100
|
+
payload.y,
|
|
10101
|
+
payload.w ?? "",
|
|
10102
|
+
payload.h ?? "",
|
|
10103
|
+
hashTerminalGraphicsString(payload.sequence),
|
|
10104
|
+
hashTerminalGraphicsString(payload.resizeSequence ?? ""),
|
|
10105
|
+
hashTerminalGraphicsString(payload.clearSequence ?? ""),
|
|
10106
|
+
payload.allowTextOverlay ? "1" : "0"
|
|
10107
|
+
].join(":");
|
|
10108
|
+
}
|
|
10109
|
+
function kittyClearSequenceKeepsImageData(sequence) {
|
|
10110
|
+
let index = 0;
|
|
10111
|
+
while (index < sequence.length) {
|
|
10112
|
+
const start = sequence.indexOf("\x1B_G", index);
|
|
10113
|
+
if (start < 0) return false;
|
|
10114
|
+
const end = sequence.indexOf("\x1B\\", start + 3);
|
|
10115
|
+
if (end < 0) return false;
|
|
10116
|
+
const body = sequence.slice(start + 3, end);
|
|
10117
|
+
const controls = body.slice(0, body.indexOf(";") < 0 ? body.length : body.indexOf(";"));
|
|
10118
|
+
const parts = controls.split(",");
|
|
10119
|
+
if (parts.includes("a=d") && parts.includes("d=i")) return true;
|
|
10120
|
+
index = end + 2;
|
|
10121
|
+
}
|
|
10122
|
+
return false;
|
|
10123
|
+
}
|
|
10124
|
+
function retainTerminalGraphic(id, active, signature, options$1 = {}) {
|
|
10125
|
+
if (!signature || active.protocol !== "kitty" || !active.resizeSequence || !active.clearSequence || !kittyClearSequenceKeepsImageData(active.clearSequence)) {
|
|
10126
|
+
retainedGraphics.delete(id);
|
|
10127
|
+
return;
|
|
10128
|
+
}
|
|
10129
|
+
retainedGraphics.set(id, {
|
|
10130
|
+
active,
|
|
10131
|
+
signature,
|
|
10132
|
+
autoRedrawOnResize: Boolean(options$1.autoRedrawOnResize)
|
|
10133
|
+
});
|
|
10134
|
+
}
|
|
10135
|
+
function kittyPlacementKey(sequence) {
|
|
10136
|
+
if (!sequence) return null;
|
|
10137
|
+
const start = sequence.indexOf("\x1B_G");
|
|
10138
|
+
if (start < 0) return null;
|
|
10139
|
+
const end = sequence.indexOf("\x1B\\", start + 3);
|
|
10140
|
+
if (end < 0) return null;
|
|
10141
|
+
const body = sequence.slice(start + 3, end);
|
|
10142
|
+
const controlsRaw = body.slice(0, body.indexOf(";") < 0 ? body.length : body.indexOf(";"));
|
|
10143
|
+
const controls = new Map();
|
|
10144
|
+
for (const part of controlsRaw.split(",")) {
|
|
10145
|
+
const eq = part.indexOf("=");
|
|
10146
|
+
if (eq <= 0) continue;
|
|
10147
|
+
controls.set(part.slice(0, eq), part.slice(eq + 1));
|
|
10148
|
+
}
|
|
10149
|
+
const imageId = controls.get("i");
|
|
10150
|
+
const placementId = controls.get("p");
|
|
10151
|
+
if (controls.get("a") !== "p" || !imageId || !placementId) return null;
|
|
10152
|
+
if (imageId === "0" || placementId === "0") return null;
|
|
10153
|
+
return `${imageId}:${placementId}`;
|
|
10154
|
+
}
|
|
10155
|
+
function kittyImageId(sequence) {
|
|
10156
|
+
if (!sequence) return null;
|
|
10157
|
+
const start = sequence.indexOf("\x1B_G");
|
|
10158
|
+
if (start < 0) return null;
|
|
10159
|
+
const end = sequence.indexOf("\x1B\\", start + 3);
|
|
10160
|
+
if (end < 0) return null;
|
|
10161
|
+
const body = sequence.slice(start + 3, end);
|
|
10162
|
+
const controlsRaw = body.slice(0, body.indexOf(";") < 0 ? body.length : body.indexOf(";"));
|
|
10163
|
+
for (const part of controlsRaw.split(",")) {
|
|
10164
|
+
if (!part.startsWith("i=")) continue;
|
|
10165
|
+
const imageId = Number(part.slice(2));
|
|
10166
|
+
return Number.isInteger(imageId) && imageId > 0 ? imageId : null;
|
|
10167
|
+
}
|
|
10168
|
+
return null;
|
|
10169
|
+
}
|
|
10170
|
+
function canReplaceKittyPlacementWithoutClear(previous, payload) {
|
|
10171
|
+
if (payload.terminalResizeRedraw) return false;
|
|
10172
|
+
if (!payload.resizeRedraw || previous.protocol !== "kitty" || payload.protocol !== "kitty") return false;
|
|
10173
|
+
const nextKey = kittyPlacementKey(payload.resizeSequence ?? payload.sequence);
|
|
10174
|
+
if (!nextKey) return false;
|
|
10175
|
+
return kittyPlacementKey(previous.resizeSequence ?? previous.sequence) === nextKey && (payload.placementMoveWithoutClear || sameGraphicRect(previous, {
|
|
10176
|
+
x: payload.x,
|
|
10177
|
+
y: payload.y,
|
|
10178
|
+
w: payload.w ?? previous.w,
|
|
10179
|
+
h: payload.h ?? previous.h
|
|
10180
|
+
}));
|
|
10181
|
+
}
|
|
10182
|
+
function queueTerminalGraphicClear(id, options$1 = {}) {
|
|
10183
|
+
if (disposed) return false;
|
|
10184
|
+
const removedPendingDraw = pendingGraphics.delete(`${id}:draw`);
|
|
10185
|
+
pendingGraphicSignatures.delete(id);
|
|
10186
|
+
terminalResizeDirtyGraphics.delete(id);
|
|
10187
|
+
const active = activeGraphics.get(id);
|
|
10188
|
+
if (!active) {
|
|
10189
|
+
if (!options$1.retainOnClear) retainedGraphics.delete(id);
|
|
10190
|
+
return removedPendingDraw;
|
|
10191
|
+
}
|
|
10192
|
+
if (active.clearSequence) {
|
|
10193
|
+
const payload = {
|
|
10194
|
+
id,
|
|
10195
|
+
x: active.x,
|
|
10196
|
+
y: active.y,
|
|
10197
|
+
w: active.w,
|
|
10198
|
+
h: active.h,
|
|
10199
|
+
protocol: active.protocol,
|
|
10200
|
+
sequence: active.clearSequence,
|
|
10201
|
+
retainOnClear: options$1.retainOnClear,
|
|
10202
|
+
op: "clear",
|
|
10203
|
+
order: nextGraphicsOrder++
|
|
10204
|
+
};
|
|
10205
|
+
if (validateTerminalGraphicsPayload(payload, graphicsCapabilities)) {
|
|
10206
|
+
pendingGraphics.set(`${id}:clear`, payload);
|
|
10207
|
+
recordTerminalGraphicTrace({
|
|
10208
|
+
type: "clear",
|
|
10209
|
+
id,
|
|
10210
|
+
protocol: payload.protocol
|
|
10211
|
+
});
|
|
10212
|
+
requestTerminalGraphicsFlush();
|
|
10213
|
+
return true;
|
|
10214
|
+
}
|
|
10215
|
+
}
|
|
10216
|
+
pendingGraphicClears.add(id);
|
|
10217
|
+
recordTerminalGraphicTrace({
|
|
10218
|
+
type: "clear",
|
|
10219
|
+
id
|
|
10220
|
+
});
|
|
10221
|
+
requestTerminalGraphicsFlush();
|
|
10222
|
+
return true;
|
|
10223
|
+
}
|
|
10224
|
+
function clearAllTerminalGraphics() {
|
|
10225
|
+
if (disposed || graphicsCapabilities.preferredProtocol !== "kitty") return false;
|
|
10226
|
+
const imageIds = new Set(knownKittyImageIds);
|
|
10227
|
+
let needsVisibleFallback = false;
|
|
10228
|
+
const rememberImageId = (...sequences) => {
|
|
10229
|
+
for (const sequence of sequences) {
|
|
10230
|
+
const imageId = kittyImageId(sequence);
|
|
10231
|
+
if (imageId != null) {
|
|
10232
|
+
imageIds.add(imageId);
|
|
10233
|
+
return;
|
|
10234
|
+
}
|
|
10235
|
+
}
|
|
10236
|
+
needsVisibleFallback = true;
|
|
10237
|
+
};
|
|
10238
|
+
for (const active of activeGraphics.values()) rememberImageId(active.sequence, active.resizeSequence, active.clearSequence);
|
|
10239
|
+
for (const retained of retainedGraphics.values()) rememberImageId(retained.active.sequence, retained.active.resizeSequence, retained.active.clearSequence);
|
|
10240
|
+
for (const payload of pendingGraphics.values()) rememberImageId(payload.sequence, payload.resizeSequence, payload.clearSequence);
|
|
10241
|
+
pendingGraphics.clear();
|
|
10242
|
+
pendingGraphicClears.clear();
|
|
10243
|
+
activeGraphics.clear();
|
|
10244
|
+
pendingGraphicSignatures.clear();
|
|
10245
|
+
activeGraphicSignatures.clear();
|
|
10246
|
+
retainedGraphics.clear();
|
|
10247
|
+
knownKittyImageIds.clear();
|
|
10248
|
+
terminalResizeDirtyGraphics.clear();
|
|
10249
|
+
for (const imageId of imageIds) {
|
|
10250
|
+
const payload = {
|
|
10251
|
+
id: `__terminal_graphics_clear_image_${imageId}__`,
|
|
10252
|
+
x: 0,
|
|
10253
|
+
y: 0,
|
|
10254
|
+
w: 1,
|
|
10255
|
+
h: 1,
|
|
10256
|
+
protocol: "kitty",
|
|
10257
|
+
sequence: createKittyDeleteGraphicsSequence({
|
|
10258
|
+
imageId,
|
|
10259
|
+
freeImageData: true
|
|
10260
|
+
}),
|
|
10261
|
+
op: "clear",
|
|
10262
|
+
order: nextGraphicsOrder++
|
|
10263
|
+
};
|
|
10264
|
+
if (validateTerminalGraphicsPayload(payload, graphicsCapabilities)) pendingGraphics.set(`${payload.id}:clear`, payload);
|
|
10265
|
+
}
|
|
10266
|
+
if (needsVisibleFallback) {
|
|
10267
|
+
const payload = {
|
|
10268
|
+
id: "__terminal_graphics_clear_visible__",
|
|
10269
|
+
x: 0,
|
|
10270
|
+
y: 0,
|
|
10271
|
+
w: 1,
|
|
10272
|
+
h: 1,
|
|
10273
|
+
protocol: "kitty",
|
|
10274
|
+
sequence: createKittyDeleteGraphicsSequence({
|
|
10275
|
+
allVisible: true,
|
|
10276
|
+
freeImageData: true
|
|
10277
|
+
}),
|
|
10278
|
+
op: "clear",
|
|
10279
|
+
order: nextGraphicsOrder++
|
|
10280
|
+
};
|
|
10281
|
+
if (validateTerminalGraphicsPayload(payload, graphicsCapabilities)) pendingGraphics.set(`${payload.id}:clear`, payload);
|
|
10282
|
+
}
|
|
10283
|
+
if (pendingGraphics.size === 0) return false;
|
|
10284
|
+
requestTerminalGraphicsFlush();
|
|
10285
|
+
return true;
|
|
10286
|
+
}
|
|
10287
|
+
function queueTerminalGraphicsForResizeRedraw(size) {
|
|
10288
|
+
if (isDebugEnabled()) getDebugLog().render(`graphics resize redraw queue: size=${size.cols}x${size.rows}, activeGraphics=${activeGraphics.size}, pendingGraphics=${pendingGraphics.size}, pendingClears=${pendingGraphicClears.size}`);
|
|
10289
|
+
for (const [id, active] of activeGraphics) {
|
|
10290
|
+
terminalResizeDirtyGraphics.add(id);
|
|
10291
|
+
pendingGraphics.delete(`${id}:draw`);
|
|
10292
|
+
const anchored = anchoredGraphicRectInViewport(active, size);
|
|
10293
|
+
if (anchored && !active.resizeSequence) {
|
|
10294
|
+
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`);
|
|
10295
|
+
continue;
|
|
10296
|
+
}
|
|
10297
|
+
const signature = activeGraphicSignatures.get(id);
|
|
10298
|
+
const sequence = active.sequence;
|
|
10299
|
+
pendingGraphics.set(`${id}:draw`, {
|
|
10300
|
+
id,
|
|
10301
|
+
x: active.x,
|
|
10302
|
+
y: active.y,
|
|
10303
|
+
w: active.w,
|
|
10304
|
+
h: active.h,
|
|
10305
|
+
protocol: active.protocol,
|
|
10306
|
+
sequence,
|
|
10307
|
+
resizeSequence: active.resizeSequence,
|
|
10308
|
+
clearSequence: active.clearSequence,
|
|
10309
|
+
allowTextOverlay: active.allowTextOverlay,
|
|
10310
|
+
op: "draw",
|
|
10311
|
+
order: nextGraphicsOrder++,
|
|
10312
|
+
resizeRedraw: true,
|
|
10313
|
+
terminalResizeRedraw: true
|
|
10314
|
+
});
|
|
10315
|
+
if (signature) pendingGraphicSignatures.set(id, signature);
|
|
10316
|
+
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}`);
|
|
10317
|
+
}
|
|
10318
|
+
for (const [id, retained] of retainedGraphics) {
|
|
10319
|
+
if (activeGraphics.has(id) || !retained.autoRedrawOnResize) continue;
|
|
10320
|
+
const { active, signature } = retained;
|
|
10321
|
+
if (!anchoredGraphicRectInViewport(active, size)) continue;
|
|
10322
|
+
retainedGraphics.delete(id);
|
|
10323
|
+
activeGraphics.set(id, active);
|
|
10324
|
+
activeGraphicSignatures.set(id, signature);
|
|
10325
|
+
pendingGraphicClears.delete(id);
|
|
10326
|
+
pendingGraphics.delete(`${id}:clear`);
|
|
10327
|
+
pendingGraphics.set(`${id}:draw`, {
|
|
10328
|
+
id,
|
|
10329
|
+
x: active.x,
|
|
10330
|
+
y: active.y,
|
|
10331
|
+
w: active.w,
|
|
10332
|
+
h: active.h,
|
|
10333
|
+
protocol: active.protocol,
|
|
10334
|
+
sequence: active.sequence,
|
|
10335
|
+
resizeSequence: active.resizeSequence,
|
|
10336
|
+
clearSequence: active.clearSequence,
|
|
10337
|
+
allowTextOverlay: active.allowTextOverlay,
|
|
10338
|
+
op: "draw",
|
|
10339
|
+
order: nextGraphicsOrder++,
|
|
10340
|
+
resizeRedraw: true,
|
|
10341
|
+
terminalResizeRedraw: true
|
|
10342
|
+
});
|
|
10343
|
+
pendingGraphicSignatures.set(id, signature);
|
|
10344
|
+
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}`);
|
|
10345
|
+
}
|
|
10346
|
+
}
|
|
10347
|
+
const graphicsOutput = {
|
|
10348
|
+
capabilities: graphicsCapabilities,
|
|
10349
|
+
isActive(id) {
|
|
10350
|
+
if (pendingGraphicClears.has(id) || pendingGraphics.has(`${id}:clear`)) return false;
|
|
10351
|
+
return activeGraphics.has(id) || retainedGraphics.has(id) || pendingGraphics.has(`${id}:draw`);
|
|
10352
|
+
},
|
|
10353
|
+
queue(payload) {
|
|
10354
|
+
if (disposed) return false;
|
|
10355
|
+
const x = Math.floor(payload.x);
|
|
10356
|
+
const y = Math.floor(payload.y);
|
|
10357
|
+
const op = payload.op ?? "draw";
|
|
10358
|
+
const normalized = {
|
|
10359
|
+
...payload,
|
|
10360
|
+
x,
|
|
10361
|
+
y,
|
|
10362
|
+
w: payload.w == null ? void 0 : Math.floor(payload.w),
|
|
10363
|
+
h: payload.h == null ? void 0 : Math.floor(payload.h),
|
|
10364
|
+
op,
|
|
10365
|
+
order: nextGraphicsOrder++
|
|
10366
|
+
};
|
|
10367
|
+
if (!normalized.id.trim()) return false;
|
|
10368
|
+
if (!Number.isFinite(normalized.x) || !Number.isFinite(normalized.y)) return false;
|
|
10369
|
+
if (!canUseTerminalGraphicsProtocol(normalized.protocol, graphicsCapabilities)) return false;
|
|
10370
|
+
if (op === "draw") {
|
|
10371
|
+
const frame = validateTerminalGraphicFrame({
|
|
10372
|
+
id: normalized.id,
|
|
10373
|
+
protocol: normalized.protocol,
|
|
10374
|
+
sequence: normalized.sequence,
|
|
10375
|
+
fallbackText: normalized.fallbackText,
|
|
10376
|
+
width: normalized.w ?? 1,
|
|
10377
|
+
height: normalized.h ?? 1
|
|
10378
|
+
});
|
|
10379
|
+
if (!frame) return false;
|
|
10380
|
+
const imageId = kittyImageId(frame.sequence) ?? kittyImageId(normalized.resizeSequence);
|
|
10381
|
+
if (imageId != null) knownKittyImageIds.add(imageId);
|
|
10382
|
+
if (isDebugEnabled()) {
|
|
10383
|
+
const size = terminal.size();
|
|
10384
|
+
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}`);
|
|
10385
|
+
}
|
|
10386
|
+
if (!anchoredGraphicRectInViewport({
|
|
10387
|
+
x: normalized.x,
|
|
10388
|
+
y: normalized.y,
|
|
10389
|
+
w: frame.width,
|
|
10390
|
+
h: frame.height
|
|
10391
|
+
}, terminal.size())) {
|
|
10392
|
+
if (isDebugEnabled()) {
|
|
10393
|
+
const size = terminal.size();
|
|
10394
|
+
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}`);
|
|
10395
|
+
}
|
|
10396
|
+
queueTerminalGraphicClear(frame.id, { retainOnClear: normalized.retainOnClear });
|
|
10397
|
+
return false;
|
|
10398
|
+
}
|
|
10399
|
+
const clearSequence = normalized.clearSequence && isSafeTerminalGraphicsSequence(normalized.clearSequence, normalized.protocol, "clear") ? normalized.clearSequence : void 0;
|
|
10400
|
+
const resizeSequence = normalized.resizeSequence && isSafeTerminalGraphicsSequence(normalized.resizeSequence, normalized.protocol, "draw") ? normalized.resizeSequence : void 0;
|
|
10401
|
+
const signature = terminalGraphicsPayloadSignature({
|
|
10402
|
+
...normalized,
|
|
10403
|
+
id: frame.id,
|
|
10404
|
+
w: frame.width,
|
|
10405
|
+
h: frame.height,
|
|
10406
|
+
sequence: frame.sequence,
|
|
10407
|
+
resizeSequence,
|
|
10408
|
+
clearSequence
|
|
10409
|
+
});
|
|
10410
|
+
const forceTerminalResizeRedraw = terminalResizeDirtyGraphics.has(frame.id);
|
|
10411
|
+
const removedPendingGraphicClear = pendingGraphics.delete(`${frame.id}:clear`);
|
|
10412
|
+
const removedPendingClear = pendingGraphicClears.delete(frame.id);
|
|
10413
|
+
const canceledPendingClear = removedPendingGraphicClear || removedPendingClear;
|
|
10414
|
+
if (!forceTerminalResizeRedraw && !normalized.forceDraw && !canceledPendingClear && (pendingGraphicSignatures.get(frame.id) === signature || activeGraphicSignatures.get(frame.id) === signature)) {
|
|
10415
|
+
recordTerminalGraphicTrace({
|
|
10416
|
+
type: "queue-dedupe",
|
|
10417
|
+
id: frame.id,
|
|
10418
|
+
protocol: normalized.protocol
|
|
10419
|
+
});
|
|
10420
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphic queue draw dedupe: id=${frame.id}, x=${normalized.x}, y=${normalized.y}, w=${frame.width}, h=${frame.height}`);
|
|
10421
|
+
return true;
|
|
10422
|
+
}
|
|
10423
|
+
if (!forceTerminalResizeRedraw && !normalized.forceDraw && canceledPendingClear && activeGraphicSignatures.get(frame.id) === signature) {
|
|
10424
|
+
recordTerminalGraphicTrace({
|
|
10425
|
+
type: "queue-dedupe",
|
|
10426
|
+
id: frame.id,
|
|
10427
|
+
protocol: normalized.protocol
|
|
10428
|
+
});
|
|
10429
|
+
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}`);
|
|
10430
|
+
return true;
|
|
10431
|
+
}
|
|
10432
|
+
const active = activeGraphics.get(frame.id);
|
|
10433
|
+
const activeCanReplacePlacement = active && active.sequence === frame.sequence && resizeSequence && canReplaceKittyPlacementWithoutClear(active, {
|
|
10434
|
+
...normalized,
|
|
10435
|
+
id: frame.id,
|
|
10436
|
+
w: frame.width,
|
|
10437
|
+
h: frame.height,
|
|
10438
|
+
sequence: resizeSequence,
|
|
10439
|
+
resizeSequence,
|
|
10440
|
+
clearSequence,
|
|
10441
|
+
fallbackText: frame.fallbackText,
|
|
10442
|
+
resizeRedraw: true,
|
|
10443
|
+
placementMoveWithoutClear: true
|
|
10444
|
+
});
|
|
10445
|
+
if (!forceTerminalResizeRedraw && !normalized.forceDraw && !normalized.resizeRedraw && activeCanReplacePlacement && resizeSequence) {
|
|
10446
|
+
pendingGraphics.set(`${frame.id}:draw`, {
|
|
10447
|
+
...normalized,
|
|
10448
|
+
id: frame.id,
|
|
10449
|
+
w: frame.width,
|
|
10450
|
+
h: frame.height,
|
|
10451
|
+
sequence: resizeSequence,
|
|
10452
|
+
resizeSequence,
|
|
10453
|
+
clearSequence,
|
|
10454
|
+
fallbackText: frame.fallbackText,
|
|
10455
|
+
resizeRedraw: true,
|
|
10456
|
+
placementMoveWithoutClear: false
|
|
10457
|
+
});
|
|
10458
|
+
pendingGraphicSignatures.set(frame.id, signature);
|
|
10459
|
+
recordTerminalGraphicTrace({
|
|
10460
|
+
type: "queue",
|
|
10461
|
+
id: frame.id,
|
|
10462
|
+
protocol: normalized.protocol,
|
|
10463
|
+
bytes: resizeSequence.length
|
|
10464
|
+
});
|
|
10465
|
+
requestTerminalGraphicsFlush(Boolean(normalized.deferFlush));
|
|
10466
|
+
return true;
|
|
10467
|
+
}
|
|
10468
|
+
const retained = retainedGraphics.get(frame.id);
|
|
10469
|
+
const retainedCanReplacePlacement = retained && retained.active.sequence === frame.sequence && resizeSequence && canReplaceKittyPlacementWithoutClear(retained.active, {
|
|
10470
|
+
...normalized,
|
|
10471
|
+
id: frame.id,
|
|
10472
|
+
w: frame.width,
|
|
10473
|
+
h: frame.height,
|
|
10474
|
+
sequence: resizeSequence,
|
|
10475
|
+
resizeSequence,
|
|
10476
|
+
clearSequence,
|
|
10477
|
+
fallbackText: frame.fallbackText,
|
|
10478
|
+
resizeRedraw: true,
|
|
10479
|
+
placementMoveWithoutClear: true
|
|
10480
|
+
});
|
|
10481
|
+
if (!canceledPendingClear && retained && resizeSequence && (retained.signature === signature || retainedCanReplacePlacement)) {
|
|
10482
|
+
activeGraphics.set(frame.id, retained.active);
|
|
10483
|
+
activeGraphicSignatures.set(frame.id, retained.signature);
|
|
10484
|
+
retainedGraphics.delete(frame.id);
|
|
10485
|
+
pendingGraphics.set(`${frame.id}:draw`, {
|
|
10486
|
+
...normalized,
|
|
10487
|
+
id: frame.id,
|
|
10488
|
+
w: frame.width,
|
|
10489
|
+
h: frame.height,
|
|
10490
|
+
sequence: forceTerminalResizeRedraw ? frame.sequence : resizeSequence,
|
|
10491
|
+
resizeSequence,
|
|
10492
|
+
clearSequence,
|
|
10493
|
+
fallbackText: frame.fallbackText,
|
|
10494
|
+
resizeRedraw: true,
|
|
10495
|
+
placementMoveWithoutClear: false,
|
|
10496
|
+
terminalResizeRedraw: forceTerminalResizeRedraw
|
|
10497
|
+
});
|
|
10498
|
+
pendingGraphicSignatures.set(frame.id, signature);
|
|
10499
|
+
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}`);
|
|
10500
|
+
recordTerminalGraphicTrace({
|
|
10501
|
+
type: "queue",
|
|
10502
|
+
id: frame.id,
|
|
10503
|
+
protocol: normalized.protocol,
|
|
10504
|
+
bytes: resizeSequence.length
|
|
10505
|
+
});
|
|
10506
|
+
requestTerminalGraphicsFlush(Boolean(normalized.deferFlush));
|
|
10507
|
+
return true;
|
|
10508
|
+
}
|
|
10509
|
+
retainedGraphics.delete(frame.id);
|
|
10510
|
+
pendingGraphics.set(`${frame.id}:draw`, {
|
|
10511
|
+
...normalized,
|
|
10512
|
+
id: frame.id,
|
|
10513
|
+
w: frame.width,
|
|
10514
|
+
h: frame.height,
|
|
10515
|
+
sequence: frame.sequence,
|
|
10516
|
+
resizeSequence,
|
|
10517
|
+
clearSequence,
|
|
10518
|
+
fallbackText: frame.fallbackText,
|
|
10519
|
+
terminalResizeRedraw: forceTerminalResizeRedraw
|
|
10520
|
+
});
|
|
10521
|
+
pendingGraphicSignatures.set(frame.id, signature);
|
|
10522
|
+
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}`);
|
|
10523
|
+
recordTerminalGraphicTrace({
|
|
10524
|
+
type: "queue",
|
|
10525
|
+
id: frame.id,
|
|
10526
|
+
protocol: normalized.protocol,
|
|
10527
|
+
bytes: frame.sequence.length
|
|
10528
|
+
});
|
|
10529
|
+
requestTerminalGraphicsFlush(Boolean(normalized.deferFlush));
|
|
10530
|
+
return true;
|
|
10531
|
+
}
|
|
10532
|
+
if (!validateTerminalGraphicsPayload(normalized, graphicsCapabilities)) return false;
|
|
10533
|
+
pendingGraphics.delete(`${normalized.id}:draw`);
|
|
10534
|
+
pendingGraphicSignatures.delete(normalized.id);
|
|
10535
|
+
retainedGraphics.delete(normalized.id);
|
|
10536
|
+
pendingGraphics.set(`${normalized.id}:clear`, {
|
|
10537
|
+
...normalized,
|
|
10538
|
+
w: normalized.w,
|
|
10539
|
+
h: normalized.h
|
|
10540
|
+
});
|
|
10541
|
+
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}`);
|
|
10542
|
+
recordTerminalGraphicTrace({
|
|
10543
|
+
type: "clear",
|
|
10544
|
+
id: normalized.id,
|
|
10545
|
+
protocol: normalized.protocol
|
|
10546
|
+
});
|
|
10547
|
+
requestTerminalGraphicsFlush(Boolean(normalized.deferFlush));
|
|
10548
|
+
return true;
|
|
10549
|
+
},
|
|
10550
|
+
clear(id) {
|
|
10551
|
+
return queueTerminalGraphicClear(id);
|
|
10552
|
+
},
|
|
10553
|
+
clearAll() {
|
|
10554
|
+
return clearAllTerminalGraphics();
|
|
10555
|
+
}
|
|
10556
|
+
};
|
|
10557
|
+
const unregisterGraphicsOutput = registerTerminalGraphicsOutput(terminal, graphicsOutput);
|
|
8594
10558
|
const MIN_FRAME_MS = outputIsTTY ? 16 : 0;
|
|
10559
|
+
const ROWS_ONLY_RESIZE_REPAINT_DELAY_MS = 500;
|
|
8595
10560
|
function clampCellToViewport(cell, size) {
|
|
8596
10561
|
const maxX = Math.max(0, Math.floor(size.cols) - 1);
|
|
8597
10562
|
const maxY = Math.max(0, Math.floor(size.rows) - 1);
|
|
@@ -8604,6 +10569,92 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8604
10569
|
y
|
|
8605
10570
|
};
|
|
8606
10571
|
}
|
|
10572
|
+
function normalizeGraphicRect(rect) {
|
|
10573
|
+
const x0 = Math.floor(rect.x);
|
|
10574
|
+
const y0 = Math.floor(rect.y);
|
|
10575
|
+
const w0 = Math.floor(rect.w);
|
|
10576
|
+
const h0 = Math.floor(rect.h);
|
|
10577
|
+
if (!Number.isFinite(x0) || !Number.isFinite(y0) || !Number.isFinite(w0) || !Number.isFinite(h0)) return null;
|
|
10578
|
+
const size = normalizeTerminalGraphicSize(w0, h0);
|
|
10579
|
+
if (!size) return null;
|
|
10580
|
+
return {
|
|
10581
|
+
x: x0,
|
|
10582
|
+
y: y0,
|
|
10583
|
+
w: size.width,
|
|
10584
|
+
h: size.height
|
|
10585
|
+
};
|
|
10586
|
+
}
|
|
10587
|
+
function clipGraphicRectToViewport(rect, size) {
|
|
10588
|
+
const cols = Math.max(0, Math.floor(size.cols));
|
|
10589
|
+
const rows = Math.max(0, Math.floor(size.rows));
|
|
10590
|
+
if (cols <= 0 || rows <= 0) return null;
|
|
10591
|
+
const normalized = normalizeGraphicRect(rect);
|
|
10592
|
+
if (!normalized) return null;
|
|
10593
|
+
const x0 = normalized.x;
|
|
10594
|
+
const y0 = normalized.y;
|
|
10595
|
+
const w0 = normalized.w;
|
|
10596
|
+
const h0 = normalized.h;
|
|
10597
|
+
const left = Math.max(0, x0);
|
|
10598
|
+
const top = Math.max(0, y0);
|
|
10599
|
+
const right = Math.min(cols, x0 + w0);
|
|
10600
|
+
const bottom = Math.min(rows, y0 + h0);
|
|
10601
|
+
if (right <= left || bottom <= top) return null;
|
|
10602
|
+
return {
|
|
10603
|
+
x: left,
|
|
10604
|
+
y: top,
|
|
10605
|
+
w: right - left,
|
|
10606
|
+
h: bottom - top
|
|
10607
|
+
};
|
|
10608
|
+
}
|
|
10609
|
+
function anchoredGraphicRectInViewport(rect, size) {
|
|
10610
|
+
const cols = Math.max(0, Math.floor(size.cols));
|
|
10611
|
+
const rows = Math.max(0, Math.floor(size.rows));
|
|
10612
|
+
if (cols <= 0 || rows <= 0) return null;
|
|
10613
|
+
const normalized = normalizeGraphicRect(rect);
|
|
10614
|
+
if (!normalized) return null;
|
|
10615
|
+
return normalized.x >= 0 && normalized.y >= 0 && normalized.x < cols && normalized.y < rows ? normalized : null;
|
|
10616
|
+
}
|
|
10617
|
+
function clearGraphicRect(rect) {
|
|
10618
|
+
const blank = " ".repeat(Math.max(0, rect.w));
|
|
10619
|
+
let out$1 = "";
|
|
10620
|
+
for (let row = 0; row < rect.h; row++) out$1 += `\u001B[${rect.y + row + 1};${rect.x + 1}H${blank}`;
|
|
10621
|
+
return out$1;
|
|
10622
|
+
}
|
|
10623
|
+
function sameGraphicRect(a, b) {
|
|
10624
|
+
return Boolean(a && a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h);
|
|
10625
|
+
}
|
|
10626
|
+
function maybeWrapTerminalGraphic(sequence) {
|
|
10627
|
+
return wrapTerminalGraphicsForMultiplexer(sequence, graphicsCapabilities);
|
|
10628
|
+
}
|
|
10629
|
+
function kittyClearTargetsCurrentCell(sequence) {
|
|
10630
|
+
const prefix = "\x1B_G";
|
|
10631
|
+
const terminator = "\x1B\\";
|
|
10632
|
+
let index = 0;
|
|
10633
|
+
while (index < sequence.length) {
|
|
10634
|
+
if (!sequence.startsWith(prefix, index)) return false;
|
|
10635
|
+
const end = sequence.indexOf(terminator, index + prefix.length);
|
|
10636
|
+
if (end < 0) return false;
|
|
10637
|
+
const body = sequence.slice(index + prefix.length, end);
|
|
10638
|
+
const semicolon = body.indexOf(";");
|
|
10639
|
+
const controlsText = semicolon < 0 ? body : body.slice(0, semicolon);
|
|
10640
|
+
let action = "";
|
|
10641
|
+
let deleteMode = "";
|
|
10642
|
+
for (const part of controlsText.split(",")) {
|
|
10643
|
+
const eq = part.indexOf("=");
|
|
10644
|
+
if (eq <= 0) continue;
|
|
10645
|
+
const key = part.slice(0, eq);
|
|
10646
|
+
const value = part.slice(eq + 1);
|
|
10647
|
+
if (key === "a") action = value;
|
|
10648
|
+
else if (key === "d") deleteMode = value;
|
|
10649
|
+
}
|
|
10650
|
+
if (action === "d" && (deleteMode === "c" || deleteMode === "C")) return true;
|
|
10651
|
+
index = end + terminator.length;
|
|
10652
|
+
}
|
|
10653
|
+
return false;
|
|
10654
|
+
}
|
|
10655
|
+
function clearSequenceNeedsVisibleCell(sequence, protocol) {
|
|
10656
|
+
return protocol === "kitty" && kittyClearTargetsCurrentCell(sequence);
|
|
10657
|
+
}
|
|
8607
10658
|
function resolveColorMode() {
|
|
8608
10659
|
const opt = (options === null || options === void 0 ? void 0 : options.colorMode) ?? "auto";
|
|
8609
10660
|
if (opt !== "auto") return opt;
|
|
@@ -8755,6 +10806,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8755
10806
|
const MAX_CELL_TEXT_IDS = 131072;
|
|
8756
10807
|
let prevOverlayBlockedRows = [];
|
|
8757
10808
|
let prevOverlayPartialRows = [];
|
|
10809
|
+
let prevOverlayVisibleSpans = new Map();
|
|
8758
10810
|
const hrefIndex = new Map();
|
|
8759
10811
|
let nextHrefId = 1;
|
|
8760
10812
|
const MAX_HREF_IDS = 8192;
|
|
@@ -8779,6 +10831,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
8779
10831
|
fpPrevValid = false;
|
|
8780
10832
|
prevOverlayBlockedRows = [];
|
|
8781
10833
|
prevOverlayPartialRows = [];
|
|
10834
|
+
prevOverlayVisibleSpans = new Map();
|
|
8782
10835
|
}
|
|
8783
10836
|
function cellFingerprintFromStyleKey(_ch, key) {
|
|
8784
10837
|
return key >>> 0;
|
|
@@ -9476,12 +11529,46 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9476
11529
|
lastFrameTime = Date.now();
|
|
9477
11530
|
const renderStart = performance.now();
|
|
9478
11531
|
const size = terminal.size();
|
|
11532
|
+
const rowsOnlyResizeBaseline = preserveNextRowsOnlyResizeBaseline && fpPrevValid && fpCols === size.cols ? {
|
|
11533
|
+
cols: fpCols,
|
|
11534
|
+
rows: fpRows,
|
|
11535
|
+
fp: prevFP.slice(),
|
|
11536
|
+
hrefIds: prevHrefIds.slice(),
|
|
11537
|
+
textIds: prevTextIds.slice()
|
|
11538
|
+
} : null;
|
|
11539
|
+
preserveNextRowsOnlyResizeBaseline = false;
|
|
11540
|
+
const pendingGraphicClearsToRender = new Set(pendingGraphicClears);
|
|
11541
|
+
let graphicsClearsToRender = Array.from(pendingGraphicClearsToRender);
|
|
11542
|
+
let graphicsEntriesToRender = Array.from(pendingGraphics.entries()).sort(([, a], [, b]) => {
|
|
11543
|
+
const opA = a.op === "clear" ? 0 : 1;
|
|
11544
|
+
const opB = b.op === "clear" ? 0 : 1;
|
|
11545
|
+
return opA - opB || a.order - b.order;
|
|
11546
|
+
});
|
|
11547
|
+
let graphicsToRender = graphicsEntriesToRender.map(([, payload]) => payload);
|
|
11548
|
+
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);
|
|
11549
|
+
allowNextGraphicsOnlyRenderWithoutBaseline = false;
|
|
11550
|
+
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}`);
|
|
11551
|
+
let terminalGraphicsBlockScrollRegions = false;
|
|
9479
11552
|
ensureRowEscapes(Math.max(size.rows, lastRenderedRows));
|
|
9480
11553
|
ensureFingerprints(size.cols, size.rows);
|
|
9481
11554
|
const bgSeq = openBg(defaultBg);
|
|
9482
11555
|
const bgOnlyStyle = { bg: defaultBg };
|
|
9483
11556
|
const bgKey = styleKeyFromParts({ bg: defaultBg });
|
|
9484
11557
|
const blankFP = cellFingerprintFromStyleKey(" ", bgKey);
|
|
11558
|
+
if (rowsOnlyResizeBaseline && rowsOnlyResizeBaseline.cols === size.cols) {
|
|
11559
|
+
prevFP.fill(blankFP);
|
|
11560
|
+
prevHrefIds.fill(0);
|
|
11561
|
+
prevTextIds.fill(blankTextId);
|
|
11562
|
+
const rowsToCopy = Math.min(size.rows, rowsOnlyResizeBaseline.rows);
|
|
11563
|
+
for (let y = 0; y < rowsToCopy; y++) {
|
|
11564
|
+
const start = y * size.cols;
|
|
11565
|
+
const end = start + size.cols;
|
|
11566
|
+
prevFP.set(rowsOnlyResizeBaseline.fp.subarray(start, end), start);
|
|
11567
|
+
prevHrefIds.set(rowsOnlyResizeBaseline.hrefIds.subarray(start, end), start);
|
|
11568
|
+
prevTextIds.set(rowsOnlyResizeBaseline.textIds.subarray(start, end), start);
|
|
11569
|
+
}
|
|
11570
|
+
fpPrevValid = true;
|
|
11571
|
+
}
|
|
9485
11572
|
let dirtySorted = true;
|
|
9486
11573
|
const forceFullRender = hrefIndexResetRequiresBaseline || fingerprintInternResetRequiresBaseline;
|
|
9487
11574
|
if (forceFullRender) {
|
|
@@ -9507,7 +11594,172 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9507
11594
|
if (!outOps.length) return null;
|
|
9508
11595
|
return outOps;
|
|
9509
11596
|
})();
|
|
11597
|
+
const terminalGraphicsAffectedRows = new Set();
|
|
11598
|
+
const terminalGraphicTextPreserveSpans = new Map();
|
|
11599
|
+
const addTerminalGraphicRows = (rect) => {
|
|
11600
|
+
if (!rect) return;
|
|
11601
|
+
const visible = clipGraphicRectToViewport(rect, size);
|
|
11602
|
+
if (!visible) return;
|
|
11603
|
+
for (let y = visible.y; y < visible.y + visible.h; y++) terminalGraphicsAffectedRows.add(y);
|
|
11604
|
+
};
|
|
11605
|
+
const addTerminalGraphicTextPreserveSpans = (rect) => {
|
|
11606
|
+
if (!rect) return;
|
|
11607
|
+
const visible = clipGraphicRectToViewport(rect, size);
|
|
11608
|
+
if (!visible) return;
|
|
11609
|
+
const start = Math.max(0, Math.min(size.cols, visible.x));
|
|
11610
|
+
const end = Math.max(start, Math.min(size.cols, visible.x + visible.w));
|
|
11611
|
+
if (end <= start) return;
|
|
11612
|
+
for (let y = visible.y; y < visible.y + visible.h; y++) {
|
|
11613
|
+
const spans = terminalGraphicTextPreserveSpans.get(y);
|
|
11614
|
+
if (spans) spans.push({
|
|
11615
|
+
start,
|
|
11616
|
+
end
|
|
11617
|
+
});
|
|
11618
|
+
else terminalGraphicTextPreserveSpans.set(y, [{
|
|
11619
|
+
start,
|
|
11620
|
+
end
|
|
11621
|
+
}]);
|
|
11622
|
+
}
|
|
11623
|
+
};
|
|
11624
|
+
const payloadRect = (payload) => ({
|
|
11625
|
+
x: payload.x,
|
|
11626
|
+
y: payload.y,
|
|
11627
|
+
w: payload.w ?? 1,
|
|
11628
|
+
h: payload.h ?? 1
|
|
11629
|
+
});
|
|
11630
|
+
const intersectsScrollOperations = (rect) => {
|
|
11631
|
+
if (!rect || !(normalizedScrollOperations === null || normalizedScrollOperations === void 0 ? void 0 : normalizedScrollOperations.length)) return false;
|
|
11632
|
+
const top = rect.y;
|
|
11633
|
+
const bottom = rect.y + rect.h;
|
|
11634
|
+
for (const op of normalizedScrollOperations) if (top < op.endY && bottom > op.startY) return true;
|
|
11635
|
+
return false;
|
|
11636
|
+
};
|
|
11637
|
+
const graphicRectVisible = (rect) => Boolean(rect && clipGraphicRectToViewport(rect, size));
|
|
11638
|
+
const pendingGraphicIds = new Set(graphicsToRender.map((payload) => payload.id));
|
|
11639
|
+
const explicitGraphicClears = new Set(graphicsClearsToRender);
|
|
11640
|
+
if ((normalizedScrollOperations === null || normalizedScrollOperations === void 0 ? void 0 : normalizedScrollOperations.length) && activeGraphics.size > 0) for (const [id, active] of activeGraphics) {
|
|
11641
|
+
if (explicitGraphicClears.has(id) || pendingGraphicIds.has(id)) continue;
|
|
11642
|
+
if (!intersectsScrollOperations(active)) continue;
|
|
11643
|
+
const signature = activeGraphicSignatures.get(id);
|
|
11644
|
+
graphicsToRender.push({
|
|
11645
|
+
id,
|
|
11646
|
+
x: active.x,
|
|
11647
|
+
y: active.y,
|
|
11648
|
+
w: active.w,
|
|
11649
|
+
h: active.h,
|
|
11650
|
+
protocol: active.protocol,
|
|
11651
|
+
sequence: active.sequence,
|
|
11652
|
+
resizeSequence: active.resizeSequence,
|
|
11653
|
+
clearSequence: active.clearSequence,
|
|
11654
|
+
allowTextOverlay: active.allowTextOverlay,
|
|
11655
|
+
op: "draw",
|
|
11656
|
+
order: nextGraphicsOrder++
|
|
11657
|
+
});
|
|
11658
|
+
if (signature) pendingGraphicSignatures.set(id, signature);
|
|
11659
|
+
pendingGraphicIds.add(id);
|
|
11660
|
+
}
|
|
11661
|
+
for (const [id, active] of activeGraphics) {
|
|
11662
|
+
if (explicitGraphicClears.has(id)) continue;
|
|
11663
|
+
if (pendingGraphicIds.has(id)) continue;
|
|
11664
|
+
if (intersectsScrollOperations(active)) continue;
|
|
11665
|
+
if (!active.allowTextOverlay) addTerminalGraphicTextPreserveSpans(active);
|
|
11666
|
+
}
|
|
11667
|
+
if ((normalizedScrollOperations === null || normalizedScrollOperations === void 0 ? void 0 : normalizedScrollOperations.length) && activeGraphics.size > 0) for (const active of activeGraphics.values()) {
|
|
11668
|
+
if (!intersectsScrollOperations(active)) continue;
|
|
11669
|
+
terminalGraphicsBlockScrollRegions = true;
|
|
11670
|
+
addTerminalGraphicRows(active);
|
|
11671
|
+
}
|
|
11672
|
+
for (const id of graphicsClearsToRender) {
|
|
11673
|
+
const active = activeGraphics.get(id);
|
|
11674
|
+
addTerminalGraphicRows(active);
|
|
11675
|
+
if (intersectsScrollOperations(active)) terminalGraphicsBlockScrollRegions = true;
|
|
11676
|
+
}
|
|
11677
|
+
for (const payload of graphicsToRender) {
|
|
11678
|
+
const active = activeGraphics.get(payload.id);
|
|
11679
|
+
if (payload.op === "clear") {
|
|
11680
|
+
const rect = active ?? payloadRect(payload);
|
|
11681
|
+
addTerminalGraphicRows(rect);
|
|
11682
|
+
if (intersectsScrollOperations(rect)) terminalGraphicsBlockScrollRegions = true;
|
|
11683
|
+
continue;
|
|
11684
|
+
}
|
|
11685
|
+
const next = payloadRect(payload);
|
|
11686
|
+
if (!payload.allowTextOverlay) addTerminalGraphicTextPreserveSpans(next);
|
|
11687
|
+
addTerminalGraphicRows(active);
|
|
11688
|
+
addTerminalGraphicRows(next);
|
|
11689
|
+
if (intersectsScrollOperations(active) || intersectsScrollOperations(next)) terminalGraphicsBlockScrollRegions = true;
|
|
11690
|
+
}
|
|
11691
|
+
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({
|
|
11692
|
+
x: payload.x,
|
|
11693
|
+
y: payload.y,
|
|
11694
|
+
w: payload.w ?? 1,
|
|
11695
|
+
h: payload.h ?? 1
|
|
11696
|
+
}, size))))) terminalGraphicsBlockScrollRegions = true;
|
|
11697
|
+
let forceDirtyRowsRepaintForFrame = forceDirtyRowsRepaint;
|
|
11698
|
+
const forceTerminalGraphicsRowRepaint = (y) => forceDirtyRowsRepaintForFrame || terminalGraphicsAffectedRows.has(y) || terminalGraphicTextPreserveSpans.has(y);
|
|
11699
|
+
for (const [y, spans] of terminalGraphicTextPreserveSpans) {
|
|
11700
|
+
spans.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
11701
|
+
const merged = [];
|
|
11702
|
+
for (const span of spans) {
|
|
11703
|
+
const previous = merged[merged.length - 1];
|
|
11704
|
+
if (previous && span.start <= previous.end) previous.end = Math.max(previous.end, span.end);
|
|
11705
|
+
else merged.push({ ...span });
|
|
11706
|
+
}
|
|
11707
|
+
terminalGraphicTextPreserveSpans.set(y, merged);
|
|
11708
|
+
}
|
|
11709
|
+
const mergeSpans = (spans) => {
|
|
11710
|
+
if (!spans.length) return [];
|
|
11711
|
+
const sorted = [...spans].sort((a, b) => a.start - b.start || a.end - b.end);
|
|
11712
|
+
const merged = [];
|
|
11713
|
+
for (const span of sorted) {
|
|
11714
|
+
const start = Math.max(0, Math.min(size.cols, span.start));
|
|
11715
|
+
const end = Math.max(start, Math.min(size.cols, span.end));
|
|
11716
|
+
if (end <= start) continue;
|
|
11717
|
+
const previous = merged[merged.length - 1];
|
|
11718
|
+
if (previous && start <= previous.end) previous.end = Math.max(previous.end, end);
|
|
11719
|
+
else merged.push({
|
|
11720
|
+
start,
|
|
11721
|
+
end
|
|
11722
|
+
});
|
|
11723
|
+
}
|
|
11724
|
+
return merged;
|
|
11725
|
+
};
|
|
11726
|
+
const overlayVisibleSpansForRows = (rows) => {
|
|
11727
|
+
const overlay = getPlaneTerminal(terminal, "overlay");
|
|
11728
|
+
const result = new Map();
|
|
11729
|
+
for (const y of rows) {
|
|
11730
|
+
if (y < 0 || y >= size.rows) continue;
|
|
11731
|
+
const row = overlay.getRow(y);
|
|
11732
|
+
const spans = [];
|
|
11733
|
+
let start = null;
|
|
11734
|
+
let end = 0;
|
|
11735
|
+
for (let x = 0; x < size.cols; x++) {
|
|
11736
|
+
const cell = row[x];
|
|
11737
|
+
const visible = cell != null && !cell.continuation && (cell.ch !== " " || styleKey(cell.style) !== bgKey || renderedHref(cell.style.href) != null);
|
|
11738
|
+
if (visible) {
|
|
11739
|
+
if (start == null) start = x;
|
|
11740
|
+
end = Math.max(end, Math.min(size.cols, x + Math.max(1, cell.width ?? 1)));
|
|
11741
|
+
continue;
|
|
11742
|
+
}
|
|
11743
|
+
if (start != null && x >= end) {
|
|
11744
|
+
spans.push({
|
|
11745
|
+
start,
|
|
11746
|
+
end
|
|
11747
|
+
});
|
|
11748
|
+
start = null;
|
|
11749
|
+
}
|
|
11750
|
+
}
|
|
11751
|
+
if (start != null) spans.push({
|
|
11752
|
+
start,
|
|
11753
|
+
end: Math.max(end, start + 1)
|
|
11754
|
+
});
|
|
11755
|
+
if (spans.length) result.set(y, mergeSpans(spans));
|
|
11756
|
+
}
|
|
11757
|
+
return result;
|
|
11758
|
+
};
|
|
11759
|
+
const overlayCoverage = overlayPlaneCoverageRows(size.rows);
|
|
11760
|
+
const overlayVisibleSpans = overlayVisibleSpansForRows(overlayCoverage.blockedRows);
|
|
9510
11761
|
let rowsToRender = (() => {
|
|
11762
|
+
if (allowGraphicsOnlyWithoutBaseline) return [];
|
|
9511
11763
|
if (forceFullRender || !fpPrevValid) return null;
|
|
9512
11764
|
if (!dirtyRows) return null;
|
|
9513
11765
|
if (dirtyRows.length === 0) return [];
|
|
@@ -9529,7 +11781,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9529
11781
|
if (!sorted) outRows.sort((a, b) => a - b);
|
|
9530
11782
|
return outRows;
|
|
9531
11783
|
})();
|
|
9532
|
-
if ((rowsToRender === null || rowsToRender === void 0 ? void 0 : rowsToRender.length) === 0 && !normalizedScrollOperations && !getImeAnchor) {
|
|
11784
|
+
if ((rowsToRender === null || rowsToRender === void 0 ? void 0 : rowsToRender.length) === 0 && !normalizedScrollOperations && !getImeAnchor && graphicsClearsToRender.length === 0 && graphicsToRender.length === 0) {
|
|
9533
11785
|
if (isDebugEnabled()) getDebugLog().render(" No valid dirty rows; frame skipped");
|
|
9534
11786
|
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutNoOutput();
|
|
9535
11787
|
return;
|
|
@@ -9548,10 +11800,13 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9548
11800
|
currentHrefIds.set(prevHrefIds);
|
|
9549
11801
|
currentTextIds.set(prevTextIds);
|
|
9550
11802
|
}
|
|
11803
|
+
const frameHasTerminalGraphics = activeGraphics.size > 0 || graphicsClearsToRender.length > 0 || graphicsToRender.length > 0;
|
|
11804
|
+
const useFrameSyncOutput = useSyncOutput || isGhostty && frameHasTerminalGraphics;
|
|
9551
11805
|
const frameParts = [];
|
|
9552
|
-
frameParts.push(
|
|
9553
|
-
frameParts.push("\x1B[?7l");
|
|
11806
|
+
frameParts.push(useFrameSyncOutput ? SYNC_START : "");
|
|
11807
|
+
frameParts.push(allowGraphicsOnlyWithoutBaseline || keepLineWrapDisabled ? "" : "\x1B[?7l");
|
|
9554
11808
|
frameParts.push(SGR_RESET, bgSeq);
|
|
11809
|
+
if (hideCursor && !getImeAnchor) frameParts.push(CURSOR_HOME);
|
|
9555
11810
|
let lastRenderedY = -1;
|
|
9556
11811
|
let lastRenderWasFullRow = false;
|
|
9557
11812
|
let hasFrameOutput = false;
|
|
@@ -9566,6 +11821,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9566
11821
|
inverse: false,
|
|
9567
11822
|
href: null
|
|
9568
11823
|
};
|
|
11824
|
+
let overlayTouchedRowSet = null;
|
|
9569
11825
|
const closeActiveHrefBeforeCursorMove = () => {
|
|
9570
11826
|
if (!enableOsc8Links || !activeStyle.href) return;
|
|
9571
11827
|
frameParts.push(OSC8_CLOSE);
|
|
@@ -9668,6 +11924,65 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9668
11924
|
lastRenderedY = y;
|
|
9669
11925
|
lastRenderWasFullRow = spanStart === 0 && (spanEnd >= size.cols || shouldClearToEol);
|
|
9670
11926
|
};
|
|
11927
|
+
const overlayBypassSpansForRow = (y) => {
|
|
11928
|
+
const current = overlayVisibleSpans.get(y) ?? [];
|
|
11929
|
+
const previous = prevOverlayVisibleSpans.get(y) ?? [];
|
|
11930
|
+
return current.length || previous.length ? mergeSpans([...current, ...previous]) : [];
|
|
11931
|
+
};
|
|
11932
|
+
const subtractSpans = (spans, bypass) => {
|
|
11933
|
+
if (!bypass.length) return [...spans];
|
|
11934
|
+
const result = [];
|
|
11935
|
+
for (const span of spans) {
|
|
11936
|
+
let cursor = span.start;
|
|
11937
|
+
for (const cut of bypass) {
|
|
11938
|
+
if (cut.end <= cursor) continue;
|
|
11939
|
+
if (cut.start >= span.end) break;
|
|
11940
|
+
if (cursor < cut.start) result.push({
|
|
11941
|
+
start: cursor,
|
|
11942
|
+
end: Math.min(cut.start, span.end)
|
|
11943
|
+
});
|
|
11944
|
+
cursor = Math.max(cursor, cut.end);
|
|
11945
|
+
if (cursor >= span.end) break;
|
|
11946
|
+
}
|
|
11947
|
+
if (cursor < span.end) result.push({
|
|
11948
|
+
start: cursor,
|
|
11949
|
+
end: span.end
|
|
11950
|
+
});
|
|
11951
|
+
}
|
|
11952
|
+
return result;
|
|
11953
|
+
};
|
|
11954
|
+
const preserveFingerprintSpans = (y, spans) => {
|
|
11955
|
+
if (!fpPrevValid || y < 0 || y >= fpRows || currentFP.length !== prevFP.length) return;
|
|
11956
|
+
const base = y * fpCols;
|
|
11957
|
+
for (const span of spans) {
|
|
11958
|
+
const start = Math.max(0, Math.min(fpCols, span.start));
|
|
11959
|
+
const end = Math.max(start, Math.min(fpCols, span.end));
|
|
11960
|
+
for (let x = start; x < end; x++) {
|
|
11961
|
+
currentFP[base + x] = prevFP[base + x];
|
|
11962
|
+
currentHrefIds[base + x] = prevHrefIds[base + x];
|
|
11963
|
+
currentTextIds[base + x] = prevTextIds[base + x];
|
|
11964
|
+
}
|
|
11965
|
+
}
|
|
11966
|
+
};
|
|
11967
|
+
const renderRowPreservingTerminalGraphics = (y, row) => {
|
|
11968
|
+
const spans = terminalGraphicTextPreserveSpans.get(y);
|
|
11969
|
+
if (!(spans === null || spans === void 0 ? void 0 : spans.length)) {
|
|
11970
|
+
renderRow(y, row);
|
|
11971
|
+
return;
|
|
11972
|
+
}
|
|
11973
|
+
const effectiveSpans = subtractSpans(spans, overlayBypassSpansForRow(y));
|
|
11974
|
+
if (!effectiveSpans.length) {
|
|
11975
|
+
renderRow(y, row);
|
|
11976
|
+
return;
|
|
11977
|
+
}
|
|
11978
|
+
let cursor = 0;
|
|
11979
|
+
for (const span of effectiveSpans) {
|
|
11980
|
+
if (cursor < span.start) renderRow(y, row, cursor, span.start, false);
|
|
11981
|
+
cursor = Math.max(cursor, span.end);
|
|
11982
|
+
}
|
|
11983
|
+
if (cursor < size.cols) renderRow(y, row, cursor, size.cols, false);
|
|
11984
|
+
preserveFingerprintSpans(y, effectiveSpans);
|
|
11985
|
+
};
|
|
9671
11986
|
const lastRenderableColumnInCurrentRow = (rowY, cols, blankFingerprint) => {
|
|
9672
11987
|
if (!fpCols || rowY < 0 || rowY >= fpRows) return -1;
|
|
9673
11988
|
const base = rowY * fpCols;
|
|
@@ -9732,16 +12047,15 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9732
12047
|
} else for (const span of spansToPaint) renderRow(rowY, row, span.startX, span.endXExclusive, false);
|
|
9733
12048
|
if (clearStartX != null && !paintTailInsteadOfEscK) renderRow(rowY, row, clearStartX, clearStartX, true);
|
|
9734
12049
|
};
|
|
9735
|
-
const overlayCoverage = overlayPlaneCoverageRows(size.rows);
|
|
9736
12050
|
const overlayRows = Array.from(new Set([...overlayCoverage.blockedRows, ...prevOverlayBlockedRows])).sort((a, b) => a - b);
|
|
9737
12051
|
const overlayRowSet = overlayRows.length ? new Set(overlayRows) : null;
|
|
9738
12052
|
const overlayPartialRows = Array.from(new Set([...overlayCoverage.partialRows, ...prevOverlayPartialRows])).sort((a, b) => a - b);
|
|
9739
12053
|
const overlayPartialRowSet = overlayPartialRows.length ? new Set(overlayPartialRows) : null;
|
|
9740
|
-
|
|
12054
|
+
overlayTouchedRowSet = (() => {
|
|
9741
12055
|
if (!overlayRowSet && !overlayPartialRowSet) return null;
|
|
9742
12056
|
return new Set([...overlayRowSet ? Array.from(overlayRowSet) : [], ...overlayPartialRowSet ? Array.from(overlayPartialRowSet) : []]);
|
|
9743
12057
|
})();
|
|
9744
|
-
let explicitScrollOperations = normalizedScrollOperations;
|
|
12058
|
+
let explicitScrollOperations = terminalGraphicsBlockScrollRegions ? null : normalizedScrollOperations;
|
|
9745
12059
|
let hiddenExplicitDirtyRows = null;
|
|
9746
12060
|
let allowInferredScrollRegions = true;
|
|
9747
12061
|
if (explicitScrollOperations && overlayRows.length) {
|
|
@@ -9756,6 +12070,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9756
12070
|
for (const op of explicitScrollOperations) for (let y = op.startY; y < op.endY; y++) expandedRows$1.add(y);
|
|
9757
12071
|
rowsToRender = Array.from(expandedRows$1).sort((a, b) => a - b);
|
|
9758
12072
|
dirtySorted = true;
|
|
12073
|
+
forceDirtyRowsRepaintForFrame = true;
|
|
9759
12074
|
explicitScrollOperations = null;
|
|
9760
12075
|
hiddenExplicitDirtyRows = null;
|
|
9761
12076
|
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 +12085,18 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9770
12085
|
expandedRows.add(y);
|
|
9771
12086
|
}
|
|
9772
12087
|
};
|
|
12088
|
+
if (terminalGraphicsBlockScrollRegions && normalizedScrollOperations && rowsToRender) {
|
|
12089
|
+
includeRowsForPendingScrollOperations(normalizedScrollOperations);
|
|
12090
|
+
rowsToRender = Array.from(expandedRows).sort((a, b) => a - b);
|
|
12091
|
+
dirtySorted = true;
|
|
12092
|
+
forceDirtyRowsRepaintForFrame = true;
|
|
12093
|
+
if (isDebugEnabled()) getDebugLog().render(" Scroll regions disabled for frame with active/pending terminal graphics");
|
|
12094
|
+
}
|
|
9773
12095
|
if (explicitScrollOperations && rowsToRender && (!enableScrollRegions || !fpPrevValid)) {
|
|
9774
12096
|
includeRowsForPendingScrollOperations(explicitScrollOperations);
|
|
9775
12097
|
rowsToRender = Array.from(expandedRows).sort((a, b) => a - b);
|
|
9776
12098
|
dirtySorted = true;
|
|
12099
|
+
forceDirtyRowsRepaintForFrame = true;
|
|
9777
12100
|
explicitScrollOperations = null;
|
|
9778
12101
|
hiddenExplicitDirtyRows = null;
|
|
9779
12102
|
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 +12104,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9781
12104
|
const denseDirtyRows = Boolean(rowsToRender && size.rows > 1 && rowsToRender.length >= size.rows * dirtyFullThreshold);
|
|
9782
12105
|
if (denseDirtyRows) rowsToRender = null;
|
|
9783
12106
|
let profiledRowCount = rowsToRender ? rowsToRender.length : size.rows;
|
|
9784
|
-
const useScrollRegions = enableScrollRegions && fpPrevValid && scrollRowsCandidate && scrollRowsCandidate.length >= 3 && !forceDirtyRowsRepaint && allowInferredScrollRegions;
|
|
12107
|
+
const useScrollRegions = !terminalGraphicsBlockScrollRegions && enableScrollRegions && fpPrevValid && scrollRowsCandidate && scrollRowsCandidate.length >= 3 && !forceDirtyRowsRepaint && allowInferredScrollRegions;
|
|
9785
12108
|
let scrollHandled = false;
|
|
9786
12109
|
if (enableScrollRegions && explicitScrollOperations && scrollRowsCandidate && fpPrevValid) {
|
|
9787
12110
|
if (currentFP.length === prevFP.length) {
|
|
@@ -9856,9 +12179,9 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9856
12179
|
for (const y of explicitDirtyRows) {
|
|
9857
12180
|
const row = terminal.getRow(y);
|
|
9858
12181
|
const overlayRow = overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y);
|
|
9859
|
-
if (
|
|
12182
|
+
if (forceTerminalGraphicsRowRepaint(y) || !shouldUseDirtySpans() || overlayRow) {
|
|
9860
12183
|
fingerprintRow(row, y, size.cols);
|
|
9861
|
-
|
|
12184
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9862
12185
|
paintedExplicitRows.push(y);
|
|
9863
12186
|
continue;
|
|
9864
12187
|
}
|
|
@@ -9935,12 +12258,12 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9935
12258
|
for (let y = shift.newRowStart; y < shift.newRowEnd; y++) {
|
|
9936
12259
|
const row = terminal.getRow(y);
|
|
9937
12260
|
fingerprintRow(row, y, size.cols);
|
|
9938
|
-
|
|
12261
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9939
12262
|
}
|
|
9940
12263
|
const extraDirtyRows = overlayRowSet ? shift.extraDirtyRows.filter((y) => !overlayRowSet.has(y) || Boolean(overlayPartialRowSet === null || overlayPartialRowSet === void 0 ? void 0 : overlayPartialRowSet.has(y))) : shift.extraDirtyRows;
|
|
9941
12264
|
for (const y of extraDirtyRows) {
|
|
9942
12265
|
const row = terminal.getRow(y);
|
|
9943
|
-
if (shouldUseDirtySpans()) {
|
|
12266
|
+
if (!forceTerminalGraphicsRowRepaint(y) && shouldUseDirtySpans()) {
|
|
9944
12267
|
const spans = resolveChangedSpansAgainstReference(row, y, size.cols, currentFP, currentHrefIds, currentTextIds);
|
|
9945
12268
|
if (!spans.length) {
|
|
9946
12269
|
fingerprintRow(row, y, size.cols);
|
|
@@ -9952,7 +12275,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9952
12275
|
continue;
|
|
9953
12276
|
}
|
|
9954
12277
|
fingerprintRow(row, y, size.cols);
|
|
9955
|
-
|
|
12278
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9956
12279
|
}
|
|
9957
12280
|
for (let y = shift.newRowStart; y < shift.newRowEnd; y++) fingerprintRow(terminal.getRow(y), y, size.cols);
|
|
9958
12281
|
const renderedRows = new Set();
|
|
@@ -9972,7 +12295,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9972
12295
|
for (let y = 0; y < size.rows; y++) {
|
|
9973
12296
|
const row = terminal.getRow(y);
|
|
9974
12297
|
fingerprintRow(row, y, size.cols);
|
|
9975
|
-
|
|
12298
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9976
12299
|
}
|
|
9977
12300
|
} else {
|
|
9978
12301
|
const overlayDirtyRows = overlayTouchedRowSet ? rowsToRender.filter((y) => overlayTouchedRowSet.has(y)) : [];
|
|
@@ -9980,8 +12303,8 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9980
12303
|
for (const y of rowsToRender) {
|
|
9981
12304
|
const row = terminal.getRow(y);
|
|
9982
12305
|
fingerprintRow(row, y, size.cols);
|
|
9983
|
-
if (
|
|
9984
|
-
|
|
12306
|
+
if (forceTerminalGraphicsRowRepaint(y) || !shouldUseDirtySpans()) {
|
|
12307
|
+
renderRowPreservingTerminalGraphics(y, row);
|
|
9985
12308
|
continue;
|
|
9986
12309
|
}
|
|
9987
12310
|
const spans = resolveChangedSpans(row, y, size.cols, (dirtyRowSnapshots === null || dirtyRowSnapshots === void 0 ? void 0 : dirtyRowSnapshots.get(y)) ?? null);
|
|
@@ -9990,7 +12313,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
9990
12313
|
renderDirtySpans(y, row, spans, rewriteTail);
|
|
9991
12314
|
}
|
|
9992
12315
|
}
|
|
9993
|
-
if (!rowsToRender && lastRenderedRows > size.rows) {
|
|
12316
|
+
if (!rowsToRender && lastRenderedRows > size.rows && !rowsOnlyResizeBaseline) {
|
|
9994
12317
|
const extraRows = lastRenderedRows - size.rows;
|
|
9995
12318
|
if (activeStyleKey !== bgKey) {
|
|
9996
12319
|
frameParts.push(SGR_RESET, bgSeq);
|
|
@@ -10001,7 +12324,8 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10001
12324
|
frameParts.push(rowClearToEol[size.rows + i]);
|
|
10002
12325
|
}
|
|
10003
12326
|
}
|
|
10004
|
-
const nextLastRenderedRows = !rowsToRender ? size.rows : lastRenderedRows;
|
|
12327
|
+
const nextLastRenderedRows = !rowsToRender || rowsToRender.length === 0 ? size.rows : lastRenderedRows;
|
|
12328
|
+
const graphicsOnlyFrame = Boolean(rowsToRender && rowsToRender.length === 0) && !scrollHandled && (graphicsClearsToRender.length > 0 || graphicsToRender.length > 0);
|
|
10005
12329
|
const commitRenderBaseline = () => {
|
|
10006
12330
|
lastRenderedRows = nextLastRenderedRows;
|
|
10007
12331
|
const tmpFP = prevFP;
|
|
@@ -10013,10 +12337,243 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10013
12337
|
const tmpTextIds = prevTextIds;
|
|
10014
12338
|
prevTextIds = currentTextIds;
|
|
10015
12339
|
currentTextIds = tmpTextIds;
|
|
10016
|
-
fpPrevValid = !hrefIndexResetRequiresBaseline && !fingerprintInternResetRequiresBaseline;
|
|
12340
|
+
fpPrevValid = graphicsOnlyFrame ? fpPrevValid : !hrefIndexResetRequiresBaseline && !fingerprintInternResetRequiresBaseline;
|
|
10017
12341
|
prevOverlayBlockedRows = overlayCoverage.blockedRows;
|
|
10018
12342
|
prevOverlayPartialRows = overlayCoverage.partialRows;
|
|
12343
|
+
prevOverlayVisibleSpans = overlayVisibleSpans;
|
|
10019
12344
|
};
|
|
12345
|
+
if (graphicsOnlyFrame && fpPrevValid && currentFP.length === prevFP.length) {
|
|
12346
|
+
currentFP.set(prevFP);
|
|
12347
|
+
currentHrefIds.set(prevHrefIds);
|
|
12348
|
+
currentTextIds.set(prevTextIds);
|
|
12349
|
+
}
|
|
12350
|
+
let renderedRowsLookup;
|
|
12351
|
+
const rowWasPaintedByTextRenderer = (y) => {
|
|
12352
|
+
if (scrollHandled) return true;
|
|
12353
|
+
if (!rowsToRender) return true;
|
|
12354
|
+
renderedRowsLookup ??= new Set(rowsToRender);
|
|
12355
|
+
return renderedRowsLookup.has(y);
|
|
12356
|
+
};
|
|
12357
|
+
const clearGraphicRectForRowsNotPainted = (rect) => {
|
|
12358
|
+
if (scrollHandled) return "";
|
|
12359
|
+
const erase = `\u001B[${Math.max(0, rect.w)}X`;
|
|
12360
|
+
const clearStyle = bgSeq;
|
|
12361
|
+
let out$1 = "";
|
|
12362
|
+
for (let row = 0; row < rect.h; row++) {
|
|
12363
|
+
const y = rect.y + row;
|
|
12364
|
+
const spans = terminalGraphicTextPreserveSpans.get(y);
|
|
12365
|
+
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));
|
|
12366
|
+
if ((!rowsToRender || rowWasPaintedByTextRenderer(y)) && !preservedGraphicSpan) continue;
|
|
12367
|
+
out$1 += `\u001B[${y + 1};${rect.x + 1}H${clearStyle}${erase}${SGR_RESET}`;
|
|
12368
|
+
}
|
|
12369
|
+
return out$1;
|
|
12370
|
+
};
|
|
12371
|
+
let commitTerminalGraphicsState = null;
|
|
12372
|
+
let restoreTerminalGraphicsAfterWriteFailure = null;
|
|
12373
|
+
let terminalGraphicsMetrics = null;
|
|
12374
|
+
const mergeGraphicsQueuedDuringPaint = () => {
|
|
12375
|
+
const seenEntries = new Set(graphicsEntriesToRender.map(([key]) => key));
|
|
12376
|
+
let changed = false;
|
|
12377
|
+
for (const entry of pendingGraphics.entries()) {
|
|
12378
|
+
if (seenEntries.has(entry[0])) continue;
|
|
12379
|
+
graphicsEntriesToRender.push(entry);
|
|
12380
|
+
changed = true;
|
|
12381
|
+
}
|
|
12382
|
+
for (const id of pendingGraphicClears) {
|
|
12383
|
+
if (pendingGraphicClearsToRender.has(id)) continue;
|
|
12384
|
+
pendingGraphicClearsToRender.add(id);
|
|
12385
|
+
graphicsClearsToRender.push(id);
|
|
12386
|
+
}
|
|
12387
|
+
if (!changed) return;
|
|
12388
|
+
graphicsEntriesToRender = graphicsEntriesToRender.sort(([, a], [, b]) => {
|
|
12389
|
+
const opA = a.op === "clear" ? 0 : 1;
|
|
12390
|
+
const opB = b.op === "clear" ? 0 : 1;
|
|
12391
|
+
return opA - opB || a.order - b.order;
|
|
12392
|
+
});
|
|
12393
|
+
graphicsToRender = graphicsEntriesToRender.map(([, payload]) => payload);
|
|
12394
|
+
};
|
|
12395
|
+
mergeGraphicsQueuedDuringPaint();
|
|
12396
|
+
if (graphicsClearsToRender.length > 0 || graphicsToRender.length > 0) {
|
|
12397
|
+
const nextActiveGraphics = new Map(activeGraphics);
|
|
12398
|
+
const nextActiveGraphicSignatures = new Map(activeGraphicSignatures);
|
|
12399
|
+
const nextPendingGraphicSignatures = new Map(pendingGraphicSignatures);
|
|
12400
|
+
let terminalGraphicsDraws = 0;
|
|
12401
|
+
let terminalGraphicsClears = 0;
|
|
12402
|
+
let terminalGraphicsBytes = 0;
|
|
12403
|
+
const countGraphicsBytes = (value) => {
|
|
12404
|
+
terminalGraphicsBytes += Buffer.byteLength(value, "utf8");
|
|
12405
|
+
return value;
|
|
12406
|
+
};
|
|
12407
|
+
const appendTerminalGraphicSequenceAt = (sequence, rect, fallbackCell, skipWithoutRect = false) => {
|
|
12408
|
+
if (!rect && skipWithoutRect) return false;
|
|
12409
|
+
const cell = rect ? {
|
|
12410
|
+
x: rect.x,
|
|
12411
|
+
y: rect.y
|
|
12412
|
+
} : clampCellToViewport(fallbackCell, size);
|
|
12413
|
+
frameParts.push(countGraphicsBytes(`\u001B[${cell.y + 1};${cell.x + 1}H`), countGraphicsBytes(maybeWrapTerminalGraphic(sequence)), countGraphicsBytes(SGR_RESET));
|
|
12414
|
+
return true;
|
|
12415
|
+
};
|
|
12416
|
+
const appendActiveGraphicProtocolClear = (active, rect) => {
|
|
12417
|
+
if (!active.clearSequence) return false;
|
|
12418
|
+
return appendTerminalGraphicSequenceAt(active.clearSequence, rect, {
|
|
12419
|
+
cellX: active.x,
|
|
12420
|
+
cellY: active.y
|
|
12421
|
+
}, clearSequenceNeedsVisibleCell(active.clearSequence, active.protocol));
|
|
12422
|
+
};
|
|
12423
|
+
hasFrameOutput = true;
|
|
12424
|
+
if (enableOsc8Links && activeStyle.href) frameParts.push(OSC8_CLOSE);
|
|
12425
|
+
if (allowGraphicsOnlyWithoutBaseline) frameParts.push(CURSOR_SAVE);
|
|
12426
|
+
activeStyle = {
|
|
12427
|
+
fg: null,
|
|
12428
|
+
bg: defaultBg,
|
|
12429
|
+
bold: false,
|
|
12430
|
+
dim: false,
|
|
12431
|
+
italic: false,
|
|
12432
|
+
underline: false,
|
|
12433
|
+
inverse: false,
|
|
12434
|
+
href: null
|
|
12435
|
+
};
|
|
12436
|
+
activeStyleKey = null;
|
|
12437
|
+
frameParts.push(countGraphicsBytes(SGR_RESET));
|
|
12438
|
+
for (const id of graphicsClearsToRender) {
|
|
12439
|
+
const active = nextActiveGraphics.get(id);
|
|
12440
|
+
if (!active) continue;
|
|
12441
|
+
const visibleRect = clipGraphicRectToViewport(active, size);
|
|
12442
|
+
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"}`);
|
|
12443
|
+
let wroteClear = false;
|
|
12444
|
+
if (visibleRect) {
|
|
12445
|
+
const clearRect$1 = clearGraphicRectForRowsNotPainted(visibleRect);
|
|
12446
|
+
if (clearRect$1) {
|
|
12447
|
+
frameParts.push(countGraphicsBytes(clearRect$1));
|
|
12448
|
+
wroteClear = true;
|
|
12449
|
+
}
|
|
12450
|
+
}
|
|
12451
|
+
wroteClear = appendActiveGraphicProtocolClear(active, visibleRect) || wroteClear;
|
|
12452
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
12453
|
+
retainedGraphics.delete(id);
|
|
12454
|
+
terminalResizeDirtyGraphics.delete(id);
|
|
12455
|
+
nextActiveGraphics.delete(id);
|
|
12456
|
+
nextActiveGraphicSignatures.delete(id);
|
|
12457
|
+
nextPendingGraphicSignatures.delete(id);
|
|
12458
|
+
}
|
|
12459
|
+
for (const payload of graphicsToRender) {
|
|
12460
|
+
if (payload.op === "clear") {
|
|
12461
|
+
const active = nextActiveGraphics.get(payload.id);
|
|
12462
|
+
const rect$1 = clipGraphicRectToViewport({
|
|
12463
|
+
x: (active === null || active === void 0 ? void 0 : active.x) ?? payload.x,
|
|
12464
|
+
y: (active === null || active === void 0 ? void 0 : active.y) ?? payload.y,
|
|
12465
|
+
w: (active === null || active === void 0 ? void 0 : active.w) ?? payload.w ?? 1,
|
|
12466
|
+
h: (active === null || active === void 0 ? void 0 : active.h) ?? payload.h ?? 1
|
|
12467
|
+
}, size);
|
|
12468
|
+
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"}`);
|
|
12469
|
+
const clearRect$2 = rect$1 ? clearGraphicRectForRowsNotPainted(rect$1) : "";
|
|
12470
|
+
let wroteClear = false;
|
|
12471
|
+
if (clearRect$2) {
|
|
12472
|
+
frameParts.push(countGraphicsBytes(clearRect$2));
|
|
12473
|
+
wroteClear = true;
|
|
12474
|
+
}
|
|
12475
|
+
wroteClear = appendTerminalGraphicSequenceAt(payload.sequence, rect$1, {
|
|
12476
|
+
cellX: (active === null || active === void 0 ? void 0 : active.x) ?? payload.x,
|
|
12477
|
+
cellY: (active === null || active === void 0 ? void 0 : active.y) ?? payload.y
|
|
12478
|
+
}, clearSequenceNeedsVisibleCell(payload.sequence, payload.protocol)) || wroteClear;
|
|
12479
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
12480
|
+
if (active && payload.retainOnClear) retainTerminalGraphic(payload.id, active, nextActiveGraphicSignatures.get(payload.id));
|
|
12481
|
+
else retainedGraphics.delete(payload.id);
|
|
12482
|
+
terminalResizeDirtyGraphics.delete(payload.id);
|
|
12483
|
+
nextActiveGraphics.delete(payload.id);
|
|
12484
|
+
nextActiveGraphicSignatures.delete(payload.id);
|
|
12485
|
+
nextPendingGraphicSignatures.delete(payload.id);
|
|
12486
|
+
continue;
|
|
12487
|
+
}
|
|
12488
|
+
const previous = nextActiveGraphics.get(payload.id);
|
|
12489
|
+
const rect = anchoredGraphicRectInViewport({
|
|
12490
|
+
x: payload.x,
|
|
12491
|
+
y: payload.y,
|
|
12492
|
+
w: payload.w ?? 1,
|
|
12493
|
+
h: payload.h ?? 1
|
|
12494
|
+
}, size);
|
|
12495
|
+
if (!rect) {
|
|
12496
|
+
if (previous) {
|
|
12497
|
+
const visiblePrevious = clipGraphicRectToViewport(previous, size);
|
|
12498
|
+
let wroteClear = false;
|
|
12499
|
+
if (visiblePrevious) {
|
|
12500
|
+
const clearPrevious = clearGraphicRectForRowsNotPainted(visiblePrevious);
|
|
12501
|
+
if (clearPrevious) {
|
|
12502
|
+
frameParts.push(countGraphicsBytes(clearPrevious));
|
|
12503
|
+
wroteClear = true;
|
|
12504
|
+
}
|
|
12505
|
+
}
|
|
12506
|
+
wroteClear = appendActiveGraphicProtocolClear(previous, visiblePrevious) || wroteClear;
|
|
12507
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
12508
|
+
retainTerminalGraphic(payload.id, previous, nextActiveGraphicSignatures.get(payload.id), { autoRedrawOnResize: true });
|
|
12509
|
+
nextActiveGraphics.delete(payload.id);
|
|
12510
|
+
nextActiveGraphicSignatures.delete(payload.id);
|
|
12511
|
+
}
|
|
12512
|
+
terminalResizeDirtyGraphics.delete(payload.id);
|
|
12513
|
+
nextPendingGraphicSignatures.delete(payload.id);
|
|
12514
|
+
continue;
|
|
12515
|
+
}
|
|
12516
|
+
const previousSignature = previous ? nextActiveGraphicSignatures.get(payload.id) : void 0;
|
|
12517
|
+
const nextSignature = nextPendingGraphicSignatures.get(payload.id) ?? terminalGraphicsPayloadSignature(payload);
|
|
12518
|
+
const canReplacePlacement = previous != null && payload.resizeRedraw && canReplaceKittyPlacementWithoutClear(previous, payload);
|
|
12519
|
+
const terminalResizePlacementOnly = previous != null && payload.terminalResizeRedraw && payload.resizeSequence != null && previous.sequence === payload.sequence;
|
|
12520
|
+
const resizeRedrawNeedsClear = previous && (payload.resizeRedraw || payload.terminalResizeRedraw) && Boolean(previous.clearSequence) && !canReplacePlacement;
|
|
12521
|
+
if (previous && (!canReplacePlacement && (previousSignature !== nextSignature || !sameGraphicRect(previous, rect)) || resizeRedrawNeedsClear)) {
|
|
12522
|
+
const visiblePrevious = clipGraphicRectToViewport(previous, size);
|
|
12523
|
+
let wroteClear = false;
|
|
12524
|
+
if (visiblePrevious) {
|
|
12525
|
+
const clearPrevious = clearGraphicRectForRowsNotPainted(visiblePrevious);
|
|
12526
|
+
if (clearPrevious) {
|
|
12527
|
+
frameParts.push(countGraphicsBytes(clearPrevious));
|
|
12528
|
+
wroteClear = true;
|
|
12529
|
+
}
|
|
12530
|
+
}
|
|
12531
|
+
wroteClear = appendActiveGraphicProtocolClear(previous, visiblePrevious) || wroteClear;
|
|
12532
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
12533
|
+
}
|
|
12534
|
+
const visibleRect = clipGraphicRectToViewport(rect, size);
|
|
12535
|
+
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"}`);
|
|
12536
|
+
const clearRect$1 = visibleRect ? clearGraphicRectForRowsNotPainted(visibleRect) : "";
|
|
12537
|
+
const cursor = `\u001B[${rect.y + 1};${rect.x + 1}H`;
|
|
12538
|
+
const sequencePayload = (canReplacePlacement || terminalResizePlacementOnly) && payload.resizeSequence ? payload.resizeSequence : payload.sequence;
|
|
12539
|
+
const sequence = maybeWrapTerminalGraphic(sequencePayload);
|
|
12540
|
+
frameParts.push(countGraphicsBytes(cursor), countGraphicsBytes(sequence), countGraphicsBytes(SGR_RESET), clearRect$1 ? countGraphicsBytes(clearRect$1) : "");
|
|
12541
|
+
terminalGraphicsDraws++;
|
|
12542
|
+
nextActiveGraphics.set(payload.id, {
|
|
12543
|
+
...rect,
|
|
12544
|
+
protocol: payload.protocol,
|
|
12545
|
+
sequence: previous && (canReplacePlacement || terminalResizePlacementOnly) ? previous.sequence : payload.sequence,
|
|
12546
|
+
resizeSequence: payload.resizeSequence ?? (previous === null || previous === void 0 ? void 0 : previous.resizeSequence),
|
|
12547
|
+
clearSequence: payload.clearSequence,
|
|
12548
|
+
allowTextOverlay: payload.allowTextOverlay ?? (previous === null || previous === void 0 ? void 0 : previous.allowTextOverlay)
|
|
12549
|
+
});
|
|
12550
|
+
nextActiveGraphicSignatures.set(payload.id, nextSignature);
|
|
12551
|
+
nextPendingGraphicSignatures.delete(payload.id);
|
|
12552
|
+
terminalResizeDirtyGraphics.delete(payload.id);
|
|
12553
|
+
}
|
|
12554
|
+
if (allowGraphicsOnlyWithoutBaseline) frameParts.push(CURSOR_RESTORE);
|
|
12555
|
+
restoreTerminalGraphicsAfterWriteFailure = () => {
|
|
12556
|
+
for (const id of graphicsClearsToRender) pendingGraphicClears.add(id);
|
|
12557
|
+
for (const [key, payload] of graphicsEntriesToRender) pendingGraphics.set(key, payload);
|
|
12558
|
+
};
|
|
12559
|
+
commitTerminalGraphicsState = () => {
|
|
12560
|
+
for (const id of pendingGraphicClearsToRender) pendingGraphicClears.delete(id);
|
|
12561
|
+
for (const [key, payload] of graphicsEntriesToRender) if (pendingGraphics.get(key) === payload) pendingGraphics.delete(key);
|
|
12562
|
+
activeGraphics.clear();
|
|
12563
|
+
for (const [id, active] of nextActiveGraphics) activeGraphics.set(id, active);
|
|
12564
|
+
activeGraphicSignatures.clear();
|
|
12565
|
+
for (const [id, signature] of nextActiveGraphicSignatures) activeGraphicSignatures.set(id, signature);
|
|
12566
|
+
pendingGraphicSignatures.clear();
|
|
12567
|
+
for (const [id, signature] of nextPendingGraphicSignatures) pendingGraphicSignatures.set(id, signature);
|
|
12568
|
+
};
|
|
12569
|
+
terminalGraphicsMetrics = {
|
|
12570
|
+
draws: terminalGraphicsDraws,
|
|
12571
|
+
clears: terminalGraphicsClears,
|
|
12572
|
+
bytes: terminalGraphicsBytes,
|
|
12573
|
+
active: nextActiveGraphics.size
|
|
12574
|
+
};
|
|
12575
|
+
if (isDebugEnabled()) getDebugLog().render(`terminal graphics frame: draws=${terminalGraphicsDraws}, clears=${terminalGraphicsClears}, bytes=${terminalGraphicsBytes}, activeNext=${nextActiveGraphics.size}`);
|
|
12576
|
+
}
|
|
10020
12577
|
let emittedCursorPos = null;
|
|
10021
12578
|
if (getImeAnchor) {
|
|
10022
12579
|
const anchor = getImeAnchor();
|
|
@@ -10041,8 +12598,9 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10041
12598
|
}
|
|
10042
12599
|
if (enableOsc8Links && activeStyle.href) frameParts.push(OSC8_CLOSE);
|
|
10043
12600
|
frameParts.push(SGR_RESET);
|
|
10044
|
-
frameParts.push(
|
|
10045
|
-
frameParts.push(
|
|
12601
|
+
if (hideCursor && !getImeAnchor) frameParts.push(CURSOR_HOME);
|
|
12602
|
+
frameParts.push(allowGraphicsOnlyWithoutBaseline || keepLineWrapDisabled ? "" : "\x1B[?7h");
|
|
12603
|
+
frameParts.push(useFrameSyncOutput ? SYNC_END : "");
|
|
10046
12604
|
const frame = frameParts.join("");
|
|
10047
12605
|
const frameBytes = Buffer.byteLength(frame, "utf8");
|
|
10048
12606
|
if (profiler) profiler.recordRender({
|
|
@@ -10103,10 +12661,11 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10103
12661
|
const resetCount = countResets(frame);
|
|
10104
12662
|
const buildTime = (performance.now() - renderStart).toFixed(2);
|
|
10105
12663
|
getDebugLog().render(` Frame built: ${frameSize} bytes, ${cursorSeqCount} cursor sequences, ${resetCount} resets, ${buildTime}ms`);
|
|
10106
|
-
getDebugLog().render(` Terminal: ${isGhostty ? "GHOSTTY" : "other"}, useSyncOutput: ${useSyncOutput}`);
|
|
12664
|
+
getDebugLog().render(` Terminal: ${isGhostty ? "GHOSTTY" : "other"}, useSyncOutput: ${useSyncOutput}, useFrameSyncOutput: ${useFrameSyncOutput}`);
|
|
10107
12665
|
}
|
|
10108
12666
|
const writeStart = performance.now();
|
|
10109
12667
|
const resolveWriteMode = (frameSizeBytes) => {
|
|
12668
|
+
if (frameHasTerminalGraphics && frameSizeBytes <= syncMaxBytes) return canUseSyncStdout ? "sync" : "stream";
|
|
10110
12669
|
if (isGhostty) return "chunked";
|
|
10111
12670
|
const preferChunked = frameSizeBytes >= chunkThresholdBytes || writeEmaMs >= 24;
|
|
10112
12671
|
if (preferChunked) return "chunked";
|
|
@@ -10136,12 +12695,15 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10136
12695
|
getDebugLog().render(` Write completed in ${writeTime}ms`);
|
|
10137
12696
|
}
|
|
10138
12697
|
} catch (writeError) {
|
|
12698
|
+
restoreTerminalGraphicsAfterWriteFailure === null || restoreTerminalGraphicsAfterWriteFailure === void 0 || restoreTerminalGraphicsAfterWriteFailure();
|
|
10139
12699
|
if (isDebugEnabled()) getDebugLog().error(`Write ERROR:`, writeError);
|
|
10140
12700
|
try {
|
|
10141
|
-
out.write(`\u001B[?7h${
|
|
12701
|
+
out.write(`\u001B[?7h${useFrameSyncOutput ? SYNC_END : ""}`);
|
|
10142
12702
|
} catch {}
|
|
10143
12703
|
throw writeError;
|
|
10144
12704
|
}
|
|
12705
|
+
commitTerminalGraphicsState === null || commitTerminalGraphicsState === void 0 || commitTerminalGraphicsState();
|
|
12706
|
+
if (terminalGraphicsMetrics) recordStdoutTerminalGraphics(terminalGraphicsMetrics);
|
|
10145
12707
|
commitRenderBaseline();
|
|
10146
12708
|
{
|
|
10147
12709
|
const writeMs = performance.now() - writeStart;
|
|
@@ -10149,6 +12711,9 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10149
12711
|
if (emittedCursorPos) {
|
|
10150
12712
|
lastCursorX = emittedCursorPos.x;
|
|
10151
12713
|
lastCursorY = emittedCursorPos.y;
|
|
12714
|
+
} else if (hideCursor && !getImeAnchor) {
|
|
12715
|
+
lastCursorX = 0;
|
|
12716
|
+
lastCursorY = 0;
|
|
10152
12717
|
} else {
|
|
10153
12718
|
lastCursorX = null;
|
|
10154
12719
|
lastCursorY = null;
|
|
@@ -10315,6 +12880,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10315
12880
|
*/
|
|
10316
12881
|
function render(dirtyRows, sync, scrollOperations) {
|
|
10317
12882
|
if (disposed) return;
|
|
12883
|
+
if (dirtyRows == null || sync) deferGraphicsFlushUntilResizeCommit = false;
|
|
10318
12884
|
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
12885
|
if (dirtyRows == null) {
|
|
10320
12886
|
accumulatedAllRows = true;
|
|
@@ -10326,7 +12892,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10326
12892
|
accumulatedScrollOperations = null;
|
|
10327
12893
|
} else if (dirtyRows.length === 0) {
|
|
10328
12894
|
if (scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length) mergeScrollOperations(scrollOperations);
|
|
10329
|
-
else if (!accumulatedAllRows && accumulatedDirtyCount === 0 && !getImeAnchor) {
|
|
12895
|
+
else if (!accumulatedAllRows && accumulatedDirtyCount === 0 && !getImeAnchor && !hasPendingTerminalGraphics()) {
|
|
10330
12896
|
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(0);
|
|
10331
12897
|
return;
|
|
10332
12898
|
}
|
|
@@ -10345,8 +12911,8 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10345
12911
|
}
|
|
10346
12912
|
}
|
|
10347
12913
|
}
|
|
10348
|
-
const now$
|
|
10349
|
-
const elapsed = now$
|
|
12914
|
+
const now$3 = Date.now();
|
|
12915
|
+
const elapsed = now$3 - lastFrameTime;
|
|
10350
12916
|
const queuedDelayMs = Math.max(0, MIN_FRAME_MS - elapsed);
|
|
10351
12917
|
if (pendingRender && !sync) {
|
|
10352
12918
|
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(queuedDelayMs);
|
|
@@ -10436,13 +13002,94 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10436
13002
|
} catch {}
|
|
10437
13003
|
}
|
|
10438
13004
|
installFingerprintFn();
|
|
13005
|
+
let suppressNextResizeCommitRender = false;
|
|
13006
|
+
function consumeResizeDirtyState() {
|
|
13007
|
+
suppressNextResizeCommitRender = true;
|
|
13008
|
+
try {
|
|
13009
|
+
terminal.commit({ sync: true });
|
|
13010
|
+
} finally {
|
|
13011
|
+
suppressNextResizeCommitRender = false;
|
|
13012
|
+
}
|
|
13013
|
+
}
|
|
13014
|
+
function clearRowsOnlyResizeRepaintTimer() {
|
|
13015
|
+
if (!rowsOnlyResizeRepaintTimer) return;
|
|
13016
|
+
clearTimeout(rowsOnlyResizeRepaintTimer);
|
|
13017
|
+
rowsOnlyResizeRepaintTimer = null;
|
|
13018
|
+
}
|
|
13019
|
+
function repaintRowsAfterRowsOnlyResize() {
|
|
13020
|
+
if (disposed) return;
|
|
13021
|
+
const { rows } = terminal.size();
|
|
13022
|
+
if (rows <= 0) return;
|
|
13023
|
+
if (isDebugEnabled()) getDebugLog().render(`rows-only resize repaint: rows=${rows}`);
|
|
13024
|
+
preserveNextRowsOnlyResizeBaseline = true;
|
|
13025
|
+
const dirtyRows = Array.from({ length: rows }, (_, y) => y);
|
|
13026
|
+
accumulatedDirtyRowsRequireRepaint = true;
|
|
13027
|
+
deferGraphicsFlushUntilResizeCommit = false;
|
|
13028
|
+
allowNextGraphicsOnlyRenderWithoutBaseline = false;
|
|
13029
|
+
render(dirtyRows, true);
|
|
13030
|
+
}
|
|
13031
|
+
function scheduleRowsOnlyResizeRepaint() {
|
|
13032
|
+
clearRowsOnlyResizeRepaintTimer();
|
|
13033
|
+
if (isDebugEnabled()) getDebugLog().render(`rows-only resize repaint scheduled: delay=${ROWS_ONLY_RESIZE_REPAINT_DELAY_MS}ms`);
|
|
13034
|
+
rowsOnlyResizeRepaintTimer = setTimeout(() => {
|
|
13035
|
+
rowsOnlyResizeRepaintTimer = null;
|
|
13036
|
+
repaintRowsAfterRowsOnlyResize();
|
|
13037
|
+
}, ROWS_ONLY_RESIZE_REPAINT_DELAY_MS);
|
|
13038
|
+
}
|
|
10439
13039
|
if (altScreen && outputIsTTY) out.write("\x1B[?1049h");
|
|
13040
|
+
if (keepLineWrapDisabled) out.write("\x1B[?7l");
|
|
10440
13041
|
if (hideCursor) out.write("\x1B[?25l");
|
|
10441
13042
|
if (clear) out.write(`${SGR_RESET}${openBg(defaultBg)}\u001B[2J\u001B[H${SGR_RESET}`);
|
|
10442
13043
|
const off = terminal.on("commit", ({ dirtyRows, scrollOperations, sync }) => {
|
|
13044
|
+
if (suppressNextResizeCommitRender) return;
|
|
13045
|
+
const deferRowsOnlyResizeCommit = rowsOnlyResizeRepaintTimer && (dirtyRows == null || dirtyRows.length >= terminal.size().rows);
|
|
13046
|
+
if (deferRowsOnlyResizeCommit) {
|
|
13047
|
+
if (isDebugEnabled()) getDebugLog().render(`rows-only resize commit deferred: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}${sync ? " (sync)" : ""}`);
|
|
13048
|
+
scheduleRowsOnlyResizeRepaint();
|
|
13049
|
+
return;
|
|
13050
|
+
}
|
|
10443
13051
|
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
13052
|
render(dirtyRows, sync, scrollOperations);
|
|
10445
13053
|
});
|
|
13054
|
+
let terminalResizeCols = terminal.size().cols;
|
|
13055
|
+
let terminalResizeRows = terminal.size().rows;
|
|
13056
|
+
const offTerminalResize = terminal.on("resize", ({ cols, rows }) => {
|
|
13057
|
+
const colsChanged = cols !== terminalResizeCols;
|
|
13058
|
+
const rowsChanged = rows !== terminalResizeRows;
|
|
13059
|
+
const rowsIncreased = rows > terminalResizeRows;
|
|
13060
|
+
terminalResizeCols = cols;
|
|
13061
|
+
terminalResizeRows = rows;
|
|
13062
|
+
if (!colsChanged && !rowsChanged) return;
|
|
13063
|
+
if (pendingRender) {
|
|
13064
|
+
pendingRender = false;
|
|
13065
|
+
if (renderTimer) {
|
|
13066
|
+
clearTimeout(renderTimer);
|
|
13067
|
+
renderTimer = null;
|
|
13068
|
+
}
|
|
13069
|
+
if (isDebugEnabled()) getDebugLog().render("pending stdout render canceled until resize commit");
|
|
13070
|
+
}
|
|
13071
|
+
queueTerminalGraphicsForResizeRedraw({
|
|
13072
|
+
cols,
|
|
13073
|
+
rows
|
|
13074
|
+
});
|
|
13075
|
+
if (!colsChanged) {
|
|
13076
|
+
consumeResizeDirtyState();
|
|
13077
|
+
preserveNextRowsOnlyResizeBaseline = true;
|
|
13078
|
+
if (rowsIncreased) {
|
|
13079
|
+
clearRowsOnlyResizeRepaintTimer();
|
|
13080
|
+
repaintRowsAfterRowsOnlyResize();
|
|
13081
|
+
return;
|
|
13082
|
+
}
|
|
13083
|
+
scheduleRowsOnlyResizeRepaint();
|
|
13084
|
+
if (hasPendingTerminalGraphics()) {
|
|
13085
|
+
deferGraphicsFlushUntilResizeCommit = false;
|
|
13086
|
+
allowNextGraphicsOnlyRenderWithoutBaseline = true;
|
|
13087
|
+
render([], true);
|
|
13088
|
+
}
|
|
13089
|
+
return;
|
|
13090
|
+
}
|
|
13091
|
+
clearRowsOnlyResizeRepaintTimer();
|
|
13092
|
+
});
|
|
10446
13093
|
const resizeSource = (options === null || options === void 0 ? void 0 : options.output) ?? process.stdout;
|
|
10447
13094
|
const canTrackResize = Boolean(trackResize && outputIsTTY && typeof (resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.on) === "function");
|
|
10448
13095
|
const onResize = () => {
|
|
@@ -10450,9 +13097,13 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10450
13097
|
const rows = Number(resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.rows);
|
|
10451
13098
|
if (!Number.isFinite(cols) || !Number.isFinite(rows)) return;
|
|
10452
13099
|
const size = terminal.size();
|
|
13100
|
+
if (isDebugEnabled()) getDebugLog().render(`stdout resize event: output=${cols}x${rows}, terminal=${size.cols}x${size.rows}, trackResize=${trackResize ? "true" : "false"}`);
|
|
10453
13101
|
if (cols === size.cols && rows === size.rows) return;
|
|
13102
|
+
const colsChanged = cols !== size.cols;
|
|
13103
|
+
const rowsChanged = rows !== size.rows;
|
|
10454
13104
|
terminal.resize(cols, rows);
|
|
10455
|
-
|
|
13105
|
+
consumeResizeDirtyState();
|
|
13106
|
+
if (isDebugEnabled()) getDebugLog().render(`stdout resize consumed: target=${cols}x${rows}, colsChanged=${colsChanged ? "true" : "false"}, rowsChanged=${rowsChanged ? "true" : "false"}`);
|
|
10456
13107
|
};
|
|
10457
13108
|
if (canTrackResize) try {
|
|
10458
13109
|
resizeSource.on("resize", onResize);
|
|
@@ -10482,17 +13133,73 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10482
13133
|
function dispose() {
|
|
10483
13134
|
if (disposed) return;
|
|
10484
13135
|
disposed = true;
|
|
13136
|
+
let disposeError = null;
|
|
10485
13137
|
if (renderTimer) {
|
|
10486
13138
|
clearTimeout(renderTimer);
|
|
10487
13139
|
renderTimer = null;
|
|
10488
13140
|
}
|
|
13141
|
+
if (terminalGraphicsFlushTimer) {
|
|
13142
|
+
clearTimeout(terminalGraphicsFlushTimer);
|
|
13143
|
+
terminalGraphicsFlushTimer = null;
|
|
13144
|
+
}
|
|
13145
|
+
clearRowsOnlyResizeRepaintTimer();
|
|
10489
13146
|
accumulatedAllRows = false;
|
|
10490
13147
|
accumulatedDirtyBits = null;
|
|
10491
13148
|
accumulatedDirtyCount = 0;
|
|
10492
13149
|
accumulatedDirtyMin = Number.POSITIVE_INFINITY;
|
|
10493
13150
|
accumulatedDirtyMax = -1;
|
|
10494
13151
|
accumulatedDirtyRowsRequireRepaint = false;
|
|
13152
|
+
pendingGraphics.clear();
|
|
13153
|
+
pendingGraphicClears.clear();
|
|
13154
|
+
pendingGraphicSignatures.clear();
|
|
13155
|
+
retainedGraphics.clear();
|
|
13156
|
+
knownKittyImageIds.clear();
|
|
13157
|
+
terminalResizeDirtyGraphics.clear();
|
|
13158
|
+
try {
|
|
13159
|
+
if (activeGraphics.size > 0) {
|
|
13160
|
+
const size = terminal.size();
|
|
13161
|
+
const clearParts = [];
|
|
13162
|
+
let terminalGraphicsClears = 0;
|
|
13163
|
+
for (const active of activeGraphics.values()) {
|
|
13164
|
+
const visibleRect = clipGraphicRectToViewport(active, size);
|
|
13165
|
+
let wroteClear = false;
|
|
13166
|
+
if (visibleRect) {
|
|
13167
|
+
clearParts.push(clearGraphicRect(visibleRect));
|
|
13168
|
+
wroteClear = true;
|
|
13169
|
+
}
|
|
13170
|
+
if (active.clearSequence && (visibleRect || !clearSequenceNeedsVisibleCell(active.clearSequence, active.protocol))) {
|
|
13171
|
+
const cell = visibleRect ? {
|
|
13172
|
+
x: visibleRect.x,
|
|
13173
|
+
y: visibleRect.y
|
|
13174
|
+
} : clampCellToViewport({
|
|
13175
|
+
cellX: active.x,
|
|
13176
|
+
cellY: active.y
|
|
13177
|
+
}, size);
|
|
13178
|
+
clearParts.push(`\u001B[${cell.y + 1};${cell.x + 1}H`, maybeWrapTerminalGraphic(active.clearSequence));
|
|
13179
|
+
wroteClear = true;
|
|
13180
|
+
}
|
|
13181
|
+
if (wroteClear) terminalGraphicsClears++;
|
|
13182
|
+
}
|
|
13183
|
+
activeGraphics.clear();
|
|
13184
|
+
activeGraphicSignatures.clear();
|
|
13185
|
+
if (clearParts.length > 0) {
|
|
13186
|
+
const frame = `${SGR_RESET}${clearParts.join("")}${SGR_RESET}`;
|
|
13187
|
+
out.write(frame);
|
|
13188
|
+
recordStdoutTerminalGraphics({
|
|
13189
|
+
clears: terminalGraphicsClears,
|
|
13190
|
+
bytes: Buffer.byteLength(frame, "utf8"),
|
|
13191
|
+
active: 0
|
|
13192
|
+
});
|
|
13193
|
+
} else recordStdoutTerminalGraphics({ active: 0 });
|
|
13194
|
+
}
|
|
13195
|
+
} catch {
|
|
13196
|
+
activeGraphics.clear();
|
|
13197
|
+
activeGraphicSignatures.clear();
|
|
13198
|
+
recordStdoutTerminalGraphics({ active: 0 });
|
|
13199
|
+
}
|
|
13200
|
+
unregisterGraphicsOutput();
|
|
10495
13201
|
off();
|
|
13202
|
+
offTerminalResize();
|
|
10496
13203
|
releaseFingerprintFn();
|
|
10497
13204
|
if (canTrackResize && typeof (resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.off) === "function") try {
|
|
10498
13205
|
resizeSource.off("resize", onResize);
|
|
@@ -10500,9 +13207,15 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10500
13207
|
else if (canTrackResize && typeof (resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.removeListener) === "function") try {
|
|
10501
13208
|
resizeSource.removeListener("resize", onResize);
|
|
10502
13209
|
} catch {}
|
|
10503
|
-
|
|
10504
|
-
|
|
13210
|
+
try {
|
|
13211
|
+
if (keepLineWrapDisabled) out.write("\x1B[?7h");
|
|
13212
|
+
if (hideCursor) out.write("\x1B[?25h");
|
|
13213
|
+
if (altScreen && outputIsTTY) out.write("\x1B[?1049l");
|
|
13214
|
+
} catch (err) {
|
|
13215
|
+
if (disposeError == null) disposeError = err;
|
|
13216
|
+
}
|
|
10505
13217
|
profiler === null || profiler === void 0 || profiler.dispose();
|
|
13218
|
+
if (disposeError) throw disposeError;
|
|
10506
13219
|
}
|
|
10507
13220
|
const updateTheme = (next) => {
|
|
10508
13221
|
if (disposed) return;
|
|
@@ -10517,10 +13230,12 @@ function createStdoutRenderer(terminal, options) {
|
|
|
10517
13230
|
fpPrevValid = false;
|
|
10518
13231
|
prevOverlayBlockedRows = [];
|
|
10519
13232
|
prevOverlayPartialRows = [];
|
|
13233
|
+
prevOverlayVisibleSpans = new Map();
|
|
10520
13234
|
render();
|
|
10521
13235
|
};
|
|
10522
13236
|
return {
|
|
10523
13237
|
capabilities: STDOUT_RENDERER_CAPABILITIES,
|
|
13238
|
+
graphicsCapabilities,
|
|
10524
13239
|
render,
|
|
10525
13240
|
dispose,
|
|
10526
13241
|
setCursor,
|
|
@@ -10554,4 +13269,4 @@ function createNodeMentionPathProvider() {
|
|
|
10554
13269
|
}
|
|
10555
13270
|
|
|
10556
13271
|
//#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 };
|
|
13272
|
+
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 };
|