@simon_he/vue-tui 1.1.3 → 1.1.4

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.
Files changed (51) hide show
  1. package/dist/{TMermaidText-frVr8Ysb.js → TMermaidText-wLnMMvVS.js} +1 -1
  2. package/dist/{TSelect-Dx34M1pF.js → TSelect-CMBOOFwK.js} +5 -5
  3. package/dist/{TTree-DdAjCPHu.js → TTree-kk8ntrpg.js} +6 -5
  4. package/dist/agent/mermaid.d.cts +2 -2
  5. package/dist/agent/mermaid.d.ts +2 -2
  6. package/dist/agent.cjs +538 -266
  7. package/dist/agent.js +25 -82
  8. package/dist/{block-source-Crro3mxi.js → block-source-D3YGTErb.js} +299 -239
  9. package/dist/cli.cjs +52 -15
  10. package/dist/cli.js +69 -14
  11. package/dist/core.js +3 -3
  12. package/dist/{hyperlink-_1FAj7Wq.js → create-terminal-Db_-UGVQ.js} +474 -102
  13. package/dist/{dom-renderer-DXx8fWzD.js → dom-renderer-BfwAEQMf.js} +3 -2
  14. package/dist/experimental.cjs +99 -66
  15. package/dist/experimental.js +20 -74
  16. package/dist/hyperlink-clbb_ha_.js +100 -0
  17. package/dist/index.js +8 -8
  18. package/dist/{linkify-BjI4zVfY.js → linkify-CL9wwnZN.js} +3 -3
  19. package/dist/markdown.cjs +521 -212
  20. package/dist/markdown.d.cts +3 -0
  21. package/dist/markdown.d.ts +3 -0
  22. package/dist/markdown.js +75 -8
  23. package/dist/math-image-BZhmfUeu.js +308 -0
  24. package/dist/mermaid-uEfRItDe.js +1205 -0
  25. package/dist/mermaid.cjs +1089 -3
  26. package/dist/mermaid.d.cts +4 -0
  27. package/dist/mermaid.d.ts +4 -0
  28. package/dist/mermaid.js +7 -5
  29. package/dist/{rect-DUpeDfBg.js → rect-JzWMJxxc.js} +1 -1
  30. package/dist/renderer/cli/stdout-renderer.d.ts +44 -0
  31. package/dist/renderer/terminal-graphics.d.ts +44 -0
  32. package/dist/renderer-dom.js +4 -4
  33. package/dist/{terminal-graphics-Bbe83wSr.js → terminal-graphics-DWZrl3oh.js} +85 -2
  34. package/dist/{tlog-theme-i6S_Oftd.js → tlog-theme-DqnF_zNe.js} +5 -4
  35. package/dist/vue/components/TAgentTerminalGraphic.d.ts +1 -1
  36. package/dist/vue/components/TMarkdownText.d.ts +70 -2
  37. package/dist/vue/components/TMermaidImage.d.ts +733 -0
  38. package/dist/vue/components/TMermaidText.d.ts +2 -2
  39. package/dist/vue/components/TVirtualMarkdown.d.ts +70 -2
  40. package/dist/vue/markdown/ast.d.ts +5 -0
  41. package/dist/vue/markdown/document.d.ts +3 -0
  42. package/dist/vue/markdown/math-image.d.ts +68 -0
  43. package/dist/vue/markdown/theme.d.ts +12 -0
  44. package/dist/vue/markdown/types.d.ts +12 -2
  45. package/dist/vue/mermaid/beautiful-mermaid.d.ts +4 -4
  46. package/dist/vue/mermaid/mermaid-image.d.ts +65 -0
  47. package/dist/vue.js +9 -9
  48. package/package.json +14 -1
  49. package/dist/mermaid-BNhM1jAZ.js +0 -123
  50. package/dist/width-GqllnV8C.js +0 -474
  51. /package/dist/{ansi-palette-CH6jc2Z7.js → ansi-palette-BHF1rN7R.js} +0 -0
package/dist/mermaid.cjs CHANGED
@@ -28,11 +28,21 @@ __export(mermaid_exports, {
28
28
  TBeautifulMermaid: () => TBeautifulMermaid,
29
29
  TBeautifulMermaidText: () => TBeautifulMermaidText,
30
30
  TMermaid: () => TMermaid,
31
+ TMermaidImage: () => TMermaidImage,
31
32
  TMermaidText: () => TMermaidText2,
32
33
  beautifulMermaidRenderer: () => beautifulMermaidRenderer,
34
+ clearMermaidImageCache: () => clearMermaidImageCache,
33
35
  createBeautifulMermaidRenderer: () => createBeautifulMermaidRenderer,
36
+ getCachedMermaidImage: () => getCachedMermaidImage,
37
+ getMermaidImage: () => getMermaidImage,
38
+ isMermaidImageRendererReady: () => isMermaidImageRendererReady,
34
39
  isSimpleMermaidFlowchartSource: () => isSimpleMermaidFlowchartSource,
35
- markMermaidRenderErrorFatal: () => markMermaidRenderErrorFatal
40
+ loadMermaidImageRenderer: () => loadMermaidImageRenderer,
41
+ markMermaidRenderErrorFatal: () => markMermaidRenderErrorFatal,
42
+ normalizeMermaidImageOptions: () => normalizeMermaidImageOptions,
43
+ resolveMermaidImageColor: () => resolveMermaidImageColor,
44
+ setMermaidImageRasterizer: () => setMermaidImageRasterizer,
45
+ subscribeMermaidImage: () => subscribeMermaidImage
36
46
  });
37
47
  module.exports = __toCommonJS(mermaid_exports);
38
48
 
@@ -1385,8 +1395,8 @@ var tMermaidTextProps = {
1385
1395
  return snapshot && snapshot.source === source.value && hasVisibleRenderedOutput(snapshot.lines) ? snapshot.lines : sourceLines.value;
1386
1396
  }), currentStyle = (0, import_vue8.computed)(() => props.style ?? defaultStyle.value), fullHeight = (0, import_vue8.computed)(() => {
1387
1397
  if (props.h != null) {
1388
- let h3 = Math.floor(Number(props.h));
1389
- return Number.isFinite(h3) ? Math.max(0, h3) : 0;
1398
+ let h4 = Math.floor(Number(props.h));
1399
+ return Number.isFinite(h4) ? Math.max(0, h4) : 0;
1390
1400
  }
1391
1401
  let autoContentHeight = Math.max(1, displayLines.value.length);
1392
1402
  return reservesBoxRows.value ? autoContentHeight + 2 : autoContentHeight;
@@ -1705,3 +1715,1079 @@ var TMermaidText2 = (0, import_vue9.defineComponent)({
1705
1715
  };
1706
1716
  }
1707
1717
  }), TMermaid = TMermaidText2, TBeautifulMermaidText = TMermaidText2, TBeautifulMermaid = TMermaidText2;
1718
+
1719
+ // src/vue/components/TMermaidImage.ts
1720
+ var import_vue10 = require("vue");
1721
+
1722
+ // src/core/terminal/create-terminal.ts
1723
+ var TERMINAL_PLANE_INTERNALS = Symbol.for("@simon_he/vue-tui:v1:terminal-plane-internals"), TERMINAL_ROOT = Symbol.for("@simon_he/vue-tui:v1:terminal-root");
1724
+ function getRootTerminal(terminal) {
1725
+ return terminal[TERMINAL_ROOT] ?? terminal;
1726
+ }
1727
+
1728
+ // src/renderer/terminal-graphics.ts
1729
+ var ESC2 = "\x1B", BEL2 = "\x07", ST = `${ESC2}\\`, ESC_RE = "\\u001B", BEL_RE = "\\u0007", CSI_RE = new RegExp(`${ESC_RE}\\[[0-?]*[ -/]*[@-~]`, "g"), OSC_RE = new RegExp(`${ESC_RE}\\][\\s\\S]*?(?:${BEL_RE}|${ESC_RE}\\\\)`, "g"), DCS_RE = new RegExp(`${ESC_RE}P[\\s\\S]*?${ESC_RE}\\\\`, "g"), APC_RE = new RegExp(`${ESC_RE}_[\\s\\S]*?${ESC_RE}\\\\`, "g"), C1_CSI_RE = new RegExp("\\u009B[0-?]*[ -/]*[@-~]", "g"), C1_OSC_RE = new RegExp(`\\u009D[\\s\\S]*?(?:${BEL_RE}|\\u009C)`, "g"), C1_DCS_RE = new RegExp("\\u0090[\\s\\S]*?\\u009C", "g"), C1_APC_RE = new RegExp("\\u009F[\\s\\S]*?\\u009C", "g"), MAX_TERMINAL_GRAPHICS_SEQUENCE_CHARS = 16 * 1024 * 1024;
1730
+ var MAX_TERMINAL_GRAPHIC_CELLS = 1e4, TERMINAL_GRAPHICS_REGISTRY = Symbol.for("@simon_he/vue-tui:v1:terminal-graphics"), terminalGraphicsGlobal = globalThis, terminalGraphicsRegistry = terminalGraphicsGlobal[TERMINAL_GRAPHICS_REGISTRY] ?? {
1731
+ outputs: /* @__PURE__ */ new WeakMap(),
1732
+ outputVersions: /* @__PURE__ */ new WeakMap(),
1733
+ outputListeners: /* @__PURE__ */ new WeakMap()
1734
+ };
1735
+ terminalGraphicsGlobal[TERMINAL_GRAPHICS_REGISTRY] = terminalGraphicsRegistry;
1736
+ var terminalGraphicsOutputs = terminalGraphicsRegistry.outputs, terminalGraphicsOutputVersions = terminalGraphicsRegistry.outputVersions, terminalGraphicsOutputListeners = terminalGraphicsRegistry.outputListeners;
1737
+ function getTerminalGraphicsOutput(terminal) {
1738
+ return terminalGraphicsOutputs.get(getRootTerminal(terminal)) ?? null;
1739
+ }
1740
+ function getTerminalGraphicsOutputVersion(terminal) {
1741
+ return terminalGraphicsOutputVersions.get(getRootTerminal(terminal)) ?? 0;
1742
+ }
1743
+ function subscribeTerminalGraphicsOutput(terminal, listener) {
1744
+ let rootTerminal = getRootTerminal(terminal), listeners = terminalGraphicsOutputListeners.get(rootTerminal);
1745
+ return listeners || (listeners = /* @__PURE__ */ new Set(), terminalGraphicsOutputListeners.set(rootTerminal, listeners)), listeners.add(listener), () => {
1746
+ listeners.delete(listener), listeners.size === 0 && terminalGraphicsOutputListeners.delete(rootTerminal);
1747
+ };
1748
+ }
1749
+ function stableTerminalGraphicNumericId(input, options = {}) {
1750
+ let min = Math.floor(options.min ?? 1), max = Math.floor(options.max ?? 2147483647), span = Math.max(1, max - min + 1), hash = 2166136261;
1751
+ for (let index = 0; index < input.length; index += 1)
1752
+ hash ^= input.charCodeAt(index), hash = Math.imul(hash, 16777619);
1753
+ return min + (hash >>> 0) % span;
1754
+ }
1755
+ function positiveGraphicInt(value, max) {
1756
+ let n = Math.trunc(Number(value));
1757
+ return !Number.isFinite(n) || n <= 0 ? null : Math.min(max, n);
1758
+ }
1759
+ function normalizeTerminalGraphicSize(width, height) {
1760
+ let w = positiveGraphicInt(width, MAX_TERMINAL_GRAPHIC_CELLS), h4 = positiveGraphicInt(height, MAX_TERMINAL_GRAPHIC_CELLS);
1761
+ return w == null || h4 == null || w * h4 > MAX_TERMINAL_GRAPHIC_CELLS ? null : { width: w, height: h4 };
1762
+ }
1763
+ function isBase64ish(value) {
1764
+ return /^[A-Za-z0-9+/=]*$/.test(value);
1765
+ }
1766
+ var KITTY_UINT32_MAX = 4294967295, KITTY_INT32_MIN = -2147483648, KITTY_INT32_MAX = 2147483647;
1767
+ function validateIterm2Dimension(value) {
1768
+ return /^auto$/i.test(value) || /^(?:[1-9]\d{0,4})(?:px|%)?$/.test(value);
1769
+ }
1770
+ function uint32Control(key, value, min = 0) {
1771
+ if (value == null)
1772
+ return "";
1773
+ let n = Math.floor(value);
1774
+ return Number.isSafeInteger(n) && n >= min && n <= KITTY_UINT32_MAX ? `${key}=${n}` : "";
1775
+ }
1776
+ function int32Control(key, value) {
1777
+ if (value == null)
1778
+ return "";
1779
+ let n = Math.floor(value);
1780
+ return Number.isSafeInteger(n) && n >= KITTY_INT32_MIN && n <= KITTY_INT32_MAX ? `${key}=${n}` : "";
1781
+ }
1782
+ function sanitizeBase64(value) {
1783
+ let data = String(value ?? "").replace(/\s+/g, "");
1784
+ return isBase64ish(data) ? data : "";
1785
+ }
1786
+ function kittyGraphicCellControls(columns, rows) {
1787
+ if (columns == null && rows == null)
1788
+ return [];
1789
+ let size = normalizeTerminalGraphicSize(columns ?? 1, rows ?? 1);
1790
+ return size ? [columns == null ? "" : `c=${size.width}`, rows == null ? "" : `r=${size.height}`] : [];
1791
+ }
1792
+ function kittyGraphicSourceControls(sourceX, sourceY, sourceWidth, sourceHeight) {
1793
+ return [
1794
+ uint32Control("x", sourceX),
1795
+ uint32Control("y", sourceY),
1796
+ uint32Control("w", sourceWidth, 1),
1797
+ uint32Control("h", sourceHeight, 1)
1798
+ ];
1799
+ }
1800
+ function chunkBase64(value, chunkSize) {
1801
+ let normalizedSize = Math.max(4, Math.floor(chunkSize / 4) * 4), chunks = [];
1802
+ for (let index = 0; index < value.length; index += normalizedSize)
1803
+ chunks.push(value.slice(index, index + normalizedSize));
1804
+ return chunks.length ? chunks : [""];
1805
+ }
1806
+ function createKittyPlacementSequence(options) {
1807
+ let imageId = uint32Control("i", options.imageId), imageNumber = uint32Control("I", options.imageNumber);
1808
+ if (!imageId && !imageNumber)
1809
+ return "";
1810
+ let controls = [
1811
+ "a=p",
1812
+ options.quiet === !1 ? "" : "q=2",
1813
+ options.noCursorMove === !1 ? "" : "C=1",
1814
+ imageId,
1815
+ imageNumber,
1816
+ uint32Control("p", options.placementId),
1817
+ ...kittyGraphicCellControls(options.columns, options.rows),
1818
+ ...kittyGraphicSourceControls(
1819
+ options.sourceX,
1820
+ options.sourceY,
1821
+ options.sourceWidth,
1822
+ options.sourceHeight
1823
+ ),
1824
+ int32Control("z", options.zIndex)
1825
+ ].filter(Boolean);
1826
+ return `${ESC2}_G${controls.join(",")}${ST}`;
1827
+ }
1828
+ function createKittyGraphicsSequence(base64Png, options = {}) {
1829
+ let data = sanitizeBase64(base64Png);
1830
+ if (!data)
1831
+ return "";
1832
+ let chunks = chunkBase64(data, options.chunkSize ?? 4096), baseControls = [
1833
+ "a=T",
1834
+ "f=100",
1835
+ options.quiet === !1 ? "" : "q=2",
1836
+ options.noCursorMove === !1 ? "" : "C=1",
1837
+ uint32Control("i", options.imageId),
1838
+ uint32Control("I", options.imageNumber),
1839
+ uint32Control("p", options.placementId),
1840
+ ...kittyGraphicCellControls(options.columns, options.rows),
1841
+ ...kittyGraphicSourceControls(
1842
+ options.sourceX,
1843
+ options.sourceY,
1844
+ options.sourceWidth,
1845
+ options.sourceHeight
1846
+ ),
1847
+ int32Control("z", options.zIndex)
1848
+ ].filter(Boolean);
1849
+ return chunks.map((chunk, index) => {
1850
+ let last = index === chunks.length - 1, controls = index === 0 ? [...baseControls, chunks.length > 1 ? `m=${last ? 0 : 1}` : ""] : [options.quiet === !1 ? "" : "q=2", `m=${last ? 0 : 1}`].filter(Boolean);
1851
+ return `${ESC2}_G${controls.filter(Boolean).join(",")};${chunk}${ST}`;
1852
+ }).join("");
1853
+ }
1854
+ function createKittyDeleteGraphicsSequence(options = {}) {
1855
+ let controls = ["a=d"];
1856
+ if (options.allVisible)
1857
+ controls.push(`d=${options.freeImageData ? "A" : "a"}`);
1858
+ else if (options.imageId != null) {
1859
+ let imageId = uint32Control("i", options.imageId), placementId = uint32Control("p", options.placementId);
1860
+ if (!imageId || options.placementId != null && !placementId)
1861
+ return "";
1862
+ controls.push(`d=${options.freeImageData ? "I" : "i"}`), controls.push(imageId), controls.push(placementId);
1863
+ } else if (options.currentCell)
1864
+ controls.push(`d=${options.freeImageData ? "C" : "c"}`);
1865
+ else
1866
+ return "";
1867
+ return options.quiet !== !1 && controls.push("q=2"), `${ESC2}_G${controls.filter(Boolean).join(",")}${ST}`;
1868
+ }
1869
+ function createIterm2InlineImageSequence(base64Data, options = {}) {
1870
+ let data = sanitizeBase64(base64Data);
1871
+ if (!data)
1872
+ return "";
1873
+ let params = [
1874
+ "inline=1",
1875
+ options.width != null ? `width=${formatItermDimension(options.width)}` : "",
1876
+ options.height != null ? `height=${formatItermDimension(options.height)}` : "",
1877
+ `preserveAspectRatio=${options.preserveAspectRatio === !1 ? 0 : 1}`,
1878
+ options.doNotMoveCursor === !1 ? "" : "doNotMoveCursor=1"
1879
+ ].filter(Boolean);
1880
+ return `${ESC2}]1337;File=${params.join(";")}:${data}${BEL2}`;
1881
+ }
1882
+ function formatItermDimension(value) {
1883
+ if (typeof value == "number") {
1884
+ let n = Math.floor(value);
1885
+ return Number.isFinite(n) ? String(Math.min(99999, Math.max(1, n))) : "auto";
1886
+ }
1887
+ let raw = String(value ?? "").trim();
1888
+ return validateIterm2Dimension(raw) ? raw : "auto";
1889
+ }
1890
+ function resolveKittyPngSourceCrop(rect, fullRect, sourceWidth, sourceHeight) {
1891
+ if (fullRect.w <= 0 || fullRect.h <= 0)
1892
+ return null;
1893
+ let offsetX = Math.max(0, rect.x - fullRect.x), offsetY = Math.max(0, rect.y - fullRect.y), visibleW = Math.max(0, Math.min(rect.w, fullRect.w - offsetX)), visibleH = Math.max(0, Math.min(rect.h, fullRect.h - offsetY));
1894
+ if (offsetX <= 0 && offsetY <= 0 && visibleW >= fullRect.w && visibleH >= fullRect.h)
1895
+ return null;
1896
+ let sourceX = Math.max(
1897
+ 0,
1898
+ Math.min(sourceWidth - 1, Math.floor(offsetX * sourceWidth / fullRect.w))
1899
+ ), sourceY = Math.max(
1900
+ 0,
1901
+ Math.min(sourceHeight - 1, Math.floor(offsetY * sourceHeight / fullRect.h))
1902
+ ), sourceRight = Math.max(
1903
+ sourceX + 1,
1904
+ Math.min(sourceWidth, Math.ceil((offsetX + visibleW) * sourceWidth / fullRect.w))
1905
+ ), sourceBottom = Math.max(
1906
+ sourceY + 1,
1907
+ Math.min(sourceHeight, Math.ceil((offsetY + visibleH) * sourceHeight / fullRect.h))
1908
+ );
1909
+ return {
1910
+ sourceX,
1911
+ sourceY,
1912
+ sourceWidth: sourceRight - sourceX,
1913
+ sourceHeight: sourceBottom - sourceY
1914
+ };
1915
+ }
1916
+ function createTerminalGraphicPngSequence(options) {
1917
+ if (options.protocol === "kitty") {
1918
+ let placement = {
1919
+ columns: options.placementColumns,
1920
+ rows: options.placementRows
1921
+ };
1922
+ if (options.rect && options.fullRect && options.sourceWidth && options.sourceHeight) {
1923
+ let crop = resolveKittyPngSourceCrop(
1924
+ options.rect,
1925
+ options.fullRect,
1926
+ options.sourceWidth,
1927
+ options.sourceHeight
1928
+ );
1929
+ crop && (placement = { ...placement, ...crop });
1930
+ }
1931
+ return {
1932
+ type: "sequence",
1933
+ protocol: "kitty",
1934
+ sequence: createKittyGraphicsSequence(options.base64, {
1935
+ imageId: options.imageId,
1936
+ placementId: options.placementId,
1937
+ zIndex: options.zIndex,
1938
+ ...placement
1939
+ }),
1940
+ resizeSequence: createKittyPlacementSequence({
1941
+ imageId: options.imageId,
1942
+ placementId: options.placementId,
1943
+ zIndex: options.zIndex,
1944
+ ...placement
1945
+ }),
1946
+ clearSequence: createKittyDeleteGraphicsSequence({
1947
+ imageId: options.imageId,
1948
+ placementId: options.placementId,
1949
+ freeImageData: options.freeImageData
1950
+ }),
1951
+ ...options.fallback != null ? { fallback: options.fallback } : {},
1952
+ ...options.cols != null ? { cols: options.cols } : {},
1953
+ ...options.rows != null ? { rows: options.rows } : {},
1954
+ ...options.sourceWidth != null ? { sourceWidth: options.sourceWidth } : {},
1955
+ ...options.sourceHeight != null ? { sourceHeight: options.sourceHeight } : {},
1956
+ ...options.zIndex != null ? { zIndex: options.zIndex } : {}
1957
+ };
1958
+ }
1959
+ return options.protocol === "iterm2" ? {
1960
+ type: "sequence",
1961
+ protocol: "iterm2",
1962
+ sequence: createIterm2InlineImageSequence(options.base64, {
1963
+ width: options.cols,
1964
+ height: options.rows,
1965
+ preserveAspectRatio: !0,
1966
+ doNotMoveCursor: !0
1967
+ }),
1968
+ ...options.fallback != null ? { fallback: options.fallback } : {},
1969
+ ...options.cols != null ? { cols: options.cols } : {},
1970
+ ...options.rows != null ? { rows: options.rows } : {},
1971
+ ...options.sourceWidth != null ? { sourceWidth: options.sourceWidth } : {},
1972
+ ...options.sourceHeight != null ? { sourceHeight: options.sourceHeight } : {}
1973
+ } : null;
1974
+ }
1975
+
1976
+ // src/vue/markdown/math-image.ts
1977
+ var DEFAULT_MATH_IMAGE_OPTIONS = Object.freeze({
1978
+ cellWidthPx: 8,
1979
+ cellHeightPx: 16,
1980
+ scale: 2,
1981
+ color: "#f8f8f2",
1982
+ maxWidthCells: 0,
1983
+ baselineRatio: 0.78
1984
+ });
1985
+ var NAMED_STYLE_FG_HEX = Object.freeze({
1986
+ black: "#000000",
1987
+ red: "#e53935",
1988
+ green: "#43a047",
1989
+ yellow: "#fdd835",
1990
+ blue: "#1e88e5",
1991
+ magenta: "#d81b60",
1992
+ cyan: "#00acc1",
1993
+ white: "#ffffff",
1994
+ gray: "#9e9e9e",
1995
+ grey: "#9e9e9e",
1996
+ blackBright: "#4a4a4a",
1997
+ redBright: "#ff6e6e",
1998
+ greenBright: "#69db7c",
1999
+ yellowBright: "#ffe066",
2000
+ blueBright: "#74c0fc",
2001
+ magentaBright: "#f783ac",
2002
+ cyanBright: "#3bc9db",
2003
+ whiteBright: "#f8f8f2",
2004
+ grayBright: "#bdbdbd",
2005
+ greyBright: "#bdbdbd"
2006
+ });
2007
+ function resolveMarkdownMathColor(fg) {
2008
+ if (typeof fg != "string" || !fg)
2009
+ return;
2010
+ let trimmed = fg.trim();
2011
+ return trimmed.startsWith("#") && /^#[0-9a-f]{3,8}$/i.test(trimmed) ? trimmed.toLowerCase() : NAMED_STYLE_FG_HEX[trimmed.toLowerCase()];
2012
+ }
2013
+
2014
+ // src/vue/mermaid/mermaid-image.ts
2015
+ var DEFAULT_MERMAID_IMAGE_OPTIONS = Object.freeze({
2016
+ cellWidthPx: 8,
2017
+ cellHeightPx: 16,
2018
+ scale: 2,
2019
+ bg: "#1e1e2e",
2020
+ fg: "#f8f8f2",
2021
+ maxWidthCells: 0,
2022
+ maxHeightCells: 0,
2023
+ padding: 40
2024
+ }), MAX_CACHE_ENTRIES = 48, MAX_FAILED_ENTRIES = 96, mermaidImageCache = /* @__PURE__ */ new Map(), mermaidImageFailed = /* @__PURE__ */ new Set(), mermaidImageInflight = /* @__PURE__ */ new Map(), mermaidImageListeners = /* @__PURE__ */ new Set(), customRasterizer = null, builtinRasterizerLoad = null, builtinRasterizerReady = !1;
2025
+ function normalizeMermaidImageOptions(options) {
2026
+ return {
2027
+ cellWidthPx: Math.max(
2028
+ 1,
2029
+ Math.floor(options?.cellWidthPx ?? DEFAULT_MERMAID_IMAGE_OPTIONS.cellWidthPx)
2030
+ ),
2031
+ cellHeightPx: Math.max(
2032
+ 1,
2033
+ Math.floor(options?.cellHeightPx ?? DEFAULT_MERMAID_IMAGE_OPTIONS.cellHeightPx)
2034
+ ),
2035
+ scale: Math.max(1, Math.floor(options?.scale ?? DEFAULT_MERMAID_IMAGE_OPTIONS.scale)),
2036
+ bg: options?.bg ?? DEFAULT_MERMAID_IMAGE_OPTIONS.bg,
2037
+ fg: options?.fg ?? DEFAULT_MERMAID_IMAGE_OPTIONS.fg,
2038
+ maxWidthCells: Math.max(0, Math.floor(options?.maxWidthCells ?? 0)),
2039
+ maxHeightCells: Math.max(0, Math.floor(options?.maxHeightCells ?? 0)),
2040
+ padding: Math.max(0, Math.floor(options?.padding ?? DEFAULT_MERMAID_IMAGE_OPTIONS.padding))
2041
+ };
2042
+ }
2043
+ function resolveMermaidImageColor(fg) {
2044
+ return resolveMarkdownMathColor(fg);
2045
+ }
2046
+ function setMermaidImageRasterizer(rasterizer) {
2047
+ customRasterizer = rasterizer;
2048
+ }
2049
+ function subscribeMermaidImage(listener) {
2050
+ return mermaidImageListeners.add(listener), () => mermaidImageListeners.delete(listener);
2051
+ }
2052
+ function isMermaidImageRendererReady() {
2053
+ return customRasterizer != null || builtinRasterizerReady;
2054
+ }
2055
+ async function loadMermaidImageRenderer() {
2056
+ return isMermaidImageRendererReady() ? !0 : (builtinRasterizerReady = (customRasterizer ?? await loadBuiltinMermaidRasterizer()) != null, builtinRasterizerReady);
2057
+ }
2058
+ function hashMermaidImageKey(value) {
2059
+ let hash = 2166136261;
2060
+ for (let i = 0; i < value.length; i++)
2061
+ hash ^= value.charCodeAt(i), hash = Math.imul(hash, 16777619);
2062
+ return (hash >>> 0).toString(36);
2063
+ }
2064
+ function mermaidImageCacheKey(code, options) {
2065
+ return hashMermaidImageKey(
2066
+ [
2067
+ code,
2068
+ options.cellWidthPx,
2069
+ options.cellHeightPx,
2070
+ options.scale,
2071
+ options.bg,
2072
+ options.fg,
2073
+ options.maxWidthCells,
2074
+ options.maxHeightCells,
2075
+ options.padding
2076
+ ].join("")
2077
+ );
2078
+ }
2079
+ function notifyMermaidImageListeners() {
2080
+ for (let listener of mermaidImageListeners)
2081
+ try {
2082
+ listener();
2083
+ } catch {
2084
+ }
2085
+ }
2086
+ function getCachedMermaidImage(code, options) {
2087
+ return mermaidImageCache.get(mermaidImageCacheKey(code, normalizeMermaidImageOptions(options))) ?? null;
2088
+ }
2089
+ function clearMermaidImageCache() {
2090
+ mermaidImageCache.clear(), mermaidImageFailed.clear();
2091
+ }
2092
+ function evictOldestMermaidImageEntry() {
2093
+ let oldest = mermaidImageCache.keys().next().value;
2094
+ oldest != null && mermaidImageCache.delete(oldest);
2095
+ }
2096
+ async function getMermaidImage(code, options) {
2097
+ let source = String(code ?? "").trim();
2098
+ if (!source)
2099
+ return null;
2100
+ let normalized = normalizeMermaidImageOptions(options), key = mermaidImageCacheKey(source, normalized), cached = mermaidImageCache.get(key);
2101
+ if (cached)
2102
+ return cached;
2103
+ if (mermaidImageFailed.has(key))
2104
+ return null;
2105
+ let inflight = mermaidImageInflight.get(key);
2106
+ if (inflight)
2107
+ return inflight;
2108
+ let pending = (async () => {
2109
+ try {
2110
+ let rasterizer = customRasterizer ?? await loadBuiltinMermaidRasterizer();
2111
+ if (!rasterizer)
2112
+ return null;
2113
+ let result = await rasterizer(source, normalized);
2114
+ if (result && result.base64)
2115
+ mermaidImageCache.set(key, result), mermaidImageCache.size > MAX_CACHE_ENTRIES && evictOldestMermaidImageEntry(), notifyMermaidImageListeners();
2116
+ else if (result === null && (mermaidImageFailed.add(key), mermaidImageFailed.size > MAX_FAILED_ENTRIES)) {
2117
+ let oldest = mermaidImageFailed.values().next().value;
2118
+ oldest != null && mermaidImageFailed.delete(oldest);
2119
+ }
2120
+ return result;
2121
+ } catch {
2122
+ return null;
2123
+ } finally {
2124
+ mermaidImageInflight.delete(key);
2125
+ }
2126
+ })();
2127
+ return mermaidImageInflight.set(key, pending), pending;
2128
+ }
2129
+ function base64FromBytes(bytes) {
2130
+ let binary = "";
2131
+ for (let offset = 0; offset < bytes.length; offset += 32768)
2132
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
2133
+ return typeof btoa == "function" ? btoa(binary) : Buffer.from(bytes).toString("base64");
2134
+ }
2135
+ function positiveInt(value) {
2136
+ let n = Math.floor(Number(value));
2137
+ return Number.isFinite(n) && n > 0 ? n : void 0;
2138
+ }
2139
+ function clampCellsToLimits(widthCells, heightCells, maxWidthCells, maxHeightCells) {
2140
+ let w = widthCells, h4 = heightCells;
2141
+ return maxWidthCells > 0 && w > maxWidthCells && (h4 = Math.max(1, Math.round(h4 * maxWidthCells / w)), w = maxWidthCells), maxHeightCells > 0 && h4 > maxHeightCells && (w = Math.max(1, Math.round(w * maxHeightCells / h4)), h4 = maxHeightCells), { widthCells: Math.max(1, w), heightCells: Math.max(1, h4) };
2142
+ }
2143
+ var RESVG_MODULE_ID = "@resvg/resvg-js";
2144
+ function svgRenderFunction(mod) {
2145
+ let candidates = [
2146
+ mod.renderMermaidSVGAsync,
2147
+ mod.renderMermaidSVG,
2148
+ mod.renderMermaid,
2149
+ mod.default?.renderMermaidSVGAsync,
2150
+ mod.default?.renderMermaidSVG
2151
+ ];
2152
+ for (let candidate of candidates)
2153
+ if (typeof candidate == "function")
2154
+ return candidate;
2155
+ return null;
2156
+ }
2157
+ function loadBuiltinMermaidRasterizer() {
2158
+ return builtinRasterizerLoad || (builtinRasterizerLoad = (async () => {
2159
+ try {
2160
+ let [mermaidMod, resvgMod] = await Promise.all([
2161
+ import("beautiful-mermaid").then(
2162
+ (mod) => mod,
2163
+ () => null
2164
+ ),
2165
+ import(RESVG_MODULE_ID).then(
2166
+ (mod) => mod,
2167
+ () => null
2168
+ )
2169
+ ]), renderSvg = svgRenderFunction(mermaidMod ?? {}), Resvg = resvgMod?.Resvg;
2170
+ return !renderSvg || typeof Resvg != "function" ? null : async (code, options) => {
2171
+ let svg = await renderSvg(code, {
2172
+ bg: options.bg,
2173
+ fg: options.fg,
2174
+ padding: options.padding,
2175
+ transparent: !0
2176
+ }), svgText = String(svg ?? "");
2177
+ if (!svgText.includes("<svg"))
2178
+ return null;
2179
+ let rendered = new Resvg(svgText, {
2180
+ background: "rgba(0,0,0,0)"
2181
+ }).render(), naturalWidth = positiveInt(rendered?.width), naturalHeight = positiveInt(rendered?.height), png = typeof rendered?.asPng == "function" ? rendered.asPng() : void 0;
2182
+ if (!png || png.length < 8 || naturalWidth == null || naturalHeight == null)
2183
+ return null;
2184
+ let rawWidthCells = Math.max(
2185
+ 1,
2186
+ Math.round(naturalWidth / (options.cellWidthPx * options.scale))
2187
+ ), rawHeightCells = Math.max(
2188
+ 1,
2189
+ Math.round(naturalHeight / (options.cellHeightPx * options.scale))
2190
+ ), { widthCells, heightCells } = clampCellsToLimits(
2191
+ rawWidthCells,
2192
+ rawHeightCells,
2193
+ options.maxWidthCells,
2194
+ options.maxHeightCells
2195
+ );
2196
+ return {
2197
+ base64: base64FromBytes(png),
2198
+ widthCells,
2199
+ heightCells,
2200
+ naturalWidth,
2201
+ naturalHeight
2202
+ };
2203
+ };
2204
+ } catch {
2205
+ return null;
2206
+ }
2207
+ })()), builtinRasterizerLoad;
2208
+ }
2209
+
2210
+ // src/vue/components/TMermaidImage.ts
2211
+ var UNICODE_MERMAID_IMAGE_BOX_CHARS = Object.freeze({
2212
+ tl: "\u250C",
2213
+ tr: "\u2510",
2214
+ bl: "\u2514",
2215
+ br: "\u2518",
2216
+ h: "\u2500",
2217
+ v: "\u2502"
2218
+ }), ASCII_MERMAID_IMAGE_BOX_CHARS = Object.freeze({
2219
+ tl: "+",
2220
+ tr: "+",
2221
+ bl: "+",
2222
+ br: "+",
2223
+ h: "-",
2224
+ v: "|"
2225
+ }), DEFAULT_MERMAID_IMAGE_COPIED_DURATION_MS = 1200, DEFAULT_MERMAID_IMAGE_MAX_RENDER_SOURCE_CHARS = 2e4, DEFAULT_MERMAID_IMAGE_MAX_RENDER_SOURCE_LINES = 400, ESC3 = "\x1B", BEL3 = "\x07", TERMINAL_ESCAPE_RE2 = new RegExp(
2226
+ [
2227
+ `${ESC3}\\][\\s\\S]*?(?:${BEL3}|${ESC3}\\\\)`,
2228
+ `${ESC3}[PX^_][\\s\\S]*?${ESC3}\\\\`,
2229
+ `${ESC3}\\[[0-?]*[ -/]*[@-~]`,
2230
+ `${ESC3}[@-Z\\\\-_]`
2231
+ ].join("|"),
2232
+ "g"
2233
+ );
2234
+ function stripTerminalEscapes2(value) {
2235
+ return value.replace(TERMINAL_ESCAPE_RE2, "");
2236
+ }
2237
+ function normalizeNonNegativeInt2(value, fallback) {
2238
+ let n = Number(value);
2239
+ return Number.isFinite(n) ? Math.max(0, Math.floor(n)) : fallback;
2240
+ }
2241
+ function countLinesUpTo2(value, max) {
2242
+ if (max <= 0)
2243
+ return 0;
2244
+ let lines = 1;
2245
+ for (let index = 0; index < value.length; index++) {
2246
+ let code = value.charCodeAt(index);
2247
+ if (!(code !== 10 && code !== 13) && (lines++, code === 13 && value.charCodeAt(index + 1) === 10 && index++, lines > max))
2248
+ return lines;
2249
+ }
2250
+ return lines;
2251
+ }
2252
+ function splitRenderedOutput2(value) {
2253
+ let lines = sanitizeTextBlock(
2254
+ stripTerminalEscapes2(String(value ?? "")).replace(/\r\n?/g, `
2255
+ `)
2256
+ ).split(`
2257
+ `);
2258
+ return lines.length ? lines : [""];
2259
+ }
2260
+ function fitImageCells(cells, maxW, maxH) {
2261
+ if (maxW <= 0 || maxH <= 0)
2262
+ return null;
2263
+ let w = Math.max(1, Math.floor(cells.widthCells)), h4 = Math.max(1, Math.floor(cells.heightCells));
2264
+ return w > maxW && (h4 = Math.max(1, Math.round(h4 * maxW / w)), w = maxW), h4 > maxH && (w = Math.max(1, Math.round(w * maxH / h4)), h4 = maxH), { displayW: Math.max(1, w), displayH: Math.max(1, h4) };
2265
+ }
2266
+ var tMermaidImageProps = {
2267
+ x: { type: Number, required: !0 },
2268
+ y: { type: Number, required: !0 },
2269
+ w: { type: Number, required: !0 },
2270
+ h: { type: Number, default: void 0 },
2271
+ zIndex: { type: Number, default: 0 },
2272
+ content: { type: String, default: "" },
2273
+ code: { type: String, default: void 0 },
2274
+ style: { type: Object, default: void 0 },
2275
+ clear: { type: Boolean, default: !0 },
2276
+ final: { type: Boolean, default: !0 },
2277
+ streaming: { type: Boolean, default: !1 },
2278
+ // Image pipeline. Without a renderer the built-in lazy rasterizer
2279
+ // (beautiful-mermaid SVG + @resvg/resvg-js) is used; when graphics are
2280
+ // unsupported or the rasterizer is missing, the raw source is shown.
2281
+ renderer: {
2282
+ type: Function,
2283
+ default: void 0
2284
+ },
2285
+ cellWidthPx: { type: Number, default: void 0 },
2286
+ cellHeightPx: { type: Number, default: void 0 },
2287
+ scale: { type: Number, default: void 0 },
2288
+ bg: { type: String, default: void 0 },
2289
+ fg: { type: String, default: void 0 },
2290
+ maxWidthCells: { type: Number, default: void 0 },
2291
+ maxHeightCells: { type: Number, default: void 0 },
2292
+ padding: { type: Number, default: void 0 },
2293
+ // Box chrome (mirrors TMermaidText).
2294
+ box: { type: Boolean, default: !0 },
2295
+ title: { type: String, default: "mermaid" },
2296
+ copyButton: { type: Boolean, default: !0 },
2297
+ copyText: { type: String, default: "copy" },
2298
+ copiedText: { type: String, default: "copied" },
2299
+ copiedDurationMs: { type: Number, default: DEFAULT_MERMAID_IMAGE_COPIED_DURATION_MS },
2300
+ renderTimeoutMs: { type: Number, default: 0 },
2301
+ maxRenderSourceChars: { type: Number, default: DEFAULT_MERMAID_IMAGE_MAX_RENDER_SOURCE_CHARS },
2302
+ maxRenderSourceLines: { type: Number, default: DEFAULT_MERMAID_IMAGE_MAX_RENDER_SOURCE_LINES },
2303
+ // Clicking the diagram (or the copy button) copies the full raw mermaid source.
2304
+ copyOnClick: { type: Boolean, default: !0 },
2305
+ ascii: { type: Boolean, default: !1 }
2306
+ }, TMermaidImage = (0, import_vue10.defineComponent)({
2307
+ name: "TMermaidImage",
2308
+ props: tMermaidImageProps,
2309
+ emits: {
2310
+ copy: (_payload) => !0
2311
+ },
2312
+ setup(props, { emit }) {
2313
+ let instance = (0, import_vue10.getCurrentInstance)(), terminalContext = useTerminal(), { terminal, defaultStyle, scheduler, widthProvider } = terminalContext, layout = useLayout(), { visible, rootProps } = useVisibility(), parentEventZ = (0, import_vue10.inject)(EventZIndexContextKey, (0, import_vue10.computed)(() => 0)), imageCells = (0, import_vue10.shallowRef)(null), documentVersion = (0, import_vue10.shallowRef)(0), copied = (0, import_vue10.shallowRef)(!1), builtOnce = !1, renderVersion = 0, alive = !0, frameTaskId = `TMermaidImage:${instance?.uid ?? "unknown"}:mermaid-image`, uid = instance?.uid ?? 0, copiedTimer = null, copyRequestVersion = 0, activeGraphicId = null, source = (0, import_vue10.computed)(() => props.code ?? props.content ?? ""), waitingForStreamingSourceToFinish = (0, import_vue10.computed)(() => props.streaming && !props.final), graphicsOutputVersion = (0, import_vue10.shallowRef)(getTerminalGraphicsOutputVersion(terminal)), graphicsOutput = (0, import_vue10.computed)(() => (graphicsOutputVersion.value, getTerminalGraphicsOutput(terminal))), graphicsProtocol = (0, import_vue10.computed)(() => {
2314
+ let output = graphicsOutput.value;
2315
+ if (!output?.capabilities.supported)
2316
+ return null;
2317
+ let protocol = output.capabilities.preferredProtocol;
2318
+ return protocol === "kitty" || protocol === "iterm2" ? protocol : null;
2319
+ });
2320
+ function bump() {
2321
+ documentVersion.value++;
2322
+ }
2323
+ function clearCopiedTimer() {
2324
+ copiedTimer != null && (clearTimeout(copiedTimer), copiedTimer = null);
2325
+ }
2326
+ function setCopied(next, repaint = !0) {
2327
+ next || clearCopiedTimer(), copied.value !== next && (copied.value = next, repaint && bump());
2328
+ }
2329
+ function resetCopyFeedback(repaint = !0) {
2330
+ copyRequestVersion++, setCopied(!1, repaint);
2331
+ }
2332
+ function showCopiedFeedback() {
2333
+ clearCopiedTimer();
2334
+ let duration = normalizeNonNegativeInt2(
2335
+ props.copiedDurationMs,
2336
+ DEFAULT_MERMAID_IMAGE_COPIED_DURATION_MS
2337
+ );
2338
+ if (duration <= 0) {
2339
+ setCopied(!1);
2340
+ return;
2341
+ }
2342
+ setCopied(!0), copiedTimer = setTimeout(() => {
2343
+ copiedTimer = null, alive && setCopied(!1);
2344
+ }, duration);
2345
+ }
2346
+ function queueClearGraphic() {
2347
+ if (activeGraphicId == null)
2348
+ return;
2349
+ let id = activeGraphicId;
2350
+ activeGraphicId = null;
2351
+ try {
2352
+ graphicsOutput.value?.clear?.(id);
2353
+ } catch {
2354
+ }
2355
+ }
2356
+ let hasBox = (0, import_vue10.computed)(() => props.box !== !1), normalizedWidth = (0, import_vue10.computed)(() => {
2357
+ let width = Math.floor(Number(props.w));
2358
+ return Number.isFinite(width) ? Math.max(0, width) : 0;
2359
+ }), reservesBoxRows = (0, import_vue10.computed)(() => hasBox.value && normalizedWidth.value >= 2), boxChars = (0, import_vue10.computed)(
2360
+ () => props.ascii ? ASCII_MERMAID_IMAGE_BOX_CHARS : UNICODE_MERMAID_IMAGE_BOX_CHARS
2361
+ ), sourceLines = (0, import_vue10.computed)(() => splitRenderedOutput2(source.value)), currentStyle = (0, import_vue10.computed)(() => props.style ?? defaultStyle.value), innerWidth = (0, import_vue10.computed)(() => {
2362
+ let w = normalizedWidth.value;
2363
+ return reservesBoxRows.value ? Math.max(0, w - 2) : w;
2364
+ }), fixedInnerHeight = (0, import_vue10.computed)(() => {
2365
+ if (props.h == null)
2366
+ return 0;
2367
+ let h4 = Math.floor(Number(props.h));
2368
+ if (!Number.isFinite(h4))
2369
+ return 0;
2370
+ let value = Math.max(0, h4);
2371
+ return reservesBoxRows.value ? Math.max(0, value - 2) : value;
2372
+ }), autoHeight = (0, import_vue10.computed)(() => props.h == null), displayFit = (0, import_vue10.computed)(() => {
2373
+ let cells = imageCells.value;
2374
+ return cells ? autoHeight.value ? fitImageCells(cells, innerWidth.value, Number.MAX_SAFE_INTEGER) : fitImageCells(cells, innerWidth.value, fixedInnerHeight.value) : null;
2375
+ }), contentHeight = (0, import_vue10.computed)(() => autoHeight.value ? displayFit.value?.displayH ?? Math.max(1, sourceLines.value.length) : fixedInnerHeight.value), fullHeight = (0, import_vue10.computed)(() => {
2376
+ if (props.h != null) {
2377
+ let h4 = Math.floor(Number(props.h));
2378
+ return Number.isFinite(h4) ? Math.max(0, h4) : 0;
2379
+ }
2380
+ return reservesBoxRows.value ? contentHeight.value + 2 : contentHeight.value;
2381
+ }), fullRect = (0, import_vue10.computed)(() => translateRect(
2382
+ { x: props.x, y: props.y, w: props.w, h: fullHeight.value },
2383
+ layout.originX,
2384
+ layout.originY
2385
+ )), absRect = (0, import_vue10.computed)(() => {
2386
+ let translated = fullRect.value;
2387
+ return layout.clipRect ? intersectRect(translated, layout.clipRect) ?? { x: 0, y: 0, w: 0, h: 0 } : translated;
2388
+ }), copyLabel = (0, import_vue10.computed)(() => copied.value ? props.copiedText : props.copyText);
2389
+ function cellWidth(value) {
2390
+ return withTextWidthProvider(widthProvider, () => textCellWidth(value));
2391
+ }
2392
+ function sliceCells(text, maxCells) {
2393
+ return withTextWidthProvider(widthProvider, () => sliceByCells(text, maxCells));
2394
+ }
2395
+ function sliceCellsRange(text, startCells, endCells) {
2396
+ return withTextWidthProvider(
2397
+ widthProvider,
2398
+ () => sliceByCellsRange(text, startCells, endCells)
2399
+ );
2400
+ }
2401
+ function padCells(text, width) {
2402
+ return withTextWidthProvider(widthProvider, () => padEndByCells(text, width));
2403
+ }
2404
+ function resolveImageOptions() {
2405
+ let resolvedFg = props.fg ?? resolveMermaidImageColor(currentStyle.value.fg) ?? void 0;
2406
+ return normalizeMermaidImageOptions({
2407
+ cellWidthPx: props.cellWidthPx,
2408
+ cellHeightPx: props.cellHeightPx,
2409
+ scale: props.scale,
2410
+ bg: props.bg,
2411
+ fg: resolvedFg,
2412
+ maxWidthCells: props.maxWidthCells,
2413
+ maxHeightCells: props.maxHeightCells,
2414
+ padding: props.padding
2415
+ });
2416
+ }
2417
+ function shouldSkipRenderForSize(code) {
2418
+ let maxChars = normalizeNonNegativeInt2(
2419
+ props.maxRenderSourceChars,
2420
+ DEFAULT_MERMAID_IMAGE_MAX_RENDER_SOURCE_CHARS
2421
+ );
2422
+ if (maxChars > 0 && code.length > maxChars)
2423
+ return !0;
2424
+ let maxLines = normalizeNonNegativeInt2(
2425
+ props.maxRenderSourceLines,
2426
+ DEFAULT_MERMAID_IMAGE_MAX_RENDER_SOURCE_LINES
2427
+ );
2428
+ return maxLines > 0 && countLinesUpTo2(code, maxLines) > maxLines;
2429
+ }
2430
+ async function rasterizeWithTimeout(code, options) {
2431
+ let timeoutMs = normalizeNonNegativeInt2(props.renderTimeoutMs, 0);
2432
+ if (timeoutMs <= 0)
2433
+ return await getMermaidImage(code, options);
2434
+ let timer = null;
2435
+ try {
2436
+ return await Promise.race([
2437
+ getMermaidImage(code, options),
2438
+ new Promise((resolve) => {
2439
+ timer = setTimeout(() => resolve(null), timeoutMs);
2440
+ })
2441
+ ]);
2442
+ } finally {
2443
+ timer != null && clearTimeout(timer);
2444
+ }
2445
+ }
2446
+ async function renderImage(version) {
2447
+ let code = source.value;
2448
+ if (!code.trim()) {
2449
+ if (!alive || version !== renderVersion)
2450
+ return;
2451
+ imageCells.value = null, bump();
2452
+ return;
2453
+ }
2454
+ if (waitingForStreamingSourceToFinish.value || shouldSkipRenderForSize(code)) {
2455
+ if (!alive || version !== renderVersion)
2456
+ return;
2457
+ imageCells.value = null, bump();
2458
+ return;
2459
+ }
2460
+ if (imageCells.value = null, bump(), !graphicsProtocol.value)
2461
+ return;
2462
+ let options = resolveImageOptions(), cached = getCachedMermaidImage(code, options);
2463
+ if (cached) {
2464
+ if (!alive || version !== renderVersion)
2465
+ return;
2466
+ imageCells.value = cached, bump();
2467
+ return;
2468
+ }
2469
+ if (!isMermaidImageRendererReady()) {
2470
+ loadMermaidImageRenderer().then((ready) => {
2471
+ !alive || version !== renderVersion || !ready || renderImage(version);
2472
+ });
2473
+ return;
2474
+ }
2475
+ let result = await rasterizeWithTimeout(code, options);
2476
+ !alive || version !== renderVersion || (imageCells.value = result, bump());
2477
+ }
2478
+ function scheduleRender() {
2479
+ let version = ++renderVersion;
2480
+ if (resetCopyFeedback(!1), imageCells.value = null, waitingForStreamingSourceToFinish.value) {
2481
+ builtOnce = !0, scheduler.cancelFrameTask?.(frameTaskId), bump();
2482
+ return;
2483
+ }
2484
+ if (!builtOnce || !props.streaming) {
2485
+ builtOnce = !0, renderImage(version);
2486
+ return;
2487
+ }
2488
+ scheduler.queueFrameTask({
2489
+ id: frameTaskId,
2490
+ reason: "stream",
2491
+ priority: "low",
2492
+ sync: !1,
2493
+ run: () => {
2494
+ alive && version === renderVersion && renderImage(version);
2495
+ }
2496
+ }) === !1 && renderImage(version);
2497
+ }
2498
+ (0, import_vue10.watch)(
2499
+ [
2500
+ source,
2501
+ () => props.renderer,
2502
+ () => props.cellWidthPx,
2503
+ () => props.cellHeightPx,
2504
+ () => props.scale,
2505
+ () => props.bg,
2506
+ () => props.fg,
2507
+ () => props.maxWidthCells,
2508
+ () => props.maxHeightCells,
2509
+ () => props.padding,
2510
+ () => props.streaming,
2511
+ () => props.final,
2512
+ () => props.maxRenderSourceChars,
2513
+ () => props.maxRenderSourceLines,
2514
+ graphicsOutputVersion
2515
+ ],
2516
+ () => {
2517
+ scheduleRender();
2518
+ },
2519
+ { immediate: !0, deep: !0 }
2520
+ );
2521
+ let unsubscribeMermaidImage = subscribeMermaidImage(() => {
2522
+ alive && scheduleRender();
2523
+ }), unsubscribeGraphicsOutput = subscribeTerminalGraphicsOutput(terminal, () => {
2524
+ alive && (graphicsOutputVersion.value = getTerminalGraphicsOutputVersion(terminal), scheduleRender());
2525
+ });
2526
+ (0, import_vue10.onBeforeUnmount)(() => {
2527
+ alive = !1, renderVersion++, clearCopiedTimer(), queueClearGraphic(), unsubscribeMermaidImage(), unsubscribeGraphicsOutput(), scheduler.cancelFrameTask?.(frameTaskId);
2528
+ });
2529
+ function canDrawBox(width, height) {
2530
+ return hasBox.value && Math.floor(width) >= 2 && Math.floor(height) >= 2;
2531
+ }
2532
+ function headerCopySegment(width) {
2533
+ if (!hasBox.value || !props.copyButton)
2534
+ return null;
2535
+ let rowWidth = Math.max(0, Math.floor(width));
2536
+ if (rowWidth < 4)
2537
+ return null;
2538
+ let label = sanitizeInlineText(copyLabel.value);
2539
+ if (!label)
2540
+ return null;
2541
+ let maxCells = Math.max(0, rowWidth - 2), text = sliceCells(` ${label} `, maxCells), cells = cellWidth(text);
2542
+ return !text || cells <= 0 ? null : {
2543
+ text,
2544
+ start: Math.max(1, rowWidth - cells - 1),
2545
+ cells
2546
+ };
2547
+ }
2548
+ function headerTitleSegment(width, copy) {
2549
+ if (!hasBox.value)
2550
+ return null;
2551
+ let rowWidth = Math.max(0, Math.floor(width));
2552
+ if (rowWidth < 4)
2553
+ return null;
2554
+ let title = sanitizeInlineText(props.title);
2555
+ if (!title)
2556
+ return null;
2557
+ let titleStart = 1, titleEnd = copy ? Math.max(titleStart, copy.start - 1) : rowWidth - 1, maxCells = Math.max(0, titleEnd - titleStart);
2558
+ if (maxCells <= 0)
2559
+ return null;
2560
+ let text = sliceCells(` ${title} `, maxCells), cells = cellWidth(text);
2561
+ return !text || cells <= 0 ? null : {
2562
+ text,
2563
+ start: titleStart,
2564
+ cells
2565
+ };
2566
+ }
2567
+ function overlayCells(row, segment, width) {
2568
+ let rowWidth = Math.max(0, Math.floor(width)), start = Math.max(0, Math.floor(segment.start));
2569
+ if (rowWidth <= 1 || start >= rowWidth - 1 || segment.cells <= 0)
2570
+ return row;
2571
+ let maxCells = Math.max(0, rowWidth - 1 - start), text = sliceCells(segment.text, maxCells), cells = cellWidth(text);
2572
+ return !text || cells <= 0 ? row : `${sliceCells(row, start)}${text}${sliceCellsRange(row, start + cells, rowWidth)}`;
2573
+ }
2574
+ function boxRow(rowIndex, width, height) {
2575
+ let rowWidth = Math.max(0, Math.floor(width)), rowHeight = Math.max(0, Math.floor(height));
2576
+ if (!canDrawBox(rowWidth, rowHeight))
2577
+ return contentLine(rowIndex, rowWidth, props.clear);
2578
+ let chars = boxChars.value, innerW = Math.max(0, rowWidth - 2);
2579
+ if (rowIndex === 0) {
2580
+ let row = `${chars.tl}${repeatChar(chars.h, innerW)}${chars.tr}`, copy = headerCopySegment(rowWidth), title = headerTitleSegment(rowWidth, copy);
2581
+ return title && (row = overlayCells(row, title, rowWidth)), copy && (row = overlayCells(row, copy, rowWidth)), row;
2582
+ }
2583
+ return rowIndex === rowHeight - 1 ? `${chars.bl}${repeatChar(chars.h, innerW)}${chars.br}` : `${chars.v}${contentLine(rowIndex - 1, innerW, !0)}${chars.v}`;
2584
+ }
2585
+ function contentLine(rowIndex, width, pad) {
2586
+ let src = imageCells.value != null && displayFit.value != null && graphicsProtocol.value != null ? spaces(width) : sourceLines.value[rowIndex] ?? "", clipped = sliceCells(src, width);
2587
+ return pad ? padCells(clipped, width) : clipped;
2588
+ }
2589
+ function innerRectFrom(full) {
2590
+ let x = Math.floor(full.x) + (reservesBoxRows.value ? 1 : 0), y = Math.floor(full.y) + (reservesBoxRows.value ? 1 : 0), w = Math.max(0, Math.floor(full.w) - (reservesBoxRows.value ? 2 : 0)), h4 = Math.max(0, Math.floor(full.h) - (reservesBoxRows.value ? 2 : 0));
2591
+ return { x, y, w, h: h4 };
2592
+ }
2593
+ function queueImageGraphic(full, fit) {
2594
+ let protocol = graphicsProtocol.value, cells = imageCells.value;
2595
+ if (!protocol || !cells) {
2596
+ queueClearGraphic();
2597
+ return;
2598
+ }
2599
+ let inner = innerRectFrom(full);
2600
+ if (inner.w <= 0 || inner.h <= 0) {
2601
+ queueClearGraphic();
2602
+ return;
2603
+ }
2604
+ let offsetX = inner.w > fit.displayW ? Math.floor((inner.w - fit.displayW) / 2) : 0, rect = {
2605
+ x: inner.x + offsetX,
2606
+ y: inner.y,
2607
+ w: fit.displayW,
2608
+ h: fit.displayH
2609
+ }, imageId = stableTerminalGraphicNumericId(`mermaid-image:${uid}:${renderVersion}:img`), placementId = stableTerminalGraphicNumericId(
2610
+ `mermaid-image:${uid}:${renderVersion}:plc`
2611
+ ), built = createTerminalGraphicPngSequence({
2612
+ protocol,
2613
+ base64: cells.base64,
2614
+ imageId,
2615
+ placementId,
2616
+ cols: cells.widthCells,
2617
+ rows: cells.heightCells,
2618
+ sourceWidth: cells.naturalWidth,
2619
+ sourceHeight: cells.naturalHeight,
2620
+ placementColumns: fit.displayW,
2621
+ placementRows: fit.displayH,
2622
+ rect,
2623
+ fullRect: rect,
2624
+ zIndex: -1,
2625
+ fallback: source.value
2626
+ });
2627
+ if (!built) {
2628
+ queueClearGraphic();
2629
+ return;
2630
+ }
2631
+ let id = `mermaid-image:${uid}:${renderVersion}`, output = graphicsOutput.value;
2632
+ if (!output) {
2633
+ queueClearGraphic();
2634
+ return;
2635
+ }
2636
+ if (activeGraphicId != null && activeGraphicId !== id) {
2637
+ try {
2638
+ output.clear?.(activeGraphicId);
2639
+ } catch {
2640
+ }
2641
+ activeGraphicId = null;
2642
+ }
2643
+ output.queue({
2644
+ id,
2645
+ x: rect.x,
2646
+ y: rect.y,
2647
+ w: fit.displayW,
2648
+ h: fit.displayH,
2649
+ protocol,
2650
+ sequence: built.sequence,
2651
+ resizeSequence: built.resizeSequence,
2652
+ clearSequence: built.clearSequence,
2653
+ fallbackText: source.value
2654
+ }) ? activeGraphicId = id : queueClearGraphic();
2655
+ }
2656
+ let copyHitRect = (0, import_vue10.computed)(() => {
2657
+ let full = fullRect.value;
2658
+ if (!visible.value || !props.copyButton || !canDrawBox(full.w, full.h))
2659
+ return { x: 0, y: 0, w: 0, h: 0 };
2660
+ let copy = headerCopySegment(Math.max(0, Math.floor(full.w)));
2661
+ if (!copy)
2662
+ return { x: 0, y: 0, w: 0, h: 0 };
2663
+ let raw = {
2664
+ x: Math.floor(full.x) + copy.start,
2665
+ y: Math.floor(full.y),
2666
+ w: copy.cells,
2667
+ h: 1
2668
+ };
2669
+ return layout.clipRect ? intersectRect(raw, layout.clipRect) ?? { x: 0, y: 0, w: 0, h: 0 } : raw;
2670
+ }), contentHitRect = (0, import_vue10.computed)(() => {
2671
+ if (!visible.value || !props.copyOnClick)
2672
+ return { x: 0, y: 0, w: 0, h: 0 };
2673
+ let full = fullRect.value;
2674
+ if (full.w <= 0 || full.h <= 0)
2675
+ return { x: 0, y: 0, w: 0, h: 0 };
2676
+ let inner = innerRectFrom(full);
2677
+ return inner.w <= 0 || inner.h <= 0 ? { x: 0, y: 0, w: 0, h: 0 } : layout.clipRect ? intersectRect(inner, layout.clipRect) ?? { x: 0, y: 0, w: 0, h: 0 } : inner;
2678
+ });
2679
+ function clipboardCanWrite2(api) {
2680
+ return api.canWrite ?? api.supported;
2681
+ }
2682
+ async function writeClipboardText(text) {
2683
+ let contextClipboard = terminalContext.clipboard;
2684
+ if (contextClipboard) {
2685
+ if (!clipboardCanWrite2(contextClipboard))
2686
+ throw new Error("Clipboard write not available in this runtime");
2687
+ await contextClipboard.writeText(text);
2688
+ return;
2689
+ }
2690
+ let navClipboard = globalThis.navigator?.clipboard;
2691
+ if (navClipboard && typeof navClipboard.writeText == "function") {
2692
+ await navClipboard.writeText(text);
2693
+ return;
2694
+ }
2695
+ throw new Error("Clipboard write not available in this runtime");
2696
+ }
2697
+ async function copySource() {
2698
+ let text = source.value, requestVersion = ++copyRequestVersion, ok = !1, copyError;
2699
+ try {
2700
+ await writeClipboardText(text), ok = !0;
2701
+ } catch (err) {
2702
+ copyError = err;
2703
+ }
2704
+ if (!alive)
2705
+ return;
2706
+ requestVersion === copyRequestVersion && source.value === text && (ok ? showCopiedFeedback() : setCopied(!1)), emit("copy", ok ? { text, ok } : { text, ok, error: copyError });
2707
+ }
2708
+ function onCopyClick(event) {
2709
+ event.preventDefault(), event.stopPropagation(), copySource();
2710
+ }
2711
+ function onCopyKeydown(event) {
2712
+ event.key !== "Enter" && event.key !== " " || (event.preventDefault(), event.stopPropagation(), copySource());
2713
+ }
2714
+ let copyNodeActive = (0, import_vue10.computed)(
2715
+ () => visible.value && props.copyButton && copyHitRect.value.w > 0 && copyHitRect.value.h > 0
2716
+ );
2717
+ useTerminalNode(() => ({
2718
+ rect: copyHitRect.value,
2719
+ zIndex: (parentEventZ.value ?? 0) + props.zIndex + 1,
2720
+ visible: copyNodeActive.value,
2721
+ focusable: copyNodeActive.value,
2722
+ selectable: !1,
2723
+ handlers: copyNodeActive.value ? {
2724
+ click: onCopyClick,
2725
+ keydown: onCopyKeydown
2726
+ } : {}
2727
+ }));
2728
+ let contentNodeActive = (0, import_vue10.computed)(
2729
+ () => visible.value && props.copyOnClick && contentHitRect.value.w > 0 && contentHitRect.value.h > 0
2730
+ );
2731
+ return useTerminalNode(() => ({
2732
+ rect: contentHitRect.value,
2733
+ zIndex: (parentEventZ.value ?? 0) + props.zIndex,
2734
+ visible: contentNodeActive.value,
2735
+ focusable: !1,
2736
+ selectable: !1,
2737
+ handlers: contentNodeActive.value ? {
2738
+ click: onCopyClick
2739
+ } : {}
2740
+ })), useRenderNode(() => ({
2741
+ zIndex: props.zIndex,
2742
+ rect: visible.value ? absRect.value : { x: 0, y: 0, w: 0, h: 0 },
2743
+ deps: [
2744
+ visible.value,
2745
+ absRect.value,
2746
+ fullRect.value,
2747
+ imageCells.value,
2748
+ displayFit.value,
2749
+ sourceLines.value,
2750
+ currentStyle.value,
2751
+ props.clear,
2752
+ hasBox.value,
2753
+ boxChars.value,
2754
+ props.title,
2755
+ props.copyButton,
2756
+ copyLabel.value,
2757
+ graphicsOutputVersion.value,
2758
+ documentVersion.value
2759
+ ],
2760
+ paint: (dirtyRows) => {
2761
+ withTextWidthProvider(widthProvider, () => {
2762
+ if (!visible.value) {
2763
+ queueClearGraphic();
2764
+ return;
2765
+ }
2766
+ let r = absRect.value, full = fullRect.value;
2767
+ if (r.w <= 0 || r.h <= 0) {
2768
+ queueClearGraphic();
2769
+ return;
2770
+ }
2771
+ let style = currentStyle.value, dx = Math.max(0, Math.floor(r.x - full.x)), fullY = Math.floor(full.y), fullW = Math.max(0, Math.floor(full.w)), fullH = Math.max(0, Math.floor(full.h)), blank = props.clear ? spaces(r.w) : "", paintRow = (y) => {
2772
+ if (y < r.y || y >= r.y + r.h)
2773
+ return;
2774
+ let rowIndex = y - fullY;
2775
+ if (rowIndex < 0 || rowIndex >= fullH) {
2776
+ props.clear && terminal.write(blank, { x: r.x, y, style });
2777
+ return;
2778
+ }
2779
+ let src = boxRow(rowIndex, fullW, fullH), clipped = dx > 0 ? sliceCellsRange(src, dx, dx + r.w) : sliceCells(src, r.w), value = props.clear ? padCells(clipped, r.w) : clipped;
2780
+ (value || props.clear) && terminal.write(value, { x: r.x, y, style });
2781
+ };
2782
+ if (imageCells.value && displayFit.value ? queueImageGraphic(full, displayFit.value) : queueClearGraphic(), dirtyRows?.length) {
2783
+ for (let y of dirtyRows)
2784
+ paintRow(y);
2785
+ return;
2786
+ }
2787
+ for (let y = r.y; y < r.y + r.h; y++)
2788
+ paintRow(y);
2789
+ });
2790
+ }
2791
+ })), () => (0, import_vue10.h)("span", rootProps);
2792
+ }
2793
+ });