@simon_he/vue-tui 1.1.3 → 1.1.5
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 +18 -18
- package/dist/{TMermaidText-frVr8Ysb.js → TMermaidText-wLnMMvVS.js} +1 -1
- package/dist/{TSelect-Dx34M1pF.js → TSelect-CMBOOFwK.js} +5 -5
- package/dist/{TTree-DdAjCPHu.js → TTree-kk8ntrpg.js} +6 -5
- package/dist/agent/mermaid.d.cts +2 -2
- package/dist/agent/mermaid.d.ts +2 -2
- package/dist/agent.cjs +542 -266
- package/dist/agent.js +25 -82
- package/dist/{block-source-Crro3mxi.js → block-source-DhzajB9H.js} +299 -239
- package/dist/cli.cjs +57 -16
- package/dist/cli.js +70 -15
- package/dist/core.js +3 -3
- package/dist/{hyperlink-_1FAj7Wq.js → create-terminal-Db_-UGVQ.js} +474 -102
- package/dist/{dom-renderer-DXx8fWzD.js → dom-renderer-BfwAEQMf.js} +3 -2
- package/dist/experimental.cjs +103 -66
- package/dist/experimental.js +20 -74
- package/dist/hyperlink-clbb_ha_.js +100 -0
- package/dist/index.js +8 -8
- package/dist/{linkify-BjI4zVfY.js → linkify-CL9wwnZN.js} +3 -3
- package/dist/markdown.cjs +521 -212
- package/dist/markdown.d.cts +3 -0
- package/dist/markdown.d.ts +3 -0
- package/dist/markdown.js +75 -8
- package/dist/math-image-BZhmfUeu.js +308 -0
- package/dist/mermaid-N3kGTHFy.js +1697 -0
- package/dist/mermaid.cjs +1460 -6
- package/dist/mermaid.d.cts +4 -0
- package/dist/mermaid.d.ts +4 -0
- package/dist/mermaid.js +7 -5
- package/dist/{rect-DUpeDfBg.js → rect-JzWMJxxc.js} +1 -1
- package/dist/renderer/cli/stdout-renderer.d.ts +44 -0
- package/dist/renderer/terminal-graphics.d.ts +61 -0
- package/dist/renderer-dom.js +4 -4
- package/dist/{terminal-graphics-Bbe83wSr.js → terminal-graphics-2FTRg9x3.js} +90 -2
- package/dist/{tlog-theme-i6S_Oftd.js → tlog-theme-B91Wv7Zj.js} +5 -4
- package/dist/vue/components/TAgentTerminalGraphic.d.ts +1 -1
- package/dist/vue/components/TMarkdownText.d.ts +70 -2
- package/dist/vue/components/TMermaidImage.d.ts +920 -0
- package/dist/vue/components/TMermaidText.d.ts +2 -2
- package/dist/vue/components/TVirtualMarkdown.d.ts +70 -2
- package/dist/vue/markdown/ast.d.ts +5 -0
- package/dist/vue/markdown/document.d.ts +3 -0
- package/dist/vue/markdown/math-image.d.ts +68 -0
- package/dist/vue/markdown/theme.d.ts +12 -0
- package/dist/vue/markdown/types.d.ts +12 -2
- package/dist/vue/mermaid/beautiful-mermaid.d.ts +284 -240
- package/dist/vue/mermaid/mermaid-image.d.ts +73 -0
- package/dist/vue.js +9 -9
- package/package.json +24 -10
- package/dist/mermaid-BNhM1jAZ.js +0 -123
- package/dist/width-GqllnV8C.js +0 -474
- /package/dist/{ansi-palette-CH6jc2Z7.js → ansi-palette-BHF1rN7R.js} +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { hasEncodedControl, sanitizeDomHref } from "./hyperlink-
|
|
2
|
-
import { EventZIndexContextKey, currentTextWidthProvider, forEachTextCellSegment, intersectRect, normalizeCellRect, repeatChar, sanitizeInlineText, sanitizeTextBlock, sliceByCellsRange, spaces, textCellWidth$1 as textCellWidth, translateRect, useLayout, useRenderNode, useTerminal, useTerminalNode, useVisibility, withTextWidthProvider } from "./rect-
|
|
1
|
+
import { hasEncodedControl, sanitizeDomHref } from "./hyperlink-clbb_ha_.js";
|
|
2
|
+
import { EventZIndexContextKey, currentTextWidthProvider, forEachTextCellSegment, intersectRect, normalizeCellRect, repeatChar, sanitizeInlineText, sanitizeTextBlock, sliceByCellsRange, spaces, textCellWidth$1 as textCellWidth, translateRect, useLayout, useRenderNode, useTerminal, useTerminalNode, useVisibility, withTextWidthProvider } from "./rect-JzWMJxxc.js";
|
|
3
3
|
import { terminalSelectionRowSpans, terminalSelectionVisibleRowSpans } from "./terminal-selection-4W1SJj4c.js";
|
|
4
4
|
import { createDebugLogger, isDebugEnabled } from "./debug-logger-CmsGI4of.js";
|
|
5
5
|
import { applyWheelScroll, createWheelScrollState, resetWheelScrollState } from "./wheel-scroll-DASkEZr-.js";
|
|
6
|
-
import { createIterm2InlineImageSequence, createKittyDeleteGraphicsSequence, createKittyGraphicsSequence, createKittyPlacementSequence, getTerminalGraphicsOutput, getTerminalGraphicsOutputVersion, isTerminalGraphicsProtocol, stableTerminalGraphicNumericId, subscribeTerminalGraphicsOutput } from "./terminal-graphics-
|
|
6
|
+
import { createIterm2InlineImageSequence, createKittyDeleteGraphicsSequence, createKittyGraphicsSequence, createKittyPlacementSequence, getTerminalGraphicsOutput, getTerminalGraphicsOutputVersion, isTerminalGraphicsProtocol, stableTerminalGraphicNumericId, subscribeTerminalGraphicsOutput } from "./terminal-graphics-2FTRg9x3.js";
|
|
7
|
+
import { enqueueMarkdownMathImages, getCachedMarkdownMathImage, isMarkdownMathImageRendererReady, loadMarkdownMathImageRenderer, resolveMarkdownMathColor, subscribeMarkdownMathImage } from "./math-image-BZhmfUeu.js";
|
|
7
8
|
import { computed, defineComponent, getCurrentInstance, h, inject, markRaw, onBeforeUnmount, ref, shallowRef, watch, watchEffect } from "vue";
|
|
8
9
|
import { getMarkdown, parseMarkdownToStructure } from "stream-markdown-parser";
|
|
9
10
|
|
|
@@ -113,213 +114,6 @@ function readMarkdownImageDimensions(base64) {
|
|
|
113
114
|
return null;
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
//#endregion
|
|
117
|
-
//#region src/vue/markdown/math.ts
|
|
118
|
-
let loadedKatex = null;
|
|
119
|
-
let katexLoad = null;
|
|
120
|
-
const katexListeners = new Set();
|
|
121
|
-
function resolveKatexRenderer(value) {
|
|
122
|
-
if (!value || typeof value !== "object") return null;
|
|
123
|
-
const renderToString = value.renderToString;
|
|
124
|
-
return typeof renderToString === "function" ? { renderToString } : null;
|
|
125
|
-
}
|
|
126
|
-
function subscribeMarkdownMathRenderer(listener) {
|
|
127
|
-
katexListeners.add(listener);
|
|
128
|
-
return () => katexListeners.delete(listener);
|
|
129
|
-
}
|
|
130
|
-
async function loadMarkdownMathRenderer() {
|
|
131
|
-
if (loadedKatex) return true;
|
|
132
|
-
if (!katexLoad) katexLoad = import("katex").then((mod) => {
|
|
133
|
-
const renderer = resolveKatexRenderer(mod.default) ?? resolveKatexRenderer(mod);
|
|
134
|
-
if (!renderer) return false;
|
|
135
|
-
loadedKatex = renderer;
|
|
136
|
-
for (const listener of katexListeners) listener();
|
|
137
|
-
return true;
|
|
138
|
-
}).catch(() => false);
|
|
139
|
-
return katexLoad;
|
|
140
|
-
}
|
|
141
|
-
const KATEX_TEXT_OPTIONS = Object.freeze({
|
|
142
|
-
output: "mathml",
|
|
143
|
-
throwOnError: false,
|
|
144
|
-
strict: "ignore",
|
|
145
|
-
trust: false,
|
|
146
|
-
maxSize: 20,
|
|
147
|
-
maxExpand: 200
|
|
148
|
-
});
|
|
149
|
-
const KATEX_VALIDATE_OPTIONS = Object.freeze({
|
|
150
|
-
...KATEX_TEXT_OPTIONS,
|
|
151
|
-
throwOnError: true
|
|
152
|
-
});
|
|
153
|
-
const TEX_SYMBOLS = Object.freeze({
|
|
154
|
-
alpha: "α",
|
|
155
|
-
beta: "β",
|
|
156
|
-
gamma: "γ",
|
|
157
|
-
delta: "δ",
|
|
158
|
-
epsilon: "ε",
|
|
159
|
-
theta: "θ",
|
|
160
|
-
lambda: "λ",
|
|
161
|
-
mu: "μ",
|
|
162
|
-
pi: "π",
|
|
163
|
-
rho: "ρ",
|
|
164
|
-
sigma: "σ",
|
|
165
|
-
tau: "τ",
|
|
166
|
-
phi: "φ",
|
|
167
|
-
omega: "ω",
|
|
168
|
-
Gamma: "Γ",
|
|
169
|
-
Delta: "Δ",
|
|
170
|
-
Theta: "Θ",
|
|
171
|
-
Lambda: "Λ",
|
|
172
|
-
Pi: "Π",
|
|
173
|
-
Sigma: "Σ",
|
|
174
|
-
Phi: "Φ",
|
|
175
|
-
Omega: "Ω",
|
|
176
|
-
int: "∫",
|
|
177
|
-
sum: "∑",
|
|
178
|
-
prod: "∏",
|
|
179
|
-
infty: "∞",
|
|
180
|
-
infinity: "∞",
|
|
181
|
-
pm: "±",
|
|
182
|
-
times: "×",
|
|
183
|
-
cdot: "·",
|
|
184
|
-
div: "÷",
|
|
185
|
-
le: "≤",
|
|
186
|
-
leq: "≤",
|
|
187
|
-
ge: "≥",
|
|
188
|
-
geq: "≥",
|
|
189
|
-
neq: "≠",
|
|
190
|
-
ne: "≠",
|
|
191
|
-
approx: "≈",
|
|
192
|
-
equiv: "≡",
|
|
193
|
-
to: "→",
|
|
194
|
-
rightarrow: "→",
|
|
195
|
-
leftarrow: "←",
|
|
196
|
-
leftrightarrow: "↔",
|
|
197
|
-
partial: "∂",
|
|
198
|
-
nabla: "∇",
|
|
199
|
-
sqrt: "√"
|
|
200
|
-
});
|
|
201
|
-
const SUPPORTED_COMMANDS = new Set([
|
|
202
|
-
...Object.keys(TEX_SYMBOLS),
|
|
203
|
-
"frac",
|
|
204
|
-
"sqrt"
|
|
205
|
-
]);
|
|
206
|
-
function decodeXmlEntities(value) {
|
|
207
|
-
return value.replace(/&(?:#(\d+)|#x([0-9a-f]+)|([a-z]+));/gi, (match, dec, hex, named) => {
|
|
208
|
-
if (dec) return String.fromCodePoint(Number(dec));
|
|
209
|
-
if (hex) return String.fromCodePoint(Number.parseInt(hex, 16));
|
|
210
|
-
switch (String(named).toLowerCase()) {
|
|
211
|
-
case "amp": return "&";
|
|
212
|
-
case "lt": return "<";
|
|
213
|
-
case "gt": return ">";
|
|
214
|
-
case "quot": return "\"";
|
|
215
|
-
case "apos": return "'";
|
|
216
|
-
default: return match;
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
function mathmlTagName(tag) {
|
|
221
|
-
const start = tag.startsWith("/") ? 1 : 0;
|
|
222
|
-
let end = start;
|
|
223
|
-
while (end < tag.length) {
|
|
224
|
-
const ch = tag[end];
|
|
225
|
-
if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "/") break;
|
|
226
|
-
end++;
|
|
227
|
-
}
|
|
228
|
-
return tag.slice(start, end).toLowerCase();
|
|
229
|
-
}
|
|
230
|
-
function textFromKatexMathml(html) {
|
|
231
|
-
let readable = "";
|
|
232
|
-
let offset = 0;
|
|
233
|
-
const lowerHtml = html.toLowerCase();
|
|
234
|
-
while (offset < html.length) {
|
|
235
|
-
const tagStart = html.indexOf("<", offset);
|
|
236
|
-
if (tagStart < 0) {
|
|
237
|
-
readable += html.slice(offset);
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
readable += html.slice(offset, tagStart);
|
|
241
|
-
const tagEnd = html.indexOf(">", tagStart + 1);
|
|
242
|
-
if (tagEnd < 0) break;
|
|
243
|
-
const tag = html.slice(tagStart + 1, tagEnd).trim();
|
|
244
|
-
const tagName = mathmlTagName(tag);
|
|
245
|
-
const closing = tag.startsWith("/");
|
|
246
|
-
if (!closing && tagName === "annotation") {
|
|
247
|
-
const annotationEnd = lowerHtml.indexOf("</annotation>", tagEnd + 1);
|
|
248
|
-
offset = annotationEnd < 0 ? tagEnd + 1 : annotationEnd + 13;
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
if (!closing && tagName === "mfrac") readable += "(";
|
|
252
|
-
else if (closing && tagName === "mfrac") readable += ")";
|
|
253
|
-
else if (!closing && tagName === "mspace") readable += " ";
|
|
254
|
-
offset = tagEnd + 1;
|
|
255
|
-
}
|
|
256
|
-
const text = sanitizeInlineText(decodeXmlEntities(readable).replace(/[<>]/g, "").replace(/\s+/g, " ").trim());
|
|
257
|
-
return text;
|
|
258
|
-
}
|
|
259
|
-
function approximateTexToUnicode(tex) {
|
|
260
|
-
let out = String(tex ?? "");
|
|
261
|
-
out = out.replace(/\\frac\s*\{([^{}]*)\}\s*\{([^{}]*)\}/g, "$1/$2");
|
|
262
|
-
out = out.replace(/\\sqrt\s*\{([^{}]*)\}/g, "√($1)");
|
|
263
|
-
out = out.replace(/\\([A-Za-z]+)\b/g, (_match, command) => TEX_SYMBOLS[command] ?? command);
|
|
264
|
-
out = out.replace(/\\([^A-Za-z])/g, "$1");
|
|
265
|
-
out = out.replace(/[{}]/g, "");
|
|
266
|
-
out = out.replace(/\s+/g, " ").trim();
|
|
267
|
-
return sanitizeInlineText(out.replace(/[<>]/g, ""));
|
|
268
|
-
}
|
|
269
|
-
function canRenderTerminalMath(tex, katex) {
|
|
270
|
-
const source = String(tex ?? "").trim();
|
|
271
|
-
if (!source || source.length > 160) return false;
|
|
272
|
-
if (/\\(?:begin|end|left|right|matrix|cases|array|align|color|href|html|includegraphics|class|style|tag|text|operatorname)\b/.test(source)) return false;
|
|
273
|
-
const commands = source.matchAll(/\\([A-Za-z]+)\b/g);
|
|
274
|
-
for (const match of commands) if (!SUPPORTED_COMMANDS.has(match[1] ?? "")) return false;
|
|
275
|
-
try {
|
|
276
|
-
katex.renderToString(source, KATEX_VALIDATE_OPTIONS);
|
|
277
|
-
} catch {
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
return true;
|
|
281
|
-
}
|
|
282
|
-
function renderMarkdownInlineMathSegment(tex) {
|
|
283
|
-
const source = String(tex ?? "");
|
|
284
|
-
if (!source.trim()) return {
|
|
285
|
-
text: "",
|
|
286
|
-
supported: false
|
|
287
|
-
};
|
|
288
|
-
const katex = loadedKatex;
|
|
289
|
-
if (!katex) {
|
|
290
|
-
loadMarkdownMathRenderer();
|
|
291
|
-
return {
|
|
292
|
-
text: "",
|
|
293
|
-
supported: false
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
if (!canRenderTerminalMath(source, katex)) return {
|
|
297
|
-
text: "",
|
|
298
|
-
supported: false
|
|
299
|
-
};
|
|
300
|
-
try {
|
|
301
|
-
const html = katex.renderToString(source, KATEX_TEXT_OPTIONS);
|
|
302
|
-
const rendered = /\\frac\b/.test(source) ? approximateTexToUnicode(source) : textFromKatexMathml(html);
|
|
303
|
-
if (rendered && !rendered.includes("\\")) return {
|
|
304
|
-
text: rendered,
|
|
305
|
-
supported: true
|
|
306
|
-
};
|
|
307
|
-
} catch {
|
|
308
|
-
return {
|
|
309
|
-
text: "",
|
|
310
|
-
supported: false
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
const approximate = approximateTexToUnicode(source);
|
|
314
|
-
return approximate && !approximate.includes("\\") ? {
|
|
315
|
-
text: approximate,
|
|
316
|
-
supported: true
|
|
317
|
-
} : {
|
|
318
|
-
text: "",
|
|
319
|
-
supported: false
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
117
|
//#endregion
|
|
324
118
|
//#region src/vue/markdown/parser.ts
|
|
325
119
|
const markdownInstanceCache = new Map();
|
|
@@ -621,12 +415,34 @@ function inlineNodeSegments(nodes, theme, inheritedStyle, options = {}) {
|
|
|
621
415
|
case "math_inline":
|
|
622
416
|
{
|
|
623
417
|
const source = stringProp(node, "content");
|
|
624
|
-
const
|
|
625
|
-
const
|
|
626
|
-
|
|
418
|
+
const markup = stringProp(node, "markup") || "$";
|
|
419
|
+
const raw = stringProp(node, "raw") || `${markup}${source}${markup}`;
|
|
420
|
+
const mathStyle = mergeStyle$1(inheritedStyle, theme.inlineCode);
|
|
421
|
+
const tex = sanitizeInlineText(source);
|
|
422
|
+
const mathEnabled = options.math?.enabled !== false;
|
|
423
|
+
const cached = tex && mathEnabled ? getCachedMarkdownMathImage(tex, "inline", options.math) : null;
|
|
424
|
+
if (cached) pushTextSegments(out, raw, mathStyle, {
|
|
425
|
+
kind: "math",
|
|
426
|
+
tex,
|
|
427
|
+
raw,
|
|
428
|
+
base64: cached.base64,
|
|
429
|
+
displayWidth: cached.widthCells,
|
|
430
|
+
displayHeight: cached.heightCells
|
|
431
|
+
}, {
|
|
432
|
+
source: tex,
|
|
433
|
+
raw,
|
|
434
|
+
rendered: true
|
|
435
|
+
});
|
|
436
|
+
else pushTextSegments(out, raw, mathStyle, void 0, tex && mathEnabled ? {
|
|
437
|
+
source: tex,
|
|
438
|
+
raw,
|
|
439
|
+
rendered: false,
|
|
440
|
+
pendingImage: true,
|
|
441
|
+
mode: "inline"
|
|
442
|
+
} : {
|
|
627
443
|
source,
|
|
628
444
|
raw,
|
|
629
|
-
rendered:
|
|
445
|
+
rendered: false
|
|
630
446
|
});
|
|
631
447
|
}
|
|
632
448
|
break;
|
|
@@ -664,14 +480,16 @@ function inlineBlock(key, segments, context) {
|
|
|
664
480
|
function blockFromParagraph(node, key, context, theme) {
|
|
665
481
|
return inlineBlock(key, inlineNodeSegments(nodeChildren(node), theme, void 0, {
|
|
666
482
|
imageResolver: context.imageResolver,
|
|
667
|
-
imageSize: context.imageSize
|
|
483
|
+
imageSize: context.imageSize,
|
|
484
|
+
math: context.math
|
|
668
485
|
}), context);
|
|
669
486
|
}
|
|
670
487
|
function blockFromHeading(node, key, context, theme) {
|
|
671
488
|
const level = Math.min(6, Math.max(1, Math.floor(numberProp(node, "level") ?? 1)));
|
|
672
489
|
return inlineBlock(key, inlineNodeSegments(nodeChildren(node), theme, theme.heading[level - 1], {
|
|
673
490
|
imageResolver: context.imageResolver,
|
|
674
|
-
imageSize: context.imageSize
|
|
491
|
+
imageSize: context.imageSize,
|
|
492
|
+
math: context.math
|
|
675
493
|
}), context);
|
|
676
494
|
}
|
|
677
495
|
function blockFromCodeBlock(node, key, context, theme) {
|
|
@@ -690,7 +508,10 @@ function blockFromHtmlBlock(node, key, context, theme) {
|
|
|
690
508
|
type: "html_block",
|
|
691
509
|
raw: stringProp(node, "raw"),
|
|
692
510
|
content: stringProp(node, "content")
|
|
693
|
-
}], theme, void 0, {
|
|
511
|
+
}], theme, void 0, {
|
|
512
|
+
imageResolver: context.imageResolver,
|
|
513
|
+
math: context.math
|
|
514
|
+
}), context);
|
|
694
515
|
}
|
|
695
516
|
function tableRows$1(node, key) {
|
|
696
517
|
const value = node[key];
|
|
@@ -710,14 +531,16 @@ function blockFromTable(node, key, context, theme) {
|
|
|
710
531
|
const header = tableCells(headerRow ?? { type: "table_row" }).map((cell) => ({
|
|
711
532
|
segments: inlineNodeSegments(nodeChildren(cell), theme, theme.strong, {
|
|
712
533
|
imageResolver: context.imageResolver,
|
|
713
|
-
imageSize: context.imageSize
|
|
534
|
+
imageSize: context.imageSize,
|
|
535
|
+
math: context.math
|
|
714
536
|
}),
|
|
715
537
|
align: tableCellAlign(cell)
|
|
716
538
|
}));
|
|
717
539
|
const rows = tableRows$1(node, "rows").map((row) => tableCells(row).map((cell) => ({
|
|
718
540
|
segments: inlineNodeSegments(nodeChildren(cell), theme, void 0, {
|
|
719
541
|
imageResolver: context.imageResolver,
|
|
720
|
-
imageSize: context.imageSize
|
|
542
|
+
imageSize: context.imageSize,
|
|
543
|
+
math: context.math
|
|
721
544
|
}),
|
|
722
545
|
align: tableCellAlign(cell)
|
|
723
546
|
})));
|
|
@@ -755,11 +578,13 @@ function listItemBlocks(item, index, ordered, start, context, theme, keyPrefix)
|
|
|
755
578
|
const indentSegment = { text: spaces(markerCells) };
|
|
756
579
|
const firstContext = {
|
|
757
580
|
prefixSegments: [...context.prefixSegments, markerSegment],
|
|
758
|
-
continuationPrefixSegments: [...context.continuationPrefixSegments, indentSegment]
|
|
581
|
+
continuationPrefixSegments: [...context.continuationPrefixSegments, indentSegment],
|
|
582
|
+
math: context.math
|
|
759
583
|
};
|
|
760
584
|
const nestedContext = {
|
|
761
585
|
prefixSegments: [...context.continuationPrefixSegments, indentSegment],
|
|
762
|
-
continuationPrefixSegments: [...context.continuationPrefixSegments, indentSegment]
|
|
586
|
+
continuationPrefixSegments: [...context.continuationPrefixSegments, indentSegment],
|
|
587
|
+
math: context.math
|
|
763
588
|
};
|
|
764
589
|
const children = nodeChildren(item);
|
|
765
590
|
if (!children.length) return [inlineBlock(`${keyPrefix}-empty`, [], firstContext)];
|
|
@@ -791,6 +616,61 @@ function listBlocks(node, context, theme, keyPrefix) {
|
|
|
791
616
|
for (let i = 0; i < items.length; i++) out.push(...listItemBlocks(items[i], i, booleanProp(node, "ordered"), numberProp(node, "start") ?? 1, context, theme, `${keyPrefix}-${i}`));
|
|
792
617
|
return out;
|
|
793
618
|
}
|
|
619
|
+
/**
|
|
620
|
+
* Block-level display math (`$...$`). When a rasterized PNG is available this
|
|
621
|
+
* becomes a graphic segment rendered through the terminal graphics pipeline
|
|
622
|
+
* (Kitty/iTerm2/Sixel); otherwise it is wrapped in a box with the raw TeX text
|
|
623
|
+
* (also the permanent presentation when graphics/raster support is missing).
|
|
624
|
+
* Clicking either form emits `mathAction` so consumers can copy the raw content.
|
|
625
|
+
*/
|
|
626
|
+
function blockMathSegments(source, raw, math, theme) {
|
|
627
|
+
const tex = sanitizeInlineText(source);
|
|
628
|
+
const canUseImage = Boolean(tex) && math.enabled !== false;
|
|
629
|
+
const cached = canUseImage ? getCachedMarkdownMathImage(tex, "display", math) : null;
|
|
630
|
+
if (canUseImage && cached) return [{
|
|
631
|
+
text: raw,
|
|
632
|
+
style: theme.math,
|
|
633
|
+
graphic: {
|
|
634
|
+
kind: "math",
|
|
635
|
+
tex,
|
|
636
|
+
raw,
|
|
637
|
+
base64: cached.base64,
|
|
638
|
+
displayWidth: cached.widthCells,
|
|
639
|
+
displayHeight: cached.heightCells
|
|
640
|
+
},
|
|
641
|
+
mathAction: {
|
|
642
|
+
source: tex,
|
|
643
|
+
raw,
|
|
644
|
+
rendered: true
|
|
645
|
+
}
|
|
646
|
+
}];
|
|
647
|
+
const maxWidth = Math.max(8, Math.floor(math.maxWidthCells ?? 0) || 40);
|
|
648
|
+
const rawCells = textCellWidth(raw);
|
|
649
|
+
const inner = Math.min(Math.max(1, rawCells + 2), maxWidth);
|
|
650
|
+
const pad = Math.max(0, inner - rawCells);
|
|
651
|
+
return [
|
|
652
|
+
{
|
|
653
|
+
text: `┌${"─".repeat(inner)}┐`,
|
|
654
|
+
style: theme.math
|
|
655
|
+
},
|
|
656
|
+
HARD_BREAK_SEGMENT,
|
|
657
|
+
{
|
|
658
|
+
text: `│ ${raw}${" ".repeat(pad)}│`,
|
|
659
|
+
style: theme.math,
|
|
660
|
+
mathAction: {
|
|
661
|
+
source: tex,
|
|
662
|
+
raw,
|
|
663
|
+
rendered: false,
|
|
664
|
+
pendingImage: true
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
HARD_BREAK_SEGMENT,
|
|
668
|
+
{
|
|
669
|
+
text: `└${"─".repeat(inner)}┘`,
|
|
670
|
+
style: theme.math
|
|
671
|
+
}
|
|
672
|
+
];
|
|
673
|
+
}
|
|
794
674
|
function nodeToBlocks(node, context, theme, keyPrefix) {
|
|
795
675
|
switch (node.type) {
|
|
796
676
|
case "paragraph":
|
|
@@ -809,6 +689,7 @@ function nodeToBlocks(node, context, theme, keyPrefix) {
|
|
|
809
689
|
style: theme.thematicBreak,
|
|
810
690
|
prefixSegments: context.prefixSegments
|
|
811
691
|
}];
|
|
692
|
+
case "math_block": return [inlineBlock(keyPrefix, blockMathSegments(stringProp(node, "content"), stringProp(node, "raw") || `$${stringProp(node, "content")}$`, context.math ?? { enabled: true }, theme), context)];
|
|
812
693
|
case "blockquote": {
|
|
813
694
|
const quoteSegment = {
|
|
814
695
|
text: "│ ",
|
|
@@ -818,7 +699,8 @@ function nodeToBlocks(node, context, theme, keyPrefix) {
|
|
|
818
699
|
prefixSegments: [...context.prefixSegments, quoteSegment],
|
|
819
700
|
continuationPrefixSegments: [...context.continuationPrefixSegments, quoteSegment],
|
|
820
701
|
imageResolver: context.imageResolver,
|
|
821
|
-
imageSize: context.imageSize
|
|
702
|
+
imageSize: context.imageSize,
|
|
703
|
+
math: context.math
|
|
822
704
|
};
|
|
823
705
|
return childSequenceToBlocks(nodeChildren(node), quoteContext, theme, keyPrefix);
|
|
824
706
|
}
|
|
@@ -828,22 +710,30 @@ function nodeToBlocks(node, context, theme, keyPrefix) {
|
|
|
828
710
|
case "table": return [blockFromTable(node, keyPrefix, context, theme)];
|
|
829
711
|
case "inline": return [inlineBlock(keyPrefix, inlineNodeSegments(nodeChildren(node), theme, void 0, {
|
|
830
712
|
imageResolver: context.imageResolver,
|
|
831
|
-
imageSize: context.imageSize
|
|
713
|
+
imageSize: context.imageSize,
|
|
714
|
+
math: context.math
|
|
832
715
|
}), context)];
|
|
833
716
|
case "html_block":
|
|
834
717
|
if ("content" in node) return [blockFromHtmlBlock(node, keyPrefix, context, theme)];
|
|
835
718
|
break;
|
|
836
|
-
case "text": return [inlineBlock(keyPrefix, inlineNodeSegments([node], theme, void 0, {
|
|
719
|
+
case "text": return [inlineBlock(keyPrefix, inlineNodeSegments([node], theme, void 0, {
|
|
720
|
+
imageResolver: context.imageResolver,
|
|
721
|
+
math: context.math
|
|
722
|
+
}), context)];
|
|
837
723
|
}
|
|
838
724
|
if (nodeChildren(node).length) return childSequenceToBlocks(nodeChildren(node), context, theme, keyPrefix);
|
|
839
|
-
return [inlineBlock(keyPrefix, inlineNodeSegments([node], theme, void 0, {
|
|
725
|
+
return [inlineBlock(keyPrefix, inlineNodeSegments([node], theme, void 0, {
|
|
726
|
+
imageResolver: context.imageResolver,
|
|
727
|
+
math: context.math
|
|
728
|
+
}), context)];
|
|
840
729
|
}
|
|
841
730
|
function markdownAstToBlocks(nodes, theme, options = {}) {
|
|
842
731
|
const blocks = trimBlockArray(childSequenceToBlocks(nodes, {
|
|
843
732
|
prefixSegments: EMPTY_PREFIX,
|
|
844
733
|
continuationPrefixSegments: EMPTY_PREFIX,
|
|
845
734
|
imageResolver: options.imageResolver,
|
|
846
|
-
imageSize: options.imageSize
|
|
735
|
+
imageSize: options.imageSize,
|
|
736
|
+
math: options.math
|
|
847
737
|
}, theme, "md"));
|
|
848
738
|
return blocks.length ? blocks : [{
|
|
849
739
|
type: "blank",
|
|
@@ -992,7 +882,8 @@ function wrapLineSegments(source, prefixSegments, continuationPrefixSegments, wi
|
|
|
992
882
|
style: segment.style,
|
|
993
883
|
cells,
|
|
994
884
|
graphic: segment.graphic,
|
|
995
|
-
fallbackText: segment.text
|
|
885
|
+
fallbackText: segment.text,
|
|
886
|
+
...segment.mathAction ? { mathAction: segment.mathAction } : {}
|
|
996
887
|
});
|
|
997
888
|
row.remaining -= cells;
|
|
998
889
|
continue;
|
|
@@ -1260,7 +1151,8 @@ function styleSignature(style) {
|
|
|
1260
1151
|
function inlineSegmentSignature(segment) {
|
|
1261
1152
|
const graphic = segment.graphic ? [
|
|
1262
1153
|
segment.graphic.kind,
|
|
1263
|
-
segment.graphic.src,
|
|
1154
|
+
segment.graphic.src ?? "",
|
|
1155
|
+
segment.graphic.tex ?? "",
|
|
1264
1156
|
segment.graphic.alt ?? "",
|
|
1265
1157
|
segment.graphic.mime ?? "",
|
|
1266
1158
|
segment.graphic.base64 ?? "",
|
|
@@ -1435,7 +1327,8 @@ const DEFAULT_TUI_MARKDOWN_THEME = Object.freeze({
|
|
|
1435
1327
|
}),
|
|
1436
1328
|
codeBlock: freezeStyle({ fg: "yellowBright" }),
|
|
1437
1329
|
thematicBreak: freezeStyle({ dim: true }),
|
|
1438
|
-
html: freezeStyle({ dim: true })
|
|
1330
|
+
html: freezeStyle({ dim: true }),
|
|
1331
|
+
math: freezeStyle({ fg: "cyanBright" })
|
|
1439
1332
|
});
|
|
1440
1333
|
function stableSerialize(value) {
|
|
1441
1334
|
if (value == null) return "null";
|
|
@@ -1461,7 +1354,8 @@ function resolveTuiMarkdownTheme(overrides) {
|
|
|
1461
1354
|
listMarker: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.listMarker, overrides.listMarker),
|
|
1462
1355
|
codeBlock: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.codeBlock, overrides.codeBlock),
|
|
1463
1356
|
thematicBreak: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.thematicBreak, overrides.thematicBreak),
|
|
1464
|
-
html: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.html, overrides.html)
|
|
1357
|
+
html: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.html, overrides.html),
|
|
1358
|
+
math: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.math, overrides.math)
|
|
1465
1359
|
});
|
|
1466
1360
|
}
|
|
1467
1361
|
|
|
@@ -1477,7 +1371,8 @@ function buildMarkdownBlocks(content, parser, options) {
|
|
|
1477
1371
|
const nodes = parser.parse(content, options?.final ?? true);
|
|
1478
1372
|
const blocks = markdownAstToBlocks(nodes, theme, {
|
|
1479
1373
|
imageResolver: options?.imageResolver,
|
|
1480
|
-
imageSize: options?.imageSize
|
|
1374
|
+
imageSize: options?.imageSize,
|
|
1375
|
+
math: options?.math
|
|
1481
1376
|
});
|
|
1482
1377
|
return {
|
|
1483
1378
|
nodes,
|
|
@@ -1664,11 +1559,12 @@ function findMarkdownMathActionAt(rows, point, options) {
|
|
|
1664
1559
|
if (!math || segmentEnd <= clipStart || segmentStart >= clipEnd) continue;
|
|
1665
1560
|
const visibleStart = Math.max(segmentStart, clipStart);
|
|
1666
1561
|
const visibleEnd = Math.min(segmentEnd, clipEnd);
|
|
1562
|
+
const graphicHeight = segment.graphic ? Math.max(1, Math.floor(segment.graphic.displayHeight ?? 1)) : 1;
|
|
1667
1563
|
const rect = {
|
|
1668
1564
|
x: r.x + visibleStart - clipStart,
|
|
1669
1565
|
y: r.y + rowIndex - firstRow,
|
|
1670
1566
|
w: visibleEnd - visibleStart,
|
|
1671
|
-
h:
|
|
1567
|
+
h: graphicHeight
|
|
1672
1568
|
};
|
|
1673
1569
|
if (point.cellX < rect.x || point.cellY < rect.y || point.cellX >= rect.x + rect.w || point.cellY >= rect.y + rect.h) continue;
|
|
1674
1570
|
return {
|
|
@@ -1684,6 +1580,97 @@ function findMarkdownMathActionAt(rows, point, options) {
|
|
|
1684
1580
|
return null;
|
|
1685
1581
|
}
|
|
1686
1582
|
|
|
1583
|
+
//#endregion
|
|
1584
|
+
//#region src/vue/markdown/math.ts
|
|
1585
|
+
let loadedKatex = null;
|
|
1586
|
+
let katexLoad = null;
|
|
1587
|
+
const katexListeners = new Set();
|
|
1588
|
+
function resolveKatexRenderer(value) {
|
|
1589
|
+
if (!value || typeof value !== "object") return null;
|
|
1590
|
+
const renderToString = value.renderToString;
|
|
1591
|
+
return typeof renderToString === "function" ? { renderToString } : null;
|
|
1592
|
+
}
|
|
1593
|
+
function subscribeMarkdownMathRenderer(listener) {
|
|
1594
|
+
katexListeners.add(listener);
|
|
1595
|
+
return () => katexListeners.delete(listener);
|
|
1596
|
+
}
|
|
1597
|
+
async function loadMarkdownMathRenderer() {
|
|
1598
|
+
if (loadedKatex) return true;
|
|
1599
|
+
if (!katexLoad) katexLoad = import("katex").then((mod) => {
|
|
1600
|
+
const renderer = resolveKatexRenderer(mod.default) ?? resolveKatexRenderer(mod);
|
|
1601
|
+
if (!renderer) return false;
|
|
1602
|
+
loadedKatex = renderer;
|
|
1603
|
+
for (const listener of katexListeners) listener();
|
|
1604
|
+
return true;
|
|
1605
|
+
}).catch(() => false);
|
|
1606
|
+
return katexLoad;
|
|
1607
|
+
}
|
|
1608
|
+
const KATEX_TEXT_OPTIONS = Object.freeze({
|
|
1609
|
+
output: "mathml",
|
|
1610
|
+
throwOnError: false,
|
|
1611
|
+
strict: "ignore",
|
|
1612
|
+
trust: false,
|
|
1613
|
+
maxSize: 20,
|
|
1614
|
+
maxExpand: 200
|
|
1615
|
+
});
|
|
1616
|
+
const KATEX_VALIDATE_OPTIONS = Object.freeze({
|
|
1617
|
+
...KATEX_TEXT_OPTIONS,
|
|
1618
|
+
throwOnError: true
|
|
1619
|
+
});
|
|
1620
|
+
const TEX_SYMBOLS = Object.freeze({
|
|
1621
|
+
alpha: "α",
|
|
1622
|
+
beta: "β",
|
|
1623
|
+
gamma: "γ",
|
|
1624
|
+
delta: "δ",
|
|
1625
|
+
epsilon: "ε",
|
|
1626
|
+
theta: "θ",
|
|
1627
|
+
lambda: "λ",
|
|
1628
|
+
mu: "μ",
|
|
1629
|
+
pi: "π",
|
|
1630
|
+
rho: "ρ",
|
|
1631
|
+
sigma: "σ",
|
|
1632
|
+
tau: "τ",
|
|
1633
|
+
phi: "φ",
|
|
1634
|
+
omega: "ω",
|
|
1635
|
+
Gamma: "Γ",
|
|
1636
|
+
Delta: "Δ",
|
|
1637
|
+
Theta: "Θ",
|
|
1638
|
+
Lambda: "Λ",
|
|
1639
|
+
Pi: "Π",
|
|
1640
|
+
Sigma: "Σ",
|
|
1641
|
+
Phi: "Φ",
|
|
1642
|
+
Omega: "Ω",
|
|
1643
|
+
int: "∫",
|
|
1644
|
+
sum: "∑",
|
|
1645
|
+
prod: "∏",
|
|
1646
|
+
infty: "∞",
|
|
1647
|
+
infinity: "∞",
|
|
1648
|
+
pm: "±",
|
|
1649
|
+
times: "×",
|
|
1650
|
+
cdot: "·",
|
|
1651
|
+
div: "÷",
|
|
1652
|
+
le: "≤",
|
|
1653
|
+
leq: "≤",
|
|
1654
|
+
ge: "≥",
|
|
1655
|
+
geq: "≥",
|
|
1656
|
+
neq: "≠",
|
|
1657
|
+
ne: "≠",
|
|
1658
|
+
approx: "≈",
|
|
1659
|
+
equiv: "≡",
|
|
1660
|
+
to: "→",
|
|
1661
|
+
rightarrow: "→",
|
|
1662
|
+
leftarrow: "←",
|
|
1663
|
+
leftrightarrow: "↔",
|
|
1664
|
+
partial: "∂",
|
|
1665
|
+
nabla: "∇",
|
|
1666
|
+
sqrt: "√"
|
|
1667
|
+
});
|
|
1668
|
+
const SUPPORTED_COMMANDS = new Set([
|
|
1669
|
+
...Object.keys(TEX_SYMBOLS),
|
|
1670
|
+
"frac",
|
|
1671
|
+
"sqrt"
|
|
1672
|
+
]);
|
|
1673
|
+
|
|
1687
1674
|
//#endregion
|
|
1688
1675
|
//#region src/vue/markdown/render.ts
|
|
1689
1676
|
const mergedStyleCache = new WeakMap();
|
|
@@ -1710,7 +1697,7 @@ function mergeStyle(base, overlay) {
|
|
|
1710
1697
|
}
|
|
1711
1698
|
const activeMarkdownImageGraphics = new WeakMap();
|
|
1712
1699
|
function markdownImageGraphicId(segment, identity) {
|
|
1713
|
-
return `md-image:${stableTerminalGraphicNumericId(`${identity}:${segment.src}:${segment.displayWidth ?? 0}:${segment.displayHeight ?? 0}:${segment.base64 ?? ""}`)}`;
|
|
1700
|
+
return `md-image:${stableTerminalGraphicNumericId(`${identity}:${segment.src ?? segment.tex ?? ""}:${segment.displayWidth ?? 0}:${segment.displayHeight ?? 0}:${segment.base64 ?? ""}`)}`;
|
|
1714
1701
|
}
|
|
1715
1702
|
function rememberMarkdownImageGraphic(terminal, id, rect) {
|
|
1716
1703
|
let active = activeMarkdownImageGraphics.get(terminal);
|
|
@@ -1736,7 +1723,7 @@ function clearStaleMarkdownImageGraphicsForRow(terminal, y, keepIds, keepVisible
|
|
|
1736
1723
|
}
|
|
1737
1724
|
}
|
|
1738
1725
|
function canAttemptMarkdownImageGraphic(terminal, segment) {
|
|
1739
|
-
if (
|
|
1726
|
+
if (!segment.base64) return false;
|
|
1740
1727
|
const output = getTerminalGraphicsOutput(terminal);
|
|
1741
1728
|
const protocol = output?.capabilities.preferredProtocol;
|
|
1742
1729
|
return Boolean(output?.capabilities.supported && isTerminalGraphicsProtocol(protocol));
|
|
@@ -1750,7 +1737,7 @@ function clearMarkdownImageGraphics(terminal, rect) {
|
|
|
1750
1737
|
}
|
|
1751
1738
|
}
|
|
1752
1739
|
function queueMarkdownImageGraphic(terminal, segment, identity, rect) {
|
|
1753
|
-
if (
|
|
1740
|
+
if (!segment.base64) return "unavailable";
|
|
1754
1741
|
const output = getTerminalGraphicsOutput(terminal);
|
|
1755
1742
|
const protocol = output?.capabilities.preferredProtocol;
|
|
1756
1743
|
if (!output?.capabilities.supported || !isTerminalGraphicsProtocol(protocol)) return "unavailable";
|
|
@@ -1792,7 +1779,7 @@ function queueMarkdownImageGraphic(terminal, segment, identity, rect) {
|
|
|
1792
1779
|
sequence,
|
|
1793
1780
|
resizeSequence,
|
|
1794
1781
|
clearSequence,
|
|
1795
|
-
fallbackText: segment.alt ?? "image"
|
|
1782
|
+
fallbackText: segment.alt ?? (segment.kind === "math" ? segment.raw ?? segment.tex ?? "math" : "image")
|
|
1796
1783
|
});
|
|
1797
1784
|
markdownImageDebug(`queue id=${id}`, `accepted=${accepted ? "true" : "false"}`, `x=${rect.x}`, `y=${rect.y}`, `w=${width}`, `h=${height}`, `visibleW=${rect.w}`, `displayW=${segment.displayWidth ?? ""}`, `displayH=${segment.displayHeight ?? ""}`);
|
|
1798
1785
|
if (accepted) rememberMarkdownImageGraphic(terminal, id, {
|
|
@@ -1896,7 +1883,7 @@ function paintMarkdownVisualRow(terminal, row, options) {
|
|
|
1896
1883
|
const queuedGraphic = queueResult === "queued";
|
|
1897
1884
|
const suppressFallback = queuedGraphic || queueResult === "rejected" || graphicAvailable === true;
|
|
1898
1885
|
if (queuedGraphic) queuedGraphics.add(markdownImageGraphicId(segment.graphic, `${row.key}:${segmentIndex}`));
|
|
1899
|
-
terminal.write(suppressFallback ? spaces(visibleCells) : sliceByCellsRange(segment.fallbackText ?? segment.graphic.alt ?? "image", 0, visibleCells) || spaces(visibleCells), {
|
|
1886
|
+
terminal.write(suppressFallback ? spaces(visibleCells) : sliceByCellsRange(segment.fallbackText ?? segment.graphic.alt ?? (segment.graphic.kind === "math" ? segment.graphic.raw ?? segment.graphic.tex ?? "math" : "image"), 0, visibleCells) || spaces(visibleCells), {
|
|
1900
1887
|
x: cellX,
|
|
1901
1888
|
y: options.y,
|
|
1902
1889
|
style: suppressFallback ? options.baseStyle : segmentStyle
|
|
@@ -2088,6 +2075,34 @@ const TVirtualMarkdown = defineComponent({
|
|
|
2088
2075
|
type: Boolean,
|
|
2089
2076
|
default: true
|
|
2090
2077
|
},
|
|
2078
|
+
mathImages: {
|
|
2079
|
+
type: Boolean,
|
|
2080
|
+
default: true
|
|
2081
|
+
},
|
|
2082
|
+
mathCellWidthPx: {
|
|
2083
|
+
type: Number,
|
|
2084
|
+
default: void 0
|
|
2085
|
+
},
|
|
2086
|
+
mathCellHeightPx: {
|
|
2087
|
+
type: Number,
|
|
2088
|
+
default: void 0
|
|
2089
|
+
},
|
|
2090
|
+
mathScale: {
|
|
2091
|
+
type: Number,
|
|
2092
|
+
default: void 0
|
|
2093
|
+
},
|
|
2094
|
+
mathColor: {
|
|
2095
|
+
type: String,
|
|
2096
|
+
default: void 0
|
|
2097
|
+
},
|
|
2098
|
+
mathMaxWidthCells: {
|
|
2099
|
+
type: Number,
|
|
2100
|
+
default: void 0
|
|
2101
|
+
},
|
|
2102
|
+
mathBaselineRatio: {
|
|
2103
|
+
type: Number,
|
|
2104
|
+
default: void 0
|
|
2105
|
+
},
|
|
2091
2106
|
imageActions: {
|
|
2092
2107
|
type: Boolean,
|
|
2093
2108
|
default: false
|
|
@@ -2138,10 +2153,42 @@ const TVirtualMarkdown = defineComponent({
|
|
|
2138
2153
|
const graphicsOutputVersion = shallowRef(getTerminalGraphicsOutputVersion(terminal));
|
|
2139
2154
|
const unsubscribeGraphicsOutput = subscribeTerminalGraphicsOutput(terminal, () => {
|
|
2140
2155
|
graphicsOutputVersion.value = getTerminalGraphicsOutputVersion(terminal);
|
|
2156
|
+
enqueuePendingMathImages();
|
|
2141
2157
|
});
|
|
2142
2158
|
const unsubscribeMathRenderer = subscribeMarkdownMathRenderer(() => {
|
|
2143
2159
|
scheduleRebuild();
|
|
2144
2160
|
});
|
|
2161
|
+
const unsubscribeMathImage = subscribeMarkdownMathImage(() => {
|
|
2162
|
+
scheduleRebuild();
|
|
2163
|
+
});
|
|
2164
|
+
function mathOptions() {
|
|
2165
|
+
if (props.mathImages === false) return { enabled: false };
|
|
2166
|
+
const resolvedColor = props.mathColor ?? resolveMarkdownMathColor(defaultStyle.value.fg);
|
|
2167
|
+
return {
|
|
2168
|
+
enabled: true,
|
|
2169
|
+
...props.mathCellWidthPx != null ? { cellWidthPx: props.mathCellWidthPx } : {},
|
|
2170
|
+
...props.mathCellHeightPx != null ? { cellHeightPx: props.mathCellHeightPx } : {},
|
|
2171
|
+
...props.mathScale != null ? { scale: props.mathScale } : {},
|
|
2172
|
+
...resolvedColor != null ? { color: resolvedColor } : {},
|
|
2173
|
+
...props.mathBaselineRatio != null ? { baselineRatio: props.mathBaselineRatio } : {},
|
|
2174
|
+
maxWidthCells: props.mathMaxWidthCells ?? props.w
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
function enqueuePendingMathImages() {
|
|
2178
|
+
if (props.mathImages === false) return;
|
|
2179
|
+
if (!getTerminalGraphicsOutput(terminal)?.capabilities.supported) return;
|
|
2180
|
+
if (!isMarkdownMathImageRendererReady()) {
|
|
2181
|
+
loadMarkdownMathImageRenderer().then((ready) => {
|
|
2182
|
+
if (ready && alive) scheduleRebuild();
|
|
2183
|
+
});
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
const h$1 = Math.max(0, Math.floor(props.h ?? absRect.value.h));
|
|
2187
|
+
enqueueMarkdownMathImages(rows.value, mathOptions(), {
|
|
2188
|
+
firstRow: internalScrollTop.value,
|
|
2189
|
+
lastRow: internalScrollTop.value + h$1
|
|
2190
|
+
});
|
|
2191
|
+
}
|
|
2145
2192
|
watch(() => `${props.streaming ? 1 : 0}:${(props.customHtmlTags ?? []).join("\0")}`, () => {
|
|
2146
2193
|
parser.value = markRaw(createTuiMarkdownParser({
|
|
2147
2194
|
streaming: props.streaming,
|
|
@@ -2163,13 +2210,15 @@ const TVirtualMarkdown = defineComponent({
|
|
|
2163
2210
|
minHeight: props.imageMinHeight,
|
|
2164
2211
|
maxHeight: props.imageMaxHeight,
|
|
2165
2212
|
preserveAspectRatio: props.imagePreserveAspectRatio
|
|
2166
|
-
}
|
|
2213
|
+
},
|
|
2214
|
+
math: mathOptions()
|
|
2167
2215
|
}).blocks;
|
|
2168
2216
|
return layoutMarkdownBlocksCached(blocks, props.w, layoutCache);
|
|
2169
2217
|
});
|
|
2170
2218
|
layoutCache = markRaw(nextLayout.cache);
|
|
2171
2219
|
const nextRows = nextLayout.rows;
|
|
2172
2220
|
rows.value = markRaw(nextRows);
|
|
2221
|
+
enqueuePendingMathImages();
|
|
2173
2222
|
reconcileScrollTop();
|
|
2174
2223
|
const nextScrollTop = internalScrollTop.value;
|
|
2175
2224
|
const nextVisibleRows = visibleRowSignatures(nextRows, nextScrollTop);
|
|
@@ -2294,6 +2343,9 @@ const TVirtualMarkdown = defineComponent({
|
|
|
2294
2343
|
pendingSelectionScrollFocusRemap = false;
|
|
2295
2344
|
applyControlledScrollTop(props.scrollTop, remap);
|
|
2296
2345
|
});
|
|
2346
|
+
watch(internalScrollTop, () => {
|
|
2347
|
+
enqueuePendingMathImages();
|
|
2348
|
+
});
|
|
2297
2349
|
watch([
|
|
2298
2350
|
() => props.content,
|
|
2299
2351
|
() => props.blocks,
|
|
@@ -2306,7 +2358,14 @@ const TVirtualMarkdown = defineComponent({
|
|
|
2306
2358
|
() => props.imageMaxWidth,
|
|
2307
2359
|
() => props.imageMinHeight,
|
|
2308
2360
|
() => props.imageMaxHeight,
|
|
2309
|
-
() => props.imagePreserveAspectRatio
|
|
2361
|
+
() => props.imagePreserveAspectRatio,
|
|
2362
|
+
() => props.mathImages,
|
|
2363
|
+
() => props.mathCellWidthPx,
|
|
2364
|
+
() => props.mathCellHeightPx,
|
|
2365
|
+
() => props.mathScale,
|
|
2366
|
+
() => props.mathColor,
|
|
2367
|
+
() => props.mathMaxWidthCells,
|
|
2368
|
+
() => props.mathBaselineRatio
|
|
2310
2369
|
], () => {
|
|
2311
2370
|
scheduleRebuild();
|
|
2312
2371
|
}, { immediate: true });
|
|
@@ -2510,6 +2569,7 @@ const TVirtualMarkdown = defineComponent({
|
|
|
2510
2569
|
rebuildVersion++;
|
|
2511
2570
|
unsubscribeGraphicsOutput();
|
|
2512
2571
|
unsubscribeMathRenderer();
|
|
2572
|
+
unsubscribeMathImage();
|
|
2513
2573
|
clearMarkdownImageGraphics(terminal, fullRect.value);
|
|
2514
2574
|
});
|
|
2515
2575
|
useRenderNode(() => ({
|