@simon_he/vue-tui 0.0.8 → 1.0.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 +142 -30
- package/dist/TSelect-BwJJbuTt.js +6089 -0
- package/dist/TTree-DK_DQBYm.js +6480 -0
- package/dist/agent.cjs +39416 -0
- package/dist/agent.d.cts +44 -0
- package/dist/agent.d.ts +44 -0
- package/dist/agent.js +828 -0
- package/dist/ansi-palette-CNXqFciC.js +57 -0
- package/dist/ansi-styles.d.ts +200 -0
- package/dist/block-source-CKUOnkgT.js +1663 -0
- package/dist/cli/headless-renderer.d.ts +29 -0
- package/dist/cli/input.d.ts +49 -0
- package/dist/cli/node-file-writers.d.ts +13 -0
- package/dist/cli/node-module.d.ts +2 -0
- package/dist/cli/parse-kitty.d.ts +2 -0
- package/dist/cli/parse-mouse.d.ts +2 -0
- package/dist/cli/parse-utils.d.ts +14 -0
- package/dist/cli/parse-xterm.d.ts +2 -0
- package/dist/cli/path-provider-types.d.ts +1 -0
- package/dist/cli/path-provider.d.ts +4 -0
- package/dist/cli/path-suggest-core.d.ts +1 -0
- package/dist/cli/path-suggest.d.ts +15 -0
- package/dist/cli/recording.d.ts +4 -0
- package/dist/cli/stdin-buffer.d.ts +33 -0
- package/dist/cli.cjs +11061 -0
- package/dist/cli.d.cts +23 -0
- package/dist/cli.d.ts +23 -0
- package/dist/cli.js +9875 -0
- package/dist/core/ansi/capability.d.ts +20 -0
- package/dist/core/ansi/colors.d.ts +41 -0
- package/dist/core/ansi/sgr.d.ts +7 -0
- package/dist/core/ansi/theme.d.ts +6 -0
- package/dist/core/ansi-palette.d.ts +14 -0
- package/dist/core/buffer/buffer.d.ts +54 -0
- package/dist/core/buffer/width.d.ts +4 -0
- package/dist/core/debug-logger.d.ts +18 -0
- package/dist/core/hyperlink.d.ts +9 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/path-provider-types.d.ts +24 -0
- package/dist/core/path-suggest.d.ts +35 -0
- package/dist/core/render-plane.d.ts +3 -0
- package/dist/core/terminal/create-terminal.d.ts +8 -0
- package/dist/core/terminal/emitter.d.ts +7 -0
- package/dist/core/types.d.ts +107 -0
- package/dist/core.cjs +3153 -0
- package/dist/core.d.cts +14 -0
- package/dist/core.d.ts +14 -0
- package/dist/core.js +424 -0
- package/dist/create-terminal-C2oiWFJU.js +1434 -0
- package/dist/create-terminal-app.d.ts +36 -0
- package/dist/dom-renderer-BqGijQID.js +1173 -0
- package/dist/env-Cl8qmNFN.js +19 -0
- package/dist/events/index.d.ts +6 -0
- package/dist/events/manager/cli-event-manager.d.ts +22 -0
- package/dist/events/manager/event-manager.d.ts +30 -0
- package/dist/events/manager/selection-suppression.d.ts +3 -0
- package/dist/events/manager/types.d.ts +108 -0
- package/dist/events/recording.d.ts +44 -0
- package/dist/experimental.cjs +4412 -1641
- package/dist/experimental.d.cts +42 -0
- package/dist/experimental.d.ts +42 -825
- package/dist/experimental.js +31 -7392
- package/dist/frame-perf-C6Xfg85O.js +24 -0
- package/dist/hyperlink-Bn02UXJb.js +419 -0
- package/dist/index.cjs +14765 -17582
- package/dist/index.d.cts +35 -0
- package/dist/index.d.ts +35 -1528
- package/dist/index.js +17 -20026
- package/dist/linkify-D_gzn9Xq.js +562 -0
- package/dist/markdown.cjs +9321 -7623
- package/dist/markdown.d.cts +11 -0
- package/dist/markdown.d.ts +11 -112
- package/dist/markdown.js +36 -1427
- package/dist/observability/cli-latency-node.d.ts +3 -0
- package/dist/observability/cli-latency-types.d.ts +41 -0
- package/dist/observability/cli-latency.d.ts +3 -0
- package/dist/observability/frame-perf-store.d.ts +18 -0
- package/dist/observability/frame-perf.d.ts +40 -0
- package/dist/observability/perf-sink.d.ts +56 -0
- package/dist/observability/trace.d.ts +40 -0
- package/dist/observability/tui-profiler.d.ts +33 -0
- package/dist/observability.cjs +221 -0
- package/dist/observability.d.cts +8 -0
- package/dist/observability.d.ts +8 -0
- package/dist/observability.js +4 -0
- package/dist/path-mnSgEpCm.js +81 -0
- package/dist/path-suggest-BNqcuE3-.js +274 -0
- package/dist/path-suggest-Dk9TRLh5.js +3 -0
- package/dist/{path-suggest-DmrmeueH.js → path-suggest-bvR9SY6Q.js} +86 -18
- package/dist/renderer/capabilities.d.ts +13 -0
- package/dist/renderer/cli/index.d.ts +2 -0
- package/dist/renderer/cli/stdout-metrics.d.ts +18 -0
- package/dist/renderer/cli/stdout-renderer.d.ts +48 -0
- package/dist/renderer/dom/dom-renderer.d.ts +157 -0
- package/dist/renderer/dom/index.d.ts +2 -0
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer-dom.cjs +1505 -0
- package/dist/renderer-dom.d.cts +4 -0
- package/dist/renderer-dom.d.ts +4 -0
- package/dist/renderer-dom.js +7 -0
- package/dist/runtime/index.d.ts +36 -0
- package/dist/runtime/osc52.d.ts +9 -0
- package/dist/runtime-rfcZCyJq.js +1197 -0
- package/dist/runtime.cjs +1698 -0
- package/dist/runtime.d.cts +9 -0
- package/dist/runtime.d.ts +9 -0
- package/dist/runtime.js +4 -0
- package/dist/selection/terminal-selection.d.ts +123 -0
- package/dist/sgr-BmzxEjAO.js +304 -0
- package/dist/terminal-selection-DBinO6p5.js +330 -0
- package/dist/tlog-theme-qPBt5rge.js +9254 -0
- package/dist/trace-CjzYeIxN.js +182 -0
- package/dist/utils/env.d.ts +3 -0
- package/dist/utils/grapheme.d.ts +5 -0
- package/dist/utils/newlines.d.ts +1 -0
- package/dist/utils/path.d.ts +7 -0
- package/dist/utils/url-safety.d.ts +2 -0
- package/dist/vue/agent/view-models.d.ts +98 -0
- package/dist/vue/components/TAnchor.d.ts +108 -0
- package/dist/vue/components/TBox.d.ts +144 -0
- package/dist/vue/components/TCommandPalette.d.ts +587 -0
- package/dist/vue/components/TDataTable.d.ts +367 -0
- package/dist/vue/components/TDebugOverlay.d.ts +43 -0
- package/dist/vue/components/TDialog.d.ts +255 -0
- package/dist/vue/components/TFeedback.d.ts +635 -0
- package/dist/vue/components/TFlow.d.ts +85 -0
- package/dist/vue/components/TForm.d.ts +1230 -0
- package/dist/vue/components/TInput.d.ts +545 -0
- package/dist/vue/components/TInputBox.d.ts +158 -0
- package/dist/vue/components/TJsonEditor.d.ts +165 -0
- package/dist/vue/components/TLink.d.ts +239 -0
- package/dist/vue/components/TLinkifyText.d.ts +141 -0
- package/dist/vue/components/TList.d.ts +119 -0
- package/dist/vue/components/TLogLinksPanel.d.ts +238 -0
- package/dist/vue/components/TLogMinimap.d.ts +263 -0
- package/dist/vue/components/TLogScrollbar.d.ts +236 -0
- package/dist/vue/components/TLogSearchBar.d.ts +267 -0
- package/dist/vue/components/TLogSearchPager.d.ts +162 -0
- package/dist/vue/components/TLogSearchResults.d.ts +200 -0
- package/dist/vue/components/TLogView.d.ts +536 -0
- package/dist/vue/components/TLogVirtualLinksPanel.d.ts +141 -0
- package/dist/vue/components/TLogVirtualSearchResults.d.ts +146 -0
- package/dist/vue/components/TMarkdownText.d.ts +134 -0
- package/dist/vue/components/TMultilineModal.d.ts +62 -0
- package/dist/vue/components/TNavigation.d.ts +324 -0
- package/dist/vue/components/TOverlay.d.ts +366 -0
- package/dist/vue/components/TPanels.d.ts +244 -0
- package/dist/vue/components/TPathPicker.d.ts +213 -0
- package/dist/vue/components/TRenderLayer.d.ts +16 -0
- package/dist/vue/components/TRenderPlane.d.ts +17 -0
- package/dist/vue/components/TSelect.d.ts +335 -0
- package/dist/vue/components/TTable.d.ts +317 -0
- package/dist/vue/components/TText.d.ts +116 -0
- package/dist/vue/components/TThinkingView.d.ts +233 -0
- package/dist/vue/components/TToolCallView.d.ts +384 -0
- package/dist/vue/components/TTranscriptView.d.ts +221 -0
- package/dist/vue/components/TTransition.d.ts +83 -0
- package/dist/vue/components/TTree.d.ts +200 -0
- package/dist/vue/components/TUserMessageView.d.ts +344 -0
- package/dist/vue/components/TView.d.ts +127 -0
- package/dist/vue/components/TVirtualList.d.ts +182 -0
- package/dist/vue/components/TVirtualMarkdown.d.ts +168 -0
- package/dist/vue/components/TVirtualRows.d.ts +247 -0
- package/dist/vue/components/TerminalProvider.d.ts +218 -0
- package/dist/vue/components/input/host.d.ts +17 -0
- package/dist/vue/components/input/plugins/hostPlugin.d.ts +7 -0
- package/dist/vue/components/input/plugins/hostPlugin.node.d.ts +15 -0
- package/dist/vue/components/input/plugins/mentionUtils.d.ts +17 -0
- package/dist/vue/components/input/plugins/nodeMentionPathProvider.d.ts +2 -0
- package/dist/vue/components/input/plugins/promptMentionPlugin.d.ts +8 -0
- package/dist/vue/components/input/plugins/promptMentionState.d.ts +98 -0
- package/dist/vue/components/input/plugins/restrictText.d.ts +27 -0
- package/dist/vue/components/input/plugins/types.d.ts +90 -0
- package/dist/vue/components/input/utils/inlineText.d.ts +57 -0
- package/dist/vue/components/input/utils/inlineTextTokens.d.ts +34 -0
- package/dist/vue/components/input/utils/primitives.d.ts +3 -0
- package/dist/vue/components/input/utils/wordNavigation.d.ts +6 -0
- package/dist/vue/components/link/host.d.ts +15 -0
- package/dist/vue/components/list/list-geometry.d.ts +16 -0
- package/dist/vue/components/list/list-paint.d.ts +1 -0
- package/dist/vue/components/list/scroll-state.d.ts +25 -0
- package/dist/vue/components/list/selection-state.d.ts +6 -0
- package/dist/vue/components/simple-utils.d.ts +5 -0
- package/dist/vue/components/terminal-provider/copy-toast.d.ts +6 -0
- package/dist/vue/components/terminal-provider/portals.d.ts +17 -0
- package/dist/vue/components/terminal-provider/scheduler.d.ts +29 -0
- package/dist/vue/components/terminal-provider/selection-config.d.ts +15 -0
- package/dist/vue/components/terminal-provider/utils.d.ts +5 -0
- package/dist/vue/composables/use-layout.d.ts +2 -0
- package/dist/vue/composables/use-render-node.d.ts +19 -0
- package/dist/vue/composables/use-render-stack.d.ts +3 -0
- package/dist/vue/composables/use-runtime.d.ts +5 -0
- package/dist/vue/composables/use-terminal-node.d.ts +14 -0
- package/dist/vue/composables/use-terminal.d.ts +2 -0
- package/dist/vue/composables/use-visibility.d.ts +12 -0
- package/dist/vue/context.d.ts +153 -0
- package/dist/vue/index.d.ts +69 -0
- package/dist/vue/injection-key.d.ts +2 -0
- package/dist/vue/linkify.d.ts +11 -0
- package/dist/vue/log/append-only-log-store.d.ts +2 -0
- package/dist/vue/log/tlog-keymap.d.ts +28 -0
- package/dist/vue/log/tlog-plugins.d.ts +144 -0
- package/dist/vue/log/tlog-session.d.ts +81 -0
- package/dist/vue/log/tlog-theme.d.ts +68 -0
- package/dist/vue/log/types.d.ts +43 -0
- package/dist/vue/log/use-tlog-link-controller.d.ts +31 -0
- package/dist/vue/log/use-tlog-retained-index.d.ts +26 -0
- package/dist/vue/log/use-tlog-search-controller.d.ts +51 -0
- package/dist/vue/log/use-tlog-search-results-page.d.ts +31 -0
- package/dist/vue/log/use-tlog-virtual-search-results.d.ts +22 -0
- package/dist/vue/markdown/ast.d.ts +3 -0
- package/dist/vue/markdown/block-source.d.ts +22 -0
- package/dist/vue/markdown/document.d.ts +20 -0
- package/dist/vue/markdown/layout.d.ts +21 -0
- package/dist/vue/markdown/parser.d.ts +11 -0
- package/dist/vue/markdown/render.d.ts +10 -0
- package/dist/vue/markdown/theme.d.ts +186 -0
- package/dist/vue/markdown/types.d.ts +59 -0
- package/dist/vue/overlay.d.ts +27 -0
- package/dist/vue/render/context.d.ts +3 -0
- package/dist/vue/render/render-manager.d.ts +94 -0
- package/dist/vue/router/RouterView.d.ts +25 -0
- package/dist/vue/router/composables.d.ts +4 -0
- package/dist/vue/router/context.d.ts +4 -0
- package/dist/vue/router/router.d.ts +7 -0
- package/dist/vue/router/types.d.ts +29 -0
- package/dist/vue/scheduler/frame-mailbox.d.ts +55 -0
- package/dist/vue/scheduler/frame-scheduler.d.ts +51 -0
- package/dist/vue/theme.d.ts +48 -0
- package/dist/vue/transcript/hit-regions.d.ts +2 -0
- package/dist/vue/transcript/layout.d.ts +20 -0
- package/dist/vue/transcript/plain-text.d.ts +2 -0
- package/dist/vue/transcript/types.d.ts +122 -0
- package/dist/vue/utils/frame-task.d.ts +6 -0
- package/dist/vue/utils/rect.d.ts +4 -0
- package/dist/vue/utils/row-scroll.d.ts +25 -0
- package/dist/vue/utils/style-cache.d.ts +3 -0
- package/dist/vue/utils/text.d.ts +27 -0
- package/dist/vue/utils/wheel-scroll.d.ts +18 -0
- package/dist/vue.cjs +23668 -0
- package/dist/vue.d.cts +1 -0
- package/dist/vue.d.ts +1 -0
- package/dist/vue.js +3957 -0
- package/dist/{wheel-scroll-CiNsasLf.js → wheel-scroll-vBRaQ7p-.js} +404 -405
- package/package.json +185 -35
- package/dist/path-suggest-BeV6n7m-.js +0 -3
- package/dist/sgr-Tko2EQ0U.js +0 -484
- package/dist/theme-Bsm65g8k.d.ts +0 -32
- package/dist/types-ClIV2h1o.d.ts +0 -103
package/dist/markdown.js
CHANGED
|
@@ -1,889 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import "./hyperlink-Bn02UXJb.js";
|
|
2
|
+
import { intersectRect, translateRect, useLayout, useRenderNode, useTerminal, useVisibility, withTextWidthProvider } from "./wheel-scroll-vBRaQ7p-.js";
|
|
3
|
+
import "./terminal-selection-DBinO6p5.js";
|
|
4
|
+
import { TVirtualMarkdown, buildMarkdownBlocks, buildMarkdownVisualRows, createMarkdownBlockSource, createTuiMarkdownParser, isSafeMarkdownLink, layoutMarkdownBlocks, markdownThemeSignature, paintMarkdownVisualRow } from "./block-source-CKUOnkgT.js";
|
|
5
|
+
import { computed, defineComponent, getCurrentInstance, h, markRaw, onBeforeUnmount, shallowRef, watch } from "vue";
|
|
4
6
|
|
|
5
|
-
//#region src/vue/markdown/parser.ts
|
|
6
|
-
const RELATIVE_LINK_PREFIXES = [
|
|
7
|
-
"#",
|
|
8
|
-
"/",
|
|
9
|
-
"./",
|
|
10
|
-
"../"
|
|
11
|
-
];
|
|
12
|
-
const SAFE_PROTOCOLS = new Set([
|
|
13
|
-
"http:",
|
|
14
|
-
"https:",
|
|
15
|
-
"mailto:"
|
|
16
|
-
]);
|
|
17
|
-
const markdownInstanceCache = new Map();
|
|
18
|
-
const MAX_MARKDOWN_INSTANCE_CACHE = 32;
|
|
19
|
-
const SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
|
|
20
|
-
function hasControlChars(value) {
|
|
21
|
-
for (const ch of value) {
|
|
22
|
-
const code = ch.codePointAt(0);
|
|
23
|
-
if (code >= 0 && code <= 31 || code >= 127 && code <= 159) return true;
|
|
24
|
-
}
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
function isSafeMarkdownLink(url) {
|
|
28
|
-
const raw = String(url ?? "").trim();
|
|
29
|
-
if (!raw) return false;
|
|
30
|
-
if (hasControlChars(raw)) return false;
|
|
31
|
-
if (raw.startsWith("//")) return false;
|
|
32
|
-
const value = raw.toLowerCase();
|
|
33
|
-
if (value.startsWith("javascript:")) return false;
|
|
34
|
-
if (value.startsWith("data:")) return false;
|
|
35
|
-
if (RELATIVE_LINK_PREFIXES.some((prefix) => raw.startsWith(prefix))) return true;
|
|
36
|
-
if (!SCHEME_RE.test(raw)) return true;
|
|
37
|
-
try {
|
|
38
|
-
const parsed = new URL(raw);
|
|
39
|
-
return SAFE_PROTOCOLS.has(parsed.protocol);
|
|
40
|
-
} catch {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
function markdownInstanceCacheKey(config) {
|
|
45
|
-
var _config$customHtmlTag;
|
|
46
|
-
return JSON.stringify({ customHtmlTags: [...(config === null || config === void 0 || (_config$customHtmlTag = config.customHtmlTags) === null || _config$customHtmlTag === void 0 ? void 0 : _config$customHtmlTag.filter(Boolean)) ?? []].sort() });
|
|
47
|
-
}
|
|
48
|
-
function getCachedMarkdownInstance(config) {
|
|
49
|
-
var _config$customHtmlTag2;
|
|
50
|
-
const cacheKey = markdownInstanceCacheKey(config);
|
|
51
|
-
const cached = markdownInstanceCache.get(cacheKey);
|
|
52
|
-
if (cached) return cached;
|
|
53
|
-
const customHtmlTags = config === null || config === void 0 || (_config$customHtmlTag2 = config.customHtmlTags) === null || _config$customHtmlTag2 === void 0 ? void 0 : _config$customHtmlTag2.filter(Boolean);
|
|
54
|
-
const created = getMarkdown(`vue-tui-markdown:${cacheKey}`, { customHtmlTags });
|
|
55
|
-
if (markdownInstanceCache.size >= MAX_MARKDOWN_INSTANCE_CACHE) markdownInstanceCache.clear();
|
|
56
|
-
markdownInstanceCache.set(cacheKey, created);
|
|
57
|
-
return created;
|
|
58
|
-
}
|
|
59
|
-
function createTuiMarkdownParser(config) {
|
|
60
|
-
var _config$customHtmlTag3;
|
|
61
|
-
const customHtmlTags = config === null || config === void 0 || (_config$customHtmlTag3 = config.customHtmlTags) === null || _config$customHtmlTag3 === void 0 ? void 0 : _config$customHtmlTag3.filter(Boolean);
|
|
62
|
-
const md = getCachedMarkdownInstance(config);
|
|
63
|
-
function parse(content, final) {
|
|
64
|
-
return parseMarkdownToStructure(content, md, {
|
|
65
|
-
final,
|
|
66
|
-
customHtmlTags,
|
|
67
|
-
requireClosingStrong: final || !(config === null || config === void 0 ? void 0 : config.streaming),
|
|
68
|
-
validateLink: isSafeMarkdownLink
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
return { parse };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
//#endregion
|
|
75
|
-
//#region src/vue/markdown/ast.ts
|
|
76
|
-
const EMPTY_PREFIX = Object.freeze([]);
|
|
77
|
-
const HARD_BREAK_SEGMENT = Object.freeze({
|
|
78
|
-
text: "",
|
|
79
|
-
hardBreak: true
|
|
80
|
-
});
|
|
81
|
-
function mergeStyle$1(base, overlay) {
|
|
82
|
-
if (!base) return overlay;
|
|
83
|
-
if (!overlay) return base;
|
|
84
|
-
return {
|
|
85
|
-
...base,
|
|
86
|
-
...overlay
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function trimBlockArray(blocks) {
|
|
90
|
-
var _blocks$start, _blocks;
|
|
91
|
-
let start = 0;
|
|
92
|
-
let end = blocks.length;
|
|
93
|
-
while (start < end && ((_blocks$start = blocks[start]) === null || _blocks$start === void 0 ? void 0 : _blocks$start.type) === "blank") start++;
|
|
94
|
-
while (end > start && ((_blocks = blocks[end - 1]) === null || _blocks === void 0 ? void 0 : _blocks.type) === "blank") end--;
|
|
95
|
-
return blocks.slice(start, end);
|
|
96
|
-
}
|
|
97
|
-
function nodeChildren(node) {
|
|
98
|
-
return "children" in node && Array.isArray(node.children) ? node.children : [];
|
|
99
|
-
}
|
|
100
|
-
function stringProp(node, key) {
|
|
101
|
-
const value = node[key];
|
|
102
|
-
return typeof value === "string" ? value : "";
|
|
103
|
-
}
|
|
104
|
-
function booleanProp(node, key) {
|
|
105
|
-
return node[key] === true;
|
|
106
|
-
}
|
|
107
|
-
function pushTextSegments(out, text, style) {
|
|
108
|
-
if (!text) return;
|
|
109
|
-
const normalized = sanitizeTextBlock(text);
|
|
110
|
-
if (!normalized) return;
|
|
111
|
-
const parts = normalized.split("\n");
|
|
112
|
-
for (let i = 0; i < parts.length; i++) {
|
|
113
|
-
const part = sanitizeInlineText(parts[i] ?? "");
|
|
114
|
-
if (part) out.push(style ? {
|
|
115
|
-
text: part,
|
|
116
|
-
style
|
|
117
|
-
} : { text: part });
|
|
118
|
-
if (i < parts.length - 1) out.push(HARD_BREAK_SEGMENT);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
function sanitizeCodeBlockText(text, tabSize = 4) {
|
|
122
|
-
const normalized = String(text ?? "").replace(/\r\n?/g, "\n").replace(/\t/g, spaces(tabSize)).replace(/\u00a0/g, " ");
|
|
123
|
-
let out = "";
|
|
124
|
-
for (const ch of normalized) {
|
|
125
|
-
const code = ch.charCodeAt(0);
|
|
126
|
-
if (code >= 0 && code <= 8 || code === 11 || code === 12) continue;
|
|
127
|
-
if (code >= 14 && code <= 31 || code === 127) continue;
|
|
128
|
-
out += ch;
|
|
129
|
-
}
|
|
130
|
-
return out;
|
|
131
|
-
}
|
|
132
|
-
function inlineNodeSegments(nodes, theme, inheritedStyle) {
|
|
133
|
-
const out = [];
|
|
134
|
-
for (const node of nodes) switch (node.type) {
|
|
135
|
-
case "text":
|
|
136
|
-
pushTextSegments(out, stringProp(node, "content"), inheritedStyle);
|
|
137
|
-
break;
|
|
138
|
-
case "inline":
|
|
139
|
-
case "paragraph":
|
|
140
|
-
case "heading":
|
|
141
|
-
case "list_item":
|
|
142
|
-
case "blockquote":
|
|
143
|
-
out.push(...inlineNodeSegments(nodeChildren(node), theme, inheritedStyle));
|
|
144
|
-
break;
|
|
145
|
-
case "strong":
|
|
146
|
-
out.push(...inlineNodeSegments(nodeChildren(node), theme, mergeStyle$1(inheritedStyle, theme.strong)));
|
|
147
|
-
break;
|
|
148
|
-
case "emphasis":
|
|
149
|
-
out.push(...inlineNodeSegments(nodeChildren(node), theme, mergeStyle$1(inheritedStyle, theme.emphasis)));
|
|
150
|
-
break;
|
|
151
|
-
case "strikethrough":
|
|
152
|
-
out.push(...inlineNodeSegments(nodeChildren(node), theme, mergeStyle$1(inheritedStyle, theme.strikethrough)));
|
|
153
|
-
break;
|
|
154
|
-
case "highlight":
|
|
155
|
-
case "insert":
|
|
156
|
-
case "subscript":
|
|
157
|
-
case "superscript":
|
|
158
|
-
out.push(...inlineNodeSegments(nodeChildren(node), theme, inheritedStyle));
|
|
159
|
-
break;
|
|
160
|
-
case "inline_code":
|
|
161
|
-
pushTextSegments(out, stringProp(node, "code"), mergeStyle$1(inheritedStyle, theme.inlineCode));
|
|
162
|
-
break;
|
|
163
|
-
case "hardbreak":
|
|
164
|
-
out.push(HARD_BREAK_SEGMENT);
|
|
165
|
-
break;
|
|
166
|
-
case "link": {
|
|
167
|
-
const href = stringProp(node, "href");
|
|
168
|
-
const safeHref = href && isSafeMarkdownLink(href) ? href : "";
|
|
169
|
-
const linkStyle = safeHref ? mergeStyle$1(inheritedStyle, {
|
|
170
|
-
...theme.link,
|
|
171
|
-
href: safeHref
|
|
172
|
-
}) : inheritedStyle;
|
|
173
|
-
const children = nodeChildren(node);
|
|
174
|
-
if (children.length) out.push(...inlineNodeSegments(children, theme, linkStyle));
|
|
175
|
-
else pushTextSegments(out, stringProp(node, "text"), linkStyle);
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
case "image":
|
|
179
|
-
pushTextSegments(out, stringProp(node, "alt") || stringProp(node, "src"), mergeStyle$1(inheritedStyle, theme.link));
|
|
180
|
-
break;
|
|
181
|
-
case "checkbox":
|
|
182
|
-
case "checkbox_input":
|
|
183
|
-
pushTextSegments(out, booleanProp(node, "checked") ? "[x]" : "[ ]", inheritedStyle);
|
|
184
|
-
break;
|
|
185
|
-
case "emoji":
|
|
186
|
-
pushTextSegments(out, stringProp(node, "markup") || stringProp(node, "name"), inheritedStyle);
|
|
187
|
-
break;
|
|
188
|
-
case "math_inline":
|
|
189
|
-
pushTextSegments(out, stringProp(node, "content"), mergeStyle$1(inheritedStyle, theme.inlineCode));
|
|
190
|
-
break;
|
|
191
|
-
case "reference":
|
|
192
|
-
case "footnote_reference":
|
|
193
|
-
case "footnote_anchor":
|
|
194
|
-
pushTextSegments(out, node.raw, inheritedStyle);
|
|
195
|
-
break;
|
|
196
|
-
case "html_inline":
|
|
197
|
-
pushTextSegments(out, stringProp(node, "content"), mergeStyle$1(inheritedStyle, theme.html));
|
|
198
|
-
break;
|
|
199
|
-
case "html_block":
|
|
200
|
-
pushTextSegments(out, stringProp(node, "content"), mergeStyle$1(inheritedStyle, theme.html));
|
|
201
|
-
break;
|
|
202
|
-
default:
|
|
203
|
-
if (nodeChildren(node).length) {
|
|
204
|
-
out.push(...inlineNodeSegments(nodeChildren(node), theme, inheritedStyle));
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
pushTextSegments(out, node.raw, inheritedStyle);
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
return out;
|
|
211
|
-
}
|
|
212
|
-
function inlineBlock(key, segments, context) {
|
|
213
|
-
return {
|
|
214
|
-
type: "inline",
|
|
215
|
-
key,
|
|
216
|
-
segments,
|
|
217
|
-
prefixSegments: context.prefixSegments,
|
|
218
|
-
continuationPrefixSegments: context.continuationPrefixSegments
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
function blockFromParagraph(node, key, context, theme) {
|
|
222
|
-
return inlineBlock(key, inlineNodeSegments(node.children, theme), context);
|
|
223
|
-
}
|
|
224
|
-
function blockFromHeading(node, key, context, theme) {
|
|
225
|
-
const level = Math.min(6, Math.max(1, Math.floor(node.level || 1)));
|
|
226
|
-
return inlineBlock(key, inlineNodeSegments(node.children, theme, theme.heading[level - 1]), context);
|
|
227
|
-
}
|
|
228
|
-
function blockFromCodeBlock(node, key, context, theme) {
|
|
229
|
-
return {
|
|
230
|
-
type: "code_block",
|
|
231
|
-
key,
|
|
232
|
-
lines: sanitizeCodeBlockText(node.code ?? "").split("\n"),
|
|
233
|
-
style: theme.codeBlock,
|
|
234
|
-
prefixSegments: context.prefixSegments,
|
|
235
|
-
continuationPrefixSegments: context.continuationPrefixSegments
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
function blockFromHtmlBlock(node, key, context, theme) {
|
|
239
|
-
return inlineBlock(key, inlineNodeSegments([{
|
|
240
|
-
type: "html_block",
|
|
241
|
-
raw: node.raw,
|
|
242
|
-
content: node.content
|
|
243
|
-
}], theme), context);
|
|
244
|
-
}
|
|
245
|
-
function childSequenceToBlocks(nodes, context, theme, keyPrefix) {
|
|
246
|
-
const out = [];
|
|
247
|
-
let appended = false;
|
|
248
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
249
|
-
var _out, _childBlocks$;
|
|
250
|
-
const childBlocks = trimBlockArray(nodeToBlocks(nodes[i], context, theme, `${keyPrefix}-${i}`));
|
|
251
|
-
if (!childBlocks.length) continue;
|
|
252
|
-
if (appended && ((_out = out[out.length - 1]) === null || _out === void 0 ? void 0 : _out.type) !== "blank" && ((_childBlocks$ = childBlocks[0]) === null || _childBlocks$ === void 0 ? void 0 : _childBlocks$.type) !== "blank") out.push({
|
|
253
|
-
type: "blank",
|
|
254
|
-
key: `${keyPrefix}-${i}-gap`
|
|
255
|
-
});
|
|
256
|
-
out.push(...childBlocks);
|
|
257
|
-
appended = true;
|
|
258
|
-
}
|
|
259
|
-
return out;
|
|
260
|
-
}
|
|
261
|
-
function listItemBlocks(item, index, ordered, start, context, theme, keyPrefix) {
|
|
262
|
-
const markerText = ordered ? `${start + index}. ` : "- ";
|
|
263
|
-
const markerCells = textCellWidth(markerText);
|
|
264
|
-
const markerSegment = {
|
|
265
|
-
text: markerText,
|
|
266
|
-
style: theme.listMarker
|
|
267
|
-
};
|
|
268
|
-
const indentSegment = { text: spaces(markerCells) };
|
|
269
|
-
const firstContext = {
|
|
270
|
-
prefixSegments: [...context.prefixSegments, markerSegment],
|
|
271
|
-
continuationPrefixSegments: [...context.continuationPrefixSegments, indentSegment]
|
|
272
|
-
};
|
|
273
|
-
const nestedContext = {
|
|
274
|
-
prefixSegments: [...context.continuationPrefixSegments, indentSegment],
|
|
275
|
-
continuationPrefixSegments: [...context.continuationPrefixSegments, indentSegment]
|
|
276
|
-
};
|
|
277
|
-
if (!item.children.length) return [inlineBlock(`${keyPrefix}-empty`, [], firstContext)];
|
|
278
|
-
const out = [];
|
|
279
|
-
let usedLead = false;
|
|
280
|
-
for (let i = 0; i < item.children.length; i++) {
|
|
281
|
-
var _out2, _childBlocks$2, _out3, _childBlocks$3;
|
|
282
|
-
const child = item.children[i];
|
|
283
|
-
const useLeadContext = !usedLead && (child.type === "paragraph" || child.type === "heading" || child.type === "code_block");
|
|
284
|
-
if (!usedLead && !useLeadContext) {
|
|
285
|
-
out.push(inlineBlock(`${keyPrefix}-marker`, [], firstContext));
|
|
286
|
-
usedLead = true;
|
|
287
|
-
}
|
|
288
|
-
const childBlocks = trimBlockArray(nodeToBlocks(child, useLeadContext && !usedLead ? firstContext : nestedContext, theme, `${keyPrefix}-${i}`));
|
|
289
|
-
if (!childBlocks.length) continue;
|
|
290
|
-
const startsNestedList = child.type === "list" && out.length > 0 && ((_out2 = out[out.length - 1]) === null || _out2 === void 0 ? void 0 : _out2.type) === "inline" && ((_childBlocks$2 = childBlocks[0]) === null || _childBlocks$2 === void 0 ? void 0 : _childBlocks$2.type) === "inline";
|
|
291
|
-
if (out.length && ((_out3 = out[out.length - 1]) === null || _out3 === void 0 ? void 0 : _out3.type) !== "blank" && ((_childBlocks$3 = childBlocks[0]) === null || _childBlocks$3 === void 0 ? void 0 : _childBlocks$3.type) !== "blank" && !startsNestedList) out.push({
|
|
292
|
-
type: "blank",
|
|
293
|
-
key: `${keyPrefix}-${i}-gap`
|
|
294
|
-
});
|
|
295
|
-
out.push(...childBlocks);
|
|
296
|
-
usedLead = true;
|
|
297
|
-
}
|
|
298
|
-
if (!out.length) out.push(inlineBlock(`${keyPrefix}-fallback`, [], firstContext));
|
|
299
|
-
return out;
|
|
300
|
-
}
|
|
301
|
-
function listBlocks(node, context, theme, keyPrefix) {
|
|
302
|
-
const out = [];
|
|
303
|
-
for (let i = 0; i < node.items.length; i++) out.push(...listItemBlocks(node.items[i], i, node.ordered, node.start ?? 1, context, theme, `${keyPrefix}-${i}`));
|
|
304
|
-
return out;
|
|
305
|
-
}
|
|
306
|
-
function nodeToBlocks(node, context, theme, keyPrefix) {
|
|
307
|
-
switch (node.type) {
|
|
308
|
-
case "paragraph":
|
|
309
|
-
if ("children" in node && Array.isArray(node.children)) return [blockFromParagraph(node, keyPrefix, context, theme)];
|
|
310
|
-
break;
|
|
311
|
-
case "heading":
|
|
312
|
-
if ("children" in node && Array.isArray(node.children) && "level" in node) return [blockFromHeading(node, keyPrefix, context, theme)];
|
|
313
|
-
break;
|
|
314
|
-
case "code_block":
|
|
315
|
-
if ("code" in node) return [blockFromCodeBlock(node, keyPrefix, context, theme)];
|
|
316
|
-
break;
|
|
317
|
-
case "thematic_break": return [{
|
|
318
|
-
type: "thematic_break",
|
|
319
|
-
key: keyPrefix,
|
|
320
|
-
char: "─",
|
|
321
|
-
style: theme.thematicBreak,
|
|
322
|
-
prefixSegments: context.prefixSegments
|
|
323
|
-
}];
|
|
324
|
-
case "blockquote": {
|
|
325
|
-
const quoteSegment = {
|
|
326
|
-
text: "│ ",
|
|
327
|
-
style: theme.blockquote
|
|
328
|
-
};
|
|
329
|
-
const quoteContext = {
|
|
330
|
-
prefixSegments: [...context.prefixSegments, quoteSegment],
|
|
331
|
-
continuationPrefixSegments: [...context.continuationPrefixSegments, quoteSegment]
|
|
332
|
-
};
|
|
333
|
-
return childSequenceToBlocks(nodeChildren(node), quoteContext, theme, keyPrefix);
|
|
334
|
-
}
|
|
335
|
-
case "list":
|
|
336
|
-
if ("items" in node && Array.isArray(node.items)) return listBlocks(node, context, theme, keyPrefix);
|
|
337
|
-
break;
|
|
338
|
-
case "inline": return [inlineBlock(keyPrefix, inlineNodeSegments(nodeChildren(node), theme), context)];
|
|
339
|
-
case "html_block":
|
|
340
|
-
if ("content" in node) return [blockFromHtmlBlock(node, keyPrefix, context, theme)];
|
|
341
|
-
break;
|
|
342
|
-
case "text": return [inlineBlock(keyPrefix, inlineNodeSegments([node], theme), context)];
|
|
343
|
-
}
|
|
344
|
-
if (nodeChildren(node).length) return childSequenceToBlocks(nodeChildren(node), context, theme, keyPrefix);
|
|
345
|
-
return [inlineBlock(keyPrefix, inlineNodeSegments([node], theme), context)];
|
|
346
|
-
}
|
|
347
|
-
function markdownAstToBlocks(nodes, theme) {
|
|
348
|
-
const blocks = trimBlockArray(childSequenceToBlocks(nodes, {
|
|
349
|
-
prefixSegments: EMPTY_PREFIX,
|
|
350
|
-
continuationPrefixSegments: EMPTY_PREFIX
|
|
351
|
-
}, theme, "md"));
|
|
352
|
-
return blocks.length ? blocks : [{
|
|
353
|
-
type: "blank",
|
|
354
|
-
key: "md-empty"
|
|
355
|
-
}];
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
//#endregion
|
|
359
|
-
//#region src/vue/markdown/layout.ts
|
|
360
|
-
function toVisualSegment(segment) {
|
|
361
|
-
if (!segment.text) return null;
|
|
362
|
-
const cells = textCellWidth(segment.text);
|
|
363
|
-
if (cells <= 0) return null;
|
|
364
|
-
return {
|
|
365
|
-
text: segment.text,
|
|
366
|
-
style: segment.style,
|
|
367
|
-
cells
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
function segmentsPlainText(segments) {
|
|
371
|
-
return segments.map((segment) => segment.text).join("");
|
|
372
|
-
}
|
|
373
|
-
function segmentsCellWidth(segments) {
|
|
374
|
-
let cells = 0;
|
|
375
|
-
for (const segment of segments) {
|
|
376
|
-
if (segment.hardBreak || !segment.text) continue;
|
|
377
|
-
cells += textCellWidth(segment.text);
|
|
378
|
-
}
|
|
379
|
-
return cells;
|
|
380
|
-
}
|
|
381
|
-
function normalizeInlineSegments(segments) {
|
|
382
|
-
const lines = [[]];
|
|
383
|
-
for (const segment of segments) {
|
|
384
|
-
if (segment.hardBreak) {
|
|
385
|
-
lines.push([]);
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
lines[lines.length - 1].push(segment);
|
|
389
|
-
}
|
|
390
|
-
return lines;
|
|
391
|
-
}
|
|
392
|
-
function clipInlineSegmentsToWidth(segments, width) {
|
|
393
|
-
let remaining = Math.max(0, Math.floor(width));
|
|
394
|
-
if (remaining <= 0) return [];
|
|
395
|
-
const out = [];
|
|
396
|
-
for (const segment of segments) {
|
|
397
|
-
if (segment.hardBreak || !segment.text || remaining <= 0) continue;
|
|
398
|
-
const piece = sliceByCellsRange(segment.text, 0, remaining);
|
|
399
|
-
const cells = textCellWidth(piece);
|
|
400
|
-
if (!piece || cells <= 0) continue;
|
|
401
|
-
out.push(segment.style ? {
|
|
402
|
-
text: piece,
|
|
403
|
-
style: segment.style
|
|
404
|
-
} : { text: piece });
|
|
405
|
-
remaining -= cells;
|
|
406
|
-
}
|
|
407
|
-
return out;
|
|
408
|
-
}
|
|
409
|
-
function wrapLineSegments(source, prefixSegments, continuationPrefixSegments, width) {
|
|
410
|
-
const rows = [];
|
|
411
|
-
const prefixCells = segmentsCellWidth(prefixSegments);
|
|
412
|
-
const continuationPrefixCells = segmentsCellWidth(continuationPrefixSegments);
|
|
413
|
-
const firstPrefix = prefixCells >= width ? clipInlineSegmentsToWidth(prefixSegments, width) : prefixSegments;
|
|
414
|
-
const firstPrefixCells = segmentsCellWidth(firstPrefix);
|
|
415
|
-
const continuationPrefix = continuationPrefixCells >= width ? clipInlineSegmentsToWidth(continuationPrefixSegments, Math.max(0, width - 1)) : continuationPrefixSegments;
|
|
416
|
-
const trimmedContinuationPrefixCells = segmentsCellWidth(continuationPrefix);
|
|
417
|
-
const maxFirst = Math.max(0, width - firstPrefixCells);
|
|
418
|
-
const maxNext = Math.max(0, width - trimmedContinuationPrefixCells);
|
|
419
|
-
const openRow = (useContinuation) => {
|
|
420
|
-
const prefix = useContinuation ? continuationPrefix : firstPrefix;
|
|
421
|
-
const renderedPrefix = prefix.map(toVisualSegment).filter(Boolean);
|
|
422
|
-
return {
|
|
423
|
-
useContinuation,
|
|
424
|
-
segments: [...renderedPrefix],
|
|
425
|
-
remaining: useContinuation ? maxNext : maxFirst
|
|
426
|
-
};
|
|
427
|
-
};
|
|
428
|
-
const openDegradedRow = () => ({
|
|
429
|
-
useContinuation: true,
|
|
430
|
-
segments: [],
|
|
431
|
-
remaining: width
|
|
432
|
-
});
|
|
433
|
-
let row = openRow(false);
|
|
434
|
-
if (!source.length) {
|
|
435
|
-
rows.push(row.segments);
|
|
436
|
-
return rows;
|
|
437
|
-
}
|
|
438
|
-
const pushRow = () => {
|
|
439
|
-
rows.push(row.segments);
|
|
440
|
-
row = openRow(true);
|
|
441
|
-
};
|
|
442
|
-
const prefixLengthForRow = () => row.useContinuation ? continuationPrefix.length : firstPrefix.length;
|
|
443
|
-
const rowHasBody = () => row.segments.length > prefixLengthForRow();
|
|
444
|
-
for (const segment of source) {
|
|
445
|
-
let aborted = false;
|
|
446
|
-
forEachTextCellSegment(segment.text, (piece) => {
|
|
447
|
-
while (true) {
|
|
448
|
-
if (row.remaining <= 0) {
|
|
449
|
-
pushRow();
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
if (piece.cells > row.remaining) {
|
|
453
|
-
if (rowHasBody()) {
|
|
454
|
-
pushRow();
|
|
455
|
-
continue;
|
|
456
|
-
}
|
|
457
|
-
if (!row.useContinuation) {
|
|
458
|
-
rows.push(row.segments);
|
|
459
|
-
row = openDegradedRow();
|
|
460
|
-
continue;
|
|
461
|
-
}
|
|
462
|
-
if (piece.cells <= width) {
|
|
463
|
-
row = openDegradedRow();
|
|
464
|
-
continue;
|
|
465
|
-
}
|
|
466
|
-
aborted = true;
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
row.segments.push({
|
|
470
|
-
text: piece.text,
|
|
471
|
-
style: segment.style,
|
|
472
|
-
cells: piece.cells
|
|
473
|
-
});
|
|
474
|
-
row.remaining -= piece.cells;
|
|
475
|
-
return void 0;
|
|
476
|
-
}
|
|
477
|
-
});
|
|
478
|
-
if (aborted) continue;
|
|
479
|
-
}
|
|
480
|
-
rows.push(row.segments);
|
|
481
|
-
return rows;
|
|
482
|
-
}
|
|
483
|
-
function inlineBlockRows(block, width) {
|
|
484
|
-
const rows = [];
|
|
485
|
-
const lines = normalizeInlineSegments(block.segments);
|
|
486
|
-
const prefix = block.prefixSegments ?? [];
|
|
487
|
-
const continuationPrefix = block.continuationPrefixSegments ?? prefix;
|
|
488
|
-
let rowInBlock = 0;
|
|
489
|
-
for (const line of lines) {
|
|
490
|
-
const wrapped = wrapLineSegments(line, prefix, continuationPrefix, width);
|
|
491
|
-
for (const visualSegments of wrapped) {
|
|
492
|
-
rows.push({
|
|
493
|
-
key: `${block.key}:${rowInBlock}`,
|
|
494
|
-
blockKey: block.key,
|
|
495
|
-
rowInBlock,
|
|
496
|
-
plainText: segmentsPlainText(visualSegments),
|
|
497
|
-
segments: visualSegments
|
|
498
|
-
});
|
|
499
|
-
rowInBlock++;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
return rows.length ? rows : [{
|
|
503
|
-
key: `${block.key}:0`,
|
|
504
|
-
blockKey: block.key,
|
|
505
|
-
rowInBlock: 0,
|
|
506
|
-
plainText: "",
|
|
507
|
-
segments: prefix.map(toVisualSegment).filter(Boolean)
|
|
508
|
-
}];
|
|
509
|
-
}
|
|
510
|
-
function codeBlockRows(block, width) {
|
|
511
|
-
const rows = [];
|
|
512
|
-
const prefix = block.prefixSegments ?? [];
|
|
513
|
-
const continuationPrefix = block.continuationPrefixSegments ?? prefix;
|
|
514
|
-
const lineSegments = block.lines.length ? block.lines : [""];
|
|
515
|
-
let rowInBlock = 0;
|
|
516
|
-
for (const line of lineSegments) {
|
|
517
|
-
const sourceSegments = [{
|
|
518
|
-
text: line,
|
|
519
|
-
style: block.style
|
|
520
|
-
}];
|
|
521
|
-
const wrapped = wrapLineSegments(sourceSegments, prefix, continuationPrefix, width);
|
|
522
|
-
for (const visualSegments of wrapped) {
|
|
523
|
-
rows.push({
|
|
524
|
-
key: `${block.key}:${rowInBlock}`,
|
|
525
|
-
blockKey: block.key,
|
|
526
|
-
rowInBlock,
|
|
527
|
-
plainText: segmentsPlainText(visualSegments),
|
|
528
|
-
segments: visualSegments
|
|
529
|
-
});
|
|
530
|
-
rowInBlock++;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
return rows;
|
|
534
|
-
}
|
|
535
|
-
function thematicBreakRows(block, width) {
|
|
536
|
-
const prefix = (block.prefixSegments ?? []).map(toVisualSegment).filter(Boolean);
|
|
537
|
-
const prefixCells = prefix.reduce((sum, segment) => sum + segment.cells, 0);
|
|
538
|
-
const fill = Math.max(0, width - prefixCells);
|
|
539
|
-
const bar = fill > 0 ? [{
|
|
540
|
-
text: repeatChar(block.char ?? "─", fill),
|
|
541
|
-
style: block.style,
|
|
542
|
-
cells: fill
|
|
543
|
-
}] : [];
|
|
544
|
-
return [{
|
|
545
|
-
key: `${block.key}:0`,
|
|
546
|
-
blockKey: block.key,
|
|
547
|
-
rowInBlock: 0,
|
|
548
|
-
plainText: segmentsPlainText([...prefix, ...bar]),
|
|
549
|
-
segments: [...prefix, ...bar]
|
|
550
|
-
}];
|
|
551
|
-
}
|
|
552
|
-
function styleSignature(style) {
|
|
553
|
-
if (!style) return "";
|
|
554
|
-
return [
|
|
555
|
-
style.fg ?? "",
|
|
556
|
-
style.bg ?? "",
|
|
557
|
-
style.bold ? "1" : "0",
|
|
558
|
-
style.dim ? "1" : "0",
|
|
559
|
-
style.italic ? "1" : "0",
|
|
560
|
-
style.underline ? "1" : "0",
|
|
561
|
-
style.inverse ? "1" : "0",
|
|
562
|
-
style.href ?? ""
|
|
563
|
-
].join("");
|
|
564
|
-
}
|
|
565
|
-
function inlineSegmentSignature(segment) {
|
|
566
|
-
return [
|
|
567
|
-
segment.text,
|
|
568
|
-
segment.hardBreak ? "1" : "0",
|
|
569
|
-
styleSignature(segment.style)
|
|
570
|
-
].join("");
|
|
571
|
-
}
|
|
572
|
-
function inlineSegmentsSignature(segments) {
|
|
573
|
-
return (segments ?? []).map(inlineSegmentSignature).join("");
|
|
574
|
-
}
|
|
575
|
-
function blockLayoutSignature(block) {
|
|
576
|
-
switch (block.type) {
|
|
577
|
-
case "inline": return [
|
|
578
|
-
block.type,
|
|
579
|
-
inlineSegmentsSignature(block.segments),
|
|
580
|
-
inlineSegmentsSignature(block.prefixSegments),
|
|
581
|
-
inlineSegmentsSignature(block.continuationPrefixSegments)
|
|
582
|
-
].join("");
|
|
583
|
-
case "code_block": return [
|
|
584
|
-
block.type,
|
|
585
|
-
block.lines.join(""),
|
|
586
|
-
styleSignature(block.style),
|
|
587
|
-
inlineSegmentsSignature(block.prefixSegments),
|
|
588
|
-
inlineSegmentsSignature(block.continuationPrefixSegments)
|
|
589
|
-
].join("");
|
|
590
|
-
case "thematic_break": return [
|
|
591
|
-
block.type,
|
|
592
|
-
block.char ?? "",
|
|
593
|
-
styleSignature(block.style),
|
|
594
|
-
inlineSegmentsSignature(block.prefixSegments)
|
|
595
|
-
].join("");
|
|
596
|
-
case "blank": return block.type;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
function layoutMarkdownBlock(block, width) {
|
|
600
|
-
switch (block.type) {
|
|
601
|
-
case "inline": return inlineBlockRows(block, width);
|
|
602
|
-
case "code_block": return codeBlockRows(block, width);
|
|
603
|
-
case "thematic_break": return thematicBreakRows(block, width);
|
|
604
|
-
case "blank": return [{
|
|
605
|
-
key: `${block.key}:0`,
|
|
606
|
-
blockKey: block.key,
|
|
607
|
-
rowInBlock: 0,
|
|
608
|
-
plainText: "",
|
|
609
|
-
segments: []
|
|
610
|
-
}];
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
function layoutMarkdownBlocksCached(blocks, width, previous) {
|
|
614
|
-
const normalizedWidth = Math.max(0, Math.floor(width));
|
|
615
|
-
if (normalizedWidth <= 0) return {
|
|
616
|
-
rows: [],
|
|
617
|
-
cache: {
|
|
618
|
-
width: normalizedWidth,
|
|
619
|
-
entries: new Map()
|
|
620
|
-
}
|
|
621
|
-
};
|
|
622
|
-
const rows = [];
|
|
623
|
-
const entries = new Map();
|
|
624
|
-
const previousEntries = (previous === null || previous === void 0 ? void 0 : previous.width) === normalizedWidth ? previous.entries : void 0;
|
|
625
|
-
for (let index = 0; index < blocks.length; index++) {
|
|
626
|
-
const block = blocks[index];
|
|
627
|
-
const cacheKey = `${index}\u0000${block.key}`;
|
|
628
|
-
const signature = blockLayoutSignature(block);
|
|
629
|
-
const cached = previousEntries === null || previousEntries === void 0 ? void 0 : previousEntries.get(cacheKey);
|
|
630
|
-
const blockRows = (cached === null || cached === void 0 ? void 0 : cached.signature) === signature ? cached.rows : layoutMarkdownBlock(block, normalizedWidth);
|
|
631
|
-
if (blockRows.length) {
|
|
632
|
-
rows.push(...blockRows);
|
|
633
|
-
entries.set(cacheKey, {
|
|
634
|
-
signature,
|
|
635
|
-
rows: blockRows
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
if (!rows.length) {
|
|
640
|
-
const emptyRows = [{
|
|
641
|
-
key: "md-empty:0",
|
|
642
|
-
blockKey: "md-empty",
|
|
643
|
-
rowInBlock: 0,
|
|
644
|
-
plainText: "",
|
|
645
|
-
segments: []
|
|
646
|
-
}];
|
|
647
|
-
entries.set("0\0md-empty", {
|
|
648
|
-
signature: "empty",
|
|
649
|
-
rows: emptyRows
|
|
650
|
-
});
|
|
651
|
-
rows.push(...emptyRows);
|
|
652
|
-
}
|
|
653
|
-
return {
|
|
654
|
-
rows,
|
|
655
|
-
cache: {
|
|
656
|
-
width: normalizedWidth,
|
|
657
|
-
entries
|
|
658
|
-
}
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
function layoutMarkdownBlocks(blocks, width) {
|
|
662
|
-
return layoutMarkdownBlocksCached(blocks, width).rows;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
//#endregion
|
|
666
|
-
//#region src/vue/markdown/theme.ts
|
|
667
|
-
function freezeStyle(style) {
|
|
668
|
-
return Object.freeze(style);
|
|
669
|
-
}
|
|
670
|
-
function mergeFrozenStyle(base, overlay) {
|
|
671
|
-
if (!overlay) return base;
|
|
672
|
-
return freezeStyle({
|
|
673
|
-
...base,
|
|
674
|
-
...overlay
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
const DEFAULT_HEADING = Object.freeze([
|
|
678
|
-
freezeStyle({
|
|
679
|
-
bold: true,
|
|
680
|
-
fg: "cyanBright"
|
|
681
|
-
}),
|
|
682
|
-
freezeStyle({
|
|
683
|
-
bold: true,
|
|
684
|
-
fg: "cyanBright"
|
|
685
|
-
}),
|
|
686
|
-
freezeStyle({
|
|
687
|
-
bold: true,
|
|
688
|
-
fg: "blueBright"
|
|
689
|
-
}),
|
|
690
|
-
freezeStyle({
|
|
691
|
-
bold: true,
|
|
692
|
-
fg: "blueBright"
|
|
693
|
-
}),
|
|
694
|
-
freezeStyle({ bold: true }),
|
|
695
|
-
freezeStyle({ bold: true })
|
|
696
|
-
]);
|
|
697
|
-
const DEFAULT_TUI_MARKDOWN_THEME = Object.freeze({
|
|
698
|
-
heading: DEFAULT_HEADING,
|
|
699
|
-
strong: freezeStyle({ bold: true }),
|
|
700
|
-
emphasis: freezeStyle({ italic: true }),
|
|
701
|
-
strikethrough: freezeStyle({ dim: true }),
|
|
702
|
-
inlineCode: freezeStyle({ fg: "yellowBright" }),
|
|
703
|
-
link: freezeStyle({
|
|
704
|
-
fg: "blueBright",
|
|
705
|
-
underline: true
|
|
706
|
-
}),
|
|
707
|
-
blockquote: freezeStyle({ dim: true }),
|
|
708
|
-
listMarker: freezeStyle({
|
|
709
|
-
fg: "cyanBright",
|
|
710
|
-
bold: true
|
|
711
|
-
}),
|
|
712
|
-
codeBlock: freezeStyle({ fg: "yellowBright" }),
|
|
713
|
-
thematicBreak: freezeStyle({ dim: true }),
|
|
714
|
-
html: freezeStyle({ dim: true })
|
|
715
|
-
});
|
|
716
|
-
function stableSerialize(value) {
|
|
717
|
-
if (value == null) return "null";
|
|
718
|
-
if (typeof value !== "object") return JSON.stringify(value);
|
|
719
|
-
if (Array.isArray(value)) return `[${value.map((item) => stableSerialize(item)).join(",")}]`;
|
|
720
|
-
const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
|
|
721
|
-
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${stableSerialize(item)}`).join(",")}}`;
|
|
722
|
-
}
|
|
723
|
-
function markdownThemeSignature(overrides) {
|
|
724
|
-
return stableSerialize(overrides ?? null);
|
|
725
|
-
}
|
|
726
|
-
function resolveTuiMarkdownTheme(overrides) {
|
|
727
|
-
if (!overrides) return DEFAULT_TUI_MARKDOWN_THEME;
|
|
728
|
-
const heading = DEFAULT_TUI_MARKDOWN_THEME.heading.map((style, index) => {
|
|
729
|
-
var _overrides$heading;
|
|
730
|
-
return mergeFrozenStyle(style, (_overrides$heading = overrides.heading) === null || _overrides$heading === void 0 ? void 0 : _overrides$heading[index]);
|
|
731
|
-
});
|
|
732
|
-
return Object.freeze({
|
|
733
|
-
heading: Object.freeze(heading),
|
|
734
|
-
strong: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.strong, overrides.strong),
|
|
735
|
-
emphasis: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.emphasis, overrides.emphasis),
|
|
736
|
-
strikethrough: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.strikethrough, overrides.strikethrough),
|
|
737
|
-
inlineCode: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.inlineCode, overrides.inlineCode),
|
|
738
|
-
link: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.link, overrides.link),
|
|
739
|
-
blockquote: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.blockquote, overrides.blockquote),
|
|
740
|
-
listMarker: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.listMarker, overrides.listMarker),
|
|
741
|
-
codeBlock: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.codeBlock, overrides.codeBlock),
|
|
742
|
-
thematicBreak: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.thematicBreak, overrides.thematicBreak),
|
|
743
|
-
html: mergeFrozenStyle(DEFAULT_TUI_MARKDOWN_THEME.html, overrides.html)
|
|
744
|
-
});
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
//#endregion
|
|
748
|
-
//#region src/vue/markdown/document.ts
|
|
749
|
-
/**
|
|
750
|
-
* This helper always builds visual rows from the full source string. Components
|
|
751
|
-
* that need streaming reuse can call buildMarkdownBlocks and cache block layout.
|
|
752
|
-
*/
|
|
753
|
-
function buildMarkdownBlocks(content, parser, options) {
|
|
754
|
-
const theme = resolveTuiMarkdownTheme(options === null || options === void 0 ? void 0 : options.theme);
|
|
755
|
-
try {
|
|
756
|
-
const nodes = parser.parse(content, (options === null || options === void 0 ? void 0 : options.final) ?? true);
|
|
757
|
-
const blocks = markdownAstToBlocks(nodes, theme);
|
|
758
|
-
return {
|
|
759
|
-
nodes,
|
|
760
|
-
blocks
|
|
761
|
-
};
|
|
762
|
-
} catch (error) {
|
|
763
|
-
console.warn("[vue-tui] Markdown parse failed; falling back to plain text rendering.", error);
|
|
764
|
-
return {
|
|
765
|
-
nodes: [],
|
|
766
|
-
blocks: plainTextFallbackBlocks(content)
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
function buildMarkdownVisualRows(content, width, parser, options) {
|
|
771
|
-
const { blocks } = buildMarkdownBlocks(content, parser, options);
|
|
772
|
-
return layoutMarkdownBlocks(blocks, width);
|
|
773
|
-
}
|
|
774
|
-
function plainTextFallbackBlocks(content) {
|
|
775
|
-
const normalized = sanitizeTextBlock(content);
|
|
776
|
-
const lines = normalized.split("\n");
|
|
777
|
-
const blocks = [];
|
|
778
|
-
for (let index = 0; index < lines.length; index++) {
|
|
779
|
-
const line = sanitizeInlineText(lines[index] ?? "");
|
|
780
|
-
if (!line) {
|
|
781
|
-
blocks.push({
|
|
782
|
-
type: "blank",
|
|
783
|
-
key: `md-fallback:${index}`
|
|
784
|
-
});
|
|
785
|
-
continue;
|
|
786
|
-
}
|
|
787
|
-
blocks.push({
|
|
788
|
-
type: "inline",
|
|
789
|
-
key: `md-fallback:${index}`,
|
|
790
|
-
segments: [{ text: line }]
|
|
791
|
-
});
|
|
792
|
-
}
|
|
793
|
-
return blocks.length ? blocks : [{
|
|
794
|
-
type: "blank",
|
|
795
|
-
key: "md-fallback:0"
|
|
796
|
-
}];
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
//#endregion
|
|
800
|
-
//#region src/vue/markdown/render.ts
|
|
801
|
-
const mergedStyleCache = new WeakMap();
|
|
802
|
-
function mergeStyle(base, overlay) {
|
|
803
|
-
if (!overlay) return base;
|
|
804
|
-
let bucket = mergedStyleCache.get(base);
|
|
805
|
-
if (!bucket) {
|
|
806
|
-
bucket = new WeakMap();
|
|
807
|
-
mergedStyleCache.set(base, bucket);
|
|
808
|
-
}
|
|
809
|
-
const cached = bucket.get(overlay);
|
|
810
|
-
if (cached) return cached;
|
|
811
|
-
const merged = Object.freeze({
|
|
812
|
-
...base,
|
|
813
|
-
...overlay
|
|
814
|
-
});
|
|
815
|
-
bucket.set(overlay, merged);
|
|
816
|
-
return merged;
|
|
817
|
-
}
|
|
818
|
-
function paintMarkdownVisualRow(terminal, row, options) {
|
|
819
|
-
const clipStart = Math.max(0, Math.floor(options.clipStart ?? 0));
|
|
820
|
-
const clipEnd = clipStart + options.w;
|
|
821
|
-
if (!row) {
|
|
822
|
-
if (options.clear !== false) terminal.write(spaces(options.w), {
|
|
823
|
-
x: options.x,
|
|
824
|
-
y: options.y,
|
|
825
|
-
style: options.baseStyle
|
|
826
|
-
});
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
|
-
let logicalX = 0;
|
|
830
|
-
let used = 0;
|
|
831
|
-
for (const segment of row.segments) {
|
|
832
|
-
if (used >= options.w || !segment.text) {
|
|
833
|
-
logicalX += segment.cells;
|
|
834
|
-
continue;
|
|
835
|
-
}
|
|
836
|
-
const segmentStart = logicalX;
|
|
837
|
-
const segmentEnd = logicalX + segment.cells;
|
|
838
|
-
logicalX += segment.cells;
|
|
839
|
-
if (segmentEnd <= clipStart || segmentStart >= clipEnd) continue;
|
|
840
|
-
const segmentStyle = mergeStyle(options.baseStyle, segment.style);
|
|
841
|
-
let pieceStart = segmentStart;
|
|
842
|
-
forEachTextCellSegment(segment.text, (piece) => {
|
|
843
|
-
if (used >= options.w) return false;
|
|
844
|
-
const pieceEnd = pieceStart + piece.cells;
|
|
845
|
-
const visibleStart = Math.max(pieceStart, clipStart);
|
|
846
|
-
const visibleEnd = Math.min(pieceEnd, clipEnd);
|
|
847
|
-
pieceStart = pieceEnd;
|
|
848
|
-
if (visibleEnd <= visibleStart) return;
|
|
849
|
-
const expectedUsed = visibleStart - clipStart;
|
|
850
|
-
if (expectedUsed > used) {
|
|
851
|
-
const pad$1 = Math.min(expectedUsed - used, options.w - used);
|
|
852
|
-
terminal.write(spaces(pad$1), {
|
|
853
|
-
x: options.x + used,
|
|
854
|
-
y: options.y,
|
|
855
|
-
style: options.baseStyle
|
|
856
|
-
});
|
|
857
|
-
used += pad$1;
|
|
858
|
-
}
|
|
859
|
-
if (visibleStart === pieceStart - piece.cells && visibleEnd === pieceEnd) {
|
|
860
|
-
terminal.write(piece.text, {
|
|
861
|
-
x: options.x + used,
|
|
862
|
-
y: options.y,
|
|
863
|
-
style: segmentStyle
|
|
864
|
-
});
|
|
865
|
-
used += piece.cells;
|
|
866
|
-
return;
|
|
867
|
-
}
|
|
868
|
-
const pad = Math.min(visibleEnd - visibleStart, options.w - used);
|
|
869
|
-
if (pad > 0) {
|
|
870
|
-
terminal.write(spaces(pad), {
|
|
871
|
-
x: options.x + used,
|
|
872
|
-
y: options.y,
|
|
873
|
-
style: segmentStyle
|
|
874
|
-
});
|
|
875
|
-
used += pad;
|
|
876
|
-
}
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
if (used < options.w && options.clear !== false) terminal.write(spaces(options.w - used), {
|
|
880
|
-
x: options.x + used,
|
|
881
|
-
y: options.y,
|
|
882
|
-
style: options.baseStyle
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
//#endregion
|
|
887
7
|
//#region src/vue/components/TMarkdownText.ts
|
|
888
8
|
const TMarkdownText = defineComponent({
|
|
889
9
|
name: "TMarkdownText",
|
|
@@ -939,7 +59,7 @@ const TMarkdownText = defineComponent({
|
|
|
939
59
|
},
|
|
940
60
|
setup(props) {
|
|
941
61
|
const instance = getCurrentInstance();
|
|
942
|
-
const { terminal, defaultStyle, scheduler } = useTerminal();
|
|
62
|
+
const { terminal, defaultStyle, scheduler, widthProvider } = useTerminal();
|
|
943
63
|
const layout = useLayout();
|
|
944
64
|
const { visible, rootProps } = useVisibility();
|
|
945
65
|
const rows = shallowRef(markRaw([]));
|
|
@@ -958,10 +78,10 @@ const TMarkdownText = defineComponent({
|
|
|
958
78
|
}));
|
|
959
79
|
});
|
|
960
80
|
function rebuildRows() {
|
|
961
|
-
rows.value = markRaw(buildMarkdownVisualRows(props.content, props.w, parser.value, {
|
|
81
|
+
rows.value = markRaw(withTextWidthProvider(widthProvider, () => buildMarkdownVisualRows(props.content, props.w, parser.value, {
|
|
962
82
|
final: props.final,
|
|
963
83
|
theme: props.theme
|
|
964
|
-
}));
|
|
84
|
+
})));
|
|
965
85
|
documentVersion.value++;
|
|
966
86
|
}
|
|
967
87
|
function scheduleRebuild() {
|
|
@@ -972,7 +92,7 @@ const TMarkdownText = defineComponent({
|
|
|
972
92
|
return;
|
|
973
93
|
}
|
|
974
94
|
scheduler.queueFrameTask({
|
|
975
|
-
id: `TMarkdownText:${
|
|
95
|
+
id: `TMarkdownText:${instance?.uid ?? "unknown"}:markdown`,
|
|
976
96
|
reason: props.streaming ? "stream" : "data",
|
|
977
97
|
priority: props.streaming ? "low" : "normal",
|
|
978
98
|
sync: false,
|
|
@@ -1033,549 +153,38 @@ const TMarkdownText = defineComponent({
|
|
|
1033
153
|
defaultStyle.value
|
|
1034
154
|
],
|
|
1035
155
|
paint: (dirtyRows) => {
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
return () => h("span", rootProps);
|
|
1064
|
-
}
|
|
1065
|
-
});
|
|
1066
|
-
|
|
1067
|
-
//#endregion
|
|
1068
|
-
//#region src/vue/components/TVirtualMarkdown.ts
|
|
1069
|
-
function clamp(n, min, max) {
|
|
1070
|
-
return Math.max(min, Math.min(max, n));
|
|
1071
|
-
}
|
|
1072
|
-
function markdownStyleSignature(style) {
|
|
1073
|
-
if (!style) return "";
|
|
1074
|
-
return [
|
|
1075
|
-
style.fg ?? "",
|
|
1076
|
-
style.bg ?? "",
|
|
1077
|
-
style.bold ? "1" : "0",
|
|
1078
|
-
style.dim ? "1" : "0",
|
|
1079
|
-
style.italic ? "1" : "0",
|
|
1080
|
-
style.underline ? "1" : "0",
|
|
1081
|
-
style.inverse ? "1" : "0",
|
|
1082
|
-
style.href ?? ""
|
|
1083
|
-
].join("");
|
|
1084
|
-
}
|
|
1085
|
-
function markdownRowSignature(row) {
|
|
1086
|
-
if (!row) return "";
|
|
1087
|
-
return [
|
|
1088
|
-
row.key,
|
|
1089
|
-
row.plainText,
|
|
1090
|
-
row.segments.map((segment) => `${segment.text}\u0001${segment.cells}\u0001${markdownStyleSignature(segment.style)}`).join("")
|
|
1091
|
-
].join("");
|
|
1092
|
-
}
|
|
1093
|
-
function getWheelScrollInput(e) {
|
|
1094
|
-
const deltaY = Number(e.deltaY ?? 0);
|
|
1095
|
-
const deltaMode = typeof e.deltaMode === "number" ? e.deltaMode : void 0;
|
|
1096
|
-
if (Number.isInteger(deltaY) && deltaY !== 0 && Math.abs(deltaY) >= 100 && Math.abs(deltaY) % 100 === 0 && deltaMode == null) return {
|
|
1097
|
-
deltaY: deltaY / 100,
|
|
1098
|
-
mode: "line"
|
|
1099
|
-
};
|
|
1100
|
-
if (deltaMode === 1) return {
|
|
1101
|
-
deltaY,
|
|
1102
|
-
mode: "line"
|
|
1103
|
-
};
|
|
1104
|
-
if (deltaMode === 0) return {
|
|
1105
|
-
deltaY,
|
|
1106
|
-
mode: "pixel"
|
|
1107
|
-
};
|
|
1108
|
-
return {
|
|
1109
|
-
deltaY,
|
|
1110
|
-
mode: "auto"
|
|
1111
|
-
};
|
|
1112
|
-
}
|
|
1113
|
-
const TVirtualMarkdown = defineComponent({
|
|
1114
|
-
name: "TVirtualMarkdown",
|
|
1115
|
-
props: {
|
|
1116
|
-
x: {
|
|
1117
|
-
type: Number,
|
|
1118
|
-
required: true
|
|
1119
|
-
},
|
|
1120
|
-
y: {
|
|
1121
|
-
type: Number,
|
|
1122
|
-
required: true
|
|
1123
|
-
},
|
|
1124
|
-
w: {
|
|
1125
|
-
type: Number,
|
|
1126
|
-
required: true
|
|
1127
|
-
},
|
|
1128
|
-
h: {
|
|
1129
|
-
type: Number,
|
|
1130
|
-
required: true
|
|
1131
|
-
},
|
|
1132
|
-
zIndex: {
|
|
1133
|
-
type: Number,
|
|
1134
|
-
default: 0
|
|
1135
|
-
},
|
|
1136
|
-
content: {
|
|
1137
|
-
type: String,
|
|
1138
|
-
default: ""
|
|
1139
|
-
},
|
|
1140
|
-
blocks: {
|
|
1141
|
-
type: Array,
|
|
1142
|
-
default: void 0
|
|
1143
|
-
},
|
|
1144
|
-
scrollTop: {
|
|
1145
|
-
type: Number,
|
|
1146
|
-
default: 0
|
|
1147
|
-
},
|
|
1148
|
-
style: {
|
|
1149
|
-
type: Object,
|
|
1150
|
-
default: void 0
|
|
1151
|
-
},
|
|
1152
|
-
final: {
|
|
1153
|
-
type: Boolean,
|
|
1154
|
-
default: true
|
|
1155
|
-
},
|
|
1156
|
-
streaming: {
|
|
1157
|
-
type: Boolean,
|
|
1158
|
-
default: false
|
|
1159
|
-
},
|
|
1160
|
-
autoFocus: {
|
|
1161
|
-
type: Boolean,
|
|
1162
|
-
default: false
|
|
1163
|
-
},
|
|
1164
|
-
selectable: {
|
|
1165
|
-
type: Boolean,
|
|
1166
|
-
default: true
|
|
1167
|
-
},
|
|
1168
|
-
customHtmlTags: {
|
|
1169
|
-
type: Array,
|
|
1170
|
-
default: void 0
|
|
1171
|
-
},
|
|
1172
|
-
theme: {
|
|
1173
|
-
type: Object,
|
|
1174
|
-
default: void 0
|
|
1175
|
-
}
|
|
1176
|
-
},
|
|
1177
|
-
emits: [
|
|
1178
|
-
"update:scrollTop",
|
|
1179
|
-
"scroll",
|
|
1180
|
-
"focus",
|
|
1181
|
-
"blur",
|
|
1182
|
-
"keydown"
|
|
1183
|
-
],
|
|
1184
|
-
setup(props, { emit }) {
|
|
1185
|
-
const instance = getCurrentInstance();
|
|
1186
|
-
const { terminal, defaultStyle, events, scheduler } = useTerminal();
|
|
1187
|
-
const layout = useLayout();
|
|
1188
|
-
const { visible, rootProps } = useVisibility();
|
|
1189
|
-
const parentEventZ = inject(EventZIndexContextKey, computed(() => 0));
|
|
1190
|
-
const eventZ = computed(() => (parentEventZ.value ?? 0) + (props.zIndex ?? 0));
|
|
1191
|
-
const internalScrollTop = ref(0);
|
|
1192
|
-
const documentVersion = ref(0);
|
|
1193
|
-
const rows = shallowRef(markRaw([]));
|
|
1194
|
-
const wheelState = createWheelScrollState();
|
|
1195
|
-
let builtOnce = false;
|
|
1196
|
-
let rebuildVersion = 0;
|
|
1197
|
-
let layoutCache;
|
|
1198
|
-
let alive = true;
|
|
1199
|
-
const parser = shallowRef(markRaw(createTuiMarkdownParser({
|
|
1200
|
-
streaming: props.streaming,
|
|
1201
|
-
customHtmlTags: props.customHtmlTags
|
|
1202
|
-
})));
|
|
1203
|
-
watch(() => `${props.streaming ? 1 : 0}:${(props.customHtmlTags ?? []).join("\0")}`, () => {
|
|
1204
|
-
parser.value = markRaw(createTuiMarkdownParser({
|
|
1205
|
-
streaming: props.streaming,
|
|
1206
|
-
customHtmlTags: props.customHtmlTags
|
|
1207
|
-
}));
|
|
1208
|
-
});
|
|
1209
|
-
function rebuildRows() {
|
|
1210
|
-
const prevScrollTop = internalScrollTop.value;
|
|
1211
|
-
const prevVisibleRows = visibleRowSignatures(rows.value, prevScrollTop);
|
|
1212
|
-
const blocks = props.blocks ?? buildMarkdownBlocks(props.content, parser.value, {
|
|
1213
|
-
final: props.final,
|
|
1214
|
-
theme: props.theme
|
|
1215
|
-
}).blocks;
|
|
1216
|
-
const nextLayout = layoutMarkdownBlocksCached(blocks, props.w, layoutCache);
|
|
1217
|
-
layoutCache = markRaw(nextLayout.cache);
|
|
1218
|
-
const nextRows = nextLayout.rows;
|
|
1219
|
-
rows.value = markRaw(nextRows);
|
|
1220
|
-
reconcileScrollTop();
|
|
1221
|
-
const nextScrollTop = internalScrollTop.value;
|
|
1222
|
-
const nextVisibleRows = visibleRowSignatures(nextRows, nextScrollTop);
|
|
1223
|
-
const visibleChanged = prevVisibleRows.length !== nextVisibleRows.length || prevVisibleRows.some((row, index) => row !== nextVisibleRows[index]);
|
|
1224
|
-
if (!builtOnce || prevScrollTop !== nextScrollTop || visibleChanged) documentVersion.value++;
|
|
1225
|
-
}
|
|
1226
|
-
function scheduleRebuild() {
|
|
1227
|
-
const currentVersion = ++rebuildVersion;
|
|
1228
|
-
if (!builtOnce || !props.streaming) {
|
|
1229
|
-
builtOnce = true;
|
|
1230
|
-
rebuildRows();
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1233
|
-
scheduler.queueFrameTask({
|
|
1234
|
-
id: `TVirtualMarkdown:${(instance === null || instance === void 0 ? void 0 : instance.uid) ?? "unknown"}:markdown`,
|
|
1235
|
-
reason: props.streaming ? "stream" : "data",
|
|
1236
|
-
priority: props.streaming ? "low" : "normal",
|
|
1237
|
-
sync: false,
|
|
1238
|
-
run: () => {
|
|
1239
|
-
if (!alive) return;
|
|
1240
|
-
if (currentVersion !== rebuildVersion) return;
|
|
1241
|
-
rebuildRows();
|
|
1242
|
-
}
|
|
1243
|
-
});
|
|
1244
|
-
}
|
|
1245
|
-
const fullRect = computed(() => translateRect({
|
|
1246
|
-
x: props.x,
|
|
1247
|
-
y: props.y,
|
|
1248
|
-
w: props.w,
|
|
1249
|
-
h: props.h
|
|
1250
|
-
}, layout.originX, layout.originY));
|
|
1251
|
-
const absRect = computed(() => {
|
|
1252
|
-
const translated = fullRect.value;
|
|
1253
|
-
if (!layout.clipRect) return translated;
|
|
1254
|
-
return intersectRect(translated, layout.clipRect) ?? {
|
|
1255
|
-
x: 0,
|
|
1256
|
-
y: 0,
|
|
1257
|
-
w: 0,
|
|
1258
|
-
h: 0
|
|
1259
|
-
};
|
|
1260
|
-
});
|
|
1261
|
-
function normalizedRect() {
|
|
1262
|
-
return normalizeCellRect(absRect.value);
|
|
1263
|
-
}
|
|
1264
|
-
function normalizedFullRect() {
|
|
1265
|
-
return normalizeCellRect(fullRect.value);
|
|
1266
|
-
}
|
|
1267
|
-
function clipOffsets() {
|
|
1268
|
-
const full = normalizedFullRect();
|
|
1269
|
-
const clip = normalizedRect();
|
|
1270
|
-
return {
|
|
1271
|
-
x: Math.max(0, clip.x - full.x),
|
|
1272
|
-
y: Math.max(0, clip.y - full.y)
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
function maxScrollTop() {
|
|
1276
|
-
const clip = normalizedRect();
|
|
1277
|
-
const { y: clipY } = clipOffsets();
|
|
1278
|
-
return Math.max(0, rows.value.length - (clipY + clip.h));
|
|
1279
|
-
}
|
|
1280
|
-
function visibleRowSignatures(sourceRows, scrollTop) {
|
|
1281
|
-
const clip = normalizedRect();
|
|
1282
|
-
const { y: clipY } = clipOffsets();
|
|
1283
|
-
const start = Math.max(0, scrollTop + clipY);
|
|
1284
|
-
const end = Math.max(start, start + clip.h);
|
|
1285
|
-
const out = [];
|
|
1286
|
-
for (let index = start; index < end; index++) out.push(markdownRowSignature(sourceRows[index]));
|
|
1287
|
-
return out;
|
|
1288
|
-
}
|
|
1289
|
-
function hasControlledScrollTop() {
|
|
1290
|
-
return Object.prototype.hasOwnProperty.call((instance === null || instance === void 0 ? void 0 : instance.vnode.props) ?? {}, "scrollTop");
|
|
1291
|
-
}
|
|
1292
|
-
function setScrollTop(next, emitChange = true) {
|
|
1293
|
-
const clamped = clamp(Math.floor(Number(next) || 0), 0, maxScrollTop());
|
|
1294
|
-
if (internalScrollTop.value === clamped) return;
|
|
1295
|
-
internalScrollTop.value = clamped;
|
|
1296
|
-
if (emitChange) {
|
|
1297
|
-
emit("update:scrollTop", clamped);
|
|
1298
|
-
emit("scroll", clamped);
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
function reconcileScrollTop() {
|
|
1302
|
-
const desired = hasControlledScrollTop() ? Math.floor(Number(props.scrollTop) || 0) : internalScrollTop.value;
|
|
1303
|
-
const clamped = clamp(desired, 0, maxScrollTop());
|
|
1304
|
-
if (internalScrollTop.value === clamped) return;
|
|
1305
|
-
internalScrollTop.value = clamped;
|
|
1306
|
-
if (desired !== clamped) {
|
|
1307
|
-
emit("update:scrollTop", clamped);
|
|
1308
|
-
emit("scroll", clamped);
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
watch(() => props.scrollTop, () => {
|
|
1312
|
-
if (!hasControlledScrollTop()) return;
|
|
1313
|
-
const desired = Math.floor(Number(props.scrollTop) || 0);
|
|
1314
|
-
const clamped = clamp(desired, 0, maxScrollTop());
|
|
1315
|
-
internalScrollTop.value = clamped;
|
|
1316
|
-
if (desired !== clamped) {
|
|
1317
|
-
emit("update:scrollTop", clamped);
|
|
1318
|
-
emit("scroll", clamped);
|
|
1319
|
-
}
|
|
1320
|
-
});
|
|
1321
|
-
watch([
|
|
1322
|
-
() => props.content,
|
|
1323
|
-
() => props.blocks,
|
|
1324
|
-
() => props.w,
|
|
1325
|
-
() => parser.value,
|
|
1326
|
-
() => props.final,
|
|
1327
|
-
() => markdownThemeSignature(props.theme)
|
|
1328
|
-
], () => {
|
|
1329
|
-
scheduleRebuild();
|
|
1330
|
-
}, { immediate: true });
|
|
1331
|
-
watch([
|
|
1332
|
-
() => props.content,
|
|
1333
|
-
() => props.w,
|
|
1334
|
-
() => props.h,
|
|
1335
|
-
() => absRect.value.h
|
|
1336
|
-
], () => {
|
|
1337
|
-
resetWheelScrollState(wheelState);
|
|
1338
|
-
});
|
|
1339
|
-
watch([
|
|
1340
|
-
() => props.h,
|
|
1341
|
-
() => absRect.value.y,
|
|
1342
|
-
() => absRect.value.h,
|
|
1343
|
-
() => fullRect.value.y,
|
|
1344
|
-
() => fullRect.value.h
|
|
1345
|
-
], () => {
|
|
1346
|
-
reconcileScrollTop();
|
|
1347
|
-
}, { immediate: true });
|
|
1348
|
-
function onKeydown(event) {
|
|
1349
|
-
emit("keydown", event);
|
|
1350
|
-
const page = Math.max(1, normalizedRect().h);
|
|
1351
|
-
if (event.key === "ArrowUp") {
|
|
1352
|
-
event.preventDefault();
|
|
1353
|
-
setScrollTop(internalScrollTop.value - 1);
|
|
1354
|
-
return;
|
|
1355
|
-
}
|
|
1356
|
-
if (event.key === "ArrowDown") {
|
|
1357
|
-
event.preventDefault();
|
|
1358
|
-
setScrollTop(internalScrollTop.value + 1);
|
|
1359
|
-
return;
|
|
1360
|
-
}
|
|
1361
|
-
if (event.key === "PageUp") {
|
|
1362
|
-
event.preventDefault();
|
|
1363
|
-
setScrollTop(internalScrollTop.value - page);
|
|
1364
|
-
return;
|
|
1365
|
-
}
|
|
1366
|
-
if (event.key === "PageDown") {
|
|
1367
|
-
event.preventDefault();
|
|
1368
|
-
setScrollTop(internalScrollTop.value + page);
|
|
1369
|
-
return;
|
|
1370
|
-
}
|
|
1371
|
-
if (event.key === "Home") {
|
|
1372
|
-
event.preventDefault();
|
|
1373
|
-
setScrollTop(0);
|
|
1374
|
-
return;
|
|
1375
|
-
}
|
|
1376
|
-
if (event.key === "End") {
|
|
1377
|
-
event.preventDefault();
|
|
1378
|
-
setScrollTop(maxScrollTop());
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
const eventNode = useTerminalNode(() => ({
|
|
1382
|
-
rect: normalizedRect(),
|
|
1383
|
-
zIndex: eventZ.value,
|
|
1384
|
-
visible: visible.value,
|
|
1385
|
-
focusable: true,
|
|
1386
|
-
selectable: props.selectable,
|
|
1387
|
-
handlers: {
|
|
1388
|
-
click: (_event) => {},
|
|
1389
|
-
wheel: (event) => {
|
|
1390
|
-
var _event$preventDefault;
|
|
1391
|
-
const { deltaY, mode } = getWheelScrollInput(event);
|
|
1392
|
-
if (!deltaY) return;
|
|
1393
|
-
const now = typeof event.time === "number" ? event.time : typeof event.timeStamp === "number" ? event.timeStamp : Date.now();
|
|
1394
|
-
const { nextTop, dir } = applyWheelScroll(wheelState, deltaY, internalScrollTop.value, maxScrollTop(), now, mode, { disableAcceleration: mode === "pixel" });
|
|
1395
|
-
if (!dir || nextTop === internalScrollTop.value) return;
|
|
1396
|
-
(_event$preventDefault = event.preventDefault) === null || _event$preventDefault === void 0 || _event$preventDefault.call(event);
|
|
1397
|
-
setScrollTop(nextTop);
|
|
1398
|
-
},
|
|
1399
|
-
focus: () => {
|
|
1400
|
-
emit("focus");
|
|
1401
|
-
},
|
|
1402
|
-
blur: () => {
|
|
1403
|
-
emit("blur");
|
|
1404
|
-
},
|
|
1405
|
-
keydown: onKeydown
|
|
1406
|
-
}
|
|
1407
|
-
}));
|
|
1408
|
-
watchEffect(() => {
|
|
1409
|
-
if (!props.autoFocus || !visible.value) return;
|
|
1410
|
-
const manager = events.value;
|
|
1411
|
-
const nodeId = eventNode.id.value;
|
|
1412
|
-
if (!nodeId) return;
|
|
1413
|
-
if (!manager) return;
|
|
1414
|
-
if (manager.getFocused() === nodeId) return;
|
|
1415
|
-
manager.focus(nodeId);
|
|
1416
|
-
});
|
|
1417
|
-
onBeforeUnmount(() => {
|
|
1418
|
-
alive = false;
|
|
1419
|
-
rebuildVersion++;
|
|
1420
|
-
});
|
|
1421
|
-
useRenderNode(() => ({
|
|
1422
|
-
zIndex: props.zIndex,
|
|
1423
|
-
rect: visible.value ? normalizedRect() : {
|
|
1424
|
-
x: 0,
|
|
1425
|
-
y: 0,
|
|
1426
|
-
w: 0,
|
|
1427
|
-
h: 0
|
|
1428
|
-
},
|
|
1429
|
-
deps: [
|
|
1430
|
-
visible.value,
|
|
1431
|
-
absRect.value,
|
|
1432
|
-
fullRect.value,
|
|
1433
|
-
internalScrollTop.value,
|
|
1434
|
-
props.style,
|
|
1435
|
-
defaultStyle.value,
|
|
1436
|
-
documentVersion.value
|
|
1437
|
-
],
|
|
1438
|
-
paint: (dirtyRows) => {
|
|
1439
|
-
if (!visible.value) return;
|
|
1440
|
-
const r = normalizedRect();
|
|
1441
|
-
if (r.w <= 0 || r.h <= 0) return;
|
|
1442
|
-
const baseStyle = props.style ?? defaultStyle.value;
|
|
1443
|
-
const { x: clipX, y: clipY } = clipOffsets();
|
|
1444
|
-
const paintRow = (y) => {
|
|
1445
|
-
if (y < r.y || y >= r.y + r.h) return;
|
|
1446
|
-
const visualIndex = internalScrollTop.value + clipY + (y - r.y);
|
|
1447
|
-
paintMarkdownVisualRow(terminal, rows.value[visualIndex], {
|
|
1448
|
-
x: r.x,
|
|
1449
|
-
y,
|
|
1450
|
-
w: r.w,
|
|
1451
|
-
clipStart: clipX,
|
|
1452
|
-
baseStyle,
|
|
1453
|
-
clear: true
|
|
1454
|
-
});
|
|
1455
|
-
};
|
|
1456
|
-
if (dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) {
|
|
1457
|
-
for (const y of dirtyRows) paintRow(y);
|
|
1458
|
-
return;
|
|
1459
|
-
}
|
|
1460
|
-
for (let y = r.y; y < r.y + r.h; y++) paintRow(y);
|
|
156
|
+
withTextWidthProvider(widthProvider, () => {
|
|
157
|
+
if (!visible.value) return;
|
|
158
|
+
const r = absRect.value;
|
|
159
|
+
const full = fullRect.value;
|
|
160
|
+
if (r.w <= 0 || r.h <= 0) return;
|
|
161
|
+
const baseStyle = props.style ?? defaultStyle.value;
|
|
162
|
+
const clipStart = Math.max(0, Math.floor(r.x - full.x));
|
|
163
|
+
const paintRow = (y) => {
|
|
164
|
+
if (y < r.y || y >= r.y + r.h) return;
|
|
165
|
+
const rowIndex = Math.floor(y - full.y);
|
|
166
|
+
const row = rows.value[rowIndex];
|
|
167
|
+
if (!row && !props.clear) return;
|
|
168
|
+
paintMarkdownVisualRow(terminal, row, {
|
|
169
|
+
x: r.x,
|
|
170
|
+
y,
|
|
171
|
+
w: r.w,
|
|
172
|
+
clipStart,
|
|
173
|
+
baseStyle,
|
|
174
|
+
clear: props.clear
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
if (dirtyRows?.length) {
|
|
178
|
+
for (const y of dirtyRows) paintRow(y);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
for (let y = r.y; y < r.y + r.h; y++) paintRow(y);
|
|
182
|
+
});
|
|
1461
183
|
}
|
|
1462
184
|
}));
|
|
1463
185
|
return () => h("span", rootProps);
|
|
1464
186
|
}
|
|
1465
187
|
});
|
|
1466
188
|
|
|
1467
|
-
//#endregion
|
|
1468
|
-
//#region src/vue/markdown/block-source.ts
|
|
1469
|
-
function withBlockKeyPrefix(block, prefix, index) {
|
|
1470
|
-
const key = `${prefix}:${index}:${block.key}`;
|
|
1471
|
-
switch (block.type) {
|
|
1472
|
-
case "inline": return {
|
|
1473
|
-
...block,
|
|
1474
|
-
key
|
|
1475
|
-
};
|
|
1476
|
-
case "code_block": return {
|
|
1477
|
-
...block,
|
|
1478
|
-
key
|
|
1479
|
-
};
|
|
1480
|
-
case "thematic_break": return {
|
|
1481
|
-
...block,
|
|
1482
|
-
key
|
|
1483
|
-
};
|
|
1484
|
-
case "blank": return {
|
|
1485
|
-
...block,
|
|
1486
|
-
key
|
|
1487
|
-
};
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
function parseBlockGroup(text, key, parser, theme, final) {
|
|
1491
|
-
const { blocks } = buildMarkdownBlocks(text, parser, {
|
|
1492
|
-
final,
|
|
1493
|
-
theme
|
|
1494
|
-
});
|
|
1495
|
-
return {
|
|
1496
|
-
key,
|
|
1497
|
-
blocks: blocks.map((block, index) => withBlockKeyPrefix(block, key, index))
|
|
1498
|
-
};
|
|
1499
|
-
}
|
|
1500
|
-
function shouldInsertGap(previous, next) {
|
|
1501
|
-
return previous != null && next != null && previous.type !== "blank" && next.type !== "blank";
|
|
1502
|
-
}
|
|
1503
|
-
function mergeGroups(groups) {
|
|
1504
|
-
const out = [];
|
|
1505
|
-
for (const group of groups) {
|
|
1506
|
-
if (!group.blocks.length) continue;
|
|
1507
|
-
if (shouldInsertGap(out[out.length - 1], group.blocks[0])) out.push({
|
|
1508
|
-
type: "blank",
|
|
1509
|
-
key: `${group.key}:gap`
|
|
1510
|
-
});
|
|
1511
|
-
out.push(...group.blocks);
|
|
1512
|
-
}
|
|
1513
|
-
return out;
|
|
1514
|
-
}
|
|
1515
|
-
function createMarkdownBlockSource(options) {
|
|
1516
|
-
const parser = (options === null || options === void 0 ? void 0 : options.parser) ?? createTuiMarkdownParser({
|
|
1517
|
-
streaming: true,
|
|
1518
|
-
customHtmlTags: options === null || options === void 0 ? void 0 : options.customHtmlTags
|
|
1519
|
-
});
|
|
1520
|
-
const theme = options === null || options === void 0 ? void 0 : options.theme;
|
|
1521
|
-
const finalizedGroups = [];
|
|
1522
|
-
let tailText = "";
|
|
1523
|
-
let nextGroupIndex = 0;
|
|
1524
|
-
let version = 0;
|
|
1525
|
-
let cachedVersion = -1;
|
|
1526
|
-
let cachedBlocks = [];
|
|
1527
|
-
const invalidate = () => {
|
|
1528
|
-
version++;
|
|
1529
|
-
cachedVersion = -1;
|
|
1530
|
-
};
|
|
1531
|
-
const currentGroups = () => {
|
|
1532
|
-
if (!tailText) return finalizedGroups;
|
|
1533
|
-
return [...finalizedGroups, parseBlockGroup(tailText, `md-tail-${nextGroupIndex}`, parser, theme, false)];
|
|
1534
|
-
};
|
|
1535
|
-
const blocks = () => {
|
|
1536
|
-
if (cachedVersion === version) return cachedBlocks;
|
|
1537
|
-
cachedBlocks = mergeGroups(currentGroups());
|
|
1538
|
-
cachedVersion = version;
|
|
1539
|
-
return cachedBlocks;
|
|
1540
|
-
};
|
|
1541
|
-
const snapshot = () => ({
|
|
1542
|
-
version,
|
|
1543
|
-
blocks: blocks()
|
|
1544
|
-
});
|
|
1545
|
-
return {
|
|
1546
|
-
get version() {
|
|
1547
|
-
return version;
|
|
1548
|
-
},
|
|
1549
|
-
get blocks() {
|
|
1550
|
-
return blocks();
|
|
1551
|
-
},
|
|
1552
|
-
appendDelta(text) {
|
|
1553
|
-
if (!text) return;
|
|
1554
|
-
tailText += text;
|
|
1555
|
-
invalidate();
|
|
1556
|
-
},
|
|
1557
|
-
replaceTailBlock(text) {
|
|
1558
|
-
if (tailText === text) return;
|
|
1559
|
-
tailText = text;
|
|
1560
|
-
invalidate();
|
|
1561
|
-
},
|
|
1562
|
-
finalizeBlock() {
|
|
1563
|
-
if (!tailText) return;
|
|
1564
|
-
const key = `md-block-${nextGroupIndex++}`;
|
|
1565
|
-
finalizedGroups.push(parseBlockGroup(tailText, key, parser, theme, true));
|
|
1566
|
-
tailText = "";
|
|
1567
|
-
invalidate();
|
|
1568
|
-
},
|
|
1569
|
-
clear() {
|
|
1570
|
-
if (!tailText && finalizedGroups.length === 0) return;
|
|
1571
|
-
finalizedGroups.length = 0;
|
|
1572
|
-
tailText = "";
|
|
1573
|
-
nextGroupIndex = 0;
|
|
1574
|
-
invalidate();
|
|
1575
|
-
},
|
|
1576
|
-
snapshot
|
|
1577
|
-
};
|
|
1578
|
-
}
|
|
1579
|
-
|
|
1580
189
|
//#endregion
|
|
1581
190
|
export { TMarkdownText, TVirtualMarkdown, buildMarkdownBlocks, buildMarkdownVisualRows, createMarkdownBlockSource, createTuiMarkdownParser, isSafeMarkdownLink, layoutMarkdownBlocks };
|