@simon_he/vue-tui 1.0.1 → 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 +139 -46
- package/dist/TMermaidText-frVr8Ysb.js +885 -0
- package/dist/{TSelect-HzILuti9.js → TSelect-tJ87rKPM.js} +59 -242
- package/dist/{TTree-ChOot2Bh.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 +5470 -6176
- package/dist/cli.d.cts +6 -2
- package/dist/cli.d.ts +6 -2
- package/dist/cli.js +3747 -350
- package/dist/core/buffer/buffer.d.ts +2 -2
- 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/types.d.ts +0 -4
- package/dist/core.cjs +851 -1462
- 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-BqGijQID.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-C2oiWFJU.js → hyperlink-_1FAj7Wq.js} +455 -19
- package/dist/index.cjs +5025 -10332
- 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/index.d.ts +1 -1
- package/dist/renderer/cli/stdout-metrics.d.ts +10 -0
- package/dist/renderer/cli/stdout-renderer.d.ts +53 -7
- 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 +7215 -12430
- 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 +141 -18
- 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
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { sanitizeTerminalHref } from "./hyperlink-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { terminalSelectionRowSpans, terminalSelectionVisibleRowSpans } from "./terminal-selection-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { applyAnsiSgrStyle, parseAnsiSgr, sanitizeTerminalHref } from "./hyperlink-_1FAj7Wq.js";
|
|
2
|
+
import { EventZIndexContextKey, LayoutContextKey, RenderPlaneContextKey, RenderStackKey, TerminalGraphicsActivityKey, createCombinedTerminalGraphicsActivity, createTerminalGraphicsActivity, forEachTextCellSegment, formatInlineCellLine, intersectRect, normalizeCellRect, nowTerminalGraphicTraceTime, padEndByCells$1 as padEndByCells, recordTerminalGraphicTrace, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, textCellWidth$1 as textCellWidth, translateRect, useLayout, useRenderNode, useRenderStack, useTerminal, useTerminalNode, useVisibility, withTextWidthProvider, wrapByCells } from "./rect-DUpeDfBg.js";
|
|
3
|
+
import { TView, TuiThemeContextKey, createFrameMailbox, defaultActiveStyle, linkifyTextSegments, tuiDefaultTheme } from "./linkify-D68T7rdW.js";
|
|
4
|
+
import { framePerfNow } from "./frame-perf-CHpWhbC4.js";
|
|
5
|
+
import { terminalSelectionRowSpans, terminalSelectionVisibleRowSpans } from "./terminal-selection-4W1SJj4c.js";
|
|
6
|
+
import { applyWheelScroll, createWheelScrollState, resetWheelScrollState } from "./wheel-scroll-DASkEZr-.js";
|
|
7
|
+
import { canDrawTerminalGraphicRect, createKittyDeleteGraphicsSequence, createKittyPlacementSequence, getTerminalGraphicsOutput, getTerminalGraphicsOutputVersion, isSafeTerminalGraphicsSequence, isTerminalGraphicsProtocol, normalizeTerminalGraphicSize, sanitizeTerminalFallbackText, stableTerminalGraphicNumericId, subscribeTerminalGraphicsOutput } from "./terminal-graphics-Bbe83wSr.js";
|
|
8
|
+
import { computed, defineComponent, getCurrentInstance, h, inject, markRaw, onBeforeUnmount, provide, ref, shallowReactive, shallowRef, watch, watchEffect } from "vue";
|
|
8
9
|
|
|
9
10
|
//#region src/vue/utils/row-scroll.ts
|
|
10
11
|
function exposedRowsForDelta(y0, h$1, delta) {
|
|
@@ -143,6 +144,10 @@ const TVirtualList = defineComponent({
|
|
|
143
144
|
rowScrollMode: {
|
|
144
145
|
type: String,
|
|
145
146
|
default: "off"
|
|
147
|
+
},
|
|
148
|
+
terminalGraphicScrollIdleMs: {
|
|
149
|
+
type: Number,
|
|
150
|
+
default: 96
|
|
146
151
|
}
|
|
147
152
|
},
|
|
148
153
|
emits: [
|
|
@@ -165,6 +170,13 @@ const TVirtualList = defineComponent({
|
|
|
165
170
|
const eventZ = computed(() => (parentEventZ.value ?? 0) + (props.zIndex ?? 0));
|
|
166
171
|
const virtualListInstanceId = ++virtualListInstanceSeq;
|
|
167
172
|
const wheelTaskId = `TVirtualList:${virtualListInstanceId}:wheel`;
|
|
173
|
+
const parentTerminalGraphicsActivity = inject(TerminalGraphicsActivityKey, null);
|
|
174
|
+
const terminalGraphicsActivity = createTerminalGraphicsActivity({
|
|
175
|
+
scrollIdleMs: props.terminalGraphicScrollIdleMs,
|
|
176
|
+
traceId: `TVirtualList:${virtualListInstanceId}:terminal-graphics`
|
|
177
|
+
});
|
|
178
|
+
provide(TerminalGraphicsActivityKey, createCombinedTerminalGraphicsActivity(parentTerminalGraphicsActivity, terminalGraphicsActivity));
|
|
179
|
+
watch(() => props.terminalGraphicScrollIdleMs, (value) => terminalGraphicsActivity.setScrollIdleMs(value));
|
|
168
180
|
const focused = ref(false);
|
|
169
181
|
const active = ref(props.modelValue);
|
|
170
182
|
const scrollTop = ref(0);
|
|
@@ -381,6 +393,7 @@ const TVirtualList = defineComponent({
|
|
|
381
393
|
const changed = scrollTop.value !== nextTop;
|
|
382
394
|
scrollTop.value = nextTop;
|
|
383
395
|
if (!wasInitialized || !changed) return;
|
|
396
|
+
terminalGraphicsActivity.markScroll();
|
|
384
397
|
const remap = pendingSelectionScrollFocusRemap;
|
|
385
398
|
pendingSelectionScrollFocusRemap = false;
|
|
386
399
|
selection.refresh(remap ? { remapFocus: true } : void 0);
|
|
@@ -481,6 +494,7 @@ const TVirtualList = defineComponent({
|
|
|
481
494
|
if (nextTop === scrollTop.value) return false;
|
|
482
495
|
if (pendingSelectionScrollFocusRemap) return false;
|
|
483
496
|
pendingSelectionScrollFocusRemap = true;
|
|
497
|
+
terminalGraphicsActivity.markScroll();
|
|
484
498
|
emit("update:scrollTop", nextTop);
|
|
485
499
|
emit("scroll", nextTop);
|
|
486
500
|
return true;
|
|
@@ -621,6 +635,7 @@ const TVirtualList = defineComponent({
|
|
|
621
635
|
pendingWheelTop = null;
|
|
622
636
|
resetWheelScrollState(wheelState);
|
|
623
637
|
wheelMailbox.dispose();
|
|
638
|
+
terminalGraphicsActivity.dispose();
|
|
624
639
|
});
|
|
625
640
|
function viewportRows() {
|
|
626
641
|
const r = normalizedRect();
|
|
@@ -668,6 +683,7 @@ const TVirtualList = defineComponent({
|
|
|
668
683
|
controlled
|
|
669
684
|
};
|
|
670
685
|
if (controlled) {
|
|
686
|
+
terminalGraphicsActivity.markScroll();
|
|
671
687
|
if (options?.emitUpdate ?? true) emit("update:scrollTop", clampedTop);
|
|
672
688
|
if (options?.emitScroll) emit("scroll", clampedTop);
|
|
673
689
|
return {
|
|
@@ -677,6 +693,7 @@ const TVirtualList = defineComponent({
|
|
|
677
693
|
controlled
|
|
678
694
|
};
|
|
679
695
|
}
|
|
696
|
+
terminalGraphicsActivity.markScroll();
|
|
680
697
|
scrollTop.value = clampedTop;
|
|
681
698
|
if (options?.emitUpdate) emit("update:scrollTop", clampedTop);
|
|
682
699
|
const canUseTerminalRowScroll = rendererCapabilities.value.scrollOperations && rendererCapabilities.value.domRows !== true;
|
|
@@ -765,6 +782,1199 @@ const TVirtualList = defineComponent({
|
|
|
765
782
|
}
|
|
766
783
|
});
|
|
767
784
|
|
|
785
|
+
//#endregion
|
|
786
|
+
//#region src/vue/components/TAgentTerminalGraphic.ts
|
|
787
|
+
const NO_GRAPHICS_CAPABILITIES = Object.freeze({
|
|
788
|
+
supported: false,
|
|
789
|
+
kitty: false,
|
|
790
|
+
iterm2: false,
|
|
791
|
+
sixel: false,
|
|
792
|
+
preferredProtocol: null,
|
|
793
|
+
protocol: "unicode",
|
|
794
|
+
candidates: [],
|
|
795
|
+
stdoutIsTTY: false,
|
|
796
|
+
insideTmux: false,
|
|
797
|
+
insideScreen: false,
|
|
798
|
+
insideZellij: false,
|
|
799
|
+
multiplexer: null,
|
|
800
|
+
passthrough: false,
|
|
801
|
+
forced: false,
|
|
802
|
+
reason: "no-terminal-graphics-output"
|
|
803
|
+
});
|
|
804
|
+
function splitTextOutput(value) {
|
|
805
|
+
const normalized = sanitizeTextBlock(sanitizeTerminalFallbackText(value).replace(/\r\n?/g, "\n"));
|
|
806
|
+
const lines = normalized.split("\n");
|
|
807
|
+
return lines.length ? lines : [""];
|
|
808
|
+
}
|
|
809
|
+
function hasVisibleOutput(value) {
|
|
810
|
+
return value.some((line) => line.trim().length > 0);
|
|
811
|
+
}
|
|
812
|
+
function errorMessage(error) {
|
|
813
|
+
return error instanceof Error ? error.message : String(error);
|
|
814
|
+
}
|
|
815
|
+
function positiveInt(value) {
|
|
816
|
+
const n = Math.floor(Number(value));
|
|
817
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
818
|
+
}
|
|
819
|
+
function finiteInt(value) {
|
|
820
|
+
const n = Math.floor(Number(value));
|
|
821
|
+
return Number.isFinite(n) ? n : void 0;
|
|
822
|
+
}
|
|
823
|
+
function clampNumber(value, min, max) {
|
|
824
|
+
return Math.max(min, Math.min(max, value));
|
|
825
|
+
}
|
|
826
|
+
function rectArea(rect) {
|
|
827
|
+
return Math.max(0, rect.w) * Math.max(0, rect.h);
|
|
828
|
+
}
|
|
829
|
+
function sameRect(a, b) {
|
|
830
|
+
return a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;
|
|
831
|
+
}
|
|
832
|
+
function subtractRect(rect, cover) {
|
|
833
|
+
const hit = intersectRect(rect, cover);
|
|
834
|
+
if (!hit) return [rect];
|
|
835
|
+
const out = [];
|
|
836
|
+
const rectRight = rect.x + rect.w;
|
|
837
|
+
const rectBottom = rect.y + rect.h;
|
|
838
|
+
const hitRight = hit.x + hit.w;
|
|
839
|
+
const hitBottom = hit.y + hit.h;
|
|
840
|
+
if (hit.y > rect.y) out.push({
|
|
841
|
+
x: rect.x,
|
|
842
|
+
y: rect.y,
|
|
843
|
+
w: rect.w,
|
|
844
|
+
h: hit.y - rect.y
|
|
845
|
+
});
|
|
846
|
+
if (hitBottom < rectBottom) out.push({
|
|
847
|
+
x: rect.x,
|
|
848
|
+
y: hitBottom,
|
|
849
|
+
w: rect.w,
|
|
850
|
+
h: rectBottom - hitBottom
|
|
851
|
+
});
|
|
852
|
+
if (hit.x > rect.x) out.push({
|
|
853
|
+
x: rect.x,
|
|
854
|
+
y: hit.y,
|
|
855
|
+
w: hit.x - rect.x,
|
|
856
|
+
h: hit.h
|
|
857
|
+
});
|
|
858
|
+
if (hitRight < rectRight) out.push({
|
|
859
|
+
x: hitRight,
|
|
860
|
+
y: hit.y,
|
|
861
|
+
w: rectRight - hitRight,
|
|
862
|
+
h: hit.h
|
|
863
|
+
});
|
|
864
|
+
return out.filter((part) => part.w > 0 && part.h > 0);
|
|
865
|
+
}
|
|
866
|
+
function largestUncoveredRect(rect, covers) {
|
|
867
|
+
let parts = [rect];
|
|
868
|
+
for (const cover of covers) {
|
|
869
|
+
parts = parts.flatMap((part) => subtractRect(part, cover));
|
|
870
|
+
if (!parts.length) return null;
|
|
871
|
+
}
|
|
872
|
+
parts.sort((a, b) => rectArea(b) - rectArea(a) || a.y - b.y || a.x - b.x);
|
|
873
|
+
return parts[0] ?? null;
|
|
874
|
+
}
|
|
875
|
+
function parseKittyClearControls(sequence) {
|
|
876
|
+
const prefix = "\x1B_G";
|
|
877
|
+
const terminator = "\x1B\\";
|
|
878
|
+
if (!sequence.startsWith(prefix) || !sequence.endsWith(terminator)) return null;
|
|
879
|
+
const body = sequence.slice(prefix.length, -terminator.length);
|
|
880
|
+
if (body.includes(terminator) || body.includes("\x1B") || body.includes("\x07")) return null;
|
|
881
|
+
const semicolon = body.indexOf(";");
|
|
882
|
+
const rawControls = semicolon >= 0 ? body.slice(0, semicolon) : body;
|
|
883
|
+
const controls = new Map();
|
|
884
|
+
for (const part of rawControls.split(",")) {
|
|
885
|
+
const eq = part.indexOf("=");
|
|
886
|
+
if (eq <= 0) return null;
|
|
887
|
+
controls.set(part.slice(0, eq), part.slice(eq + 1));
|
|
888
|
+
}
|
|
889
|
+
return controls;
|
|
890
|
+
}
|
|
891
|
+
function kittyClearTargetsComponent(sequence, imageId, placementId) {
|
|
892
|
+
const controls = parseKittyClearControls(sequence);
|
|
893
|
+
if (!controls) return false;
|
|
894
|
+
const mode = controls.get("d");
|
|
895
|
+
if (mode !== "i" && mode !== "I") return false;
|
|
896
|
+
return controls.get("i") === String(imageId) && controls.get("p") === String(placementId);
|
|
897
|
+
}
|
|
898
|
+
function isSafeComponentClearSequence(sequence, protocol, imageId, placementId) {
|
|
899
|
+
if (!isSafeTerminalGraphicsSequence(sequence, protocol, "clear")) return false;
|
|
900
|
+
return protocol !== "kitty" || kittyClearTargetsComponent(sequence, imageId, placementId);
|
|
901
|
+
}
|
|
902
|
+
let textEncoder = null;
|
|
903
|
+
function stringByteLength(value) {
|
|
904
|
+
if (typeof TextEncoder !== "undefined") {
|
|
905
|
+
textEncoder ?? (textEncoder = new TextEncoder());
|
|
906
|
+
return textEncoder.encode(value).length;
|
|
907
|
+
}
|
|
908
|
+
let bytes = 0;
|
|
909
|
+
for (let index = 0; index < value.length; index++) {
|
|
910
|
+
const code = value.charCodeAt(index);
|
|
911
|
+
if (code <= 127) bytes += 1;
|
|
912
|
+
else if (code <= 2047) bytes += 2;
|
|
913
|
+
else if (code >= 55296 && code <= 56319 && index + 1 < value.length) {
|
|
914
|
+
bytes += 4;
|
|
915
|
+
index++;
|
|
916
|
+
} else bytes += 3;
|
|
917
|
+
}
|
|
918
|
+
return bytes;
|
|
919
|
+
}
|
|
920
|
+
function smallHash(input) {
|
|
921
|
+
let hash = 2166136261;
|
|
922
|
+
for (let i = 0; i < input.length; i++) {
|
|
923
|
+
hash ^= input.charCodeAt(i);
|
|
924
|
+
hash = Math.imul(hash, 16777619);
|
|
925
|
+
}
|
|
926
|
+
return (hash >>> 0).toString(36);
|
|
927
|
+
}
|
|
928
|
+
const tAgentTerminalGraphicProps = {
|
|
929
|
+
x: {
|
|
930
|
+
type: Number,
|
|
931
|
+
required: true
|
|
932
|
+
},
|
|
933
|
+
y: {
|
|
934
|
+
type: Number,
|
|
935
|
+
required: true
|
|
936
|
+
},
|
|
937
|
+
w: {
|
|
938
|
+
type: Number,
|
|
939
|
+
required: true
|
|
940
|
+
},
|
|
941
|
+
h: {
|
|
942
|
+
type: Number,
|
|
943
|
+
default: void 0
|
|
944
|
+
},
|
|
945
|
+
zIndex: {
|
|
946
|
+
type: Number,
|
|
947
|
+
default: 0
|
|
948
|
+
},
|
|
949
|
+
content: {
|
|
950
|
+
type: String,
|
|
951
|
+
required: true
|
|
952
|
+
},
|
|
953
|
+
kind: {
|
|
954
|
+
type: String,
|
|
955
|
+
default: "image"
|
|
956
|
+
},
|
|
957
|
+
fallback: {
|
|
958
|
+
type: String,
|
|
959
|
+
default: void 0
|
|
960
|
+
},
|
|
961
|
+
style: {
|
|
962
|
+
type: Object,
|
|
963
|
+
default: void 0
|
|
964
|
+
},
|
|
965
|
+
loadingStyle: {
|
|
966
|
+
type: Object,
|
|
967
|
+
default: void 0
|
|
968
|
+
},
|
|
969
|
+
errorStyle: {
|
|
970
|
+
type: Object,
|
|
971
|
+
default: void 0
|
|
972
|
+
},
|
|
973
|
+
clear: {
|
|
974
|
+
type: Boolean,
|
|
975
|
+
default: true
|
|
976
|
+
},
|
|
977
|
+
final: {
|
|
978
|
+
type: Boolean,
|
|
979
|
+
default: true
|
|
980
|
+
},
|
|
981
|
+
streaming: {
|
|
982
|
+
type: Boolean,
|
|
983
|
+
default: false
|
|
984
|
+
},
|
|
985
|
+
renderer: {
|
|
986
|
+
type: Function,
|
|
987
|
+
default: void 0
|
|
988
|
+
},
|
|
989
|
+
loadingText: {
|
|
990
|
+
type: String,
|
|
991
|
+
default: "Rendering terminal graphic..."
|
|
992
|
+
},
|
|
993
|
+
deferRenderUntilVisible: {
|
|
994
|
+
type: Boolean,
|
|
995
|
+
default: true
|
|
996
|
+
},
|
|
997
|
+
suspendRawWhileScrolling: {
|
|
998
|
+
type: Boolean,
|
|
999
|
+
default: true
|
|
1000
|
+
},
|
|
1001
|
+
suspendRenderWhileScrolling: {
|
|
1002
|
+
type: Boolean,
|
|
1003
|
+
default: true
|
|
1004
|
+
},
|
|
1005
|
+
scrolling: {
|
|
1006
|
+
type: Boolean,
|
|
1007
|
+
default: false
|
|
1008
|
+
},
|
|
1009
|
+
scrollVersion: {
|
|
1010
|
+
type: Number,
|
|
1011
|
+
default: 0
|
|
1012
|
+
},
|
|
1013
|
+
placementMoveWithoutClear: {
|
|
1014
|
+
type: Boolean,
|
|
1015
|
+
default: false
|
|
1016
|
+
},
|
|
1017
|
+
preserveRawWhileRendering: {
|
|
1018
|
+
type: Boolean,
|
|
1019
|
+
default: false
|
|
1020
|
+
},
|
|
1021
|
+
suspended: {
|
|
1022
|
+
type: Boolean,
|
|
1023
|
+
default: false
|
|
1024
|
+
},
|
|
1025
|
+
retainRawWhileCovered: {
|
|
1026
|
+
type: Boolean,
|
|
1027
|
+
default: false
|
|
1028
|
+
},
|
|
1029
|
+
ignoreRawCoverage: {
|
|
1030
|
+
type: Boolean,
|
|
1031
|
+
default: false
|
|
1032
|
+
},
|
|
1033
|
+
ignoreSamePlaneRawCoverage: {
|
|
1034
|
+
type: Boolean,
|
|
1035
|
+
default: false
|
|
1036
|
+
},
|
|
1037
|
+
cacheKey: {
|
|
1038
|
+
type: String,
|
|
1039
|
+
default: void 0
|
|
1040
|
+
},
|
|
1041
|
+
placementKey: {
|
|
1042
|
+
type: String,
|
|
1043
|
+
default: void 0
|
|
1044
|
+
},
|
|
1045
|
+
trace: {
|
|
1046
|
+
type: Function,
|
|
1047
|
+
default: void 0
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
function terminalDrawKey(current, rect, clearSequence, resizeSequence) {
|
|
1051
|
+
return [
|
|
1052
|
+
current.protocol,
|
|
1053
|
+
rect.x,
|
|
1054
|
+
rect.y,
|
|
1055
|
+
rect.w,
|
|
1056
|
+
rect.h,
|
|
1057
|
+
current.sequenceHash,
|
|
1058
|
+
clearSequence === current.clearSequence ? current.clearSequenceHash ?? "" : smallHash(clearSequence ?? ""),
|
|
1059
|
+
resizeSequence === current.resizeSequence ? current.resizeSequenceHash ?? "" : smallHash(resizeSequence ?? "")
|
|
1060
|
+
].join(":");
|
|
1061
|
+
}
|
|
1062
|
+
const TAgentTerminalGraphic = defineComponent({
|
|
1063
|
+
name: "TAgentTerminalGraphic",
|
|
1064
|
+
props: tAgentTerminalGraphicProps,
|
|
1065
|
+
setup(props) {
|
|
1066
|
+
const instance = getCurrentInstance();
|
|
1067
|
+
const { terminal, defaultStyle, scheduler, widthProvider, render } = useTerminal();
|
|
1068
|
+
const layout = useLayout();
|
|
1069
|
+
const { visible, rootProps } = useVisibility();
|
|
1070
|
+
const graphicsActivity = inject(TerminalGraphicsActivityKey, null);
|
|
1071
|
+
const status = shallowRef("idle");
|
|
1072
|
+
const error = shallowRef("");
|
|
1073
|
+
const graphic = shallowRef(null);
|
|
1074
|
+
const documentVersion = shallowRef(0);
|
|
1075
|
+
let builtOnce = false;
|
|
1076
|
+
let renderVersion = 0;
|
|
1077
|
+
let renderAbort = null;
|
|
1078
|
+
let alive = true;
|
|
1079
|
+
let lastRenderedContent = "";
|
|
1080
|
+
let lastRenderRawVisible = false;
|
|
1081
|
+
let lastRenderProtocol = null;
|
|
1082
|
+
let lastRenderGraphicsOutputVersion = 0;
|
|
1083
|
+
const rawIdSeed = props.placementKey ? `placement:${props.placementKey}` : props.cacheKey ? `cache:${props.cacheKey}` : `instance:${instance?.uid ?? "unknown"}`;
|
|
1084
|
+
const rawId = `TAgentTerminalGraphic:${smallHash(rawIdSeed)}`;
|
|
1085
|
+
const frameTaskId = `${rawId}:render`;
|
|
1086
|
+
const lastDrawnGraphic = shallowRef(null);
|
|
1087
|
+
const rawClearPendingRepaint = shallowRef(null);
|
|
1088
|
+
const rawDrawRejectedKey = shallowRef(null);
|
|
1089
|
+
const reservedTerminalGraphicSize = shallowRef(null);
|
|
1090
|
+
const terminalSizeVersion = shallowRef(0);
|
|
1091
|
+
const renderNodeId = shallowRef(null);
|
|
1092
|
+
let lastRawSkipScrollKey = "";
|
|
1093
|
+
let lastDeferTraceKey = "";
|
|
1094
|
+
const isParentScrolling = computed(() => props.scrolling || Boolean(graphicsActivity?.scrolling.value));
|
|
1095
|
+
const graphicsActivityVersion = computed(() => (graphicsActivity?.version.value ?? 0) + Math.floor(Number(props.scrollVersion ?? 0)));
|
|
1096
|
+
const graphicsOutput = () => getTerminalGraphicsOutput(terminal);
|
|
1097
|
+
const graphicsOutputVersion = shallowRef(getTerminalGraphicsOutputVersion(terminal));
|
|
1098
|
+
const unsubscribeGraphicsOutput = subscribeTerminalGraphicsOutput(terminal, () => {
|
|
1099
|
+
graphicsOutputVersion.value = getTerminalGraphicsOutputVersion(terminal);
|
|
1100
|
+
});
|
|
1101
|
+
const unsubscribeTerminalResize = terminal.on("resize", () => {
|
|
1102
|
+
terminalSizeVersion.value++;
|
|
1103
|
+
});
|
|
1104
|
+
const fallbackText = () => props.fallback ?? (props.kind === "math" ? props.content : "");
|
|
1105
|
+
const contentIdentity = computed(() => `${props.content.length}:${smallHash(props.content)}`);
|
|
1106
|
+
const stableGraphicKey = computed(() => [
|
|
1107
|
+
rawIdSeed,
|
|
1108
|
+
props.cacheKey ?? "",
|
|
1109
|
+
props.kind,
|
|
1110
|
+
contentIdentity.value,
|
|
1111
|
+
props.w,
|
|
1112
|
+
props.h ?? "",
|
|
1113
|
+
props.final ? "final" : "draft"
|
|
1114
|
+
].join(""));
|
|
1115
|
+
const imageId = computed(() => stableTerminalGraphicNumericId(`image:${stableGraphicKey.value}`));
|
|
1116
|
+
const placementId = computed(() => stableTerminalGraphicNumericId(`placement:${stableGraphicKey.value}`));
|
|
1117
|
+
function rememberTerminalGraphicSize(current) {
|
|
1118
|
+
if (current.type !== "terminal") return;
|
|
1119
|
+
const rows = positiveInt(current.rows);
|
|
1120
|
+
if (!rows) return;
|
|
1121
|
+
reservedTerminalGraphicSize.value = {
|
|
1122
|
+
key: stableGraphicKey.value,
|
|
1123
|
+
rows
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
function bump() {
|
|
1127
|
+
documentVersion.value++;
|
|
1128
|
+
}
|
|
1129
|
+
function currentCapabilities() {
|
|
1130
|
+
return graphicsOutput()?.capabilities ?? NO_GRAPHICS_CAPABILITIES;
|
|
1131
|
+
}
|
|
1132
|
+
function trace(type, extra = {}) {
|
|
1133
|
+
const capabilities = currentCapabilities();
|
|
1134
|
+
try {
|
|
1135
|
+
props.trace?.({
|
|
1136
|
+
type,
|
|
1137
|
+
id: rawId,
|
|
1138
|
+
kind: props.kind,
|
|
1139
|
+
protocol: capabilities.protocol,
|
|
1140
|
+
contentHash: smallHash(props.content),
|
|
1141
|
+
...extra
|
|
1142
|
+
});
|
|
1143
|
+
} catch {}
|
|
1144
|
+
const protocol = isTerminalGraphicsProtocol(capabilities.protocol) ? capabilities.protocol : void 0;
|
|
1145
|
+
const key = props.cacheKey ?? smallHash(props.content);
|
|
1146
|
+
if (type === "render-start") recordTerminalGraphicTrace({
|
|
1147
|
+
type: "renderer-start",
|
|
1148
|
+
id: rawId,
|
|
1149
|
+
key,
|
|
1150
|
+
protocol
|
|
1151
|
+
});
|
|
1152
|
+
else if (type === "render-end") recordTerminalGraphicTrace({
|
|
1153
|
+
type: extra.reason ? "renderer-error" : "renderer-end",
|
|
1154
|
+
id: rawId,
|
|
1155
|
+
key,
|
|
1156
|
+
protocol,
|
|
1157
|
+
durationMs: extra.durationMs,
|
|
1158
|
+
bytes: extra.sequenceBytes,
|
|
1159
|
+
error: extra.reason
|
|
1160
|
+
});
|
|
1161
|
+
else if (type === "defer") recordTerminalGraphicTrace({
|
|
1162
|
+
type: extra.reason === "scrolling" ? "skip-scrolling" : "skip-hidden",
|
|
1163
|
+
id: rawId,
|
|
1164
|
+
key,
|
|
1165
|
+
protocol,
|
|
1166
|
+
reason: extra.reason
|
|
1167
|
+
});
|
|
1168
|
+
else if (type === "raw-draw") {} else if (type === "render-abort") recordTerminalGraphicTrace({
|
|
1169
|
+
type: "renderer-abort",
|
|
1170
|
+
id: rawId,
|
|
1171
|
+
key,
|
|
1172
|
+
protocol,
|
|
1173
|
+
reason: extra.reason
|
|
1174
|
+
});
|
|
1175
|
+
else if (type === "raw-clear") recordTerminalGraphicTrace({
|
|
1176
|
+
type: "clear",
|
|
1177
|
+
id: rawId,
|
|
1178
|
+
key,
|
|
1179
|
+
protocol
|
|
1180
|
+
});
|
|
1181
|
+
else if (type === "raw-skip-scroll") recordTerminalGraphicTrace({
|
|
1182
|
+
type: "skip-scrolling",
|
|
1183
|
+
id: rawId,
|
|
1184
|
+
key,
|
|
1185
|
+
protocol,
|
|
1186
|
+
reason: extra.reason
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
function traceDeferOnce(reason) {
|
|
1190
|
+
const key = [
|
|
1191
|
+
reason,
|
|
1192
|
+
graphicsActivityVersion.value,
|
|
1193
|
+
stableGraphicKey.value
|
|
1194
|
+
].join(":");
|
|
1195
|
+
if (lastDeferTraceKey === key) return;
|
|
1196
|
+
lastDeferTraceKey = key;
|
|
1197
|
+
trace("defer", { reason });
|
|
1198
|
+
}
|
|
1199
|
+
function abortCurrentRender(reason) {
|
|
1200
|
+
if (!renderAbort) return;
|
|
1201
|
+
renderAbort.abort();
|
|
1202
|
+
renderAbort = null;
|
|
1203
|
+
trace("render-abort", { reason });
|
|
1204
|
+
}
|
|
1205
|
+
function normalizeResult(result) {
|
|
1206
|
+
if (result == null) return {
|
|
1207
|
+
type: "text",
|
|
1208
|
+
text: fallbackText()
|
|
1209
|
+
};
|
|
1210
|
+
if (typeof result === "string") return {
|
|
1211
|
+
type: "text",
|
|
1212
|
+
text: result
|
|
1213
|
+
};
|
|
1214
|
+
if (typeof result !== "object") return {
|
|
1215
|
+
type: "text",
|
|
1216
|
+
text: fallbackText()
|
|
1217
|
+
};
|
|
1218
|
+
if ("type" in result && result.type === "text") return {
|
|
1219
|
+
type: "text",
|
|
1220
|
+
text: result.text
|
|
1221
|
+
};
|
|
1222
|
+
const maybeRaw = result;
|
|
1223
|
+
const isRawCandidate = maybeRaw.type === "sequence" || "sequence" in result || "protocol" in result;
|
|
1224
|
+
if (!isRawCandidate && "text" in result) return {
|
|
1225
|
+
type: "text",
|
|
1226
|
+
text: result.text
|
|
1227
|
+
};
|
|
1228
|
+
const sequence = typeof maybeRaw.sequence === "string" ? maybeRaw.sequence : "";
|
|
1229
|
+
const protocol = isTerminalGraphicsProtocol(maybeRaw.protocol) ? maybeRaw.protocol : null;
|
|
1230
|
+
const fallback = typeof maybeRaw.fallback === "string" ? sanitizeTerminalFallbackText(maybeRaw.fallback) : fallbackText();
|
|
1231
|
+
const fallbackFromProps = typeof maybeRaw.fallback !== "string";
|
|
1232
|
+
if (!sequence || !protocol || !isSafeTerminalGraphicsSequence(sequence, protocol, "draw")) return {
|
|
1233
|
+
type: "text",
|
|
1234
|
+
text: fallback
|
|
1235
|
+
};
|
|
1236
|
+
const rawClear = typeof maybeRaw.clearSequence === "string" ? maybeRaw.clearSequence : void 0;
|
|
1237
|
+
const clearSequence = rawClear && isSafeComponentClearSequence(rawClear, protocol, imageId.value, placementId.value) ? rawClear : void 0;
|
|
1238
|
+
const rawResize = typeof maybeRaw.resizeSequence === "string" ? maybeRaw.resizeSequence : void 0;
|
|
1239
|
+
const resizeSequence = rawResize && isSafeTerminalGraphicsSequence(rawResize, protocol, "draw") ? rawResize : void 0;
|
|
1240
|
+
const declaredRows = positiveInt(maybeRaw.rows);
|
|
1241
|
+
const declaredCols = positiveInt(maybeRaw.cols);
|
|
1242
|
+
const sourceWidth = positiveInt(maybeRaw.sourceWidth);
|
|
1243
|
+
const sourceHeight = positiveInt(maybeRaw.sourceHeight);
|
|
1244
|
+
const zIndex = finiteInt(maybeRaw.zIndex);
|
|
1245
|
+
const declaredSize = declaredRows == null ? null : normalizeTerminalGraphicSize(declaredCols ?? props.w, declaredRows);
|
|
1246
|
+
return {
|
|
1247
|
+
type: "terminal",
|
|
1248
|
+
protocol,
|
|
1249
|
+
sequence,
|
|
1250
|
+
sequenceHash: smallHash(sequence),
|
|
1251
|
+
sequenceBytes: stringByteLength(sequence),
|
|
1252
|
+
fallback,
|
|
1253
|
+
fallbackFromProps,
|
|
1254
|
+
clearSequence,
|
|
1255
|
+
clearSequenceHash: clearSequence ? smallHash(clearSequence) : void 0,
|
|
1256
|
+
resizeSequence,
|
|
1257
|
+
resizeSequenceHash: resizeSequence ? smallHash(resizeSequence) : void 0,
|
|
1258
|
+
cols: declaredRows == null ? declaredCols : declaredSize?.width,
|
|
1259
|
+
rows: declaredSize?.height,
|
|
1260
|
+
sourceWidth,
|
|
1261
|
+
sourceHeight,
|
|
1262
|
+
zIndex
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
function defaultClearSequence(protocol) {
|
|
1266
|
+
return protocol === "kitty" ? createKittyDeleteGraphicsSequence({
|
|
1267
|
+
imageId: imageId.value,
|
|
1268
|
+
placementId: placementId.value
|
|
1269
|
+
}) : "";
|
|
1270
|
+
}
|
|
1271
|
+
function resolveClearSequence(current) {
|
|
1272
|
+
if (current.clearSequence) return current.clearSequence;
|
|
1273
|
+
const candidate = defaultClearSequence(current.protocol);
|
|
1274
|
+
if (!candidate) return void 0;
|
|
1275
|
+
return isSafeComponentClearSequence(candidate, current.protocol, imageId.value, placementId.value) ? candidate : void 0;
|
|
1276
|
+
}
|
|
1277
|
+
function resolveResizeSequence(current, rect, full) {
|
|
1278
|
+
if (current.protocol !== "kitty") return current.resizeSequence;
|
|
1279
|
+
const sourceWidth = positiveInt(current.sourceWidth);
|
|
1280
|
+
const sourceHeight = positiveInt(current.sourceHeight);
|
|
1281
|
+
if (!sourceWidth || !sourceHeight || full.w <= 0 || full.h <= 0) return current.resizeSequence;
|
|
1282
|
+
const offsetX = Math.max(0, rect.x - full.x);
|
|
1283
|
+
const offsetY = Math.max(0, rect.y - full.y);
|
|
1284
|
+
const visibleW = Math.max(0, Math.min(rect.w, full.w - offsetX));
|
|
1285
|
+
const visibleH = Math.max(0, Math.min(rect.h, full.h - offsetY));
|
|
1286
|
+
const x0 = clampNumber(Math.floor(offsetX * sourceWidth / full.w), 0, sourceWidth - 1);
|
|
1287
|
+
const y0 = clampNumber(Math.floor(offsetY * sourceHeight / full.h), 0, sourceHeight - 1);
|
|
1288
|
+
const x1 = Math.max(x0 + 1, clampNumber(Math.ceil((offsetX + visibleW) * sourceWidth / full.w), 1, sourceWidth));
|
|
1289
|
+
const y1 = Math.max(y0 + 1, clampNumber(Math.ceil((offsetY + visibleH) * sourceHeight / full.h), 1, sourceHeight));
|
|
1290
|
+
return createKittyPlacementSequence({
|
|
1291
|
+
imageId: imageId.value,
|
|
1292
|
+
placementId: placementId.value,
|
|
1293
|
+
columns: rect.w,
|
|
1294
|
+
rows: rect.h,
|
|
1295
|
+
sourceX: x0,
|
|
1296
|
+
sourceY: y0,
|
|
1297
|
+
sourceWidth: x1 - x0,
|
|
1298
|
+
sourceHeight: y1 - y0,
|
|
1299
|
+
zIndex: current.zIndex
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
function queueClearLastGraphic(options = {}) {
|
|
1303
|
+
const previous = lastDrawnGraphic.value;
|
|
1304
|
+
if (!previous) return false;
|
|
1305
|
+
const output = graphicsOutput();
|
|
1306
|
+
let accepted = false;
|
|
1307
|
+
if (output?.clear && !previous.retainOnClear) try {
|
|
1308
|
+
accepted = Boolean(output.clear(previous.id));
|
|
1309
|
+
} catch {
|
|
1310
|
+
accepted = false;
|
|
1311
|
+
}
|
|
1312
|
+
if (!accepted && output && previous.clearSequence) try {
|
|
1313
|
+
accepted = output.queue({
|
|
1314
|
+
id: previous.id,
|
|
1315
|
+
x: previous.x,
|
|
1316
|
+
y: previous.y,
|
|
1317
|
+
w: previous.w,
|
|
1318
|
+
h: previous.h,
|
|
1319
|
+
protocol: previous.protocol,
|
|
1320
|
+
sequence: previous.clearSequence,
|
|
1321
|
+
deferFlush: true,
|
|
1322
|
+
retainOnClear: previous.retainOnClear,
|
|
1323
|
+
op: "clear"
|
|
1324
|
+
});
|
|
1325
|
+
} catch {
|
|
1326
|
+
accepted = false;
|
|
1327
|
+
}
|
|
1328
|
+
if (accepted) {
|
|
1329
|
+
if (options.markPendingRepaint ?? true) rawClearPendingRepaint.value = previous;
|
|
1330
|
+
lastDrawnGraphic.value = null;
|
|
1331
|
+
trace("raw-clear", {
|
|
1332
|
+
x: previous.x,
|
|
1333
|
+
y: previous.y,
|
|
1334
|
+
w: previous.w,
|
|
1335
|
+
h: previous.h
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
return accepted;
|
|
1339
|
+
}
|
|
1340
|
+
function queueDrawGraphic(output, current, rect, full = rect, options = {}) {
|
|
1341
|
+
const clearSequence = resolveClearSequence(current);
|
|
1342
|
+
const resizeSequence = resolveResizeSequence(current, rect, full);
|
|
1343
|
+
const drawKey = terminalDrawKey(current, rect, clearSequence, resizeSequence);
|
|
1344
|
+
const activePrevious = lastDrawnGraphic.value;
|
|
1345
|
+
const retainedPrevious = rawClearPendingRepaint.value;
|
|
1346
|
+
const previous = activePrevious ?? retainedPrevious;
|
|
1347
|
+
const previousIsRetained = activePrevious == null && retainedPrevious != null;
|
|
1348
|
+
const previousStillActive = previous ? typeof output.isActive === "function" ? output.isActive(previous.id) : true : false;
|
|
1349
|
+
const preservePreviousForAtomicReplace = props.preserveRawWhileRendering && activePrevious != null && !previousIsRetained && previousStillActive;
|
|
1350
|
+
if (!previousIsRetained && !options.force && previous?.drawKey === drawKey && previousStillActive) return false;
|
|
1351
|
+
const canReusePlacementSequence = previousStillActive && previous?.protocol === current.protocol && previous.sequenceHash === current.sequenceHash && current.protocol === "kitty" && Boolean(resizeSequence);
|
|
1352
|
+
const scrollVersion = Math.floor(Number(props.scrollVersion ?? 0));
|
|
1353
|
+
const canMoveWithoutClear = canReusePlacementSequence && Boolean(options.placementMoveWithoutClear);
|
|
1354
|
+
if (!previousIsRetained && previousStillActive && !resizeSequence && previous?.protocol === current.protocol && previous.sequenceHash === current.sequenceHash && previous.x === rect.x && previous.y === rect.y && rect.w <= previous.w && rect.h <= previous.h && (options.force || !sameRect(rect, full))) {
|
|
1355
|
+
lastDrawnGraphic.value = {
|
|
1356
|
+
...previous,
|
|
1357
|
+
w: rect.w,
|
|
1358
|
+
h: rect.h,
|
|
1359
|
+
clearSequence,
|
|
1360
|
+
resizeSequence,
|
|
1361
|
+
drawKey,
|
|
1362
|
+
activityVersion: graphicsActivityVersion.value,
|
|
1363
|
+
scrollVersion
|
|
1364
|
+
};
|
|
1365
|
+
lastRawSkipScrollKey = "";
|
|
1366
|
+
return false;
|
|
1367
|
+
}
|
|
1368
|
+
if (previousStillActive && !previousIsRetained && !canReusePlacementSequence && !preservePreviousForAtomicReplace) {
|
|
1369
|
+
if (!queueClearLastGraphic({ markPendingRepaint: false })) return false;
|
|
1370
|
+
} else if (previous) {
|
|
1371
|
+
if (!previousStillActive) {
|
|
1372
|
+
lastDrawnGraphic.value = null;
|
|
1373
|
+
rawClearPendingRepaint.value = null;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
let accepted = false;
|
|
1377
|
+
try {
|
|
1378
|
+
accepted = output.queue({
|
|
1379
|
+
id: rawId,
|
|
1380
|
+
x: rect.x,
|
|
1381
|
+
y: rect.y,
|
|
1382
|
+
w: rect.w,
|
|
1383
|
+
h: rect.h,
|
|
1384
|
+
protocol: current.protocol,
|
|
1385
|
+
sequence: canReusePlacementSequence && resizeSequence ? resizeSequence : current.sequence,
|
|
1386
|
+
resizeSequence,
|
|
1387
|
+
clearSequence,
|
|
1388
|
+
retainOnClear: Boolean(props.cacheKey && resizeSequence),
|
|
1389
|
+
resizeRedraw: canReusePlacementSequence,
|
|
1390
|
+
placementMoveWithoutClear: canMoveWithoutClear,
|
|
1391
|
+
allowTextOverlay: options.allowTextOverlay,
|
|
1392
|
+
forceDraw: options.force,
|
|
1393
|
+
deferFlush: options.deferFlush ?? true,
|
|
1394
|
+
fallbackText: current.fallback
|
|
1395
|
+
});
|
|
1396
|
+
} catch {
|
|
1397
|
+
accepted = false;
|
|
1398
|
+
}
|
|
1399
|
+
if (!accepted) {
|
|
1400
|
+
if (preservePreviousForAtomicReplace) {
|
|
1401
|
+
lastDrawnGraphic.value = activePrevious;
|
|
1402
|
+
queueClearLastGraphic({ markPendingRepaint: false });
|
|
1403
|
+
} else lastDrawnGraphic.value = null;
|
|
1404
|
+
if (rawDrawRejectedKey.value !== drawKey) {
|
|
1405
|
+
rawDrawRejectedKey.value = drawKey;
|
|
1406
|
+
scheduler.invalidate({
|
|
1407
|
+
priority: "low",
|
|
1408
|
+
reason: "data"
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
return false;
|
|
1412
|
+
}
|
|
1413
|
+
rawDrawRejectedKey.value = null;
|
|
1414
|
+
rawClearPendingRepaint.value = null;
|
|
1415
|
+
lastDrawnGraphic.value = {
|
|
1416
|
+
id: rawId,
|
|
1417
|
+
x: rect.x,
|
|
1418
|
+
y: rect.y,
|
|
1419
|
+
w: rect.w,
|
|
1420
|
+
h: rect.h,
|
|
1421
|
+
protocol: current.protocol,
|
|
1422
|
+
sequenceHash: current.sequenceHash,
|
|
1423
|
+
clearSequence,
|
|
1424
|
+
resizeSequence,
|
|
1425
|
+
retainOnClear: Boolean(props.cacheKey && resizeSequence),
|
|
1426
|
+
allowTextOverlay: Boolean(options.allowTextOverlay),
|
|
1427
|
+
drawKey,
|
|
1428
|
+
activityVersion: graphicsActivityVersion.value,
|
|
1429
|
+
scrollVersion
|
|
1430
|
+
};
|
|
1431
|
+
lastRawSkipScrollKey = "";
|
|
1432
|
+
return true;
|
|
1433
|
+
}
|
|
1434
|
+
function hasRetainedActiveRawGraphic() {
|
|
1435
|
+
const output = graphicsOutput();
|
|
1436
|
+
return Boolean(status.value === "loading" && !graphic.value && output && typeof output.isActive === "function" && output.isActive(rawId));
|
|
1437
|
+
}
|
|
1438
|
+
const showingInitialLoadingText = computed(() => status.value === "loading" && !graphic.value && !hasRetainedActiveRawGraphic());
|
|
1439
|
+
const fullRect = computed(() => {
|
|
1440
|
+
const current = graphic.value;
|
|
1441
|
+
const reserved = reservedTerminalGraphicSize.value;
|
|
1442
|
+
const reservedRows = current?.type === "terminal" ? void 0 : status.value === "idle" && reserved?.key === stableGraphicKey.value ? reserved.rows : void 0;
|
|
1443
|
+
const textLines = current?.type === "text" ? splitTextOutput(current.text) : splitTextOutput(fallbackText());
|
|
1444
|
+
const height = props.h ?? (current?.type === "terminal" ? current.rows : void 0) ?? reservedRows ?? Math.max(1, textLines.length);
|
|
1445
|
+
return translateRect({
|
|
1446
|
+
x: props.x,
|
|
1447
|
+
y: props.y,
|
|
1448
|
+
w: props.w,
|
|
1449
|
+
h: height
|
|
1450
|
+
}, layout.originX, layout.originY);
|
|
1451
|
+
});
|
|
1452
|
+
const absRect = computed(() => {
|
|
1453
|
+
terminalSizeVersion.value;
|
|
1454
|
+
const translated = fullRect.value;
|
|
1455
|
+
const size = terminal.size();
|
|
1456
|
+
const terminalClip = {
|
|
1457
|
+
x: 0,
|
|
1458
|
+
y: 0,
|
|
1459
|
+
w: Math.max(0, Math.floor(size.cols)),
|
|
1460
|
+
h: Math.max(0, Math.floor(size.rows))
|
|
1461
|
+
};
|
|
1462
|
+
const clip = layout.clipRect ? intersectRect(layout.clipRect, terminalClip) : terminalClip;
|
|
1463
|
+
if (!clip) return {
|
|
1464
|
+
x: 0,
|
|
1465
|
+
y: 0,
|
|
1466
|
+
w: 0,
|
|
1467
|
+
h: 0
|
|
1468
|
+
};
|
|
1469
|
+
return intersectRect(translated, clip) ?? {
|
|
1470
|
+
x: 0,
|
|
1471
|
+
y: 0,
|
|
1472
|
+
w: 0,
|
|
1473
|
+
h: 0
|
|
1474
|
+
};
|
|
1475
|
+
});
|
|
1476
|
+
const renderRect = computed(() => absRect.value);
|
|
1477
|
+
function rawRectFitsTerminalViewport(rect) {
|
|
1478
|
+
return canDrawTerminalGraphicRect(rect, terminal.size());
|
|
1479
|
+
}
|
|
1480
|
+
function rawCoveredByHigherRenderNode(rect = fullRect.value) {
|
|
1481
|
+
if (props.retainRawWhileCovered) return false;
|
|
1482
|
+
const id = renderNodeId.value;
|
|
1483
|
+
return !props.ignoreRawCoverage && id != null && render.isRectCoveredByHigherNode(id, rect, { ignoreSamePlane: props.ignoreSamePlaneRawCoverage });
|
|
1484
|
+
}
|
|
1485
|
+
function retainedRawCoveredByHigherRenderNode(rect) {
|
|
1486
|
+
if (!props.retainRawWhileCovered) return false;
|
|
1487
|
+
const id = renderNodeId.value;
|
|
1488
|
+
return Boolean(id != null && render.isRectCoveredByHigherNode(id, rect, { ignoreSamePlane: props.ignoreSamePlaneRawCoverage }));
|
|
1489
|
+
}
|
|
1490
|
+
function rawUncoveredRenderRect(rect) {
|
|
1491
|
+
if (props.retainRawWhileCovered) return rect;
|
|
1492
|
+
const id = renderNodeId.value;
|
|
1493
|
+
if (id == null) return rect;
|
|
1494
|
+
const covers = render.higherNodeCoverageRects(id, rect, { ignoreSamePlane: props.ignoreSamePlaneRawCoverage });
|
|
1495
|
+
if (!covers.length) return rect;
|
|
1496
|
+
if (!props.ignoreRawCoverage) return null;
|
|
1497
|
+
return largestUncoveredRect(rect, covers);
|
|
1498
|
+
}
|
|
1499
|
+
const rawCanRender = computed(() => {
|
|
1500
|
+
graphicsOutputVersion.value;
|
|
1501
|
+
terminalSizeVersion.value;
|
|
1502
|
+
const current = graphic.value;
|
|
1503
|
+
const output = graphicsOutput();
|
|
1504
|
+
const rect = absRect.value;
|
|
1505
|
+
return current?.type === "terminal" && rawRectFitsTerminalViewport(rect) && Boolean(output?.capabilities.supported) && output?.capabilities.preferredProtocol === current.protocol;
|
|
1506
|
+
});
|
|
1507
|
+
const rawOutputCanRenderValue = computed(() => {
|
|
1508
|
+
graphicsOutputVersion.value;
|
|
1509
|
+
terminalSizeVersion.value;
|
|
1510
|
+
return rawOutputCanRender();
|
|
1511
|
+
});
|
|
1512
|
+
const rawSuppressedByScroll = computed(() => props.suspended || props.suspendRawWhileScrolling && isParentScrolling.value);
|
|
1513
|
+
const rawCanQueue = computed(() => rawCanRender.value && !rawSuppressedByScroll.value);
|
|
1514
|
+
function traceRawSkipScrollOnce(reason) {
|
|
1515
|
+
const r = absRect.value;
|
|
1516
|
+
const key = [
|
|
1517
|
+
reason,
|
|
1518
|
+
graphicsActivityVersion.value,
|
|
1519
|
+
stableGraphicKey.value,
|
|
1520
|
+
r.x,
|
|
1521
|
+
r.y,
|
|
1522
|
+
r.w,
|
|
1523
|
+
r.h
|
|
1524
|
+
].join(":");
|
|
1525
|
+
if (lastRawSkipScrollKey === key) return;
|
|
1526
|
+
lastRawSkipScrollKey = key;
|
|
1527
|
+
trace("raw-skip-scroll", { reason });
|
|
1528
|
+
}
|
|
1529
|
+
function hasPaintableRect() {
|
|
1530
|
+
const r = absRect.value;
|
|
1531
|
+
return visible.value && r.w > 0 && r.h > 0;
|
|
1532
|
+
}
|
|
1533
|
+
function rawOutputCanRender() {
|
|
1534
|
+
const output = graphicsOutput();
|
|
1535
|
+
const rect = absRect.value;
|
|
1536
|
+
return rawRectFitsTerminalViewport(rect) && Boolean(output?.capabilities.supported);
|
|
1537
|
+
}
|
|
1538
|
+
function renderDeferReason() {
|
|
1539
|
+
if (props.suspended) return "suspended";
|
|
1540
|
+
if (props.deferRenderUntilVisible && !hasPaintableRect()) return "not-visible";
|
|
1541
|
+
if (props.suspendRenderWhileScrolling && isParentScrolling.value) return "scrolling";
|
|
1542
|
+
return null;
|
|
1543
|
+
}
|
|
1544
|
+
function shouldDeferRender() {
|
|
1545
|
+
return renderDeferReason() != null;
|
|
1546
|
+
}
|
|
1547
|
+
function shouldRerenderForGraphicsOutputChange() {
|
|
1548
|
+
if (!props.renderer) return false;
|
|
1549
|
+
if (!props.content.trim()) return false;
|
|
1550
|
+
if (shouldDeferRender()) return false;
|
|
1551
|
+
if (rawSuppressedByScroll.value) return false;
|
|
1552
|
+
const protocol = currentCapabilities().protocol;
|
|
1553
|
+
return lastRenderProtocol != null && (lastRenderProtocol !== protocol || lastRenderGraphicsOutputVersion !== graphicsOutputVersion.value);
|
|
1554
|
+
}
|
|
1555
|
+
function shouldRetryTemporaryRawFallback(rawCovered = rawCoveredByHigherRenderNode()) {
|
|
1556
|
+
return Boolean(props.renderer) && props.content.trim().length > 0 && graphic.value?.type === "text" && status.value !== "loading" && !lastRenderRawVisible && rawOutputCanRenderValue.value && !rawSuppressedByScroll.value && !rawCovered;
|
|
1557
|
+
}
|
|
1558
|
+
function setDeferredFallback(content) {
|
|
1559
|
+
graphic.value = {
|
|
1560
|
+
type: "text",
|
|
1561
|
+
text: content.trim() ? fallbackText() : ""
|
|
1562
|
+
};
|
|
1563
|
+
lastRenderedContent = content;
|
|
1564
|
+
status.value = "idle";
|
|
1565
|
+
error.value = "";
|
|
1566
|
+
bump();
|
|
1567
|
+
}
|
|
1568
|
+
function resolveRendererContext(signal) {
|
|
1569
|
+
const capabilities = currentCapabilities();
|
|
1570
|
+
const visibleNow = hasPaintableRect();
|
|
1571
|
+
const rawVisible = rawOutputCanRenderValue.value && !rawSuppressedByScroll.value && !rawCoveredByHigherRenderNode();
|
|
1572
|
+
return {
|
|
1573
|
+
kind: props.kind,
|
|
1574
|
+
width: props.w,
|
|
1575
|
+
height: props.h,
|
|
1576
|
+
final: props.final,
|
|
1577
|
+
streaming: props.streaming,
|
|
1578
|
+
protocol: capabilities.protocol,
|
|
1579
|
+
capabilities,
|
|
1580
|
+
signal,
|
|
1581
|
+
imageId: imageId.value,
|
|
1582
|
+
placementId: placementId.value,
|
|
1583
|
+
visible: visibleNow,
|
|
1584
|
+
rawVisible,
|
|
1585
|
+
scrolling: isParentScrolling.value,
|
|
1586
|
+
cacheKey: props.cacheKey,
|
|
1587
|
+
viewport: {
|
|
1588
|
+
visible: visibleNow,
|
|
1589
|
+
rawVisible,
|
|
1590
|
+
scrolling: isParentScrolling.value,
|
|
1591
|
+
rect: absRect.value,
|
|
1592
|
+
fullRect: fullRect.value
|
|
1593
|
+
}
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
async function renderNow(version) {
|
|
1597
|
+
const protocol = currentCapabilities().protocol;
|
|
1598
|
+
recordTerminalGraphicTrace({
|
|
1599
|
+
type: "request",
|
|
1600
|
+
id: rawId,
|
|
1601
|
+
key: props.cacheKey ?? smallHash(props.content),
|
|
1602
|
+
protocol: isTerminalGraphicsProtocol(protocol) ? protocol : void 0
|
|
1603
|
+
});
|
|
1604
|
+
const content = props.content;
|
|
1605
|
+
if (!content.trim()) {
|
|
1606
|
+
abortCurrentRender("superseded");
|
|
1607
|
+
if (!alive || version !== renderVersion) return;
|
|
1608
|
+
graphic.value = {
|
|
1609
|
+
type: "text",
|
|
1610
|
+
text: ""
|
|
1611
|
+
};
|
|
1612
|
+
lastRenderedContent = content;
|
|
1613
|
+
status.value = "ready";
|
|
1614
|
+
error.value = "";
|
|
1615
|
+
bump();
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
const renderer = props.renderer;
|
|
1619
|
+
if (!renderer) {
|
|
1620
|
+
abortCurrentRender("superseded");
|
|
1621
|
+
if (!alive || version !== renderVersion) return;
|
|
1622
|
+
graphic.value = {
|
|
1623
|
+
type: "text",
|
|
1624
|
+
text: fallbackText()
|
|
1625
|
+
};
|
|
1626
|
+
lastRenderedContent = content;
|
|
1627
|
+
status.value = "ready";
|
|
1628
|
+
error.value = "";
|
|
1629
|
+
bump();
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
const deferred = renderDeferReason();
|
|
1633
|
+
if (deferred) {
|
|
1634
|
+
abortCurrentRender(deferred);
|
|
1635
|
+
if (!alive || version !== renderVersion) return;
|
|
1636
|
+
setDeferredFallback(content);
|
|
1637
|
+
traceDeferOnce(deferred);
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1640
|
+
abortCurrentRender("superseded");
|
|
1641
|
+
lastDeferTraceKey = "";
|
|
1642
|
+
const abort = new AbortController();
|
|
1643
|
+
renderAbort = abort;
|
|
1644
|
+
const startedAt = nowTerminalGraphicTraceTime();
|
|
1645
|
+
status.value = "loading";
|
|
1646
|
+
error.value = "";
|
|
1647
|
+
trace("render-start");
|
|
1648
|
+
bump();
|
|
1649
|
+
try {
|
|
1650
|
+
const contextGraphicsOutputVersion = graphicsOutputVersion.value;
|
|
1651
|
+
const context = resolveRendererContext(abort.signal);
|
|
1652
|
+
lastRenderRawVisible = context.rawVisible;
|
|
1653
|
+
lastRenderProtocol = context.protocol;
|
|
1654
|
+
lastRenderGraphicsOutputVersion = contextGraphicsOutputVersion;
|
|
1655
|
+
const result = await renderer(content, context);
|
|
1656
|
+
if (abort.signal.aborted) return;
|
|
1657
|
+
if (!alive || version !== renderVersion) return;
|
|
1658
|
+
const normalized = normalizeResult(result);
|
|
1659
|
+
rememberTerminalGraphicSize(normalized);
|
|
1660
|
+
graphic.value = normalized;
|
|
1661
|
+
lastRenderedContent = content;
|
|
1662
|
+
status.value = "ready";
|
|
1663
|
+
error.value = "";
|
|
1664
|
+
trace("render-end", {
|
|
1665
|
+
durationMs: nowTerminalGraphicTraceTime() - startedAt,
|
|
1666
|
+
sequenceChars: normalized.type === "terminal" ? normalized.sequence.length : 0,
|
|
1667
|
+
sequenceBytes: normalized.type === "terminal" ? normalized.sequenceBytes : 0
|
|
1668
|
+
});
|
|
1669
|
+
bump();
|
|
1670
|
+
if (normalized.type === "terminal") scheduler.invalidate({
|
|
1671
|
+
priority: "low",
|
|
1672
|
+
reason: "data"
|
|
1673
|
+
});
|
|
1674
|
+
} catch (err) {
|
|
1675
|
+
if (abort.signal.aborted) return;
|
|
1676
|
+
if (!alive || version !== renderVersion) return;
|
|
1677
|
+
graphic.value = {
|
|
1678
|
+
type: "text",
|
|
1679
|
+
text: fallbackText()
|
|
1680
|
+
};
|
|
1681
|
+
lastRenderedContent = content;
|
|
1682
|
+
status.value = "ready";
|
|
1683
|
+
error.value = errorMessage(err);
|
|
1684
|
+
trace("render-end", {
|
|
1685
|
+
durationMs: nowTerminalGraphicTraceTime() - startedAt,
|
|
1686
|
+
reason: error.value
|
|
1687
|
+
});
|
|
1688
|
+
bump();
|
|
1689
|
+
} finally {
|
|
1690
|
+
if (renderAbort === abort) renderAbort = null;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
function scheduleRender(options = {}) {
|
|
1694
|
+
const version = ++renderVersion;
|
|
1695
|
+
if (options.clearLastGraphic ?? !props.preserveRawWhileRendering) queueClearLastGraphic();
|
|
1696
|
+
if (!builtOnce || !props.streaming) {
|
|
1697
|
+
builtOnce = true;
|
|
1698
|
+
renderNow(version);
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
const accepted = scheduler.queueFrameTask({
|
|
1702
|
+
id: frameTaskId,
|
|
1703
|
+
reason: "stream",
|
|
1704
|
+
priority: "low",
|
|
1705
|
+
sync: false,
|
|
1706
|
+
run: () => {
|
|
1707
|
+
if (!alive) return;
|
|
1708
|
+
if (version !== renderVersion) return;
|
|
1709
|
+
renderNow(version);
|
|
1710
|
+
}
|
|
1711
|
+
});
|
|
1712
|
+
if (accepted === false) renderNow(version);
|
|
1713
|
+
}
|
|
1714
|
+
watch([
|
|
1715
|
+
() => props.content,
|
|
1716
|
+
() => props.kind,
|
|
1717
|
+
() => props.renderer,
|
|
1718
|
+
() => props.w,
|
|
1719
|
+
() => props.h,
|
|
1720
|
+
() => props.streaming,
|
|
1721
|
+
() => props.final,
|
|
1722
|
+
() => props.deferRenderUntilVisible,
|
|
1723
|
+
() => props.suspendRawWhileScrolling,
|
|
1724
|
+
() => props.suspendRenderWhileScrolling,
|
|
1725
|
+
() => props.scrolling,
|
|
1726
|
+
() => props.preserveRawWhileRendering,
|
|
1727
|
+
() => props.suspended,
|
|
1728
|
+
() => props.retainRawWhileCovered,
|
|
1729
|
+
() => props.ignoreRawCoverage,
|
|
1730
|
+
() => props.ignoreSamePlaneRawCoverage,
|
|
1731
|
+
() => props.cacheKey,
|
|
1732
|
+
() => props.placementKey
|
|
1733
|
+
], () => {
|
|
1734
|
+
scheduleRender();
|
|
1735
|
+
}, { immediate: true });
|
|
1736
|
+
watch(() => props.fallback, () => {
|
|
1737
|
+
const current = graphic.value;
|
|
1738
|
+
if (current?.type === "terminal") {
|
|
1739
|
+
if (current.fallbackFromProps) {
|
|
1740
|
+
graphic.value = {
|
|
1741
|
+
...current,
|
|
1742
|
+
fallback: fallbackText()
|
|
1743
|
+
};
|
|
1744
|
+
bump();
|
|
1745
|
+
scheduler.invalidate({
|
|
1746
|
+
priority: "low",
|
|
1747
|
+
reason: "data"
|
|
1748
|
+
});
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
scheduleRender({ clearLastGraphic: false });
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
scheduleRender();
|
|
1755
|
+
});
|
|
1756
|
+
watch(() => [graphicsOutputVersion.value, rawOutputCanRenderValue.value], () => {
|
|
1757
|
+
if (!props.renderer || !props.content.trim()) return;
|
|
1758
|
+
if (graphic.value?.type === "terminal") return;
|
|
1759
|
+
if (!rawOutputCanRenderValue.value || shouldDeferRender()) return;
|
|
1760
|
+
scheduleRender({ clearLastGraphic: false });
|
|
1761
|
+
});
|
|
1762
|
+
watch(() => [
|
|
1763
|
+
props.x,
|
|
1764
|
+
props.y,
|
|
1765
|
+
props.w,
|
|
1766
|
+
props.h,
|
|
1767
|
+
props.scrollVersion
|
|
1768
|
+
], () => {
|
|
1769
|
+
if (graphic.value?.type === "terminal") {
|
|
1770
|
+
scheduler.invalidate({
|
|
1771
|
+
priority: "low",
|
|
1772
|
+
reason: "data"
|
|
1773
|
+
});
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
if (props.kind !== "image" || status.value !== "loading" || !props.renderer) return;
|
|
1777
|
+
scheduleRender({ clearLastGraphic: false });
|
|
1778
|
+
}, { flush: "sync" });
|
|
1779
|
+
onBeforeUnmount(() => {
|
|
1780
|
+
alive = false;
|
|
1781
|
+
renderVersion++;
|
|
1782
|
+
unsubscribeTerminalResize();
|
|
1783
|
+
unsubscribeGraphicsOutput();
|
|
1784
|
+
abortCurrentRender("unmount");
|
|
1785
|
+
scheduler.cancelFrameTask?.(frameTaskId);
|
|
1786
|
+
queueClearLastGraphic();
|
|
1787
|
+
});
|
|
1788
|
+
function resolveDisplayLines(rawPlaceholderAllowed) {
|
|
1789
|
+
if (showingInitialLoadingText.value) return splitTextOutput(props.loadingText);
|
|
1790
|
+
const current = graphic.value;
|
|
1791
|
+
if (!current) return splitTextOutput(fallbackText());
|
|
1792
|
+
if (current.type === "terminal" && rawPlaceholderAllowed) {
|
|
1793
|
+
const clearSequence = resolveClearSequence(current);
|
|
1794
|
+
const drawKey = terminalDrawKey(current, absRect.value, clearSequence, resolveResizeSequence(current, absRect.value, fullRect.value));
|
|
1795
|
+
if (rawDrawRejectedKey.value !== drawKey) return markRaw([""]);
|
|
1796
|
+
}
|
|
1797
|
+
const text = current.type === "terminal" ? current.fallback : current.text;
|
|
1798
|
+
const lines = splitTextOutput(text);
|
|
1799
|
+
return text.trim().length > 0 && !hasVisibleOutput(lines) ? splitTextOutput(fallbackText()) : lines;
|
|
1800
|
+
}
|
|
1801
|
+
const displayLines = computed(() => {
|
|
1802
|
+
return resolveDisplayLines(rawCanQueue.value);
|
|
1803
|
+
});
|
|
1804
|
+
const currentStyle = computed(() => {
|
|
1805
|
+
if (error.value) return props.errorStyle ?? props.style ?? defaultStyle.value;
|
|
1806
|
+
if (showingInitialLoadingText.value) return props.loadingStyle ?? props.style ?? defaultStyle.value;
|
|
1807
|
+
return props.style ?? defaultStyle.value;
|
|
1808
|
+
});
|
|
1809
|
+
const renderNode = useRenderNode(() => ({
|
|
1810
|
+
zIndex: props.zIndex,
|
|
1811
|
+
rect: visible.value ? renderRect.value : {
|
|
1812
|
+
x: 0,
|
|
1813
|
+
y: 0,
|
|
1814
|
+
w: 0,
|
|
1815
|
+
h: 0
|
|
1816
|
+
},
|
|
1817
|
+
deps: [
|
|
1818
|
+
visible.value,
|
|
1819
|
+
renderRect.value,
|
|
1820
|
+
fullRect.value,
|
|
1821
|
+
displayLines.value,
|
|
1822
|
+
currentStyle.value,
|
|
1823
|
+
props.clear,
|
|
1824
|
+
status.value,
|
|
1825
|
+
error.value,
|
|
1826
|
+
documentVersion.value,
|
|
1827
|
+
rawOutputCanRenderValue.value,
|
|
1828
|
+
rawCanRender.value,
|
|
1829
|
+
rawCanQueue.value,
|
|
1830
|
+
rawClearPendingRepaint.value,
|
|
1831
|
+
rawDrawRejectedKey.value,
|
|
1832
|
+
rawSuppressedByScroll.value,
|
|
1833
|
+
props.placementMoveWithoutClear,
|
|
1834
|
+
props.retainRawWhileCovered,
|
|
1835
|
+
isParentScrolling.value,
|
|
1836
|
+
graphicsActivityVersion.value,
|
|
1837
|
+
graphicsOutputVersion.value
|
|
1838
|
+
],
|
|
1839
|
+
paint: (dirtyRows) => {
|
|
1840
|
+
withTextWidthProvider(widthProvider, () => {
|
|
1841
|
+
if (!visible.value) {
|
|
1842
|
+
queueClearLastGraphic();
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
const r = absRect.value;
|
|
1846
|
+
const full = fullRect.value;
|
|
1847
|
+
if (r.w <= 0 || r.h <= 0) {
|
|
1848
|
+
queueClearLastGraphic();
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
const style = currentStyle.value;
|
|
1852
|
+
const dx = Math.max(0, Math.floor(r.x - full.x));
|
|
1853
|
+
const fullY = Math.floor(full.y);
|
|
1854
|
+
const current = graphic.value;
|
|
1855
|
+
const output = graphicsOutput();
|
|
1856
|
+
const retainedActiveRawGraphic = hasRetainedActiveRawGraphic();
|
|
1857
|
+
const rawRectForPaint = rawUncoveredRenderRect(r);
|
|
1858
|
+
const rawCoverageClipped = rawRectForPaint != null && props.ignoreRawCoverage && !sameRect(rawRectForPaint, r);
|
|
1859
|
+
const rawCoveredForPaint = rawRectForPaint == null && rawCoveredByHigherRenderNode(r);
|
|
1860
|
+
const rawCanQueueForPaint = current?.type === "terminal" && rawCanQueue.value && rawRectForPaint != null;
|
|
1861
|
+
let preserveActiveRawGraphic = false;
|
|
1862
|
+
let forceActiveRawRedraw = false;
|
|
1863
|
+
let allowTextOverlay = false;
|
|
1864
|
+
if (rawCanQueueForPaint && output) {
|
|
1865
|
+
const previous = lastDrawnGraphic.value;
|
|
1866
|
+
const previousStillActive = previous ? typeof output.isActive === "function" ? output.isActive(previous.id) : true : false;
|
|
1867
|
+
if (previousStillActive && previous) {
|
|
1868
|
+
const clearSequence = resolveClearSequence(current);
|
|
1869
|
+
const resizeSequence = resolveResizeSequence(current, rawRectForPaint, full);
|
|
1870
|
+
preserveActiveRawGraphic = rawClearPendingRepaint.value == null && previous.drawKey === terminalDrawKey(current, rawRectForPaint, clearSequence, resizeSequence);
|
|
1871
|
+
allowTextOverlay = retainedRawCoveredByHigherRenderNode(r);
|
|
1872
|
+
forceActiveRawRedraw = preserveActiveRawGraphic && (previous.activityVersion !== graphicsActivityVersion.value || previous.allowTextOverlay !== allowTextOverlay);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
const preserveActiveRawGraphicForPaint = preserveActiveRawGraphic;
|
|
1876
|
+
let out = rawCanQueueForPaint ? displayLines.value : resolveDisplayLines(false);
|
|
1877
|
+
const clearingRawGraphic = rawClearPendingRepaint.value != null || lastDrawnGraphic.value != null && !preserveActiveRawGraphicForPaint;
|
|
1878
|
+
const clearOwnedRegion = preserveActiveRawGraphicForPaint || retainedActiveRawGraphic ? false : props.clear || clearingRawGraphic || Boolean(rawCanQueueForPaint);
|
|
1879
|
+
const blank = clearOwnedRegion ? spaces(r.w) : "";
|
|
1880
|
+
const paintRow = (y) => {
|
|
1881
|
+
if (y < r.y || y >= r.y + r.h) return;
|
|
1882
|
+
const rowIndex = y - fullY;
|
|
1883
|
+
if (rowIndex < 0 || rowIndex >= out.length) {
|
|
1884
|
+
if (clearOwnedRegion) terminal.write(blank, {
|
|
1885
|
+
x: r.x,
|
|
1886
|
+
y,
|
|
1887
|
+
style
|
|
1888
|
+
});
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
const src = out[rowIndex] ?? "";
|
|
1892
|
+
const clipped = dx > 0 ? sliceByCellsRange(src, dx, dx + r.w) : sliceByCells(src, r.w);
|
|
1893
|
+
const value = clearOwnedRegion ? padEndByCells(clipped, r.w) : clipped;
|
|
1894
|
+
if (value || clearOwnedRegion) terminal.write(value, {
|
|
1895
|
+
x: r.x,
|
|
1896
|
+
y,
|
|
1897
|
+
style
|
|
1898
|
+
});
|
|
1899
|
+
};
|
|
1900
|
+
const paintRows = () => {
|
|
1901
|
+
if (dirtyRows?.length) for (const y of dirtyRows) paintRow(y);
|
|
1902
|
+
else for (let y = r.y; y < r.y + r.h; y++) paintRow(y);
|
|
1903
|
+
};
|
|
1904
|
+
paintRows();
|
|
1905
|
+
if (current?.type === "terminal" && output?.capabilities.supported && output.capabilities.preferredProtocol === current.protocol && rawCanQueueForPaint) {
|
|
1906
|
+
const drawKey = terminalDrawKey(current, rawRectForPaint, resolveClearSequence(current), resolveResizeSequence(current, rawRectForPaint, full));
|
|
1907
|
+
const queued = queueDrawGraphic(output, current, rawRectForPaint, full, {
|
|
1908
|
+
force: forceActiveRawRedraw,
|
|
1909
|
+
deferFlush: preserveActiveRawGraphicForPaint,
|
|
1910
|
+
placementMoveWithoutClear: props.placementMoveWithoutClear || rawCoverageClipped,
|
|
1911
|
+
allowTextOverlay
|
|
1912
|
+
});
|
|
1913
|
+
if (queued) trace("raw-draw", {
|
|
1914
|
+
sequenceChars: current.sequence.length,
|
|
1915
|
+
sequenceBytes: current.sequenceBytes,
|
|
1916
|
+
x: rawRectForPaint.x,
|
|
1917
|
+
y: rawRectForPaint.y,
|
|
1918
|
+
w: rawRectForPaint.w,
|
|
1919
|
+
h: rawRectForPaint.h
|
|
1920
|
+
});
|
|
1921
|
+
else if (rawDrawRejectedKey.value === drawKey) {
|
|
1922
|
+
out = resolveDisplayLines(false);
|
|
1923
|
+
paintRows();
|
|
1924
|
+
}
|
|
1925
|
+
} else {
|
|
1926
|
+
if (current?.type === "terminal" && rawSuppressedByScroll.value) traceRawSkipScrollOnce(isParentScrolling.value ? "scrolling" : "suspended");
|
|
1927
|
+
queueClearLastGraphic({ markPendingRepaint: false });
|
|
1928
|
+
if (!shouldDeferRender() && shouldRetryTemporaryRawFallback(rawCoveredForPaint)) scheduleRender({ clearLastGraphic: false });
|
|
1929
|
+
}
|
|
1930
|
+
if (clearingRawGraphic) rawClearPendingRepaint.value = null;
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
}));
|
|
1934
|
+
watch(renderNode.id, (id) => {
|
|
1935
|
+
renderNodeId.value = id;
|
|
1936
|
+
}, { immediate: true });
|
|
1937
|
+
watch([
|
|
1938
|
+
visible,
|
|
1939
|
+
rawOutputCanRenderValue,
|
|
1940
|
+
rawCanRender,
|
|
1941
|
+
rawCanQueue,
|
|
1942
|
+
rawSuppressedByScroll,
|
|
1943
|
+
isParentScrolling,
|
|
1944
|
+
graphicsActivityVersion,
|
|
1945
|
+
graphicsOutputVersion,
|
|
1946
|
+
() => renderRect.value.x,
|
|
1947
|
+
() => renderRect.value.y,
|
|
1948
|
+
() => renderRect.value.w,
|
|
1949
|
+
() => renderRect.value.h,
|
|
1950
|
+
() => fullRect.value.x,
|
|
1951
|
+
() => fullRect.value.y,
|
|
1952
|
+
() => fullRect.value.w,
|
|
1953
|
+
() => fullRect.value.h
|
|
1954
|
+
], () => {
|
|
1955
|
+
if (!alive) return;
|
|
1956
|
+
const deferred = renderDeferReason();
|
|
1957
|
+
if (deferred) {
|
|
1958
|
+
abortCurrentRender(deferred);
|
|
1959
|
+
if (status.value === "loading" || !graphic.value || lastRenderedContent !== props.content) setDeferredFallback(props.content);
|
|
1960
|
+
traceDeferOnce(deferred);
|
|
1961
|
+
}
|
|
1962
|
+
if (!visible.value || !rawCanQueue.value) queueClearLastGraphic();
|
|
1963
|
+
const shouldRetryTemporaryFallback = shouldRetryTemporaryRawFallback();
|
|
1964
|
+
const shouldRerenderForOutputChange = shouldRerenderForGraphicsOutputChange();
|
|
1965
|
+
if (!shouldDeferRender() && (!graphic.value || status.value === "idle" || shouldRetryTemporaryFallback || shouldRerenderForOutputChange)) {
|
|
1966
|
+
scheduleRender();
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1969
|
+
scheduler.invalidate({
|
|
1970
|
+
priority: "low",
|
|
1971
|
+
reason: "data"
|
|
1972
|
+
});
|
|
1973
|
+
}, { flush: "post" });
|
|
1974
|
+
return () => h("span", rootProps);
|
|
1975
|
+
}
|
|
1976
|
+
});
|
|
1977
|
+
|
|
768
1978
|
//#endregion
|
|
769
1979
|
//#region src/vue/transcript/layout.ts
|
|
770
1980
|
function styleForAction(action) {
|
|
@@ -1126,6 +2336,10 @@ const TVirtualRows = defineComponent({
|
|
|
1126
2336
|
rowScrollMode: {
|
|
1127
2337
|
type: String,
|
|
1128
2338
|
default: "off"
|
|
2339
|
+
},
|
|
2340
|
+
terminalGraphicScrollIdleMs: {
|
|
2341
|
+
type: Number,
|
|
2342
|
+
default: 96
|
|
1129
2343
|
}
|
|
1130
2344
|
},
|
|
1131
2345
|
emits: [
|
|
@@ -1167,6 +2381,13 @@ const TVirtualRows = defineComponent({
|
|
|
1167
2381
|
provide(RenderStackKey, childStack);
|
|
1168
2382
|
provide(EventZIndexContextKey, eventZ);
|
|
1169
2383
|
const virtualRowsInstanceId = ++virtualRowsInstanceSeq;
|
|
2384
|
+
const parentTerminalGraphicsActivity = inject(TerminalGraphicsActivityKey, null);
|
|
2385
|
+
const terminalGraphicsActivity = createTerminalGraphicsActivity({
|
|
2386
|
+
scrollIdleMs: props.terminalGraphicScrollIdleMs,
|
|
2387
|
+
traceId: `TVirtualRows:${virtualRowsInstanceId}:terminal-graphics`
|
|
2388
|
+
});
|
|
2389
|
+
provide(TerminalGraphicsActivityKey, createCombinedTerminalGraphicsActivity(parentTerminalGraphicsActivity, terminalGraphicsActivity));
|
|
2390
|
+
watch(() => props.terminalGraphicScrollIdleMs, (value) => terminalGraphicsActivity.setScrollIdleMs(value));
|
|
1170
2391
|
const frameTaskId = `TVirtualRows:${virtualRowsInstanceId}`;
|
|
1171
2392
|
const innerScrollTop = ref(0);
|
|
1172
2393
|
const controlledScrollTop = ref(0);
|
|
@@ -1305,10 +2526,12 @@ const TVirtualRows = defineComponent({
|
|
|
1305
2526
|
const delta = clampedTop - prevTop;
|
|
1306
2527
|
if (!delta) return false;
|
|
1307
2528
|
if (isScrollControlled()) {
|
|
2529
|
+
terminalGraphicsActivity.markScroll();
|
|
1308
2530
|
if (options?.emitUpdate !== false) emit("update:scrollTop", clampedTop);
|
|
1309
2531
|
if (options?.emitScroll) emitScroll(clampedTop);
|
|
1310
2532
|
return true;
|
|
1311
2533
|
}
|
|
2534
|
+
terminalGraphicsActivity.markScroll();
|
|
1312
2535
|
setCurrentScrollTop(clampedTop);
|
|
1313
2536
|
if (options?.emitUpdate !== false) emit("update:scrollTop", clampedTop);
|
|
1314
2537
|
markScrollDamage(prevTop, clampedTop, options?.strategy);
|
|
@@ -1607,6 +2830,7 @@ const TVirtualRows = defineComponent({
|
|
|
1607
2830
|
cancelWheelScrollFrame();
|
|
1608
2831
|
const prevTop = controlledScrollTop.value;
|
|
1609
2832
|
controlledScrollTop.value = nextTop;
|
|
2833
|
+
terminalGraphicsActivity.markScroll();
|
|
1610
2834
|
markScrollDamage(prevTop, nextTop);
|
|
1611
2835
|
selection.refresh(pendingSelectionScrollFocusRemap ? { remapFocus: true } : void 0);
|
|
1612
2836
|
pendingSelectionScrollFocusRemap = false;
|
|
@@ -1655,6 +2879,7 @@ const TVirtualRows = defineComponent({
|
|
|
1655
2879
|
pendingWheelTop = null;
|
|
1656
2880
|
resetWheelScrollState(wheelState);
|
|
1657
2881
|
wheelMailbox.dispose();
|
|
2882
|
+
terminalGraphicsActivity.dispose();
|
|
1658
2883
|
});
|
|
1659
2884
|
const renderNode = useRenderNode(() => ({
|
|
1660
2885
|
zIndex: props.zIndex,
|
|
@@ -8024,7 +9249,7 @@ const TLogLinksPanel = defineComponent({
|
|
|
8024
9249
|
|
|
8025
9250
|
//#endregion
|
|
8026
9251
|
//#region src/vue/components/TLogVirtualSearchResults.ts
|
|
8027
|
-
function sliceByCells(text, start, end) {
|
|
9252
|
+
function sliceByCells$1(text, start, end) {
|
|
8028
9253
|
let cells = 0;
|
|
8029
9254
|
let out = "";
|
|
8030
9255
|
for (const ch of text) {
|
|
@@ -8040,9 +9265,9 @@ function formatItem$1(item, width, showLineNumbers) {
|
|
|
8040
9265
|
if (!item) return "";
|
|
8041
9266
|
const currentPrefix = item.current ? "*" : " ";
|
|
8042
9267
|
const linePrefix = showLineNumbers ? `${String(item.absoluteLineIndex).padStart(5, " ")} ` : "";
|
|
8043
|
-
const before = sliceByCells(item.text, 0, item.matchStartCell);
|
|
8044
|
-
const match = sliceByCells(item.text, item.matchStartCell, item.matchEndCell);
|
|
8045
|
-
const after = sliceByCells(item.text, item.matchEndCell, Number.MAX_SAFE_INTEGER);
|
|
9268
|
+
const before = sliceByCells$1(item.text, 0, item.matchStartCell);
|
|
9269
|
+
const match = sliceByCells$1(item.text, item.matchStartCell, item.matchEndCell);
|
|
9270
|
+
const after = sliceByCells$1(item.text, item.matchEndCell, Number.MAX_SAFE_INTEGER);
|
|
8046
9271
|
const formatted = `${currentPrefix}${linePrefix}${before}[${match}]${after}`;
|
|
8047
9272
|
return formatted.slice(0, Math.max(0, width));
|
|
8048
9273
|
}
|
|
@@ -9690,4 +10915,4 @@ function resolveTLogMinimapTheme(theme) {
|
|
|
9690
10915
|
}
|
|
9691
10916
|
|
|
9692
10917
|
//#endregion
|
|
9693
|
-
export { TLogLinksPanel, TLogMinimap, TLogScrollbar, TLogSearchBar, TLogSearchPager, TLogSearchResults, TLogView, TLogVirtualLinksPanel, TLogVirtualSearchResults, TTranscriptView, TVirtualList, createAppendOnlyLogStore, createTLogDensityBucketsFromMarkers, createTLogLevelPlugin, createTLogLineMatcherPlugin, createTLogLinkActionPlugin, createTLogOsc8LinkPlugin, createTLogUrlPlugin, detectTLogUrls, dispatchTLogPluginLinkAction, getTLogPluginMetadata, handleTLogKeymapEvent, matchesTLogKeyBinding, parseTLogAnnotatedText, resolveTLogLinksPanelTheme, resolveTLogMinimapTheme, resolveTLogScrollbarTheme, resolveTLogSearchBarTheme, resolveTLogSearchPagerTheme, resolveTLogSearchResultsTheme, resolveTLogViewTheme, stripTLogAnsiText, tlogDarkPreset, tlogDarkTheme, tlogDefaultKeymap, tlogDefaultPreset, tlogDefaultTheme, tlogHighContrastKeymap, tlogHighContrastPreset, tlogHighContrastTheme, toTLogExternalLinkFromVisibleLink, useTLogLinkController, useTLogRetainedIndex, useTLogSearchController, useTLogSearchResultsPage, useTLogVirtualSearchResults };
|
|
10918
|
+
export { TAgentTerminalGraphic, TLogLinksPanel, TLogMinimap, TLogScrollbar, TLogSearchBar, TLogSearchPager, TLogSearchResults, TLogView, TLogVirtualLinksPanel, TLogVirtualSearchResults, TTranscriptView, TVirtualList, createAppendOnlyLogStore, createTLogDensityBucketsFromMarkers, createTLogLevelPlugin, createTLogLineMatcherPlugin, createTLogLinkActionPlugin, createTLogOsc8LinkPlugin, createTLogUrlPlugin, detectTLogUrls, dispatchTLogPluginLinkAction, getTLogPluginMetadata, handleTLogKeymapEvent, matchesTLogKeyBinding, parseTLogAnnotatedText, resolveTLogLinksPanelTheme, resolveTLogMinimapTheme, resolveTLogScrollbarTheme, resolveTLogSearchBarTheme, resolveTLogSearchPagerTheme, resolveTLogSearchResultsTheme, resolveTLogViewTheme, stripTLogAnsiText, tlogDarkPreset, tlogDarkTheme, tlogDefaultKeymap, tlogDefaultPreset, tlogDefaultTheme, tlogHighContrastKeymap, tlogHighContrastPreset, tlogHighContrastTheme, toTLogExternalLinkFromVisibleLink, useTLogLinkController, useTLogRetainedIndex, useTLogSearchController, useTLogSearchResultsPage, useTLogVirtualSearchResults };
|