@simon_he/vue-tui 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -26
- package/dist/TMermaidText-CXm_L969.js +885 -0
- package/dist/{TSelect-DR0FomSu.js → TSelect-CiyMvwl-.js} +60 -81
- package/dist/{TTree-kzhlB5P0.js → TTree-DKGiuIcM.js} +140 -103
- package/dist/agent/mermaid.cjs +2 -0
- package/dist/agent/mermaid.d.cts +2 -0
- package/dist/agent/mermaid.d.ts +2 -0
- package/dist/agent/mermaid.js +1 -0
- package/dist/agent.cjs +31184 -24907
- package/dist/agent.d.cts +11 -1
- package/dist/agent.d.ts +11 -1
- package/dist/agent.js +1700 -13
- package/dist/block-source-5CQp4tF8.js +3230 -0
- package/dist/cli/stdin-buffer.d.ts +1 -1
- package/dist/cli.cjs +5037 -6767
- package/dist/cli.d.cts +4 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +2733 -148
- package/dist/core/buffer/eaw-ranges-unicode-17.d.ts +14 -0
- package/dist/core/perf/instrumentation-noop.d.ts +48 -0
- package/dist/core/perf/instrumentation.d.ts +136 -0
- package/dist/core/terminal/create-terminal.d.ts +1 -0
- package/dist/core.cjs +843 -1469
- package/dist/core.js +6 -6
- package/dist/{create-terminal-DBFNYr8f.js → create-terminal-DXuZ2fci.js} +39 -13
- package/dist/debug-logger-ChY_PXVk.js +74 -0
- package/dist/{dom-renderer-BniJSQyX.js → dom-renderer-DNzmg2As.js} +2 -2
- package/dist/experimental.cjs +4115 -5928
- package/dist/experimental.d.cts +2 -0
- package/dist/experimental.d.ts +2 -0
- package/dist/experimental.js +1490 -9
- package/dist/frame-perf-BBhE-iuS.js +111 -0
- package/dist/{sgr-BmzxEjAO.js → hyperlink-B35-O-cW.js} +100 -1
- package/dist/index.cjs +5017 -10339
- package/dist/index.js +16 -14
- package/dist/{linkify-D_gzn9Xq.js → linkify-CuuquMQT.js} +32 -3
- package/dist/markdown.cjs +21295 -12691
- package/dist/markdown.d.cts +1 -1
- package/dist/markdown.d.ts +1 -1
- package/dist/markdown.js +211 -51
- package/dist/mermaid-CWto52Wk.js +123 -0
- package/dist/mermaid.cjs +1707 -0
- package/dist/mermaid.d.cts +3 -0
- package/dist/mermaid.d.ts +3 -0
- package/dist/mermaid.js +6 -0
- package/dist/observability/frame-perf-store.d.ts +2 -1
- package/dist/observability/frame-perf.d.ts +33 -0
- package/dist/observability.cjs +106 -107
- package/dist/observability.d.cts +2 -2
- package/dist/observability.d.ts +2 -2
- package/dist/observability.js +3 -3
- package/dist/{path-suggest-BNqcuE3-.js → path-suggest-fPzRsgPv.js} +1 -1
- package/dist/{wheel-scroll-vBRaQ7p-.js → rect-Ng-3eKzF.js} +253 -117
- package/dist/renderer/cli/stdout-metrics.d.ts +10 -0
- package/dist/renderer/cli/stdout-renderer.d.ts +3 -0
- package/dist/renderer/terminal-graphic-render-queue.d.ts +50 -0
- package/dist/renderer/terminal-graphics-trace.d.ts +53 -0
- package/dist/renderer/terminal-graphics.d.ts +146 -0
- package/dist/renderer-dom.cjs +364 -903
- package/dist/renderer-dom.js +4 -4
- package/dist/runtime/index.d.ts +2 -0
- package/dist/{runtime-rfcZCyJq.js → runtime-D77C03RM.js} +28 -15
- package/dist/runtime.cjs +427 -889
- package/dist/runtime.js +2 -2
- package/dist/{terminal-selection-DBinO6p5.js → terminal-selection-CQYr--26.js} +4 -1
- package/dist/{tlog-theme-CvLFNMwk.js → tlog-theme-CopRt9SC.js} +37 -6
- package/dist/{trace-CjzYeIxN.js → trace-CYHDKM1m.js} +5 -0
- package/dist/vue/agent/create-png-terminal-graphic-renderer.d.ts +19 -0
- package/dist/vue/components/TAgentTerminalGraphic.d.ts +481 -0
- package/dist/vue/components/TCharts.d.ts +1121 -0
- package/dist/vue/components/TFeedback.d.ts +1 -1
- package/dist/vue/components/TFlex.d.ts +389 -0
- package/dist/vue/components/TForm.d.ts +4 -4
- package/dist/vue/components/TLogSearchBar.d.ts +3 -3
- package/dist/vue/components/TLogSearchPager.d.ts +2 -2
- package/dist/vue/components/TMarkdownText.d.ts +162 -4
- package/dist/vue/components/TMermaidText.d.ts +900 -0
- package/dist/vue/components/TVirtualList.d.ts +9 -0
- package/dist/vue/components/TVirtualMarkdown.d.ts +170 -9
- package/dist/vue/components/TVirtualRows.d.ts +9 -0
- package/dist/vue/components/TerminalProvider.d.ts +2 -0
- package/dist/vue/context.d.ts +24 -0
- package/dist/vue/index.d.ts +5 -0
- package/dist/vue/layout/flex.d.ts +67 -0
- package/dist/vue/markdown/ast.d.ts +5 -2
- package/dist/vue/markdown/document.d.ts +5 -0
- package/dist/vue/markdown/image-actions.d.ts +14 -0
- package/dist/vue/markdown/image.d.ts +11 -0
- package/dist/vue/markdown/link-actions.d.ts +14 -0
- package/dist/vue/markdown/math-actions.d.ts +14 -0
- package/dist/vue/markdown/math.d.ts +6 -0
- package/dist/vue/markdown/render.d.ts +28 -0
- package/dist/vue/markdown/types.d.ts +78 -0
- package/dist/vue/mermaid/beautiful-mermaid.d.ts +1436 -0
- package/dist/vue/render/render-manager.d.ts +7 -0
- package/dist/vue.cjs +7207 -12437
- package/dist/vue.js +706 -39
- package/dist/wheel-scroll-CQ22Hcyj.js +106 -0
- package/dist/{hyperlink-Bn02UXJb.js → width-GqllnV8C.js} +166 -111
- package/package.json +85 -14
- package/dist/block-source-CKUOnkgT.js +0 -1663
- package/dist/frame-perf-C6Xfg85O.js +0 -24
- /package/dist/{env-Cl8qmNFN.js → env-DNCzvX8b.js} +0 -0
- /package/dist/{path-mnSgEpCm.js → path-BI9W15Zt.js} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { charCellWidth, segmentedGraphemes } from "./
|
|
2
|
-
import { computed, inject, onBeforeUnmount, provide, ref, vShow, watchEffect } from "vue";
|
|
1
|
+
import { charCellWidth, segmentedGraphemes } from "./width-GqllnV8C.js";
|
|
2
|
+
import { computed, inject, onBeforeUnmount, provide, readonly, ref, vShow, watchEffect } from "vue";
|
|
3
3
|
|
|
4
4
|
//#region src/vue/injection-key.ts
|
|
5
5
|
const VUE_TUI_INJECTION_PROTOCOL = "v1";
|
|
@@ -7,6 +7,120 @@ function injectionKey(name) {
|
|
|
7
7
|
return Symbol.for(`@simon_he/vue-tui:${VUE_TUI_INJECTION_PROTOCOL}:${name}`);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/renderer/terminal-graphics-trace.ts
|
|
12
|
+
const metrics = {
|
|
13
|
+
requests: 0,
|
|
14
|
+
skippedHidden: 0,
|
|
15
|
+
skippedScrolling: 0,
|
|
16
|
+
cacheHits: 0,
|
|
17
|
+
cacheMisses: 0,
|
|
18
|
+
cacheStores: 0,
|
|
19
|
+
rendererRuns: 0,
|
|
20
|
+
rendererAborts: 0,
|
|
21
|
+
rendererErrors: 0,
|
|
22
|
+
queued: 0,
|
|
23
|
+
queueWaits: 0,
|
|
24
|
+
queueDeduped: 0,
|
|
25
|
+
cleared: 0,
|
|
26
|
+
bytesQueued: 0,
|
|
27
|
+
totalRendererMs: 0,
|
|
28
|
+
totalValidateMs: 0,
|
|
29
|
+
totalQueueWaitMs: 0,
|
|
30
|
+
maxQueueWaitMs: 0,
|
|
31
|
+
maxActiveRenders: 0,
|
|
32
|
+
maxWaitingRenders: 0,
|
|
33
|
+
maxCacheEntries: 0,
|
|
34
|
+
maxCacheBytes: 0,
|
|
35
|
+
scrollStarts: 0,
|
|
36
|
+
scrollMarks: 0,
|
|
37
|
+
scrollIdles: 0,
|
|
38
|
+
totalScrollMs: 0,
|
|
39
|
+
maxScrollMs: 0
|
|
40
|
+
};
|
|
41
|
+
const subscribers = new Set();
|
|
42
|
+
function nowTerminalGraphicTraceTime() {
|
|
43
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
44
|
+
}
|
|
45
|
+
function recordTerminalGraphicTrace(event) {
|
|
46
|
+
const normalized = {
|
|
47
|
+
...event,
|
|
48
|
+
timestamp: event.timestamp ?? nowTerminalGraphicTraceTime()
|
|
49
|
+
};
|
|
50
|
+
switch (normalized.type) {
|
|
51
|
+
case "request":
|
|
52
|
+
metrics.requests++;
|
|
53
|
+
break;
|
|
54
|
+
case "skip-hidden":
|
|
55
|
+
metrics.skippedHidden++;
|
|
56
|
+
break;
|
|
57
|
+
case "skip-scrolling":
|
|
58
|
+
metrics.skippedScrolling++;
|
|
59
|
+
break;
|
|
60
|
+
case "cache-hit":
|
|
61
|
+
metrics.cacheHits++;
|
|
62
|
+
break;
|
|
63
|
+
case "cache-miss":
|
|
64
|
+
metrics.cacheMisses++;
|
|
65
|
+
break;
|
|
66
|
+
case "cache-store":
|
|
67
|
+
metrics.cacheStores++;
|
|
68
|
+
break;
|
|
69
|
+
case "renderer-start":
|
|
70
|
+
metrics.rendererRuns++;
|
|
71
|
+
break;
|
|
72
|
+
case "renderer-end":
|
|
73
|
+
metrics.totalRendererMs += normalized.durationMs ?? 0;
|
|
74
|
+
break;
|
|
75
|
+
case "renderer-abort":
|
|
76
|
+
metrics.rendererAborts++;
|
|
77
|
+
break;
|
|
78
|
+
case "renderer-error":
|
|
79
|
+
metrics.rendererErrors++;
|
|
80
|
+
break;
|
|
81
|
+
case "validate-end":
|
|
82
|
+
metrics.totalValidateMs += normalized.durationMs ?? 0;
|
|
83
|
+
break;
|
|
84
|
+
case "queue":
|
|
85
|
+
metrics.queued++;
|
|
86
|
+
metrics.bytesQueued += normalized.bytes ?? 0;
|
|
87
|
+
break;
|
|
88
|
+
case "queue-wait": {
|
|
89
|
+
const durationMs = normalized.durationMs ?? 0;
|
|
90
|
+
metrics.queueWaits++;
|
|
91
|
+
metrics.totalQueueWaitMs += durationMs;
|
|
92
|
+
metrics.maxQueueWaitMs = Math.max(metrics.maxQueueWaitMs, durationMs);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case "queue-dedupe":
|
|
96
|
+
metrics.queueDeduped++;
|
|
97
|
+
break;
|
|
98
|
+
case "clear":
|
|
99
|
+
metrics.cleared++;
|
|
100
|
+
break;
|
|
101
|
+
case "scroll-start":
|
|
102
|
+
metrics.scrollStarts++;
|
|
103
|
+
break;
|
|
104
|
+
case "scroll-mark":
|
|
105
|
+
metrics.scrollMarks++;
|
|
106
|
+
break;
|
|
107
|
+
case "scroll-idle": {
|
|
108
|
+
const durationMs = normalized.durationMs ?? 0;
|
|
109
|
+
metrics.scrollIdles++;
|
|
110
|
+
metrics.totalScrollMs += durationMs;
|
|
111
|
+
metrics.maxScrollMs = Math.max(metrics.maxScrollMs, durationMs);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (normalized.active != null && Number.isFinite(normalized.active)) metrics.maxActiveRenders = Math.max(metrics.maxActiveRenders, Math.max(0, normalized.active));
|
|
116
|
+
if (normalized.waiting != null && Number.isFinite(normalized.waiting)) metrics.maxWaitingRenders = Math.max(metrics.maxWaitingRenders, Math.max(0, normalized.waiting));
|
|
117
|
+
if (normalized.cacheEntries != null && Number.isFinite(normalized.cacheEntries)) metrics.maxCacheEntries = Math.max(metrics.maxCacheEntries, Math.max(0, normalized.cacheEntries));
|
|
118
|
+
if (normalized.cacheBytes != null && Number.isFinite(normalized.cacheBytes)) metrics.maxCacheBytes = Math.max(metrics.maxCacheBytes, Math.max(0, normalized.cacheBytes));
|
|
119
|
+
for (const subscriber of subscribers) try {
|
|
120
|
+
subscriber(normalized);
|
|
121
|
+
} catch {}
|
|
122
|
+
}
|
|
123
|
+
|
|
10
124
|
//#endregion
|
|
11
125
|
//#region src/vue/context.ts
|
|
12
126
|
const TerminalContextKey = injectionKey("TerminalContext");
|
|
@@ -17,7 +131,95 @@ const RenderPlaneContextKey = injectionKey("RenderPlane");
|
|
|
17
131
|
const ImeAnchorContextKey = injectionKey("ImeAnchor");
|
|
18
132
|
const TInputPluginsContextKey = injectionKey("TInputPlugins");
|
|
19
133
|
const TPathPickerProviderContextKey = injectionKey("TPathPickerProvider");
|
|
134
|
+
const TerminalGraphicsActivityKey = injectionKey("TerminalGraphicsActivity");
|
|
20
135
|
const DialogContextKey = injectionKey("DialogContext");
|
|
136
|
+
function createTerminalGraphicsActivity(options = {}) {
|
|
137
|
+
let scrollIdleMs = normalizeTerminalGraphicsScrollIdleMs(options.scrollIdleMs);
|
|
138
|
+
const traceId = options.traceId ?? "TerminalGraphicsActivity";
|
|
139
|
+
const scrolling = ref(false);
|
|
140
|
+
const version = ref(0);
|
|
141
|
+
let timer = null;
|
|
142
|
+
let scrollStartedAt = 0;
|
|
143
|
+
function bump() {
|
|
144
|
+
version.value++;
|
|
145
|
+
}
|
|
146
|
+
function clearTimer() {
|
|
147
|
+
if (!timer) return;
|
|
148
|
+
clearTimeout(timer);
|
|
149
|
+
timer = null;
|
|
150
|
+
}
|
|
151
|
+
function traceScroll(type, durationMs) {
|
|
152
|
+
if (options.trace !== true) return;
|
|
153
|
+
recordTerminalGraphicTrace({
|
|
154
|
+
type,
|
|
155
|
+
id: traceId,
|
|
156
|
+
key: traceId,
|
|
157
|
+
durationMs
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
function finishScroll() {
|
|
161
|
+
if (!scrolling.value) return;
|
|
162
|
+
const endedAt = nowTerminalGraphicTraceTime();
|
|
163
|
+
const durationMs = scrollStartedAt > 0 ? endedAt - scrollStartedAt : void 0;
|
|
164
|
+
scrolling.value = false;
|
|
165
|
+
scrollStartedAt = 0;
|
|
166
|
+
traceScroll("scroll-idle", durationMs);
|
|
167
|
+
bump();
|
|
168
|
+
}
|
|
169
|
+
function markScroll() {
|
|
170
|
+
const started = !scrolling.value;
|
|
171
|
+
if (started) {
|
|
172
|
+
scrolling.value = true;
|
|
173
|
+
scrollStartedAt = nowTerminalGraphicTraceTime();
|
|
174
|
+
traceScroll("scroll-start");
|
|
175
|
+
bump();
|
|
176
|
+
} else traceScroll("scroll-mark");
|
|
177
|
+
clearTimer();
|
|
178
|
+
timer = setTimeout(() => {
|
|
179
|
+
timer = null;
|
|
180
|
+
finishScroll();
|
|
181
|
+
}, scrollIdleMs);
|
|
182
|
+
}
|
|
183
|
+
function setScrollIdleMs(value) {
|
|
184
|
+
scrollIdleMs = normalizeTerminalGraphicsScrollIdleMs(value);
|
|
185
|
+
if (!scrolling.value) return;
|
|
186
|
+
clearTimer();
|
|
187
|
+
timer = setTimeout(() => {
|
|
188
|
+
timer = null;
|
|
189
|
+
finishScroll();
|
|
190
|
+
}, scrollIdleMs);
|
|
191
|
+
}
|
|
192
|
+
function dispose() {
|
|
193
|
+
clearTimer();
|
|
194
|
+
finishScroll();
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
scrolling: readonly(scrolling),
|
|
198
|
+
version: readonly(version),
|
|
199
|
+
markScroll,
|
|
200
|
+
setScrollIdleMs,
|
|
201
|
+
dispose
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function createCombinedTerminalGraphicsActivity(parent, own) {
|
|
205
|
+
if (!parent) return own;
|
|
206
|
+
return {
|
|
207
|
+
scrolling: computed(() => parent.scrolling.value || own.scrolling.value),
|
|
208
|
+
version: computed(() => parent.version.value + own.version.value),
|
|
209
|
+
markScroll: own.markScroll,
|
|
210
|
+
setScrollIdleMs: own.setScrollIdleMs,
|
|
211
|
+
dispose: own.dispose
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function positiveFiniteInt(value, fallback) {
|
|
215
|
+
const n = Number(value);
|
|
216
|
+
if (!Number.isFinite(n)) return fallback;
|
|
217
|
+
const int = Math.floor(n);
|
|
218
|
+
return int > 0 ? int : fallback;
|
|
219
|
+
}
|
|
220
|
+
function normalizeTerminalGraphicsScrollIdleMs(value) {
|
|
221
|
+
return Math.max(16, positiveFiniteInt(value, 96));
|
|
222
|
+
}
|
|
21
223
|
|
|
22
224
|
//#endregion
|
|
23
225
|
//#region src/vue/render/context.ts
|
|
@@ -374,8 +576,10 @@ function wrapByCells(text, width, provider = currentTextWidthProvider()) {
|
|
|
374
576
|
const useCache = canUseDefaultTextCache(provider);
|
|
375
577
|
const bucket = useCache ? getWrapBucket(width) : null;
|
|
376
578
|
if (text && hasAsciiFastPath(provider) && isAscii(text)) {
|
|
377
|
-
|
|
378
|
-
|
|
579
|
+
if (bucket) {
|
|
580
|
+
const cached = bucket.get(text);
|
|
581
|
+
if (cached) return cached;
|
|
582
|
+
}
|
|
379
583
|
const out$1 = [];
|
|
380
584
|
for (const rawLine of text.replace(/\r/g, "").split("\n")) {
|
|
381
585
|
if (rawLine.length === 0) {
|
|
@@ -390,8 +594,10 @@ function wrapByCells(text, width, provider = currentTextWidthProvider()) {
|
|
|
390
594
|
}
|
|
391
595
|
return out$1;
|
|
392
596
|
}
|
|
393
|
-
|
|
394
|
-
|
|
597
|
+
if (bucket) {
|
|
598
|
+
const cached = bucket.get(text);
|
|
599
|
+
if (cached) return cached;
|
|
600
|
+
}
|
|
395
601
|
const out = [];
|
|
396
602
|
for (const rawLine of text.replace(/\r/g, "").split("\n")) {
|
|
397
603
|
if (rawLine.length === 0) {
|
|
@@ -512,47 +718,82 @@ function requestBatchedInvalidate(scheduler, plane, priority) {
|
|
|
512
718
|
});
|
|
513
719
|
});
|
|
514
720
|
}
|
|
721
|
+
function sameRenderRect(a, b) {
|
|
722
|
+
if (a === b) return true;
|
|
723
|
+
if (!a || !b) return false;
|
|
724
|
+
return a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;
|
|
725
|
+
}
|
|
726
|
+
function sameDeps(a, b) {
|
|
727
|
+
if (Object.is(a, b)) return true;
|
|
728
|
+
if (!Array.isArray(a) || !Array.isArray(b)) return false;
|
|
729
|
+
if (a.length !== b.length) return false;
|
|
730
|
+
for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false;
|
|
731
|
+
return true;
|
|
732
|
+
}
|
|
515
733
|
function useRenderNode(getOptions) {
|
|
516
734
|
const { scheduler, render, widthProvider } = useTerminal();
|
|
517
735
|
const parentStack = useRenderStack();
|
|
518
736
|
const plane = inject(RenderPlaneContextKey, ref("default"));
|
|
519
737
|
const id = ref(null);
|
|
520
738
|
const lastPlane = ref(plane.value);
|
|
739
|
+
let lastStack = null;
|
|
740
|
+
let lastZIndex = 0;
|
|
741
|
+
let lastHasRect = false;
|
|
742
|
+
let lastRect = null;
|
|
743
|
+
let lastDeps;
|
|
744
|
+
let lastHasDeps = false;
|
|
521
745
|
const options = computed(() => withTextWidthProvider(widthProvider, getOptions));
|
|
522
746
|
const stop = watchEffect(() => {
|
|
523
747
|
const opt = options.value;
|
|
524
748
|
opt.deps;
|
|
525
749
|
const stack = opt.stack ?? parentStack.value;
|
|
526
750
|
const nextPlane = plane.value;
|
|
751
|
+
const hasRect = Object.prototype.hasOwnProperty.call(opt, "rect");
|
|
752
|
+
const nextRect = hasRect ? opt.rect ?? null : null;
|
|
753
|
+
const nextZIndex = opt.zIndex ?? 0;
|
|
754
|
+
const hasDeps = Object.prototype.hasOwnProperty.call(opt, "deps");
|
|
527
755
|
if (!stack) return;
|
|
528
756
|
if (!id.value) {
|
|
529
757
|
const node = render.register({
|
|
530
758
|
stack,
|
|
531
|
-
zIndex:
|
|
532
|
-
rect:
|
|
759
|
+
zIndex: nextZIndex,
|
|
760
|
+
rect: hasRect ? nextRect : void 0,
|
|
533
761
|
plane: nextPlane,
|
|
534
762
|
paint: opt.paint
|
|
535
763
|
});
|
|
536
764
|
id.value = node.id;
|
|
537
765
|
lastPlane.value = nextPlane;
|
|
766
|
+
lastStack = stack;
|
|
767
|
+
lastZIndex = nextZIndex;
|
|
768
|
+
lastHasRect = hasRect;
|
|
769
|
+
lastRect = nextRect;
|
|
770
|
+
lastHasDeps = hasDeps;
|
|
771
|
+
lastDeps = opt.deps;
|
|
538
772
|
requestBatchedInvalidate(scheduler, nextPlane, opt.priority ?? "normal");
|
|
539
773
|
return;
|
|
540
774
|
}
|
|
541
775
|
const prevPlane = lastPlane.value;
|
|
776
|
+
if (hasDeps && lastHasDeps && !opt.dirtyRowsHint?.length && lastStack === stack && lastZIndex === nextZIndex && prevPlane === nextPlane && lastHasRect === hasRect && (!hasRect || sameRenderRect(lastRect, nextRect)) && sameDeps(lastDeps, opt.deps)) return;
|
|
542
777
|
const updatePayload = {
|
|
543
778
|
stack,
|
|
544
|
-
zIndex:
|
|
779
|
+
zIndex: nextZIndex,
|
|
545
780
|
dirtyRowsHint: opt.dirtyRowsHint,
|
|
546
781
|
plane: nextPlane,
|
|
547
782
|
paint: opt.paint
|
|
548
783
|
};
|
|
549
|
-
if (
|
|
784
|
+
if (hasRect) updatePayload.rect = nextRect;
|
|
550
785
|
render.update(id.value, updatePayload);
|
|
551
786
|
lastPlane.value = nextPlane;
|
|
787
|
+
lastStack = stack;
|
|
788
|
+
lastZIndex = nextZIndex;
|
|
789
|
+
lastHasRect = hasRect;
|
|
790
|
+
lastRect = nextRect;
|
|
791
|
+
lastHasDeps = hasDeps;
|
|
792
|
+
lastDeps = opt.deps;
|
|
552
793
|
const priority = opt.priority ?? "normal";
|
|
553
794
|
requestBatchedInvalidate(scheduler, prevPlane, priority);
|
|
554
795
|
if (prevPlane !== nextPlane) requestBatchedInvalidate(scheduler, nextPlane, priority);
|
|
555
|
-
});
|
|
796
|
+
}, { flush: "sync" });
|
|
556
797
|
onBeforeUnmount(() => {
|
|
557
798
|
stop();
|
|
558
799
|
if (id.value) {
|
|
@@ -716,109 +957,4 @@ function normalizeCellRect(rect) {
|
|
|
716
957
|
}
|
|
717
958
|
|
|
718
959
|
//#endregion
|
|
719
|
-
|
|
720
|
-
const LINE_UNIT_THRESHOLD = 3;
|
|
721
|
-
const PIXELS_PER_LINE = 16;
|
|
722
|
-
const ACCEL_WINDOW_MS = 120;
|
|
723
|
-
const MAX_ACCEL = 26;
|
|
724
|
-
const EDGE_BOUNCE_MS = 120;
|
|
725
|
-
function clamp(n, min, max) {
|
|
726
|
-
return Math.max(min, Math.min(max, n));
|
|
727
|
-
}
|
|
728
|
-
function isLineUnitDelta(deltaY, mode = "auto") {
|
|
729
|
-
if (mode === "line") return true;
|
|
730
|
-
if (mode === "pixel") return false;
|
|
731
|
-
const abs = Math.abs(deltaY);
|
|
732
|
-
return abs > 0 && abs <= LINE_UNIT_THRESHOLD && Number.isInteger(deltaY);
|
|
733
|
-
}
|
|
734
|
-
function normalizeDelta(deltaY, mode = "auto") {
|
|
735
|
-
if (mode === "line") return deltaY;
|
|
736
|
-
if (mode === "pixel") return deltaY / PIXELS_PER_LINE;
|
|
737
|
-
const abs = Math.abs(deltaY);
|
|
738
|
-
if (abs <= LINE_UNIT_THRESHOLD && Number.isInteger(deltaY)) return deltaY;
|
|
739
|
-
return deltaY / PIXELS_PER_LINE;
|
|
740
|
-
}
|
|
741
|
-
function accelFactor(now, lastAt, maxAccel = MAX_ACCEL) {
|
|
742
|
-
const dt = now - lastAt;
|
|
743
|
-
if (!Number.isFinite(dt) || dt <= 0 || dt > ACCEL_WINDOW_MS) return 1;
|
|
744
|
-
const t = 1 - dt / ACCEL_WINDOW_MS;
|
|
745
|
-
return 1 + t * (maxAccel - 1);
|
|
746
|
-
}
|
|
747
|
-
function createWheelScrollState() {
|
|
748
|
-
return {
|
|
749
|
-
accumulator: 0,
|
|
750
|
-
lastAt: 0,
|
|
751
|
-
lastEdgeDir: 0,
|
|
752
|
-
lastEdgeAt: 0
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
function resetWheelScrollState(state) {
|
|
756
|
-
state.accumulator = 0;
|
|
757
|
-
state.lastAt = 0;
|
|
758
|
-
state.lastEdgeDir = 0;
|
|
759
|
-
state.lastEdgeAt = 0;
|
|
760
|
-
}
|
|
761
|
-
function applyWheelScroll(state, deltaY, scrollTop, maxTop, now = Date.now(), deltaMode = "auto", options = {}) {
|
|
762
|
-
if (!Number.isFinite(deltaY) || deltaY === 0 || maxTop <= 0) {
|
|
763
|
-
if (maxTop <= 0) {
|
|
764
|
-
state.accumulator = 0;
|
|
765
|
-
state.lastEdgeDir = 0;
|
|
766
|
-
state.lastEdgeAt = 0;
|
|
767
|
-
}
|
|
768
|
-
return {
|
|
769
|
-
nextTop: scrollTop,
|
|
770
|
-
dir: 0,
|
|
771
|
-
lines: 0
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
const lineUnits = isLineUnitDelta(deltaY, deltaMode);
|
|
775
|
-
const normalizedDelta = normalizeDelta(deltaY, deltaMode);
|
|
776
|
-
const accel = options.disableAcceleration ? 1 : lineUnits ? 1 : state.lastAt ? accelFactor(now, state.lastAt) : 1;
|
|
777
|
-
state.lastAt = now;
|
|
778
|
-
state.accumulator += normalizedDelta * accel;
|
|
779
|
-
const lines = Math.trunc(state.accumulator);
|
|
780
|
-
if (lines === 0) return {
|
|
781
|
-
nextTop: scrollTop,
|
|
782
|
-
dir: 0,
|
|
783
|
-
lines: 0
|
|
784
|
-
};
|
|
785
|
-
state.accumulator -= lines;
|
|
786
|
-
const dir = lines > 0 ? 1 : -1;
|
|
787
|
-
const atTop = scrollTop <= 0;
|
|
788
|
-
const atBottom = scrollTop >= maxTop;
|
|
789
|
-
if (dir < 0 && atTop || dir > 0 && atBottom) {
|
|
790
|
-
state.lastEdgeDir = dir;
|
|
791
|
-
state.lastEdgeAt = now;
|
|
792
|
-
state.accumulator = 0;
|
|
793
|
-
return {
|
|
794
|
-
nextTop: scrollTop,
|
|
795
|
-
dir: 0,
|
|
796
|
-
lines: 0
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
if (state.lastEdgeDir !== 0 && now - state.lastEdgeAt < EDGE_BOUNCE_MS && dir === -state.lastEdgeDir && (atTop || atBottom)) return {
|
|
800
|
-
nextTop: scrollTop,
|
|
801
|
-
dir: 0,
|
|
802
|
-
lines: 0
|
|
803
|
-
};
|
|
804
|
-
const unclamped = scrollTop + lines;
|
|
805
|
-
const nextTop = clamp(unclamped, 0, maxTop);
|
|
806
|
-
if (nextTop === scrollTop) {
|
|
807
|
-
state.accumulator = 0;
|
|
808
|
-
return {
|
|
809
|
-
nextTop: scrollTop,
|
|
810
|
-
dir: 0,
|
|
811
|
-
lines: 0
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
if (nextTop !== unclamped) state.accumulator = 0;
|
|
815
|
-
state.lastEdgeDir = 0;
|
|
816
|
-
return {
|
|
817
|
-
nextTop,
|
|
818
|
-
dir: nextTop > scrollTop ? 1 : -1,
|
|
819
|
-
lines: nextTop - scrollTop
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
//#endregion
|
|
824
|
-
export { DialogContextKey, EventZIndexContextKey, ImeAnchorContextKey, LayoutContextKey, RenderPlaneContextKey, RenderStackKey, TInputPluginsContextKey, TPathPickerProviderContextKey, TerminalContextKey, VisibilityContextKey, applyWheelScroll, clearTextCaches, createWheelScrollState, currentTextWidthProvider, forEachTextCellSegment, formatInlineCellLine, graphemeRangeAt, hasTextWidthAsciiFastPath, injectionKey, intersectRect, normalizeCellRect, padEndByCells as padEndByCells$1, repeatChar, resetWheelScrollState, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, textCellWidth as textCellWidth$1, translateRect, useLayout, useRenderNode, useRenderStack, useTerminal, useTerminalNode, useVisibility, withTextRenderPass, withTextWidthProvider, wrapByCells };
|
|
960
|
+
export { DialogContextKey, EventZIndexContextKey, ImeAnchorContextKey, LayoutContextKey, RenderPlaneContextKey, RenderStackKey, TInputPluginsContextKey, TPathPickerProviderContextKey, TerminalContextKey, TerminalGraphicsActivityKey, VisibilityContextKey, clearTextCaches, createCombinedTerminalGraphicsActivity, createTerminalGraphicsActivity, currentTextWidthProvider, forEachTextCellSegment, formatInlineCellLine, graphemeRangeAt, hasTextWidthAsciiFastPath, injectionKey, intersectRect, normalizeCellRect, nowTerminalGraphicTraceTime, padEndByCells as padEndByCells$1, recordTerminalGraphicTrace, repeatChar, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, textCellWidth as textCellWidth$1, translateRect, useLayout, useRenderNode, useRenderStack, useTerminal, useTerminalNode, useVisibility, withTextRenderPass, withTextWidthProvider, wrapByCells };
|
|
@@ -7,6 +7,10 @@ export interface StdoutRendererMetrics {
|
|
|
7
7
|
writeMode: StdoutRendererWriteMode;
|
|
8
8
|
fps: number;
|
|
9
9
|
bytesPerSec: number;
|
|
10
|
+
terminalGraphicsDraws: number;
|
|
11
|
+
terminalGraphicsClears: number;
|
|
12
|
+
terminalGraphicsBytes: number;
|
|
13
|
+
terminalGraphicsActive: number;
|
|
10
14
|
}
|
|
11
15
|
export declare function getStdoutRendererMetrics(): StdoutRendererMetrics;
|
|
12
16
|
export declare function recordStdoutFrame(info: Readonly<{
|
|
@@ -16,3 +20,9 @@ export declare function recordStdoutFrame(info: Readonly<{
|
|
|
16
20
|
writeEmaMs: number;
|
|
17
21
|
writeMode: StdoutRendererWriteMode;
|
|
18
22
|
}>): void;
|
|
23
|
+
export declare function recordStdoutTerminalGraphics(info: Readonly<{
|
|
24
|
+
draws?: number;
|
|
25
|
+
clears?: number;
|
|
26
|
+
bytes?: number;
|
|
27
|
+
active: number;
|
|
28
|
+
}>): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Terminal } from "../../core/types.js";
|
|
2
2
|
import type { RendererCapabilities } from "../capabilities.js";
|
|
3
|
+
import type { TerminalGraphicsCapabilities, TerminalGraphicsDetectionInput } from "../terminal-graphics.js";
|
|
3
4
|
import type { ThemePalette } from "../../core/ansi-palette.js";
|
|
4
5
|
export type CliOutput = Readonly<{
|
|
5
6
|
write: (chunk: string) => unknown;
|
|
@@ -12,6 +13,7 @@ export type CliOutput = Readonly<{
|
|
|
12
13
|
}>;
|
|
13
14
|
export type StdoutRenderer = Readonly<{
|
|
14
15
|
capabilities: RendererCapabilities;
|
|
16
|
+
graphicsCapabilities?: TerminalGraphicsCapabilities;
|
|
15
17
|
render: () => void;
|
|
16
18
|
dispose: () => void;
|
|
17
19
|
/** Move terminal cursor to specified cell position for IME input */
|
|
@@ -83,6 +85,7 @@ export type StdoutRendererOptions = Readonly<{
|
|
|
83
85
|
} | null;
|
|
84
86
|
/** Use DEC 2026 synchronized output mode. */
|
|
85
87
|
useSyncOutput?: boolean;
|
|
88
|
+
terminalGraphics?: false | TerminalGraphicsCapabilities | TerminalGraphicsDetectionInput;
|
|
86
89
|
allowFileUrls?: boolean;
|
|
87
90
|
profileFileWriter?: {
|
|
88
91
|
appendFileSync?: (path: string, data: string) => void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type TerminalGraphicRenderQueueMetric = Readonly<{
|
|
2
|
+
type: "cache-hit";
|
|
3
|
+
key: string;
|
|
4
|
+
}> | Readonly<{
|
|
5
|
+
type: "cache-store";
|
|
6
|
+
key: string;
|
|
7
|
+
bytes: number;
|
|
8
|
+
}> | Readonly<{
|
|
9
|
+
type: "evict";
|
|
10
|
+
key: string;
|
|
11
|
+
bytes: number;
|
|
12
|
+
}> | Readonly<{
|
|
13
|
+
type: "queue-wait";
|
|
14
|
+
key: string;
|
|
15
|
+
waitMs: number;
|
|
16
|
+
}> | Readonly<{
|
|
17
|
+
type: "render-abort";
|
|
18
|
+
key: string;
|
|
19
|
+
}>;
|
|
20
|
+
export type TerminalGraphicRenderQueueOptions = Readonly<{
|
|
21
|
+
maxConcurrency?: number;
|
|
22
|
+
maxEntries?: number;
|
|
23
|
+
maxBytes?: number;
|
|
24
|
+
ttlMs?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Share in-flight renders for equal cache keys.
|
|
27
|
+
*
|
|
28
|
+
* Keep this disabled when render work observes a caller AbortSignal. This is
|
|
29
|
+
* the safe default for viewport-bound graphics in virtual scrollers: an
|
|
30
|
+
* offscreen row may abort while another still-visible row with the same cache
|
|
31
|
+
* key is still valid. Duplicate queued renders are still cheap because each
|
|
32
|
+
* task re-checks the cache after acquiring a concurrency slot, so a render
|
|
33
|
+
* completed by an earlier row is reused instead of rendering again.
|
|
34
|
+
*/
|
|
35
|
+
dedupeInflight?: boolean;
|
|
36
|
+
onMetric?: (metric: TerminalGraphicRenderQueueMetric) => void;
|
|
37
|
+
}>;
|
|
38
|
+
export type TerminalGraphicRenderQueue = Readonly<{
|
|
39
|
+
cached: <T>(key: string, signal: AbortSignal | undefined, render: () => Promise<T>, estimateBytes?: (value: T) => number, options?: Readonly<{
|
|
40
|
+
dedupeInflight?: boolean;
|
|
41
|
+
}>) => Promise<T>;
|
|
42
|
+
clear: () => void;
|
|
43
|
+
stats: () => Readonly<{
|
|
44
|
+
active: number;
|
|
45
|
+
waiting: number;
|
|
46
|
+
cacheEntries: number;
|
|
47
|
+
cacheBytes: number;
|
|
48
|
+
}>;
|
|
49
|
+
}>;
|
|
50
|
+
export declare function createTerminalGraphicRenderQueue(options?: TerminalGraphicRenderQueueOptions): TerminalGraphicRenderQueue;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { TerminalGraphicsProtocol } from "./terminal-graphics.js";
|
|
2
|
+
export type TerminalGraphicTraceEventType = "request" | "skip-hidden" | "skip-scrolling" | "cache-hit" | "cache-miss" | "cache-store" | "renderer-start" | "renderer-end" | "renderer-abort" | "renderer-error" | "validate-end" | "queue" | "queue-depth" | "queue-wait" | "queue-dedupe" | "clear" | "scroll-start" | "scroll-mark" | "scroll-idle";
|
|
3
|
+
export type TerminalGraphicTraceEvent = Readonly<{
|
|
4
|
+
type: TerminalGraphicTraceEventType;
|
|
5
|
+
id: string;
|
|
6
|
+
key?: string;
|
|
7
|
+
protocol?: TerminalGraphicsProtocol;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
durationMs?: number;
|
|
10
|
+
bytes?: number;
|
|
11
|
+
reason?: string;
|
|
12
|
+
error?: string;
|
|
13
|
+
active?: number;
|
|
14
|
+
waiting?: number;
|
|
15
|
+
cacheEntries?: number;
|
|
16
|
+
cacheBytes?: number;
|
|
17
|
+
}>;
|
|
18
|
+
export type TerminalGraphicTraceMetrics = Readonly<{
|
|
19
|
+
requests: number;
|
|
20
|
+
skippedHidden: number;
|
|
21
|
+
skippedScrolling: number;
|
|
22
|
+
cacheHits: number;
|
|
23
|
+
cacheMisses: number;
|
|
24
|
+
cacheStores: number;
|
|
25
|
+
rendererRuns: number;
|
|
26
|
+
rendererAborts: number;
|
|
27
|
+
rendererErrors: number;
|
|
28
|
+
queued: number;
|
|
29
|
+
queueWaits: number;
|
|
30
|
+
queueDeduped: number;
|
|
31
|
+
cleared: number;
|
|
32
|
+
bytesQueued: number;
|
|
33
|
+
totalRendererMs: number;
|
|
34
|
+
totalValidateMs: number;
|
|
35
|
+
totalQueueWaitMs: number;
|
|
36
|
+
maxQueueWaitMs: number;
|
|
37
|
+
maxActiveRenders: number;
|
|
38
|
+
maxWaitingRenders: number;
|
|
39
|
+
maxCacheEntries: number;
|
|
40
|
+
maxCacheBytes: number;
|
|
41
|
+
scrollStarts: number;
|
|
42
|
+
scrollMarks: number;
|
|
43
|
+
scrollIdles: number;
|
|
44
|
+
totalScrollMs: number;
|
|
45
|
+
maxScrollMs: number;
|
|
46
|
+
}>;
|
|
47
|
+
export declare function nowTerminalGraphicTraceTime(): number;
|
|
48
|
+
export declare function recordTerminalGraphicTrace(event: Omit<TerminalGraphicTraceEvent, "timestamp"> & {
|
|
49
|
+
timestamp?: number;
|
|
50
|
+
}): void;
|
|
51
|
+
export declare function getTerminalGraphicTraceMetrics(): TerminalGraphicTraceMetrics;
|
|
52
|
+
export declare function resetTerminalGraphicTraceMetrics(): void;
|
|
53
|
+
export declare function subscribeTerminalGraphicTrace(listener: (event: TerminalGraphicTraceEvent) => void): () => void;
|