@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
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
//#region src/observability/frame-perf.ts
|
|
2
|
+
const FRAME_PERF_REASON_PRIORITY = {
|
|
3
|
+
unknown: 0,
|
|
4
|
+
manual: 1,
|
|
5
|
+
data: 2,
|
|
6
|
+
selection: 3,
|
|
7
|
+
stream: 4,
|
|
8
|
+
resize: 5,
|
|
9
|
+
scroll: 6,
|
|
10
|
+
input: 7
|
|
11
|
+
};
|
|
12
|
+
const EMPTY_METRIC_STATS = Object.freeze({
|
|
13
|
+
avg: 0,
|
|
14
|
+
max: 0,
|
|
15
|
+
min: 0
|
|
16
|
+
});
|
|
17
|
+
function metricStats(values) {
|
|
18
|
+
if (!values.length) return EMPTY_METRIC_STATS;
|
|
19
|
+
let sum = 0;
|
|
20
|
+
let max = Number.NEGATIVE_INFINITY;
|
|
21
|
+
let min = Number.POSITIVE_INFINITY;
|
|
22
|
+
for (const value of values) {
|
|
23
|
+
sum += value;
|
|
24
|
+
if (value > max) max = value;
|
|
25
|
+
if (value < min) min = value;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
avg: sum / values.length,
|
|
29
|
+
max,
|
|
30
|
+
min
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function summarizeFramePerf(samples) {
|
|
34
|
+
const durationMs = [];
|
|
35
|
+
const renderManagerMs = [];
|
|
36
|
+
const commitMs = [];
|
|
37
|
+
const domFlushMs = [];
|
|
38
|
+
const stdoutFlushMs = [];
|
|
39
|
+
const dirtyRows = [];
|
|
40
|
+
const scannedNodes = [];
|
|
41
|
+
const paintedNodes = [];
|
|
42
|
+
const reasons = {};
|
|
43
|
+
const activePlanes = {};
|
|
44
|
+
let fullDirtyFrames = 0;
|
|
45
|
+
let coalescedInvalidates = 0;
|
|
46
|
+
let coalescedFrameTasks = 0;
|
|
47
|
+
let droppedUpdates = 0;
|
|
48
|
+
let maxQueueDepth = 0;
|
|
49
|
+
let rowBucketFallbacks = 0;
|
|
50
|
+
for (const sample of samples) {
|
|
51
|
+
durationMs.push(sample.durationMs);
|
|
52
|
+
renderManagerMs.push(sample.renderManagerMs);
|
|
53
|
+
commitMs.push(sample.commitMs);
|
|
54
|
+
scannedNodes.push(sample.scannedNodes);
|
|
55
|
+
paintedNodes.push(sample.paintedNodes);
|
|
56
|
+
if (sample.domFlushMs != null) domFlushMs.push(sample.domFlushMs);
|
|
57
|
+
if (sample.stdoutFlushMs != null) stdoutFlushMs.push(sample.stdoutFlushMs);
|
|
58
|
+
if (sample.dirtyRows == null) fullDirtyFrames++;
|
|
59
|
+
else dirtyRows.push(sample.dirtyRows);
|
|
60
|
+
reasons[sample.reason] = (reasons[sample.reason] ?? 0) + 1;
|
|
61
|
+
const planes = sample.activePlanes;
|
|
62
|
+
if (!planes) activePlanes.all = (activePlanes.all ?? 0) + 1;
|
|
63
|
+
else for (const plane of planes) activePlanes[plane] = (activePlanes[plane] ?? 0) + 1;
|
|
64
|
+
coalescedInvalidates += sample.coalescedInvalidates;
|
|
65
|
+
coalescedFrameTasks += sample.coalescedFrameTasks;
|
|
66
|
+
droppedUpdates += sample.droppedUpdates;
|
|
67
|
+
if (sample.queueDepth > maxQueueDepth) maxQueueDepth = sample.queueDepth;
|
|
68
|
+
rowBucketFallbacks += sample.rowBucketFallbacks?.length ?? 0;
|
|
69
|
+
}
|
|
70
|
+
const first = samples[0] ?? null;
|
|
71
|
+
const latest = samples[samples.length - 1] ?? null;
|
|
72
|
+
return {
|
|
73
|
+
frames: samples.length,
|
|
74
|
+
firstFrameId: first?.frameId ?? null,
|
|
75
|
+
latestFrameId: latest?.frameId ?? null,
|
|
76
|
+
windowMs: first && latest ? Math.max(0, latest.startedAt - first.startedAt) : 0,
|
|
77
|
+
durationMs: metricStats(durationMs),
|
|
78
|
+
renderManagerMs: metricStats(renderManagerMs),
|
|
79
|
+
commitMs: metricStats(commitMs),
|
|
80
|
+
domFlushMs: metricStats(domFlushMs),
|
|
81
|
+
stdoutFlushMs: metricStats(stdoutFlushMs),
|
|
82
|
+
dirtyRows: {
|
|
83
|
+
avg: dirtyRows.length ? dirtyRows.reduce((sum, value) => sum + value, 0) / dirtyRows.length : 0,
|
|
84
|
+
max: dirtyRows.length ? Math.max(...dirtyRows) : 0,
|
|
85
|
+
sampledFrames: dirtyRows.length,
|
|
86
|
+
fullFrames: fullDirtyFrames
|
|
87
|
+
},
|
|
88
|
+
scannedNodes: metricStats(scannedNodes),
|
|
89
|
+
paintedNodes: metricStats(paintedNodes),
|
|
90
|
+
coalescedInvalidates,
|
|
91
|
+
coalescedFrameTasks,
|
|
92
|
+
droppedUpdates,
|
|
93
|
+
maxQueueDepth,
|
|
94
|
+
rowBucketFallbacks,
|
|
95
|
+
reasons,
|
|
96
|
+
activePlanes
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function framePerfNow() {
|
|
100
|
+
const p = globalThis.performance;
|
|
101
|
+
if (p && typeof p.now === "function") return p.now();
|
|
102
|
+
return Date.now();
|
|
103
|
+
}
|
|
104
|
+
function mergeFramePerfReason(prev, next) {
|
|
105
|
+
const a = prev ?? "unknown";
|
|
106
|
+
const b = next ?? "unknown";
|
|
107
|
+
return FRAME_PERF_REASON_PRIORITY[b] > FRAME_PERF_REASON_PRIORITY[a] ? b : a;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
export { framePerfNow, mergeFramePerfReason, summarizeFramePerf };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { charCellWidth, segmentedGraphemes } from "./
|
|
2
|
-
import { parseAnsiSgr } from "./sgr-BmzxEjAO.js";
|
|
1
|
+
import { charCellWidth, segmentedGraphemes } from "./width-GqllnV8C.js";
|
|
3
2
|
|
|
4
3
|
//#region src/core/render-plane.ts
|
|
5
4
|
const TERMINAL_RENDER_PLANES = [
|
|
@@ -9,6 +8,309 @@ const TERMINAL_RENDER_PLANES = [
|
|
|
9
8
|
"overlay"
|
|
10
9
|
];
|
|
11
10
|
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/core/ansi/sgr.ts
|
|
13
|
+
const ESC = "\x1B";
|
|
14
|
+
function ansi16ToColorName(code) {
|
|
15
|
+
switch (code) {
|
|
16
|
+
case 30: return "black";
|
|
17
|
+
case 31: return "red";
|
|
18
|
+
case 32: return "green";
|
|
19
|
+
case 33: return "yellow";
|
|
20
|
+
case 34: return "blue";
|
|
21
|
+
case 35: return "magenta";
|
|
22
|
+
case 36: return "cyan";
|
|
23
|
+
case 37: return "white";
|
|
24
|
+
case 90: return "blackBright";
|
|
25
|
+
case 91: return "redBright";
|
|
26
|
+
case 92: return "greenBright";
|
|
27
|
+
case 93: return "yellowBright";
|
|
28
|
+
case 94: return "blueBright";
|
|
29
|
+
case 95: return "magentaBright";
|
|
30
|
+
case 96: return "cyanBright";
|
|
31
|
+
case 97: return "whiteBright";
|
|
32
|
+
default: return void 0;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function ansi16BgToColorName(code) {
|
|
36
|
+
const fgCode = code >= 40 && code <= 47 ? code - 10 : code >= 100 && code <= 107 ? code - 10 : null;
|
|
37
|
+
if (fgCode == null) return void 0;
|
|
38
|
+
return ansi16ToColorName(fgCode);
|
|
39
|
+
}
|
|
40
|
+
const ANSI16_RGB = {
|
|
41
|
+
black: {
|
|
42
|
+
r: 0,
|
|
43
|
+
g: 0,
|
|
44
|
+
b: 0
|
|
45
|
+
},
|
|
46
|
+
red: {
|
|
47
|
+
r: 201,
|
|
48
|
+
g: 27,
|
|
49
|
+
b: 0
|
|
50
|
+
},
|
|
51
|
+
green: {
|
|
52
|
+
r: 0,
|
|
53
|
+
g: 194,
|
|
54
|
+
b: 0
|
|
55
|
+
},
|
|
56
|
+
yellow: {
|
|
57
|
+
r: 199,
|
|
58
|
+
g: 196,
|
|
59
|
+
b: 0
|
|
60
|
+
},
|
|
61
|
+
blue: {
|
|
62
|
+
r: 2,
|
|
63
|
+
g: 37,
|
|
64
|
+
b: 199
|
|
65
|
+
},
|
|
66
|
+
magenta: {
|
|
67
|
+
r: 201,
|
|
68
|
+
g: 48,
|
|
69
|
+
b: 199
|
|
70
|
+
},
|
|
71
|
+
cyan: {
|
|
72
|
+
r: 0,
|
|
73
|
+
g: 197,
|
|
74
|
+
b: 199
|
|
75
|
+
},
|
|
76
|
+
white: {
|
|
77
|
+
r: 199,
|
|
78
|
+
g: 199,
|
|
79
|
+
b: 199
|
|
80
|
+
},
|
|
81
|
+
blackBright: {
|
|
82
|
+
r: 104,
|
|
83
|
+
g: 104,
|
|
84
|
+
b: 104
|
|
85
|
+
},
|
|
86
|
+
redBright: {
|
|
87
|
+
r: 255,
|
|
88
|
+
g: 110,
|
|
89
|
+
b: 103
|
|
90
|
+
},
|
|
91
|
+
greenBright: {
|
|
92
|
+
r: 95,
|
|
93
|
+
g: 250,
|
|
94
|
+
b: 104
|
|
95
|
+
},
|
|
96
|
+
yellowBright: {
|
|
97
|
+
r: 255,
|
|
98
|
+
g: 252,
|
|
99
|
+
b: 103
|
|
100
|
+
},
|
|
101
|
+
blueBright: {
|
|
102
|
+
r: 104,
|
|
103
|
+
g: 113,
|
|
104
|
+
b: 255
|
|
105
|
+
},
|
|
106
|
+
magentaBright: {
|
|
107
|
+
r: 255,
|
|
108
|
+
g: 118,
|
|
109
|
+
b: 255
|
|
110
|
+
},
|
|
111
|
+
cyanBright: {
|
|
112
|
+
r: 95,
|
|
113
|
+
g: 253,
|
|
114
|
+
b: 255
|
|
115
|
+
},
|
|
116
|
+
whiteBright: {
|
|
117
|
+
r: 255,
|
|
118
|
+
g: 255,
|
|
119
|
+
b: 255
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
function nearestAnsi16(r, g, b) {
|
|
123
|
+
let best = "white";
|
|
124
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
125
|
+
for (const [name, rgb] of Object.entries(ANSI16_RGB)) {
|
|
126
|
+
const dr = r - rgb.r;
|
|
127
|
+
const dg = g - rgb.g;
|
|
128
|
+
const db = b - rgb.b;
|
|
129
|
+
const d = dr * dr + dg * dg + db * db;
|
|
130
|
+
if (d < bestDist) {
|
|
131
|
+
bestDist = d;
|
|
132
|
+
best = name;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return best;
|
|
136
|
+
}
|
|
137
|
+
function ansi256ToRgb(index) {
|
|
138
|
+
const n = Math.max(0, Math.min(255, Math.trunc(index)));
|
|
139
|
+
if (n < 16) {
|
|
140
|
+
const map = [
|
|
141
|
+
"black",
|
|
142
|
+
"red",
|
|
143
|
+
"green",
|
|
144
|
+
"yellow",
|
|
145
|
+
"blue",
|
|
146
|
+
"magenta",
|
|
147
|
+
"cyan",
|
|
148
|
+
"white",
|
|
149
|
+
"blackBright",
|
|
150
|
+
"redBright",
|
|
151
|
+
"greenBright",
|
|
152
|
+
"yellowBright",
|
|
153
|
+
"blueBright",
|
|
154
|
+
"magentaBright",
|
|
155
|
+
"cyanBright",
|
|
156
|
+
"whiteBright"
|
|
157
|
+
];
|
|
158
|
+
const name = map[n] ?? "white";
|
|
159
|
+
return ANSI16_RGB[name];
|
|
160
|
+
}
|
|
161
|
+
if (n >= 232) {
|
|
162
|
+
const c = 8 + (n - 232) * 10;
|
|
163
|
+
return {
|
|
164
|
+
r: c,
|
|
165
|
+
g: c,
|
|
166
|
+
b: c
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const i = n - 16;
|
|
170
|
+
const rr = Math.floor(i / 36);
|
|
171
|
+
const gg = Math.floor(i % 36 / 6);
|
|
172
|
+
const bb = i % 6;
|
|
173
|
+
const toComponent = (v) => v === 0 ? 0 : 55 + v * 40;
|
|
174
|
+
return {
|
|
175
|
+
r: toComponent(rr),
|
|
176
|
+
g: toComponent(gg),
|
|
177
|
+
b: toComponent(bb)
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function applyAnsiSgrStyle(current, codes) {
|
|
181
|
+
let next = { ...current };
|
|
182
|
+
for (let i = 0; i < codes.length; i++) {
|
|
183
|
+
const code = codes[i];
|
|
184
|
+
if (code === 0) {
|
|
185
|
+
next = {};
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (code === 1) next = {
|
|
189
|
+
...next,
|
|
190
|
+
bold: true
|
|
191
|
+
};
|
|
192
|
+
else if (code === 2) next = {
|
|
193
|
+
...next,
|
|
194
|
+
dim: true
|
|
195
|
+
};
|
|
196
|
+
else if (code === 3) next = {
|
|
197
|
+
...next,
|
|
198
|
+
italic: true
|
|
199
|
+
};
|
|
200
|
+
else if (code === 4) next = {
|
|
201
|
+
...next,
|
|
202
|
+
underline: true
|
|
203
|
+
};
|
|
204
|
+
else if (code === 7) next = {
|
|
205
|
+
...next,
|
|
206
|
+
inverse: true
|
|
207
|
+
};
|
|
208
|
+
else if (code === 22) next = {
|
|
209
|
+
...next,
|
|
210
|
+
bold: false,
|
|
211
|
+
dim: false
|
|
212
|
+
};
|
|
213
|
+
else if (code === 23) next = {
|
|
214
|
+
...next,
|
|
215
|
+
italic: false
|
|
216
|
+
};
|
|
217
|
+
else if (code === 24) next = {
|
|
218
|
+
...next,
|
|
219
|
+
underline: false
|
|
220
|
+
};
|
|
221
|
+
else if (code === 27) next = {
|
|
222
|
+
...next,
|
|
223
|
+
inverse: false
|
|
224
|
+
};
|
|
225
|
+
else if (code === 39) next = {
|
|
226
|
+
...next,
|
|
227
|
+
fg: void 0
|
|
228
|
+
};
|
|
229
|
+
else if (code === 49) next = {
|
|
230
|
+
...next,
|
|
231
|
+
bg: void 0
|
|
232
|
+
};
|
|
233
|
+
else if (code >= 30 && code <= 37 || code >= 90 && code <= 97) {
|
|
234
|
+
const fg = ansi16ToColorName(code);
|
|
235
|
+
next = {
|
|
236
|
+
...next,
|
|
237
|
+
fg: fg ?? next.fg
|
|
238
|
+
};
|
|
239
|
+
} else if (code >= 40 && code <= 47 || code >= 100 && code <= 107) {
|
|
240
|
+
const bg = ansi16BgToColorName(code);
|
|
241
|
+
next = {
|
|
242
|
+
...next,
|
|
243
|
+
bg: bg ?? next.bg
|
|
244
|
+
};
|
|
245
|
+
} else if (code === 38 || code === 48) {
|
|
246
|
+
const mode = codes[i + 1];
|
|
247
|
+
if (mode === 5) {
|
|
248
|
+
const idx = codes[i + 2];
|
|
249
|
+
if (idx != null) {
|
|
250
|
+
const { r, g, b } = ansi256ToRgb(idx);
|
|
251
|
+
const name = nearestAnsi16(r, g, b);
|
|
252
|
+
next = code === 38 ? {
|
|
253
|
+
...next,
|
|
254
|
+
fg: name
|
|
255
|
+
} : {
|
|
256
|
+
...next,
|
|
257
|
+
bg: name
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
i += 2;
|
|
261
|
+
} else if (mode === 2) {
|
|
262
|
+
const r = codes[i + 2];
|
|
263
|
+
const g = codes[i + 3];
|
|
264
|
+
const b = codes[i + 4];
|
|
265
|
+
if (r != null && g != null && b != null) {
|
|
266
|
+
const name = nearestAnsi16(r, g, b);
|
|
267
|
+
next = code === 38 ? {
|
|
268
|
+
...next,
|
|
269
|
+
fg: name
|
|
270
|
+
} : {
|
|
271
|
+
...next,
|
|
272
|
+
bg: name
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
i += 4;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return next;
|
|
280
|
+
}
|
|
281
|
+
function parseAnsiSgr(input, baseStyle = {}) {
|
|
282
|
+
const segments = [];
|
|
283
|
+
let style = { ...baseStyle };
|
|
284
|
+
let lastIndex = 0;
|
|
285
|
+
for (let i = 0; i < input.length; i++) {
|
|
286
|
+
if (input[i] !== ESC || input[i + 1] !== "[") continue;
|
|
287
|
+
let j = i + 2;
|
|
288
|
+
while (j < input.length) {
|
|
289
|
+
const c = input.charCodeAt(j);
|
|
290
|
+
if (c >= 48 && c <= 57 || c === 59) {
|
|
291
|
+
j++;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
if (j >= input.length || input[j] !== "m") continue;
|
|
297
|
+
if (i > lastIndex) segments.push({
|
|
298
|
+
text: input.slice(lastIndex, i),
|
|
299
|
+
style
|
|
300
|
+
});
|
|
301
|
+
const body = input.slice(i + 2, j);
|
|
302
|
+
const codes = body.split(";").filter(Boolean).map((n) => Number.parseInt(n, 10)).filter((n) => Number.isFinite(n));
|
|
303
|
+
style = applyAnsiSgrStyle(style, codes.length ? codes : [0]);
|
|
304
|
+
lastIndex = j + 1;
|
|
305
|
+
i = j;
|
|
306
|
+
}
|
|
307
|
+
if (lastIndex < input.length) segments.push({
|
|
308
|
+
text: input.slice(lastIndex),
|
|
309
|
+
style
|
|
310
|
+
});
|
|
311
|
+
return segments;
|
|
312
|
+
}
|
|
313
|
+
|
|
12
314
|
//#endregion
|
|
13
315
|
//#region src/core/buffer/buffer.ts
|
|
14
316
|
const DEFAULT_STYLE = Object.freeze({});
|
|
@@ -106,14 +408,14 @@ function clamp(n, min, max) {
|
|
|
106
408
|
return Math.max(min, Math.min(max, n));
|
|
107
409
|
}
|
|
108
410
|
/**
|
|
109
|
-
* Register a fingerprint function on the buffer. This enables SoA fingerprint
|
|
411
|
+
* Register or clear a fingerprint function on the buffer. This enables SoA fingerprint
|
|
110
412
|
* pre-computation: cell writes will update fingerprints inline, and the renderer
|
|
111
413
|
* can read them via getRowFingerprints() instead of per-cell hash computation.
|
|
112
414
|
*/
|
|
113
415
|
function setFingerprintFn(buffer, fn) {
|
|
114
416
|
buffer.fingerprintFn = fn;
|
|
115
417
|
const len = buffer.rows * buffer.cols;
|
|
116
|
-
if (!len) {
|
|
418
|
+
if (!fn || !len) {
|
|
117
419
|
buffer.soaFingerprints = null;
|
|
118
420
|
return;
|
|
119
421
|
}
|
|
@@ -134,7 +436,10 @@ function setFingerprintFn(buffer, fn) {
|
|
|
134
436
|
*/
|
|
135
437
|
function getRowFingerprints(buffer, y) {
|
|
136
438
|
if (!buffer.soaFingerprints) return null;
|
|
137
|
-
|
|
439
|
+
if (buffer.rows <= 0 || buffer.cols <= 0) return null;
|
|
440
|
+
const yy = Math.floor(y);
|
|
441
|
+
if (!Number.isFinite(yy) || yy < 0 || yy >= buffer.rows) return null;
|
|
442
|
+
const physY = physicalRowIndex(buffer, yy);
|
|
138
443
|
const base = physY * buffer.cols;
|
|
139
444
|
return buffer.soaFingerprints.subarray(base, base + buffer.cols);
|
|
140
445
|
}
|
|
@@ -424,9 +729,12 @@ function resizeBuffer(buffer, cols, rows) {
|
|
|
424
729
|
const nextCols = Math.max(0, Math.floor(cols));
|
|
425
730
|
const nextRows = Math.max(0, Math.floor(rows));
|
|
426
731
|
if (nextCols === buffer.cols && nextRows === buffer.rows) return;
|
|
732
|
+
const prevRows = buffer.rows;
|
|
733
|
+
const prevDirtyAll = buffer.dirtyAll;
|
|
734
|
+
const prevDirtyBits = buffer.dirtyBits;
|
|
427
735
|
const blank = createBlankCell();
|
|
428
736
|
const nextGrid = Array.from({ length: nextRows }, () => Array.from({ length: nextCols }, () => blank));
|
|
429
|
-
const copyRows = Math.min(
|
|
737
|
+
const copyRows = Math.min(prevRows, nextRows);
|
|
430
738
|
const copyCols = Math.min(buffer.cols, nextCols);
|
|
431
739
|
for (let y = 0; y < copyRows; y++) {
|
|
432
740
|
const src = getBufferRow(buffer, y);
|
|
@@ -450,10 +758,21 @@ function resizeBuffer(buffer, cols, rows) {
|
|
|
450
758
|
buffer.cols = nextCols;
|
|
451
759
|
buffer.rows = nextRows;
|
|
452
760
|
buffer.dirtyBits = new Uint8Array(nextRows);
|
|
453
|
-
buffer.dirtyCount =
|
|
454
|
-
buffer.dirtyMin =
|
|
455
|
-
buffer.dirtyMax =
|
|
456
|
-
buffer.dirtyAll = nextRows > 0;
|
|
761
|
+
buffer.dirtyCount = 0;
|
|
762
|
+
buffer.dirtyMin = Number.POSITIVE_INFINITY;
|
|
763
|
+
buffer.dirtyMax = -1;
|
|
764
|
+
buffer.dirtyAll = prevDirtyAll && nextRows > 0;
|
|
765
|
+
if (buffer.dirtyAll) {
|
|
766
|
+
buffer.dirtyCount = nextRows;
|
|
767
|
+
buffer.dirtyMin = 0;
|
|
768
|
+
buffer.dirtyMax = nextRows - 1;
|
|
769
|
+
} else for (let y = 0; y < copyRows; y++) {
|
|
770
|
+
if (prevDirtyBits[y] !== 1) continue;
|
|
771
|
+
buffer.dirtyBits[y] = 1;
|
|
772
|
+
buffer.dirtyCount++;
|
|
773
|
+
if (y < buffer.dirtyMin) buffer.dirtyMin = y;
|
|
774
|
+
if (y > buffer.dirtyMax) buffer.dirtyMax = y;
|
|
775
|
+
}
|
|
457
776
|
buffer.cursorX = clamp(buffer.cursorX, 0, Math.max(0, nextCols));
|
|
458
777
|
buffer.cursorY = clamp(buffer.cursorY, 0, Math.max(0, nextRows - 1));
|
|
459
778
|
if (buffer.fingerprintFn) {
|
|
@@ -526,6 +845,10 @@ function mergePlanes(prev, next) {
|
|
|
526
845
|
return Array.from(merged);
|
|
527
846
|
}
|
|
528
847
|
const TERMINAL_PLANE_INTERNALS = Symbol.for("@simon_he/vue-tui:v1:terminal-plane-internals");
|
|
848
|
+
const TERMINAL_ROOT = Symbol.for("@simon_he/vue-tui:v1:terminal-root");
|
|
849
|
+
function getRootTerminal(terminal) {
|
|
850
|
+
return terminal[TERMINAL_ROOT] ?? terminal;
|
|
851
|
+
}
|
|
529
852
|
function createCoverage(cols, rows) {
|
|
530
853
|
return Array.from({ length: rows }, () => new Uint8Array(cols));
|
|
531
854
|
}
|
|
@@ -609,6 +932,8 @@ function markPlaneCoverageRange(state, x0, y0, x1, y1, value) {
|
|
|
609
932
|
}
|
|
610
933
|
}
|
|
611
934
|
function markPlaneCoverageForPut(state, x, y, ch, prevCell) {
|
|
935
|
+
if (!Number.isSafeInteger(x) || !Number.isSafeInteger(y)) return;
|
|
936
|
+
if (x < 0 || x >= state.buffer.cols || y < 0 || y >= state.buffer.rows) return;
|
|
612
937
|
const row = state.coverage[y];
|
|
613
938
|
if (!row) return;
|
|
614
939
|
if (prevCell?.continuation && x > 0) row[x - 1] = 1;
|
|
@@ -724,10 +1049,14 @@ function createTerminal(opts) {
|
|
|
724
1049
|
}
|
|
725
1050
|
function putForPlane(plane, x, y, ch, style) {
|
|
726
1051
|
const state = getPlaneState(plane);
|
|
727
|
-
if (
|
|
728
|
-
const
|
|
729
|
-
|
|
730
|
-
|
|
1052
|
+
if (typeof x !== "number" || typeof y !== "number") return;
|
|
1053
|
+
const cellX = Math.floor(x);
|
|
1054
|
+
const cellY = Math.floor(y);
|
|
1055
|
+
if (!Number.isFinite(cellX) || !Number.isFinite(cellY)) return;
|
|
1056
|
+
if (cellY < 0 || cellY >= state.buffer.rows || cellX < 0 || cellX >= state.buffer.cols) return;
|
|
1057
|
+
const prevCell = getBufferCell(state.buffer, cellX, cellY);
|
|
1058
|
+
putCell(state.buffer, cellX, cellY, ch, style);
|
|
1059
|
+
markPlaneCoverageForPut(state, cellX, cellY, ch, prevCell);
|
|
731
1060
|
}
|
|
732
1061
|
function writeAtForPlane(plane, text, x, y, style) {
|
|
733
1062
|
const state = getPlaneState(plane);
|
|
@@ -1219,13 +1548,18 @@ function createTerminal(opts) {
|
|
|
1219
1548
|
},
|
|
1220
1549
|
setFingerprintFn(fn) {
|
|
1221
1550
|
assertNotDisposed();
|
|
1222
|
-
|
|
1551
|
+
const state = getPlaneState(plane);
|
|
1552
|
+
setFingerprintFn(state.buffer, fn);
|
|
1223
1553
|
},
|
|
1224
1554
|
getRowFingerprints(y) {
|
|
1225
1555
|
assertNotDisposed();
|
|
1226
|
-
|
|
1556
|
+
const yy = Math.floor(y);
|
|
1557
|
+
const state = getPlaneState(plane);
|
|
1558
|
+
if (!Number.isFinite(yy) || yy < 0 || yy >= state.buffer.rows) throw new RangeError("Row out of bounds");
|
|
1559
|
+
return getRowFingerprints(state.buffer, yy);
|
|
1227
1560
|
}
|
|
1228
1561
|
};
|
|
1562
|
+
api[TERMINAL_ROOT] = base;
|
|
1229
1563
|
planeTerminals.set(plane, api);
|
|
1230
1564
|
return api;
|
|
1231
1565
|
}
|
|
@@ -1307,7 +1641,7 @@ function createTerminal(opts) {
|
|
|
1307
1641
|
const rows = collectAndClearDirtyRows(state.buffer);
|
|
1308
1642
|
if (rows === null) {
|
|
1309
1643
|
composeAllRows = true;
|
|
1310
|
-
|
|
1644
|
+
continue;
|
|
1311
1645
|
}
|
|
1312
1646
|
for (const y of rows) dirtyRows.add(y);
|
|
1313
1647
|
}
|
|
@@ -1397,7 +1731,9 @@ function createTerminal(opts) {
|
|
|
1397
1731
|
},
|
|
1398
1732
|
getRowFingerprints(y) {
|
|
1399
1733
|
assertNotDisposed();
|
|
1400
|
-
|
|
1734
|
+
const yy = Math.floor(y);
|
|
1735
|
+
if (!Number.isFinite(yy) || yy < 0 || yy >= compositeBuffer.rows) throw new RangeError("Row out of bounds");
|
|
1736
|
+
return getRowFingerprints(compositeBuffer, yy);
|
|
1401
1737
|
}
|
|
1402
1738
|
};
|
|
1403
1739
|
base[TERMINAL_PLANE_INTERNALS] = {
|
|
@@ -1427,8 +1763,108 @@ function createTerminal(opts) {
|
|
|
1427
1763
|
scrollRowsForPlane(plane, startY, endY, lines);
|
|
1428
1764
|
}
|
|
1429
1765
|
};
|
|
1766
|
+
base[TERMINAL_ROOT] = base;
|
|
1430
1767
|
return base;
|
|
1431
1768
|
}
|
|
1432
1769
|
|
|
1433
1770
|
//#endregion
|
|
1434
|
-
|
|
1771
|
+
//#region src/utils/url-safety.ts
|
|
1772
|
+
const ENCODED_ASCII_CONTROL_RE = /%(?:0[0-9a-f]|1[0-9a-f]|7f)/i;
|
|
1773
|
+
function hasControlCodePoint(value) {
|
|
1774
|
+
for (let i = 0; i < value.length; i++) {
|
|
1775
|
+
const code = value.charCodeAt(i);
|
|
1776
|
+
if (code <= 31 || code >= 127 && code <= 159) return true;
|
|
1777
|
+
}
|
|
1778
|
+
return false;
|
|
1779
|
+
}
|
|
1780
|
+
function hasEncodedControl(value) {
|
|
1781
|
+
let current = String(value ?? "");
|
|
1782
|
+
for (let depth = 0; depth < 3; depth++) {
|
|
1783
|
+
if (ENCODED_ASCII_CONTROL_RE.test(current)) return true;
|
|
1784
|
+
let decoded;
|
|
1785
|
+
try {
|
|
1786
|
+
decoded = decodeURIComponent(current);
|
|
1787
|
+
} catch {
|
|
1788
|
+
return true;
|
|
1789
|
+
}
|
|
1790
|
+
if (hasControlCodePoint(decoded)) return true;
|
|
1791
|
+
if (decoded === current) return false;
|
|
1792
|
+
current = decoded;
|
|
1793
|
+
}
|
|
1794
|
+
return ENCODED_ASCII_CONTROL_RE.test(current) || hasControlCodePoint(current);
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
//#endregion
|
|
1798
|
+
//#region src/core/hyperlink.ts
|
|
1799
|
+
const SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
|
|
1800
|
+
const BLOCKED_SCHEME_RE = /^(?:javascript|data|vbscript):/i;
|
|
1801
|
+
const SAFE_RELATIVE_HREF_RE = /^(?:[A-Za-z0-9._~!$&()*+,;=:@/?#-]|%[0-9A-Fa-f]{2})+$/u;
|
|
1802
|
+
function normalizeRawHref(value) {
|
|
1803
|
+
if (typeof value !== "string") return null;
|
|
1804
|
+
const raw = value.trim();
|
|
1805
|
+
if (!raw) return null;
|
|
1806
|
+
if (raw !== value) return null;
|
|
1807
|
+
for (let i = 0; i < value.length; i++) {
|
|
1808
|
+
const code = value.charCodeAt(i);
|
|
1809
|
+
if (code <= 31 || code >= 127 && code <= 159) return null;
|
|
1810
|
+
}
|
|
1811
|
+
if (/\s/u.test(raw)) return null;
|
|
1812
|
+
if (raw.startsWith("//")) return null;
|
|
1813
|
+
if (BLOCKED_SCHEME_RE.test(raw)) return null;
|
|
1814
|
+
if (hasEncodedControl(raw)) return null;
|
|
1815
|
+
return raw;
|
|
1816
|
+
}
|
|
1817
|
+
function hrefScheme(raw) {
|
|
1818
|
+
return raw.match(SCHEME_RE)?.[0].toLowerCase() ?? null;
|
|
1819
|
+
}
|
|
1820
|
+
function parseSafeAbsoluteUrl(raw) {
|
|
1821
|
+
if (raw.includes("\\")) return null;
|
|
1822
|
+
try {
|
|
1823
|
+
return new URL(raw);
|
|
1824
|
+
} catch {
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
function sanitizeAbsoluteHref(raw, options = {}) {
|
|
1829
|
+
const url = parseSafeAbsoluteUrl(raw);
|
|
1830
|
+
if (!url) return null;
|
|
1831
|
+
if (url.protocol === "http:" || url.protocol === "https:") {
|
|
1832
|
+
if (!/^https?:\/\//i.test(raw)) return null;
|
|
1833
|
+
return options.preserveHttpHref ? raw : url.toString();
|
|
1834
|
+
}
|
|
1835
|
+
if (url.protocol === "mailto:") return raw;
|
|
1836
|
+
return null;
|
|
1837
|
+
}
|
|
1838
|
+
function isSafeNormalizedRelativeHref(raw) {
|
|
1839
|
+
if (raw.includes("\\")) return false;
|
|
1840
|
+
if (raw.startsWith("//")) return false;
|
|
1841
|
+
if (SCHEME_RE.test(raw)) return false;
|
|
1842
|
+
if (hasEncodedControl(raw)) return false;
|
|
1843
|
+
if (!SAFE_RELATIVE_HREF_RE.test(raw)) return false;
|
|
1844
|
+
return raw.startsWith("#") || raw.startsWith("?") || raw.startsWith("/") || raw.startsWith("./") || raw.startsWith("../") || /^[A-Za-z0-9._~-]/u.test(raw);
|
|
1845
|
+
}
|
|
1846
|
+
function isSafeRelativeHref(value) {
|
|
1847
|
+
const raw = normalizeRawHref(value);
|
|
1848
|
+
return raw != null && isSafeNormalizedRelativeHref(raw);
|
|
1849
|
+
}
|
|
1850
|
+
function sanitizeTerminalHref(value, options = {}) {
|
|
1851
|
+
const raw = normalizeRawHref(value);
|
|
1852
|
+
if (!raw) return null;
|
|
1853
|
+
const sanitized = sanitizeAbsoluteHref(raw, { preserveHttpHref: true });
|
|
1854
|
+
if (sanitized) return sanitized;
|
|
1855
|
+
if (options.allowFileUrls) {
|
|
1856
|
+
const url = parseSafeAbsoluteUrl(raw);
|
|
1857
|
+
if (url?.protocol === "file:") return url.toString();
|
|
1858
|
+
}
|
|
1859
|
+
return null;
|
|
1860
|
+
}
|
|
1861
|
+
function sanitizeDomHref(value, options = {}) {
|
|
1862
|
+
const raw = normalizeRawHref(value);
|
|
1863
|
+
if (!raw) return null;
|
|
1864
|
+
const scheme = hrefScheme(raw);
|
|
1865
|
+
if (!scheme) return options.allowRelative !== false && isSafeNormalizedRelativeHref(raw) ? raw : null;
|
|
1866
|
+
return sanitizeAbsoluteHref(raw);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
//#endregion
|
|
1870
|
+
export { TERMINAL_RENDER_PLANES, applyAnsiSgrStyle, createTerminal, getPlaneTerminal, getRootTerminal, hasEncodedControl, isSafeRelativeHref, parseAnsiSgr, resetPlaneRowsForRender, sanitizeDomHref, sanitizeTerminalHref, scrollPlaneRows };
|