@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,885 @@
|
|
|
1
|
+
import { EventZIndexContextKey, intersectRect, padEndByCells$1 as padEndByCells, repeatChar, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, textCellWidth$1 as textCellWidth, translateRect, useLayout, useRenderNode, useTerminal, useTerminalNode, useVisibility, withTextWidthProvider } from "./rect-DUpeDfBg.js";
|
|
2
|
+
import { computed, defineComponent, getCurrentInstance, h, inject, markRaw, onBeforeUnmount, shallowRef, watch } from "vue";
|
|
3
|
+
|
|
4
|
+
//#region src/vue/components/TMermaidText.ts
|
|
5
|
+
const TUI_MERMAID_FATAL_RENDER_ERROR = "__vueTuiMermaidFatalRenderError";
|
|
6
|
+
const fatalMermaidRenderErrors = new WeakSet();
|
|
7
|
+
const DEFAULT_MERMAID_RENDER_TIMEOUT_MS = 2500;
|
|
8
|
+
const DEFAULT_MERMAID_MAX_RENDER_SOURCE_CHARS = 2e4;
|
|
9
|
+
const DEFAULT_MERMAID_MAX_RENDER_SOURCE_LINES = 400;
|
|
10
|
+
const DEFAULT_MERMAID_COPIED_DURATION_MS = 1200;
|
|
11
|
+
const UNICODE_MERMAID_BOX_CHARS = Object.freeze({
|
|
12
|
+
tl: "┌",
|
|
13
|
+
tr: "┐",
|
|
14
|
+
bl: "└",
|
|
15
|
+
br: "┘",
|
|
16
|
+
h: "─",
|
|
17
|
+
v: "│"
|
|
18
|
+
});
|
|
19
|
+
const ASCII_MERMAID_BOX_CHARS = Object.freeze({
|
|
20
|
+
tl: "+",
|
|
21
|
+
tr: "+",
|
|
22
|
+
bl: "+",
|
|
23
|
+
br: "+",
|
|
24
|
+
h: "-",
|
|
25
|
+
v: "|"
|
|
26
|
+
});
|
|
27
|
+
const DEFAULT_MERMAID_MAX_RENDER_FLOW_STATEMENTS = 120;
|
|
28
|
+
const SIMPLE_MERMAID_DIRECTIVE_RE = /^(?:graph|flowchart)\s+(?:TB|TD|BT|LR|RL)\s*$/i;
|
|
29
|
+
const MERMAID_INIT_DIRECTIVE_RE = /^%%\{/;
|
|
30
|
+
const MERMAID_COMMENT_RE = /^%%/;
|
|
31
|
+
const MERMAID_FRONTMATTER_DELIMITER_RE = /^---\s*$/;
|
|
32
|
+
const SIMPLE_MERMAID_FLOW_STATEMENT_START_RE = /^(?:"[^"]+"|'[^']+'|`[^`]+`|[A-Za-z0-9_][A-Za-z0-9_-]*)/;
|
|
33
|
+
const COMPLEX_MERMAID_FLOW_FEATURE_RE = /^(?:subgraph|end|classDef|class|click|style|linkStyle|accTitle|accDescr|direction)\b/i;
|
|
34
|
+
const ESC = String.fromCharCode(27);
|
|
35
|
+
const BEL = String.fromCharCode(7);
|
|
36
|
+
const TERMINAL_ESCAPE_RE = new RegExp([
|
|
37
|
+
`${ESC}\\][\\s\\S]*?(?:${BEL}|${ESC}\\\\)`,
|
|
38
|
+
`${ESC}[PX^_][\\s\\S]*?${ESC}\\\\`,
|
|
39
|
+
`${ESC}\\[[0-?]*[ -/]*[@-~]`,
|
|
40
|
+
`${ESC}[@-Z\\\\-_]`
|
|
41
|
+
].join("|"), "g");
|
|
42
|
+
function stripTerminalEscapes(value) {
|
|
43
|
+
return value.replace(TERMINAL_ESCAPE_RE, "");
|
|
44
|
+
}
|
|
45
|
+
function normalizeNonNegativeInt(value, fallback) {
|
|
46
|
+
const n = Number(value);
|
|
47
|
+
if (!Number.isFinite(n)) return fallback;
|
|
48
|
+
return Math.max(0, Math.floor(n));
|
|
49
|
+
}
|
|
50
|
+
function countLinesUpTo(value, max) {
|
|
51
|
+
if (max <= 0) return 0;
|
|
52
|
+
let lines = 1;
|
|
53
|
+
for (let index = 0; index < value.length; index++) {
|
|
54
|
+
const code = value.charCodeAt(index);
|
|
55
|
+
if (code !== 10 && code !== 13) continue;
|
|
56
|
+
lines++;
|
|
57
|
+
if (code === 13 && value.charCodeAt(index + 1) === 10) index++;
|
|
58
|
+
if (lines > max) return lines;
|
|
59
|
+
}
|
|
60
|
+
return lines;
|
|
61
|
+
}
|
|
62
|
+
function createMermaidScannerState() {
|
|
63
|
+
return {
|
|
64
|
+
quote: "",
|
|
65
|
+
escaped: false,
|
|
66
|
+
squareDepth: 0,
|
|
67
|
+
parenDepth: 0,
|
|
68
|
+
braceDepth: 0,
|
|
69
|
+
pipeLabel: false
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function scannerAtTopLevel(state) {
|
|
73
|
+
return !state.quote && !state.pipeLabel && state.squareDepth === 0 && state.parenDepth === 0 && state.braceDepth === 0;
|
|
74
|
+
}
|
|
75
|
+
function advanceMermaidScannerState(state, ch) {
|
|
76
|
+
if (state.pipeLabel) {
|
|
77
|
+
if (state.escaped) {
|
|
78
|
+
state.escaped = false;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (ch === "\\") {
|
|
82
|
+
state.escaped = true;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (ch === "|") state.pipeLabel = false;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (state.quote) {
|
|
89
|
+
if (state.escaped) {
|
|
90
|
+
state.escaped = false;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (ch === "\\") {
|
|
94
|
+
state.escaped = true;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (ch === state.quote) state.quote = "";
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (ch === "\"" || ch === "'" || ch === "`") {
|
|
101
|
+
state.quote = ch;
|
|
102
|
+
state.escaped = false;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (ch === "|" && scannerAtTopLevel(state)) {
|
|
106
|
+
state.pipeLabel = true;
|
|
107
|
+
state.escaped = false;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (ch === "[") {
|
|
111
|
+
state.squareDepth++;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (ch === "]") {
|
|
115
|
+
state.squareDepth = Math.max(0, state.squareDepth - 1);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (ch === "(") {
|
|
119
|
+
state.parenDepth++;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (ch === ")") {
|
|
123
|
+
state.parenDepth = Math.max(0, state.parenDepth - 1);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (ch === "{") {
|
|
127
|
+
state.braceDepth++;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (ch === "}") state.braceDepth = Math.max(0, state.braceDepth - 1);
|
|
131
|
+
}
|
|
132
|
+
function splitMermaidLineStatements(line) {
|
|
133
|
+
const out = [];
|
|
134
|
+
const state = createMermaidScannerState();
|
|
135
|
+
let start = 0;
|
|
136
|
+
for (let index = 0; index < line.length; index++) {
|
|
137
|
+
const ch = line[index] ?? "";
|
|
138
|
+
if (ch === ";" && scannerAtTopLevel(state)) {
|
|
139
|
+
const statement = line.slice(start, index).trim();
|
|
140
|
+
if (statement) out.push(statement);
|
|
141
|
+
start = index + 1;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
advanceMermaidScannerState(state, ch);
|
|
145
|
+
}
|
|
146
|
+
const tail = line.slice(start).trim();
|
|
147
|
+
if (tail) out.push(tail);
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
function stripTopLevelMermaidComment(statement) {
|
|
151
|
+
const state = createMermaidScannerState();
|
|
152
|
+
for (let index = 0; index < statement.length; index++) {
|
|
153
|
+
const ch = statement[index] ?? "";
|
|
154
|
+
if (ch === "%" && statement[index + 1] === "%" && scannerAtTopLevel(state)) return statement.slice(0, index).trim();
|
|
155
|
+
advanceMermaidScannerState(state, ch);
|
|
156
|
+
}
|
|
157
|
+
return statement.trim();
|
|
158
|
+
}
|
|
159
|
+
function mermaidSourceLines(code) {
|
|
160
|
+
return String(code ?? "").replace(/\r\n?/g, "\n").split("\n");
|
|
161
|
+
}
|
|
162
|
+
function mermaidSourceStatements(code) {
|
|
163
|
+
const statements = [];
|
|
164
|
+
for (const rawLine of mermaidSourceLines(code)) {
|
|
165
|
+
const line = rawLine.trim();
|
|
166
|
+
if (!line) continue;
|
|
167
|
+
if (MERMAID_INIT_DIRECTIVE_RE.test(line) || MERMAID_FRONTMATTER_DELIMITER_RE.test(line)) {
|
|
168
|
+
statements.push(line);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (MERMAID_COMMENT_RE.test(line)) continue;
|
|
172
|
+
for (const rawStatement of splitMermaidLineStatements(line)) {
|
|
173
|
+
const statement = stripTopLevelMermaidComment(rawStatement);
|
|
174
|
+
if (!statement || MERMAID_COMMENT_RE.test(statement)) continue;
|
|
175
|
+
statements.push(statement);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return statements;
|
|
179
|
+
}
|
|
180
|
+
function isForbiddenMermaidFlowStatement(statement) {
|
|
181
|
+
return MERMAID_INIT_DIRECTIVE_RE.test(statement) || MERMAID_FRONTMATTER_DELIMITER_RE.test(statement) || COMPLEX_MERMAID_FLOW_FEATURE_RE.test(statement);
|
|
182
|
+
}
|
|
183
|
+
function hasTopLevelMermaidComplexToken(statement) {
|
|
184
|
+
const state = createMermaidScannerState();
|
|
185
|
+
for (let index = 0; index < statement.length; index++) {
|
|
186
|
+
const ch = statement[index] ?? "";
|
|
187
|
+
if (scannerAtTopLevel(state)) {
|
|
188
|
+
if (ch === "@") return true;
|
|
189
|
+
if (statement.startsWith(":::", index) && /[A-Za-z_]/.test(statement[index + 3] ?? "")) return true;
|
|
190
|
+
}
|
|
191
|
+
advanceMermaidScannerState(state, ch);
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
function isSimpleMermaidFlowStatement(statement) {
|
|
196
|
+
if (SIMPLE_MERMAID_DIRECTIVE_RE.test(statement)) return false;
|
|
197
|
+
if (isForbiddenMermaidFlowStatement(statement)) return false;
|
|
198
|
+
if (hasTopLevelMermaidComplexToken(statement)) return false;
|
|
199
|
+
return SIMPLE_MERMAID_FLOW_STATEMENT_START_RE.test(statement);
|
|
200
|
+
}
|
|
201
|
+
function isSimpleMermaidFlowchartSource(code) {
|
|
202
|
+
const statements = mermaidSourceStatements(code);
|
|
203
|
+
let sawDirective = false;
|
|
204
|
+
let renderableStatements = 0;
|
|
205
|
+
for (const statement of statements) {
|
|
206
|
+
if (!sawDirective) {
|
|
207
|
+
if (!SIMPLE_MERMAID_DIRECTIVE_RE.test(statement)) return false;
|
|
208
|
+
sawDirective = true;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (!isSimpleMermaidFlowStatement(statement)) return false;
|
|
212
|
+
renderableStatements++;
|
|
213
|
+
if (renderableStatements > DEFAULT_MERMAID_MAX_RENDER_FLOW_STATEMENTS) return false;
|
|
214
|
+
}
|
|
215
|
+
return sawDirective && renderableStatements > 0;
|
|
216
|
+
}
|
|
217
|
+
function clipboardCanWrite(api) {
|
|
218
|
+
return api.canWrite ?? api.supported;
|
|
219
|
+
}
|
|
220
|
+
const MERMAID_RENDER_TIMEOUT = Symbol("MERMAID_RENDER_TIMEOUT");
|
|
221
|
+
function markMermaidRenderErrorFatal(error) {
|
|
222
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
223
|
+
fatalMermaidRenderErrors.add(normalized);
|
|
224
|
+
try {
|
|
225
|
+
Object.defineProperty(normalized, TUI_MERMAID_FATAL_RENDER_ERROR, {
|
|
226
|
+
value: true,
|
|
227
|
+
configurable: true
|
|
228
|
+
});
|
|
229
|
+
} catch {
|
|
230
|
+
try {
|
|
231
|
+
normalized[TUI_MERMAID_FATAL_RENDER_ERROR] = true;
|
|
232
|
+
} catch {}
|
|
233
|
+
}
|
|
234
|
+
return normalized;
|
|
235
|
+
}
|
|
236
|
+
function splitRenderedOutput(value) {
|
|
237
|
+
const normalized = sanitizeTextBlock(stripTerminalEscapes(String(value ?? "")).replace(/\r\n?/g, "\n"));
|
|
238
|
+
const lines = normalized.split("\n");
|
|
239
|
+
return lines.length ? lines : [""];
|
|
240
|
+
}
|
|
241
|
+
function hasVisibleRenderedOutput(value) {
|
|
242
|
+
return value.some((line) => line.trim().length > 0);
|
|
243
|
+
}
|
|
244
|
+
const tMermaidTextProps = {
|
|
245
|
+
x: {
|
|
246
|
+
type: Number,
|
|
247
|
+
required: true
|
|
248
|
+
},
|
|
249
|
+
y: {
|
|
250
|
+
type: Number,
|
|
251
|
+
required: true
|
|
252
|
+
},
|
|
253
|
+
w: {
|
|
254
|
+
type: Number,
|
|
255
|
+
required: true
|
|
256
|
+
},
|
|
257
|
+
h: {
|
|
258
|
+
type: Number,
|
|
259
|
+
default: void 0
|
|
260
|
+
},
|
|
261
|
+
zIndex: {
|
|
262
|
+
type: Number,
|
|
263
|
+
default: 0
|
|
264
|
+
},
|
|
265
|
+
content: {
|
|
266
|
+
type: String,
|
|
267
|
+
default: ""
|
|
268
|
+
},
|
|
269
|
+
code: {
|
|
270
|
+
type: String,
|
|
271
|
+
default: void 0
|
|
272
|
+
},
|
|
273
|
+
style: {
|
|
274
|
+
type: Object,
|
|
275
|
+
default: void 0
|
|
276
|
+
},
|
|
277
|
+
loadingStyle: {
|
|
278
|
+
type: Object,
|
|
279
|
+
default: void 0
|
|
280
|
+
},
|
|
281
|
+
errorStyle: {
|
|
282
|
+
type: Object,
|
|
283
|
+
default: void 0
|
|
284
|
+
},
|
|
285
|
+
clear: {
|
|
286
|
+
type: Boolean,
|
|
287
|
+
default: true
|
|
288
|
+
},
|
|
289
|
+
final: {
|
|
290
|
+
type: Boolean,
|
|
291
|
+
default: true
|
|
292
|
+
},
|
|
293
|
+
streaming: {
|
|
294
|
+
type: Boolean,
|
|
295
|
+
default: false
|
|
296
|
+
},
|
|
297
|
+
ascii: {
|
|
298
|
+
type: Boolean,
|
|
299
|
+
default: false
|
|
300
|
+
},
|
|
301
|
+
paddingX: {
|
|
302
|
+
type: Number,
|
|
303
|
+
default: void 0
|
|
304
|
+
},
|
|
305
|
+
paddingY: {
|
|
306
|
+
type: Number,
|
|
307
|
+
default: void 0
|
|
308
|
+
},
|
|
309
|
+
boxBorderPadding: {
|
|
310
|
+
type: Number,
|
|
311
|
+
default: void 0
|
|
312
|
+
},
|
|
313
|
+
options: {
|
|
314
|
+
type: Object,
|
|
315
|
+
default: void 0
|
|
316
|
+
},
|
|
317
|
+
renderer: {
|
|
318
|
+
type: Function,
|
|
319
|
+
default: void 0
|
|
320
|
+
},
|
|
321
|
+
isTransientError: {
|
|
322
|
+
type: Function,
|
|
323
|
+
default: void 0
|
|
324
|
+
},
|
|
325
|
+
shouldRenderSource: {
|
|
326
|
+
type: Function,
|
|
327
|
+
default: void 0
|
|
328
|
+
},
|
|
329
|
+
loadingText: {
|
|
330
|
+
type: String,
|
|
331
|
+
default: "Rendering Mermaid diagram..."
|
|
332
|
+
},
|
|
333
|
+
incompleteText: {
|
|
334
|
+
type: String,
|
|
335
|
+
default: "Waiting for complete Mermaid diagram..."
|
|
336
|
+
},
|
|
337
|
+
missingDependencyText: {
|
|
338
|
+
type: String,
|
|
339
|
+
default: "Install the Mermaid renderer package and use TMermaidText from @simon_he/vue-tui/mermaid or @simon_he/vue-tui/agent/mermaid, or pass a renderer prop."
|
|
340
|
+
},
|
|
341
|
+
errorText: {
|
|
342
|
+
type: String,
|
|
343
|
+
default: "Mermaid render failed"
|
|
344
|
+
},
|
|
345
|
+
showErrorDetails: {
|
|
346
|
+
type: Boolean,
|
|
347
|
+
default: true
|
|
348
|
+
},
|
|
349
|
+
box: {
|
|
350
|
+
type: Boolean,
|
|
351
|
+
default: true
|
|
352
|
+
},
|
|
353
|
+
title: {
|
|
354
|
+
type: String,
|
|
355
|
+
default: "mermaid"
|
|
356
|
+
},
|
|
357
|
+
copyButton: {
|
|
358
|
+
type: Boolean,
|
|
359
|
+
default: true
|
|
360
|
+
},
|
|
361
|
+
copyText: {
|
|
362
|
+
type: String,
|
|
363
|
+
default: "copy"
|
|
364
|
+
},
|
|
365
|
+
copiedText: {
|
|
366
|
+
type: String,
|
|
367
|
+
default: "copied"
|
|
368
|
+
},
|
|
369
|
+
renderTimeoutMs: {
|
|
370
|
+
type: Number,
|
|
371
|
+
default: DEFAULT_MERMAID_RENDER_TIMEOUT_MS
|
|
372
|
+
},
|
|
373
|
+
maxRenderSourceChars: {
|
|
374
|
+
type: Number,
|
|
375
|
+
default: DEFAULT_MERMAID_MAX_RENDER_SOURCE_CHARS
|
|
376
|
+
},
|
|
377
|
+
maxRenderSourceLines: {
|
|
378
|
+
type: Number,
|
|
379
|
+
default: DEFAULT_MERMAID_MAX_RENDER_SOURCE_LINES
|
|
380
|
+
},
|
|
381
|
+
copiedDurationMs: {
|
|
382
|
+
type: Number,
|
|
383
|
+
default: DEFAULT_MERMAID_COPIED_DURATION_MS
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
const TMermaidText = defineComponent({
|
|
387
|
+
name: "TMermaidText",
|
|
388
|
+
props: tMermaidTextProps,
|
|
389
|
+
emits: { copy: (_payload) => true },
|
|
390
|
+
setup(props, { emit }) {
|
|
391
|
+
const instance = getCurrentInstance();
|
|
392
|
+
const terminalContext = useTerminal();
|
|
393
|
+
const { terminal, defaultStyle, scheduler, widthProvider } = terminalContext;
|
|
394
|
+
const layout = useLayout();
|
|
395
|
+
const { visible, rootProps } = useVisibility();
|
|
396
|
+
const parentEventZ = inject(EventZIndexContextKey, computed(() => 0));
|
|
397
|
+
const renderedSnapshot = shallowRef(null);
|
|
398
|
+
const documentVersion = shallowRef(0);
|
|
399
|
+
const copied = shallowRef(false);
|
|
400
|
+
let builtOnce = false;
|
|
401
|
+
let renderVersion = 0;
|
|
402
|
+
let alive = true;
|
|
403
|
+
const frameTaskId = `TMermaidText:${instance?.uid ?? "unknown"}:mermaid`;
|
|
404
|
+
let copiedTimer = null;
|
|
405
|
+
let copyRequestVersion = 0;
|
|
406
|
+
const source = computed(() => props.code ?? props.content ?? "");
|
|
407
|
+
const waitingForStreamingSourceToFinish = computed(() => props.streaming && !props.final);
|
|
408
|
+
function bump() {
|
|
409
|
+
documentVersion.value++;
|
|
410
|
+
}
|
|
411
|
+
function resolveAsciiOptions() {
|
|
412
|
+
const base = props.options ?? {};
|
|
413
|
+
return {
|
|
414
|
+
...base,
|
|
415
|
+
useAscii: props.ascii,
|
|
416
|
+
paddingX: props.paddingX ?? base.paddingX,
|
|
417
|
+
paddingY: props.paddingY ?? base.paddingY,
|
|
418
|
+
boxBorderPadding: props.boxBorderPadding ?? base.boxBorderPadding,
|
|
419
|
+
colorMode: "none"
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function clearCopiedTimer() {
|
|
423
|
+
if (copiedTimer == null) return;
|
|
424
|
+
clearTimeout(copiedTimer);
|
|
425
|
+
copiedTimer = null;
|
|
426
|
+
}
|
|
427
|
+
function setCopied(next, repaint = true) {
|
|
428
|
+
if (!next) clearCopiedTimer();
|
|
429
|
+
if (copied.value === next) return;
|
|
430
|
+
copied.value = next;
|
|
431
|
+
if (repaint) bump();
|
|
432
|
+
}
|
|
433
|
+
function resetCopyFeedback(repaint = true) {
|
|
434
|
+
copyRequestVersion++;
|
|
435
|
+
setCopied(false, repaint);
|
|
436
|
+
}
|
|
437
|
+
function clearRenderedSnapshot() {
|
|
438
|
+
if (renderedSnapshot.value == null) return false;
|
|
439
|
+
renderedSnapshot.value = null;
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
function showCopiedFeedback() {
|
|
443
|
+
clearCopiedTimer();
|
|
444
|
+
const duration = normalizeNonNegativeInt(props.copiedDurationMs, DEFAULT_MERMAID_COPIED_DURATION_MS);
|
|
445
|
+
if (duration <= 0) {
|
|
446
|
+
setCopied(false);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
setCopied(true);
|
|
450
|
+
copiedTimer = setTimeout(() => {
|
|
451
|
+
copiedTimer = null;
|
|
452
|
+
if (!alive) return;
|
|
453
|
+
setCopied(false);
|
|
454
|
+
}, duration);
|
|
455
|
+
}
|
|
456
|
+
function shouldSkipRenderForSize(code) {
|
|
457
|
+
const maxChars = normalizeNonNegativeInt(props.maxRenderSourceChars, DEFAULT_MERMAID_MAX_RENDER_SOURCE_CHARS);
|
|
458
|
+
if (maxChars > 0 && code.length > maxChars) return true;
|
|
459
|
+
const maxLines = normalizeNonNegativeInt(props.maxRenderSourceLines, DEFAULT_MERMAID_MAX_RENDER_SOURCE_LINES);
|
|
460
|
+
if (maxLines > 0 && countLinesUpTo(code, maxLines) > maxLines) return true;
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
function shouldSkipRender(code) {
|
|
464
|
+
if (shouldSkipRenderForSize(code)) return true;
|
|
465
|
+
const shouldRenderSource = props.shouldRenderSource;
|
|
466
|
+
if (!shouldRenderSource) return false;
|
|
467
|
+
try {
|
|
468
|
+
return !shouldRenderSource(code, {
|
|
469
|
+
final: props.final,
|
|
470
|
+
streaming: props.streaming
|
|
471
|
+
});
|
|
472
|
+
} catch {
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
async function renderWithTimeout(renderer, code, options) {
|
|
477
|
+
const timeoutMs = normalizeNonNegativeInt(props.renderTimeoutMs, DEFAULT_MERMAID_RENDER_TIMEOUT_MS);
|
|
478
|
+
if (timeoutMs <= 0) return await renderer(code, options);
|
|
479
|
+
let timer = null;
|
|
480
|
+
try {
|
|
481
|
+
return await Promise.race([Promise.resolve().then(() => renderer(code, options)), new Promise((_resolve, reject) => {
|
|
482
|
+
timer = setTimeout(() => reject(MERMAID_RENDER_TIMEOUT), timeoutMs);
|
|
483
|
+
})]);
|
|
484
|
+
} finally {
|
|
485
|
+
if (timer != null) clearTimeout(timer);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function clearRenderState() {
|
|
489
|
+
renderedSnapshot.value = null;
|
|
490
|
+
}
|
|
491
|
+
function acceptRenderedSnapshot(code, rendered) {
|
|
492
|
+
const renderedLines = splitRenderedOutput(rendered);
|
|
493
|
+
if (!hasVisibleRenderedOutput(renderedLines)) {
|
|
494
|
+
renderedSnapshot.value = null;
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
renderedSnapshot.value = markRaw({
|
|
498
|
+
source: code,
|
|
499
|
+
lines: markRaw(renderedLines)
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
async function renderNow(version) {
|
|
503
|
+
const code = source.value;
|
|
504
|
+
if (!code.trim()) {
|
|
505
|
+
if (!alive || version !== renderVersion) return;
|
|
506
|
+
clearRenderState();
|
|
507
|
+
bump();
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (waitingForStreamingSourceToFinish.value) {
|
|
511
|
+
if (!alive || version !== renderVersion) return;
|
|
512
|
+
clearRenderState();
|
|
513
|
+
bump();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (shouldSkipRender(code)) {
|
|
517
|
+
if (!alive || version !== renderVersion) return;
|
|
518
|
+
clearRenderState();
|
|
519
|
+
bump();
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
renderedSnapshot.value = null;
|
|
523
|
+
bump();
|
|
524
|
+
try {
|
|
525
|
+
const renderer = props.renderer;
|
|
526
|
+
if (!renderer) {
|
|
527
|
+
if (!alive || version !== renderVersion) return;
|
|
528
|
+
clearRenderState();
|
|
529
|
+
bump();
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
const rendered = await renderWithTimeout(renderer, code, resolveAsciiOptions());
|
|
533
|
+
if (!alive || version !== renderVersion) return;
|
|
534
|
+
acceptRenderedSnapshot(code, rendered);
|
|
535
|
+
bump();
|
|
536
|
+
} catch {
|
|
537
|
+
if (!alive || version !== renderVersion) return;
|
|
538
|
+
clearRenderState();
|
|
539
|
+
bump();
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
function scheduleRender() {
|
|
543
|
+
const version = ++renderVersion;
|
|
544
|
+
const copiedWasVisible = copied.value;
|
|
545
|
+
resetCopyFeedback(false);
|
|
546
|
+
const snapshotCleared = clearRenderedSnapshot();
|
|
547
|
+
if (waitingForStreamingSourceToFinish.value) {
|
|
548
|
+
builtOnce = true;
|
|
549
|
+
scheduler.cancelFrameTask?.(frameTaskId);
|
|
550
|
+
if (copiedWasVisible || snapshotCleared) bump();
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (!builtOnce || !props.streaming) {
|
|
554
|
+
builtOnce = true;
|
|
555
|
+
renderNow(version);
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (copiedWasVisible || snapshotCleared) bump();
|
|
559
|
+
const accepted = scheduler.queueFrameTask({
|
|
560
|
+
id: frameTaskId,
|
|
561
|
+
reason: "stream",
|
|
562
|
+
priority: "low",
|
|
563
|
+
sync: false,
|
|
564
|
+
run: () => {
|
|
565
|
+
if (!alive) return;
|
|
566
|
+
if (version !== renderVersion) return;
|
|
567
|
+
renderNow(version);
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
if (accepted === false) renderNow(version);
|
|
571
|
+
}
|
|
572
|
+
watch([
|
|
573
|
+
source,
|
|
574
|
+
() => props.renderer,
|
|
575
|
+
() => props.ascii,
|
|
576
|
+
() => props.paddingX,
|
|
577
|
+
() => props.paddingY,
|
|
578
|
+
() => props.boxBorderPadding,
|
|
579
|
+
() => props.options,
|
|
580
|
+
() => props.streaming,
|
|
581
|
+
() => props.final,
|
|
582
|
+
() => props.renderTimeoutMs,
|
|
583
|
+
() => props.maxRenderSourceChars,
|
|
584
|
+
() => props.maxRenderSourceLines,
|
|
585
|
+
() => props.shouldRenderSource
|
|
586
|
+
], () => {
|
|
587
|
+
scheduleRender();
|
|
588
|
+
}, {
|
|
589
|
+
immediate: true,
|
|
590
|
+
deep: true
|
|
591
|
+
});
|
|
592
|
+
onBeforeUnmount(() => {
|
|
593
|
+
alive = false;
|
|
594
|
+
renderVersion++;
|
|
595
|
+
clearCopiedTimer();
|
|
596
|
+
scheduler.cancelFrameTask?.(frameTaskId);
|
|
597
|
+
});
|
|
598
|
+
const hasBox = computed(() => props.box !== false);
|
|
599
|
+
const normalizedWidth = computed(() => {
|
|
600
|
+
const width = Math.floor(Number(props.w));
|
|
601
|
+
return Number.isFinite(width) ? Math.max(0, width) : 0;
|
|
602
|
+
});
|
|
603
|
+
const reservesBoxRows = computed(() => hasBox.value && normalizedWidth.value >= 2);
|
|
604
|
+
const boxChars = computed(() => props.ascii ? ASCII_MERMAID_BOX_CHARS : UNICODE_MERMAID_BOX_CHARS);
|
|
605
|
+
const sourceLines = computed(() => splitRenderedOutput(source.value));
|
|
606
|
+
const displayLines = computed(() => {
|
|
607
|
+
const snapshot = renderedSnapshot.value;
|
|
608
|
+
if (snapshot && snapshot.source === source.value && hasVisibleRenderedOutput(snapshot.lines)) return snapshot.lines;
|
|
609
|
+
return sourceLines.value;
|
|
610
|
+
});
|
|
611
|
+
const currentStyle = computed(() => {
|
|
612
|
+
return props.style ?? defaultStyle.value;
|
|
613
|
+
});
|
|
614
|
+
const fullHeight = computed(() => {
|
|
615
|
+
if (props.h != null) {
|
|
616
|
+
const h$1 = Math.floor(Number(props.h));
|
|
617
|
+
return Number.isFinite(h$1) ? Math.max(0, h$1) : 0;
|
|
618
|
+
}
|
|
619
|
+
const autoContentHeight = Math.max(1, displayLines.value.length);
|
|
620
|
+
return reservesBoxRows.value ? autoContentHeight + 2 : autoContentHeight;
|
|
621
|
+
});
|
|
622
|
+
const fullRect = computed(() => {
|
|
623
|
+
return translateRect({
|
|
624
|
+
x: props.x,
|
|
625
|
+
y: props.y,
|
|
626
|
+
w: props.w,
|
|
627
|
+
h: fullHeight.value
|
|
628
|
+
}, layout.originX, layout.originY);
|
|
629
|
+
});
|
|
630
|
+
const absRect = computed(() => {
|
|
631
|
+
const translated = fullRect.value;
|
|
632
|
+
if (!layout.clipRect) return translated;
|
|
633
|
+
return intersectRect(translated, layout.clipRect) ?? {
|
|
634
|
+
x: 0,
|
|
635
|
+
y: 0,
|
|
636
|
+
w: 0,
|
|
637
|
+
h: 0
|
|
638
|
+
};
|
|
639
|
+
});
|
|
640
|
+
const copyLabel = computed(() => copied.value ? props.copiedText : props.copyText);
|
|
641
|
+
function cellWidth(value) {
|
|
642
|
+
return withTextWidthProvider(widthProvider, () => textCellWidth(value));
|
|
643
|
+
}
|
|
644
|
+
function sliceCells(text, maxCells) {
|
|
645
|
+
return withTextWidthProvider(widthProvider, () => sliceByCells(text, maxCells));
|
|
646
|
+
}
|
|
647
|
+
function sliceCellsRange(text, startCells, endCells) {
|
|
648
|
+
return withTextWidthProvider(widthProvider, () => sliceByCellsRange(text, startCells, endCells));
|
|
649
|
+
}
|
|
650
|
+
function padCells(text, width) {
|
|
651
|
+
return withTextWidthProvider(widthProvider, () => padEndByCells(text, width));
|
|
652
|
+
}
|
|
653
|
+
function canDrawBox(width, height) {
|
|
654
|
+
return hasBox.value && Math.floor(width) >= 2 && Math.floor(height) >= 2;
|
|
655
|
+
}
|
|
656
|
+
function segmentCells(text) {
|
|
657
|
+
return cellWidth(text);
|
|
658
|
+
}
|
|
659
|
+
function headerCopySegment(width) {
|
|
660
|
+
if (!hasBox.value || !props.copyButton) return null;
|
|
661
|
+
const rowWidth = Math.max(0, Math.floor(width));
|
|
662
|
+
if (rowWidth < 4) return null;
|
|
663
|
+
const label = sanitizeInlineText(copyLabel.value);
|
|
664
|
+
if (!label) return null;
|
|
665
|
+
const maxCells = Math.max(0, rowWidth - 2);
|
|
666
|
+
const text = sliceCells(` ${label} `, maxCells);
|
|
667
|
+
const cells = segmentCells(text);
|
|
668
|
+
if (!text || cells <= 0) return null;
|
|
669
|
+
return {
|
|
670
|
+
text,
|
|
671
|
+
start: Math.max(1, rowWidth - cells - 1),
|
|
672
|
+
cells
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
function headerTitleSegment(width, copy) {
|
|
676
|
+
if (!hasBox.value) return null;
|
|
677
|
+
const rowWidth = Math.max(0, Math.floor(width));
|
|
678
|
+
if (rowWidth < 4) return null;
|
|
679
|
+
const title = sanitizeInlineText(props.title);
|
|
680
|
+
if (!title) return null;
|
|
681
|
+
const titleStart = 1;
|
|
682
|
+
const titleEnd = copy ? Math.max(titleStart, copy.start - 1) : rowWidth - 1;
|
|
683
|
+
const maxCells = Math.max(0, titleEnd - titleStart);
|
|
684
|
+
if (maxCells <= 0) return null;
|
|
685
|
+
const text = sliceCells(` ${title} `, maxCells);
|
|
686
|
+
const cells = segmentCells(text);
|
|
687
|
+
if (!text || cells <= 0) return null;
|
|
688
|
+
return {
|
|
689
|
+
text,
|
|
690
|
+
start: titleStart,
|
|
691
|
+
cells
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
const copyHitRect = computed(() => {
|
|
695
|
+
const full = fullRect.value;
|
|
696
|
+
if (!visible.value || !props.copyButton || !canDrawBox(full.w, full.h)) return {
|
|
697
|
+
x: 0,
|
|
698
|
+
y: 0,
|
|
699
|
+
w: 0,
|
|
700
|
+
h: 0
|
|
701
|
+
};
|
|
702
|
+
const copy = headerCopySegment(Math.max(0, Math.floor(full.w)));
|
|
703
|
+
if (!copy) return {
|
|
704
|
+
x: 0,
|
|
705
|
+
y: 0,
|
|
706
|
+
w: 0,
|
|
707
|
+
h: 0
|
|
708
|
+
};
|
|
709
|
+
const raw = {
|
|
710
|
+
x: Math.floor(full.x) + copy.start,
|
|
711
|
+
y: Math.floor(full.y),
|
|
712
|
+
w: copy.cells,
|
|
713
|
+
h: 1
|
|
714
|
+
};
|
|
715
|
+
if (!layout.clipRect) return raw;
|
|
716
|
+
return intersectRect(raw, layout.clipRect) ?? {
|
|
717
|
+
x: 0,
|
|
718
|
+
y: 0,
|
|
719
|
+
w: 0,
|
|
720
|
+
h: 0
|
|
721
|
+
};
|
|
722
|
+
});
|
|
723
|
+
async function writeClipboardText(text) {
|
|
724
|
+
const contextClipboard = terminalContext.clipboard;
|
|
725
|
+
if (contextClipboard) {
|
|
726
|
+
if (!clipboardCanWrite(contextClipboard)) throw new Error("Clipboard write not available in this runtime");
|
|
727
|
+
await contextClipboard.writeText(text);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
const navClipboard = globalThis.navigator?.clipboard;
|
|
731
|
+
if (navClipboard && typeof navClipboard.writeText === "function") {
|
|
732
|
+
await navClipboard.writeText(text);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
throw new Error("Clipboard write not available in this runtime");
|
|
736
|
+
}
|
|
737
|
+
async function copySource() {
|
|
738
|
+
const text = source.value;
|
|
739
|
+
const requestVersion = ++copyRequestVersion;
|
|
740
|
+
let ok = false;
|
|
741
|
+
let copyError;
|
|
742
|
+
try {
|
|
743
|
+
await writeClipboardText(text);
|
|
744
|
+
ok = true;
|
|
745
|
+
} catch (err) {
|
|
746
|
+
copyError = err;
|
|
747
|
+
}
|
|
748
|
+
if (!alive) return;
|
|
749
|
+
const isLatestForCurrentSource = requestVersion === copyRequestVersion && source.value === text;
|
|
750
|
+
if (isLatestForCurrentSource) if (ok) showCopiedFeedback();
|
|
751
|
+
else setCopied(false);
|
|
752
|
+
emit("copy", ok ? {
|
|
753
|
+
text,
|
|
754
|
+
ok
|
|
755
|
+
} : {
|
|
756
|
+
text,
|
|
757
|
+
ok,
|
|
758
|
+
error: copyError
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
function onCopyClick(event) {
|
|
762
|
+
event.preventDefault();
|
|
763
|
+
event.stopPropagation();
|
|
764
|
+
copySource();
|
|
765
|
+
}
|
|
766
|
+
function onCopyKeydown(event) {
|
|
767
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
768
|
+
event.preventDefault();
|
|
769
|
+
event.stopPropagation();
|
|
770
|
+
copySource();
|
|
771
|
+
}
|
|
772
|
+
const copyNodeActive = computed(() => visible.value && props.copyButton && copyHitRect.value.w > 0 && copyHitRect.value.h > 0);
|
|
773
|
+
useTerminalNode(() => ({
|
|
774
|
+
rect: copyHitRect.value,
|
|
775
|
+
zIndex: (parentEventZ.value ?? 0) + props.zIndex + 1,
|
|
776
|
+
visible: copyNodeActive.value,
|
|
777
|
+
focusable: copyNodeActive.value,
|
|
778
|
+
selectable: false,
|
|
779
|
+
handlers: copyNodeActive.value ? {
|
|
780
|
+
click: onCopyClick,
|
|
781
|
+
keydown: onCopyKeydown
|
|
782
|
+
} : {}
|
|
783
|
+
}));
|
|
784
|
+
function overlayCells(row, segment, width) {
|
|
785
|
+
const rowWidth = Math.max(0, Math.floor(width));
|
|
786
|
+
const start = Math.max(0, Math.floor(segment.start));
|
|
787
|
+
if (rowWidth <= 1 || start >= rowWidth - 1 || segment.cells <= 0) return row;
|
|
788
|
+
const maxCells = Math.max(0, rowWidth - 1 - start);
|
|
789
|
+
const text = sliceCells(segment.text, maxCells);
|
|
790
|
+
const cells = segmentCells(text);
|
|
791
|
+
if (!text || cells <= 0) return row;
|
|
792
|
+
return `${sliceCells(row, start)}${text}${sliceCellsRange(row, start + cells, rowWidth)}`;
|
|
793
|
+
}
|
|
794
|
+
function contentLine(rowIndex, width, pad) {
|
|
795
|
+
const src = displayLines.value[rowIndex] ?? "";
|
|
796
|
+
const clipped = sliceCells(src, width);
|
|
797
|
+
return pad ? padCells(clipped, width) : clipped;
|
|
798
|
+
}
|
|
799
|
+
function boxRow(rowIndex, width, height) {
|
|
800
|
+
const rowWidth = Math.max(0, Math.floor(width));
|
|
801
|
+
const rowHeight = Math.max(0, Math.floor(height));
|
|
802
|
+
if (!canDrawBox(rowWidth, rowHeight)) return contentLine(rowIndex, rowWidth, props.clear);
|
|
803
|
+
const chars = boxChars.value;
|
|
804
|
+
const innerW = Math.max(0, rowWidth - 2);
|
|
805
|
+
if (rowIndex === 0) {
|
|
806
|
+
let row = `${chars.tl}${repeatChar(chars.h, innerW)}${chars.tr}`;
|
|
807
|
+
const copy = headerCopySegment(rowWidth);
|
|
808
|
+
const title = headerTitleSegment(rowWidth, copy);
|
|
809
|
+
if (title) row = overlayCells(row, title, rowWidth);
|
|
810
|
+
if (copy) row = overlayCells(row, copy, rowWidth);
|
|
811
|
+
return row;
|
|
812
|
+
}
|
|
813
|
+
if (rowIndex === rowHeight - 1) return `${chars.bl}${repeatChar(chars.h, innerW)}${chars.br}`;
|
|
814
|
+
return `${chars.v}${contentLine(rowIndex - 1, innerW, true)}${chars.v}`;
|
|
815
|
+
}
|
|
816
|
+
useRenderNode(() => ({
|
|
817
|
+
zIndex: props.zIndex,
|
|
818
|
+
rect: visible.value ? absRect.value : {
|
|
819
|
+
x: 0,
|
|
820
|
+
y: 0,
|
|
821
|
+
w: 0,
|
|
822
|
+
h: 0
|
|
823
|
+
},
|
|
824
|
+
deps: [
|
|
825
|
+
visible.value,
|
|
826
|
+
absRect.value,
|
|
827
|
+
fullRect.value,
|
|
828
|
+
displayLines.value,
|
|
829
|
+
currentStyle.value,
|
|
830
|
+
props.clear,
|
|
831
|
+
renderedSnapshot.value,
|
|
832
|
+
hasBox.value,
|
|
833
|
+
boxChars.value,
|
|
834
|
+
props.title,
|
|
835
|
+
props.copyButton,
|
|
836
|
+
copyLabel.value,
|
|
837
|
+
documentVersion.value
|
|
838
|
+
],
|
|
839
|
+
paint: (dirtyRows) => {
|
|
840
|
+
withTextWidthProvider(widthProvider, () => {
|
|
841
|
+
if (!visible.value) return;
|
|
842
|
+
const r = absRect.value;
|
|
843
|
+
const full = fullRect.value;
|
|
844
|
+
if (r.w <= 0 || r.h <= 0) return;
|
|
845
|
+
const style = currentStyle.value;
|
|
846
|
+
const dx = Math.max(0, Math.floor(r.x - full.x));
|
|
847
|
+
const fullY = Math.floor(full.y);
|
|
848
|
+
const fullW = Math.max(0, Math.floor(full.w));
|
|
849
|
+
const fullH = Math.max(0, Math.floor(full.h));
|
|
850
|
+
const blank = props.clear ? spaces(r.w) : "";
|
|
851
|
+
const paintRow = (y) => {
|
|
852
|
+
if (y < r.y || y >= r.y + r.h) return;
|
|
853
|
+
const rowIndex = y - fullY;
|
|
854
|
+
if (rowIndex < 0 || rowIndex >= fullH) {
|
|
855
|
+
if (props.clear) terminal.write(blank, {
|
|
856
|
+
x: r.x,
|
|
857
|
+
y,
|
|
858
|
+
style
|
|
859
|
+
});
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
const src = boxRow(rowIndex, fullW, fullH);
|
|
863
|
+
const clipped = dx > 0 ? sliceCellsRange(src, dx, dx + r.w) : sliceCells(src, r.w);
|
|
864
|
+
const value = props.clear ? padCells(clipped, r.w) : clipped;
|
|
865
|
+
if (value || props.clear) terminal.write(value, {
|
|
866
|
+
x: r.x,
|
|
867
|
+
y,
|
|
868
|
+
style
|
|
869
|
+
});
|
|
870
|
+
};
|
|
871
|
+
if (dirtyRows?.length) {
|
|
872
|
+
for (const y of dirtyRows) paintRow(y);
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
for (let y = r.y; y < r.y + r.h; y++) paintRow(y);
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
}));
|
|
879
|
+
return () => h("span", rootProps);
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
const TMermaid = TMermaidText;
|
|
883
|
+
|
|
884
|
+
//#endregion
|
|
885
|
+
export { TMermaid as TMermaid$1, TMermaidText as TMermaidText$1, isSimpleMermaidFlowchartSource, markMermaidRenderErrorFatal, tMermaidTextProps };
|