@simon_he/vue-tui 1.1.4 → 1.1.6

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/dist/agent.cjs CHANGED
@@ -5673,7 +5673,7 @@ function pickBestTerminalGraphicsProtocol(protocols) {
5673
5673
  }
5674
5674
  function detectCandidates(env) {
5675
5675
  let candidates = [], term = String(envString(env, "TERM") ?? "").toLowerCase(), termProgram = String(envString(env, "TERM_PROGRAM") ?? "").toLowerCase(), termProgramVersion = String(envString(env, "TERM_PROGRAM_VERSION") ?? "").toLowerCase();
5676
- return (envString(env, "KITTY_WINDOW_ID") || envString(env, "GHOSTTY_RESOURCES_DIR") || /(?:^|-)kitty(?:-|$)/i.test(term) || term.includes("ghostty") || termProgram.includes("ghostty")) && candidates.push("kitty"), (termProgram.includes("iterm") || termProgram.includes("wezterm") || envString(env, "WEZTERM_PANE") || envString(env, "WEZTERM_EXECUTABLE")) && candidates.push("iterm2"), (truthy(envString(env, "VUE_TUI_SIXEL")) || truthy(envString(env, "VUE_TUI_GRAPHICS_SIXEL")) || String(envString(env, "TERMINAL_GRAPHICS") ?? "").toLowerCase().includes("sixel") || /\bsixel\b/i.test(`${term} ${termProgram} ${termProgramVersion}`)) && candidates.push("sixel"), uniqueProtocols(candidates);
5676
+ return (envString(env, "KITTY_WINDOW_ID") || envString(env, "GHOSTTY_RESOURCES_DIR") || /(?:^|-)kitty(?:-|$)/i.test(term) || term.includes("ghostty") || termProgram.includes("ghostty") || termProgram.includes("wezterm") || envString(env, "WEZTERM_PANE") || envString(env, "WEZTERM_EXECUTABLE")) && candidates.push("kitty"), termProgram.includes("iterm") && candidates.push("iterm2"), (truthy(envString(env, "VUE_TUI_SIXEL")) || truthy(envString(env, "VUE_TUI_GRAPHICS_SIXEL")) || String(envString(env, "TERMINAL_GRAPHICS") ?? "").toLowerCase().includes("sixel") || /\bsixel\b/i.test(`${term} ${termProgram} ${termProgramVersion}`)) && candidates.push("sixel"), uniqueProtocols(candidates);
5677
5677
  }
5678
5678
  function capabilitiesFor(protocol, input) {
5679
5679
  let supported = protocol === "kitty" || protocol === "iterm2" || protocol === "sixel", candidates = uniqueProtocols([...input.candidates ?? (supported ? [protocol] : [])]);
@@ -6193,6 +6193,10 @@ function createTerminalGraphicPngSequence(options) {
6193
6193
  );
6194
6194
  crop && (placement = { ...placement, ...crop });
6195
6195
  }
6196
+ let transmissionPlacement = options.cropTransmission !== !1 ? placement : {
6197
+ columns: options.transmissionColumns ?? options.placementColumns,
6198
+ rows: options.transmissionRows ?? options.placementRows
6199
+ };
6196
6200
  return {
6197
6201
  type: "sequence",
6198
6202
  protocol: "kitty",
@@ -6200,7 +6204,7 @@ function createTerminalGraphicPngSequence(options) {
6200
6204
  imageId: options.imageId,
6201
6205
  placementId: options.placementId,
6202
6206
  zIndex: options.zIndex,
6203
- ...placement
6207
+ ...transmissionPlacement
6204
6208
  }),
6205
6209
  resizeSequence: createKittyPlacementSequence({
6206
6210
  imageId: options.imageId,
@@ -6373,6 +6377,7 @@ var tAgentTerminalGraphicProps = {
6373
6377
  suspendRenderWhileScrolling: { type: Boolean, default: !0 },
6374
6378
  scrolling: { type: Boolean, default: !1 },
6375
6379
  scrollVersion: { type: Number, default: 0 },
6380
+ /** Advanced Kitty-only opt-in for moving an unchanged image via a reusable placement sequence. */
6376
6381
  placementMoveWithoutClear: { type: Boolean, default: !1 },
6377
6382
  preserveRawWhileRendering: { type: Boolean, default: !1 },
6378
6383
  suspended: { type: Boolean, default: !1 },
@@ -15107,7 +15112,7 @@ function loadBuiltinMathRasterizer() {
15107
15112
  })()), builtinRasterizerLoad;
15108
15113
  }
15109
15114
 
15110
- // node_modules/.pnpm/stream-markdown-parser@1.1.9/node_modules/stream-markdown-parser/dist/index.js
15115
+ // node_modules/.pnpm/stream-markdown-parser@1.2.3/node_modules/stream-markdown-parser/dist/index.js
15111
15116
  var __create2 = Object.create, __defProp$1 = Object.defineProperty, __getOwnPropDesc2 = Object.getOwnPropertyDescriptor, __getOwnPropNames2 = Object.getOwnPropertyNames, __getProtoOf2 = Object.getPrototypeOf, __hasOwnProp2 = Object.prototype.hasOwnProperty, __commonJS = (cb, mod) => function() {
15112
15117
  return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15113
15118
  }, __export$1 = (all) => {
@@ -25011,7 +25016,23 @@ function shouldDemoteFilenameLikeLinkify(linkText, context = {}) {
25011
25016
  let extension = String(extensionMatch[1] ?? "").toLowerCase();
25012
25017
  return isMarketTickerLikeText(linkText, extension, context.marketTicker === !0) ? !0 : FILENAMEISH_LINK_EXTENSIONS.has(extension) ? !AMBIGUOUS_BARE_DOMAIN_EXTENSIONS.has(extension) || context.filename ? !0 : hasStrongFilenameSignals(linkText) : !!(context.explicitFilename && EXPLICIT_FILENAME_CONTEXT_ONLY_EXTENSIONS.has(extension) || context.filename && FILENAME_CONTEXT_ONLY_EXTENSIONS.has(extension));
25013
25018
  }
25019
+ var syntheticLinkOrigins = /* @__PURE__ */ new WeakMap(), cacheStableLinkValidators = /* @__PURE__ */ new WeakSet();
25020
+ function setSyntheticLinkOrigin(token, origin) {
25021
+ return syntheticLinkOrigins.set(token, origin), token;
25022
+ }
25023
+ function readSyntheticLinkOrigin(token) {
25024
+ return syntheticLinkOrigins.get(token);
25025
+ }
25026
+ function registerCacheStableLinkValidator(validateLink$1) {
25027
+ cacheStableLinkValidators.add(validateLink$1);
25028
+ }
25029
+ function isCacheStableLinkValidator(validateLink$1) {
25030
+ return validateLink$1 === void 0 || cacheStableLinkValidators.has(validateLink$1);
25031
+ }
25014
25032
  var LINKIFY_HARD_STOP_CHARS = ["\uFF01"];
25033
+ function getSyntheticLinkOrigin(markup) {
25034
+ return markup === "linkify" || markup === "autolink" ? markup : "recovery";
25035
+ }
25015
25036
  function textToken(content) {
25016
25037
  return {
25017
25038
  type: "text",
@@ -25057,13 +25078,13 @@ function pushEmClose(arr, type) {
25057
25078
  nesting: -1
25058
25079
  }));
25059
25080
  }
25060
- function createLinkToken(text$1, href, loading) {
25081
+ function createLinkToken(text$1, href, loading, origin = "recovery") {
25061
25082
  let title = "";
25062
25083
  if (href.includes('"')) {
25063
25084
  let temps = href.split('"');
25064
25085
  href = temps[0].trim(), title = temps[1].trim();
25065
25086
  }
25066
- return {
25087
+ return setSyntheticLinkOrigin({
25067
25088
  type: "link",
25068
25089
  loading,
25069
25090
  href,
@@ -25075,7 +25096,7 @@ function createLinkToken(text$1, href, loading) {
25075
25096
  raw: text$1
25076
25097
  }],
25077
25098
  raw: `[${text$1}](${href})`
25078
- };
25099
+ }, origin);
25079
25100
  }
25080
25101
  function appendToLinkToken(link$1, suffix) {
25081
25102
  if (!(!link$1 || !suffix) && (link$1.href = String(link$1.href ?? "") + suffix, link$1.text = String(link$1.text ?? "") + suffix, link$1.raw = `[${link$1.text}](${link$1.href})`, Array.isArray(link$1.children) && link$1.children.length)) {
@@ -25239,13 +25260,13 @@ function fixLinkToken(tokens, raw) {
25239
25260
  } else if (curToken?.type === "text" && curToken.content?.endsWith("(") && tokens[i + 1]?.type === "link_open") {
25240
25261
  let match = curToken.content.match(/\[([^\]]+)\]/);
25241
25262
  if (match) {
25242
- let beforeText = curToken.content.slice(0, match.index), emphasisMatch = beforeText.match(/(\*+)$/), replacerTokens = [];
25263
+ let beforeText = curToken.content.slice(0, match.index), emphasisMatch = beforeText.match(/(\*+)$/), origin = getSyntheticLinkOrigin(tokens[i + 1]?.markup), replacerTokens = [];
25243
25264
  if (emphasisMatch) {
25244
25265
  beforeText = beforeText.slice(0, emphasisMatch.index), beforeText && replacerTokens.push(textToken(beforeText));
25245
25266
  let text$1 = match[1], type = emphasisMatch[1].length;
25246
25267
  pushEmOpen(replacerTokens, type);
25247
25268
  let href = tokens[i + 2]?.content || "";
25248
- if (tokens[i + 4]?.type === "text" && !tokens[i + 4].content?.startsWith(")") && (href += tokens[i + 4]?.content || "", tokens[i + 4].content = ""), replacerTokens.push(createLinkToken(text$1, href, !tokens[i + 4]?.content?.startsWith(")"))), pushEmClose(replacerTokens, type), tokens[i + 4]?.type === "text") {
25269
+ if (tokens[i + 4]?.type === "text" && !tokens[i + 4].content?.startsWith(")") && (href += tokens[i + 4]?.content || "", tokens[i + 4].content = ""), replacerTokens.push(createLinkToken(text$1, href, !tokens[i + 4]?.content?.startsWith(")"), origin)), pushEmClose(replacerTokens, type), tokens[i + 4]?.type === "text") {
25249
25270
  let afterText = tokens[i + 4].content?.replace(/^\)\**/, "");
25250
25271
  afterText && replacerTokens.push(textToken(afterText)), tokens.splice(i, 5, ...replacerTokens);
25251
25272
  } else
@@ -25257,7 +25278,7 @@ function fixLinkToken(tokens, raw) {
25257
25278
  let type = emphasisMatch$1[0].length;
25258
25279
  text$1 = text$1.replace(/^\*+/, "").replace(/\*+$/, "");
25259
25280
  let href$1 = tokens[i + 2]?.content || "";
25260
- if (tokens[i + 4]?.type === "text" && !tokens[i + 4].content?.startsWith(")") && (href$1 += tokens[i + 4]?.content || "", tokens[i + 4].content = ""), pushEmOpen(replacerTokens, type), replacerTokens.push(createLinkToken(text$1, href$1, !tokens[i + 4]?.content?.startsWith(")"))), pushEmClose(replacerTokens, type), tokens[i + 4]?.type === "text") {
25281
+ if (tokens[i + 4]?.type === "text" && !tokens[i + 4].content?.startsWith(")") && (href$1 += tokens[i + 4]?.content || "", tokens[i + 4].content = ""), pushEmOpen(replacerTokens, type), replacerTokens.push(createLinkToken(text$1, href$1, !tokens[i + 4]?.content?.startsWith(")"), origin)), pushEmClose(replacerTokens, type), tokens[i + 4]?.type === "text") {
25261
25282
  let afterText = tokens[i + 4].content?.replace(/^\)/, "");
25262
25283
  afterText && replacerTokens.push(textToken(afterText)), tokens.splice(i, 5, ...replacerTokens);
25263
25284
  } else
@@ -25266,7 +25287,7 @@ function fixLinkToken(tokens, raw) {
25266
25287
  continue;
25267
25288
  }
25268
25289
  let href = tokens[i + 2]?.content || "";
25269
- if (tokens[i + 4]?.type === "text" && !tokens[i + 4].content?.startsWith(")") && (href += tokens[i + 4]?.content || "", tokens[i + 4].content = ""), replacerTokens.push(createLinkToken(text$1, href, !tokens[i + 4]?.content?.startsWith(")"))), tokens[i + 4]?.type === "text") {
25290
+ if (tokens[i + 4]?.type === "text" && !tokens[i + 4].content?.startsWith(")") && (href += tokens[i + 4]?.content || "", tokens[i + 4].content = ""), replacerTokens.push(createLinkToken(text$1, href, !tokens[i + 4]?.content?.startsWith(")"), origin)), tokens[i + 4]?.type === "text") {
25270
25291
  let afterText = tokens[i + 4].content?.replace(/^\)/, "");
25271
25292
  afterText && replacerTokens.push(textToken(afterText)), tokens.splice(i, 5, ...replacerTokens);
25272
25293
  } else
@@ -25280,11 +25301,11 @@ function fixLinkToken(tokens, raw) {
25280
25301
  let replacerTokens = [], text$1 = tokens[i - 3].content || "", href = curToken.attrs?.find((attr) => attr[0] === "href")?.[1] || "";
25281
25302
  if (tokens[i + 3]?.type === "text") {
25282
25303
  let m = (tokens[i + 3]?.content ?? "").indexOf(")"), loading = m === -1;
25283
- m === -1 && (href += tokens[i + 3]?.content?.slice(0, m) || "", tokens[i + 3].content = ""), replacerTokens.push(createLinkToken(text$1, href, loading));
25304
+ m === -1 && (href += tokens[i + 3]?.content?.slice(0, m) || "", tokens[i + 3].content = ""), replacerTokens.push(createLinkToken(text$1, href, loading, "linkify"));
25284
25305
  let afterText = tokens[i + 3].content?.replace(/^\)\**/, "");
25285
25306
  afterText && replacerTokens.push(textToken(afterText)), tokens.splice(i - 4, 8, ...replacerTokens);
25286
25307
  } else
25287
- replacerTokens.push({
25308
+ replacerTokens.push(setSyntheticLinkOrigin({
25288
25309
  type: "link",
25289
25310
  loading: !0,
25290
25311
  href,
@@ -25296,7 +25317,7 @@ function fixLinkToken(tokens, raw) {
25296
25317
  raw: href
25297
25318
  }],
25298
25319
  raw: `[${text$1}](${href})`
25299
- }), tokens.splice(i - 4, 7, ...replacerTokens);
25320
+ }, "linkify")), tokens.splice(i - 4, 7, ...replacerTokens);
25300
25321
  continue;
25301
25322
  } else if (tokens[i - 1].content === "](" && tokens[i - 3]?.type === "text" && tokens[i - 3].content?.endsWith(")"))
25302
25323
  if (tokens[i - 2]?.type === "strong_open") {
@@ -25330,7 +25351,7 @@ function fixLinkToken(tokens, raw) {
25330
25351
  count += 1;
25331
25352
  }
25332
25353
  }
25333
- let linkToken = {
25354
+ let linkToken = setSyntheticLinkOrigin({
25334
25355
  type: "link",
25335
25356
  loading: !1,
25336
25357
  href,
@@ -25342,7 +25363,7 @@ function fixLinkToken(tokens, raw) {
25342
25363
  raw: text$1
25343
25364
  }],
25344
25365
  raw: `[${text$1}](${href})`
25345
- };
25366
+ }, curToken.markup ? getSyntheticLinkOrigin(curToken.markup) : "explicit");
25346
25367
  if (replacerTokens.push(linkToken), emphasisMatch) {
25347
25368
  let type = emphasisMatch[1].length;
25348
25369
  pushEmClose(replacerTokens, type);
@@ -26872,10 +26893,14 @@ function factory(opts = {}) {
26872
26893
  ...experimental
26873
26894
  }
26874
26895
  });
26875
- return hasCustomValidateLink || md.set({ validateLink: (url) => !isUnsafeHtmlUrl(url, {
26876
- tagName: "a",
26877
- attrName: "href"
26878
- }) }), applyInlineUrlValidation(md), applyLinkifyCandidateFilter(md), (opts.enableMath ?? !0) && applyMath(md, {
26896
+ if (!hasCustomValidateLink) {
26897
+ let validateLink$1 = (url) => !isUnsafeHtmlUrl(url, {
26898
+ tagName: "a",
26899
+ attrName: "href"
26900
+ });
26901
+ registerCacheStableLinkValidator(validateLink$1), md.set({ validateLink: validateLink$1 });
26902
+ }
26903
+ return applyInlineUrlValidation(md), applyLinkifyCandidateFilter(md), (opts.enableMath ?? !0) && applyMath(md, {
26879
26904
  ...getDefaultMathOptions() ?? {},
26880
26905
  ...opts.mathOptions ?? {}
26881
26906
  }), (opts.enableContainers ?? !0) && applyContainers(md), opts.enableFixIndentedCodeBlock !== !1 && applyFixIndentedCodeBlock(md), applyFixLinkTokens(md), applyFixStrongTokens(md), applyFixListItem(md), applyFixTableTokens(md), applyRenderRules(md), applyFixHtmlInlineTokens(md, { customHtmlTags: opts.customHtmlTags }), md;
@@ -26924,7 +26949,11 @@ function parseEmphasisToken(tokens, startIndex, options) {
26924
26949
  nextIndex: i < tokens.length ? i + 1 : tokens.length
26925
26950
  };
26926
26951
  }
26927
- var TRAILING_FENCE_LINE_RE = /\r?\n[ \t]*`+\s*$/, DIFF_HEADER_PREFIXES = [
26952
+ function TRAILING_OWN_FENCE_LINE_RE(marker, minLen) {
26953
+ return /* @__PURE__ */ new RegExp(`\r?
26954
+ [ \\t]*${marker}{${minLen},}[ \\t]*$`);
26955
+ }
26956
+ var DIFF_HEADER_PREFIXES = [
26928
26957
  "diff ",
26929
26958
  "index ",
26930
26959
  "--- ",
@@ -26977,7 +27006,11 @@ function parseFenceToken(token) {
26977
27006
  let s = info, sp = s.indexOf(" ");
26978
27007
  return sp === -1 ? "" : String(s.slice(sp + 1) ?? "");
26979
27008
  })() : info, content = String(token.content ?? "");
26980
- if (TRAILING_FENCE_LINE_RE.test(content) && (content = content.replace(TRAILING_FENCE_LINE_RE, "")), diff) {
27009
+ if (!closed && token.markup) {
27010
+ let marker = token.markup[0], minLen = token.markup.length, trailingFenceLineRe = TRAILING_OWN_FENCE_LINE_RE(marker, minLen);
27011
+ trailingFenceLineRe.test(content) && (content = content.replace(trailingFenceLineRe, ""));
27012
+ }
27013
+ if (diff) {
26981
27014
  let { original, updated } = splitUnifiedDiff(content, closed === !0);
26982
27015
  return {
26983
27016
  type: "code_block",
@@ -28270,11 +28303,11 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
28270
28303
  content
28271
28304
  });
28272
28305
  if (currentTextNode) {
28273
- currentTextNode.content += stripTrailingMidStateMarker(textNode.content, token, markerFlags), currentTextNode.raw += textNode.raw;
28306
+ currentTextNode.content += options?.final ? textNode.content : stripTrailingMidStateMarker(textNode.content, token, markerFlags), currentTextNode.raw += textNode.raw;
28274
28307
  return;
28275
28308
  }
28276
28309
  let maybeMath = preToken?.tag === "br" && tokens[i - 2]?.content === "[";
28277
- nextToken || (textNode.content = stripTrailingMidStateMarker(textNode.content, token, markerFlags)), currentTextNode = textNode, currentTextNode.center = maybeMath, result.push(currentTextNode);
28310
+ nextToken || (textNode.content = options?.final ? textNode.content : stripTrailingMidStateMarker(textNode.content, token, markerFlags)), currentTextNode = textNode, currentTextNode.center = maybeMath, result.push(currentTextNode);
28278
28311
  }
28279
28312
  function handleTextToken(token) {
28280
28313
  let rawContent = String(token.content ?? ""), rawMarkerFlags = getInlineTextMarkerFlags(rawContent), rawHasBackslash = (rawMarkerFlags & INLINE_TEXT_MARKER_BACKSLASH) !== 0, rawSource = tokens.length === 1 && rawHasBackslash && typeof raw == "string" ? String(raw) : "", content = rawSource ? decodeVisibleTextFromRaw(rawSource) : rawHasBackslash ? rawContent.replace(ESCAPED_PUNCTUATION_RE, "$1") : rawContent, markerFlags = content === rawContent ? rawMarkerFlags : getInlineTextMarkerFlags(content);
@@ -28297,7 +28330,7 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
28297
28330
  i++;
28298
28331
  return;
28299
28332
  }
28300
- if (!nextToken && markerFlags & INLINE_TEXT_MARKER_OPEN_PAREN && /[^\]]\s*\(\s*$/.test(content) && (content = content.replace(/\(\s*$/, "")), !content) {
28333
+ if (!nextToken && options?.final !== !0 && markerFlags & INLINE_TEXT_MARKER_OPEN_PAREN && /[^\]]\s*\(\s*$/.test(content) && (content = content.replace(/\(\s*$/, "")), !content) {
28301
28334
  i++;
28302
28335
  return;
28303
28336
  }
@@ -29635,16 +29668,23 @@ function recordInternalNodeSourceRange(node, token, options) {
29635
29668
  end: offsets[Math.max(0, Math.trunc(endLine))] ?? source.length
29636
29669
  });
29637
29670
  }
29638
- var tolerantMathBoundaryStreamCache = /* @__PURE__ */ new WeakMap(), pendingExplicitMathTailCache = /* @__PURE__ */ new WeakMap(), TOLERANT_BOUNDARY_SPLIT_OPENERS = ["$$", "\\["], STREAMING_ADMONITION_OPEN_RE = /(^|\r?\n)[\t ]*:::[\t ]*(?:warning|info|note|tip|danger|caution|error)(?=[\t ]|\r?\n|$)[^\r\n]*(?:\r?\n[\t ]*)*$/, structuredStreamCache = /* @__PURE__ */ new WeakMap(), topLevelStreamParseMode = /* @__PURE__ */ new WeakMap(), REUSABLE_INLINE_TOKEN_TYPES = /* @__PURE__ */ new Set([
29671
+ var tolerantMathBoundaryStreamCache = /* @__PURE__ */ new WeakMap(), pendingExplicitMathTailCache = /* @__PURE__ */ new WeakMap(), TOLERANT_BOUNDARY_SPLIT_OPENERS = ["$", "\\["], STREAMING_ADMONITION_OPEN_RE = /(^|\r?\n)[\t ]*:::[\t ]*(?:warning|info|note|tip|danger|caution|error)(?=[\t ]|\r?\n|$)[^\r\n]*(?:\r?\n[\t ]*)*$/, SAFE_MARKDOWN_WINDOW_MARGIN = 1024, SAFE_MARKDOWN_WINDOW_OVERLAP = 16, safeMarkdownCache = /* @__PURE__ */ new WeakMap(), structuredStreamCache = /* @__PURE__ */ new WeakMap(), topLevelStreamParseMode = /* @__PURE__ */ new WeakMap(), REUSABLE_INLINE_TOKEN_TYPES = /* @__PURE__ */ new Set([
29639
29672
  "code_inline",
29640
29673
  "em_close",
29641
29674
  "em_open",
29642
29675
  "emoji",
29643
29676
  "hardbreak",
29677
+ "html_block",
29678
+ "html_inline",
29679
+ "image",
29644
29680
  "ins_close",
29645
29681
  "ins_open",
29682
+ "link",
29683
+ "link_close",
29684
+ "link_open",
29646
29685
  "mark_close",
29647
29686
  "mark_open",
29687
+ "math_inline",
29648
29688
  "s_close",
29649
29689
  "s_open",
29650
29690
  "softbreak",
@@ -29664,6 +29704,7 @@ var tolerantMathBoundaryStreamCache = /* @__PURE__ */ new WeakMap(), pendingExpl
29664
29704
  "code_block",
29665
29705
  "fence",
29666
29706
  "hr",
29707
+ "inline",
29667
29708
  "math_block"
29668
29709
  ]);
29669
29710
  function getParserNow() {
@@ -29695,21 +29736,38 @@ function processTokensWithTiming(tokens, options, timing) {
29695
29736
  let startedAt = getParserNow(), result = processTokens(tokens, options);
29696
29737
  return addTiming(timing, "processTokensMs", getParserNow() - startedAt), result;
29697
29738
  }
29698
- function hasOnlyReusableInlineTokens(tokens) {
29739
+ function hasOnlyReusableInlineTokens(tokens, validateLink$1) {
29699
29740
  return tokens.every((token) => {
29700
- if (!REUSABLE_INLINE_TOKEN_TYPES.has(token.type))
29741
+ if (!REUSABLE_INLINE_TOKEN_TYPES.has(token.type) || (token.type === "link" || token.type === "link_open" || token.type === "link_close") && !isCacheStableLinkValidator(validateLink$1))
29701
29742
  return !1;
29743
+ if (token.type === "link") {
29744
+ let origin = readSyntheticLinkOrigin(token);
29745
+ if (origin !== "explicit" && origin !== "linkify" && origin !== "autolink")
29746
+ return !1;
29747
+ }
29748
+ if (token.type === "link_open" || token.type === "link_close") {
29749
+ let markup = token.markup ?? "";
29750
+ if (markup !== "" && markup !== "linkify" && markup !== "autolink")
29751
+ return !1;
29752
+ }
29702
29753
  let children = token.children;
29703
- return !Array.isArray(children) || hasOnlyReusableInlineTokens(children);
29754
+ return !Array.isArray(children) || hasOnlyReusableInlineTokens(children, validateLink$1);
29704
29755
  });
29705
29756
  }
29706
- function getReusableTopLevelTokenGroups(tokens) {
29757
+ function getReusableTopLevelPairedCloseType(tokenType) {
29758
+ let known = REUSABLE_TOP_LEVEL_PAIRED_TOKEN_TYPES.get(tokenType);
29759
+ if (known)
29760
+ return known;
29761
+ let containerMatch = /^container_(.+)_open$/.exec(tokenType);
29762
+ return containerMatch ? `container_${containerMatch[1]}_close` : void 0;
29763
+ }
29764
+ function getReusableTopLevelTokenGroups(tokens, validateLink$1) {
29707
29765
  let groupStarts = [], mixed = !1, index = 0;
29708
29766
  for (; index < tokens.length; ) {
29709
29767
  let token = tokens[index];
29710
29768
  if (!token || token.level !== 0)
29711
29769
  return null;
29712
- let closeType = REUSABLE_TOP_LEVEL_PAIRED_TOKEN_TYPES.get(token.type), groupEnd = index + 1;
29770
+ let closeType = getReusableTopLevelPairedCloseType(token.type), groupEnd = index + 1;
29713
29771
  if (closeType) {
29714
29772
  if (token.nesting !== 1)
29715
29773
  return null;
@@ -29741,7 +29799,7 @@ function getReusableTopLevelTokenGroups(tokens) {
29741
29799
  if (current.type !== "inline")
29742
29800
  continue;
29743
29801
  let children = current.children;
29744
- if (!Array.isArray(children) || !hasOnlyReusableInlineTokens(children))
29802
+ if (!Array.isArray(children) || !hasOnlyReusableInlineTokens(children, validateLink$1))
29745
29803
  return null;
29746
29804
  }
29747
29805
  groupStarts.push(index), index = groupEnd;
@@ -29776,24 +29834,36 @@ function updateStructuredStreamCache(md, source, tokens, groups, nodes, options)
29776
29834
  source,
29777
29835
  nodes,
29778
29836
  stableGroupCount: groups.mixed ? Math.max(0, groupStarts.length - 1) : sourceEndsWithBlankLine(source) ? groupStarts.length : Math.max(0, groupStarts.length - 1),
29779
- requireClosingStrong: options.requireClosingStrong
29837
+ requireClosingStrong: options.requireClosingStrong,
29838
+ validateLink: options.validateLink
29780
29839
  });
29781
29840
  }
29782
29841
  function hasStableStructuredStreamGroupBoundaries(previous, tokens, groupStarts, stableGroupCount) {
29842
+ let lastGroupIndex = groupStarts.length - 1;
29783
29843
  for (let index = 0; index < stableGroupCount; index++) {
29784
29844
  let start = groupStarts[index], end = groupStarts[index + 1] ?? tokens.length, boundary = previous.groupBoundaries[index];
29785
- if (!boundary || boundary.firstToken !== tokens[start] || boundary.lastToken !== tokens[end - 1] || boundary.tokenCount !== end - start)
29845
+ if (!boundary || boundary.tokenCount !== end - start)
29846
+ return !1;
29847
+ if (!(boundary.firstToken === tokens[start] && boundary.lastToken === tokens[end - 1]) && (index >= lastGroupIndex || !isSameTokenShapeForReuse(boundary.firstToken, tokens[start]) || !isSameTokenShapeForReuse(boundary.lastToken, tokens[end - 1])))
29786
29848
  return !1;
29787
29849
  }
29788
29850
  return !0;
29789
29851
  }
29790
29852
  function processTopLevelTokensWithReuse(md, source, tokens, options, timing) {
29791
- let owner = md, groups = getReusableTopLevelTokenGroups(tokens);
29792
- if (!(shouldUseTopLevelStreamParse(md, options) && canReuseStructuredStreamNodes(options) && groups !== null))
29853
+ let owner = md, structuredReuseDisabled = options.__disableStructuredReuse === !0;
29854
+ if (!(shouldUseTopLevelStreamParse(md, options) && canReuseStructuredStreamNodes(options)))
29855
+ return structuredReuseDisabled || structuredStreamCache.delete(owner), processTokensWithTiming(tokens, options, timing);
29856
+ if (structuredReuseDisabled)
29857
+ return processTokensWithTiming(tokens, options, timing);
29858
+ let groups = getReusableTopLevelTokenGroups(tokens, options.validateLink);
29859
+ if (!groups)
29793
29860
  return structuredStreamCache.delete(owner), processTokensWithTiming(tokens, options, timing);
29794
29861
  let groupStarts = groups.starts, previous = structuredStreamCache.get(owner), mode = topLevelStreamParseMode.get(owner), stableGroupCount = previous && groups.mixed ? Math.min(previous.stableGroupCount, Math.max(0, previous.groupBoundaries.length - 1)) : previous?.stableGroupCount ?? 0;
29795
- if (previous && stableGroupCount > 0 && previous.requireClosingStrong === options.requireClosingStrong && source.startsWith(previous.source) && groupStarts.length >= stableGroupCount && (mode === "append" || mode === "tail") && hasStableStructuredStreamGroupBoundaries(previous, tokens, groupStarts, stableGroupCount)) {
29796
- let tailStart = groupStarts[stableGroupCount] ?? tokens.length, tailNodes = processTokensWithTiming(tokens.slice(tailStart), options, timing), expectedTailNodes = groupStarts.length - stableGroupCount;
29862
+ if (previous && stableGroupCount > 0 && previous.requireClosingStrong === options.requireClosingStrong && previous.validateLink === options.validateLink && source.startsWith(previous.source) && groupStarts.length >= stableGroupCount && (mode === "append" || mode === "tail") && hasStableStructuredStreamGroupBoundaries(previous, tokens, groupStarts, stableGroupCount)) {
29863
+ let tailStart = groupStarts[stableGroupCount] ?? tokens.length, tailNodes = processTokensWithTiming(tokens.slice(tailStart), {
29864
+ ...options,
29865
+ __linkifyDemotionSeed: previous.nodes.slice(0, stableGroupCount).map((node) => String(node.raw ?? ""))
29866
+ }, timing), expectedTailNodes = groupStarts.length - stableGroupCount;
29797
29867
  if (tailNodes.length === expectedTailNodes) {
29798
29868
  let result$1 = previous.nodes.slice(0, stableGroupCount).concat(tailNodes);
29799
29869
  return addTiming(timing, "processTokensReusedTopLevelNodes", stableGroupCount), updateStructuredStreamCache(md, source, tokens, groups, result$1, options), result$1;
@@ -30401,6 +30471,22 @@ function sameTokenMap(left, right) {
30401
30471
  let leftMap = left?.map, rightMap = right?.map;
30402
30472
  return leftMap === rightMap ? !0 : !Array.isArray(leftMap) || !Array.isArray(rightMap) ? !1 : leftMap.length === rightMap.length && leftMap.every((value, index) => value === rightMap[index]);
30403
30473
  }
30474
+ function sameTokenAttrs(left, right) {
30475
+ let leftAttrs = left?.attrs, rightAttrs = right?.attrs;
30476
+ if (leftAttrs === rightAttrs)
30477
+ return !0;
30478
+ if (!Array.isArray(leftAttrs) || !Array.isArray(rightAttrs) || leftAttrs.length !== rightAttrs.length)
30479
+ return !1;
30480
+ for (let index = 0; index < leftAttrs.length; index++) {
30481
+ let leftAttr = leftAttrs[index], rightAttr = rightAttrs[index];
30482
+ if (leftAttr[0] !== rightAttr[0] || leftAttr[1] !== rightAttr[1])
30483
+ return !1;
30484
+ }
30485
+ return !0;
30486
+ }
30487
+ function isSameTokenShapeForReuse(left, right) {
30488
+ return !!left && !!right && left.type === right.type && left.tag === right.tag && left.nesting === right.nesting && left.level === right.level && left.markup === right.markup && left.content === right.content && left.info === right.info && sameTokenMap(left, right) && sameTokenAttrs(left, right);
30489
+ }
30404
30490
  function isSameTokenShape(left, right) {
30405
30491
  return !!left && !!right && left.type === right.type && left.tag === right.tag && left.nesting === right.nesting && left.markup === right.markup && left.content === right.content && sameTokenMap(left, right);
30406
30492
  }
@@ -30828,7 +30914,8 @@ function hasTopLevelHtmlBlock(nodes) {
30828
30914
  function parseDetailsFragmentChildren(fragment, md, options) {
30829
30915
  return fragment.trim() ? parseMarkdownToStructure(fragment, md, {
30830
30916
  ...options,
30831
- __disableStreamParse: !0
30917
+ __disableStreamParse: !0,
30918
+ __disableStructuredReuse: !0
30832
30919
  }) : [];
30833
30920
  }
30834
30921
  function parseSummaryChildren(fragment, md, options) {
@@ -31024,54 +31111,7 @@ function stripDanglingHtmlLikeTail(markdown) {
31024
31111
  }
31025
31112
  }
31026
31113
  return !0;
31027
- }, isInsideFencedCodeBlock = (src, pos) => {
31028
- let inFence = !1, fenceChar = "", fenceLen = 0, isIndentWs = (ch) => ch === " " || ch === " ", parseFenceMarker = (line) => {
31029
- let i = 0;
31030
- for (; i < line.length && isIndentWs(line[i]); )
31031
- i++;
31032
- let ch = line[i];
31033
- if (ch !== "`" && ch !== "~")
31034
- return null;
31035
- let j = i;
31036
- for (; j < line.length && line[j] === ch; )
31037
- j++;
31038
- let len = j - i;
31039
- return len < 3 ? null : {
31040
- markerChar: ch,
31041
- markerLen: len,
31042
- rest: line.slice(j)
31043
- };
31044
- }, stripBlockquotePrefix = (line) => {
31045
- let i = 0;
31046
- for (; i < line.length && isIndentWs(line[i]); )
31047
- i++;
31048
- let saw = !1;
31049
- for (; i < line.length && line[i] === ">"; )
31050
- for (saw = !0, i++; i < line.length && isIndentWs(line[i]); )
31051
- i++;
31052
- return saw ? line.slice(i) : null;
31053
- }, matchFence = (rawLine) => {
31054
- let direct = parseFenceMarker(rawLine);
31055
- if (direct)
31056
- return direct;
31057
- let afterQuote = stripBlockquotePrefix(rawLine);
31058
- return afterQuote == null ? null : parseFenceMarker(afterQuote);
31059
- }, offset = 0, lines = src.split(/\r?\n/);
31060
- for (let line of lines) {
31061
- let lineStart = offset, lineEnd$2 = offset + line.length;
31062
- if (pos < lineStart)
31063
- break;
31064
- let fenceMatch = matchFence(line);
31065
- if (fenceMatch) {
31066
- let markerChar = fenceMatch.markerChar, markerLen = fenceMatch.markerLen;
31067
- inFence ? markerChar === fenceChar && markerLen >= fenceLen && /^\s*$/.test(fenceMatch.rest) && (inFence = !1, fenceChar = "", fenceLen = 0) : (inFence = !0, fenceChar = markerChar, fenceLen = markerLen);
31068
- }
31069
- if (pos <= lineEnd$2)
31070
- break;
31071
- offset = lineEnd$2 + 1;
31072
- }
31073
- return inFence;
31074
- }, s = String(markdown ?? ""), lastLt = s.lastIndexOf("<");
31114
+ }, isInsideFencedCodeBlock = (src, pos) => isInsideOpenMarkdownFenceBeforeOffset(src, pos), s = String(markdown ?? ""), lastLt = s.lastIndexOf("<");
31075
31115
  if (lastLt === -1 || isInsideFencedCodeBlock(s, lastLt))
31076
31116
  return s;
31077
31117
  if (lastLt > 0) {
@@ -31717,9 +31757,76 @@ function ensureBlankLineBeforeCustomHtmlBlocks(markdown, tags) {
31717
31757
  }
31718
31758
  return out;
31719
31759
  }
31720
- function parseMarkdownToStructure(markdown, md, options = {}) {
31721
- let timing = getParseTiming(options), parseStartedAt = timing ? getParserNow() : 0, isFinal = !!options.final, sourceMarkdown = (markdown ?? "").toString(), safeMarkdown = sourceMarkdown.replace(/([^\\])\r(ight|ho)/g, "$1\\r$2").replace(/([^\\])\r?\n(abla|eq|ot|exists)/g, "$1\\n$2");
31722
- if (shouldResetTopLevelStreamCacheForFinalAutoParse(md, options) && (md.stream.reset(), clearTolerantMathBoundaryStreamCache(md)), isFinal || (safeMarkdown.endsWith("- *") && (safeMarkdown = safeMarkdown.replace(/- \*$/, "- \\*")), /(?:^|\n)\s*-\s*$/.test(safeMarkdown) ? safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*-\s*$/, (m) => m.startsWith(`
31760
+ function createLatexSplitMathScanner(source) {
31761
+ let inFence = !1, fenceMarker = "", fenceLen = 0, inDollarBlock = !1, inBracketMath = !1, singleDollarOpen = !1, scanned = 0, processLine = (line, _lineStartOffset) => {
31762
+ let fenceMatch = matchMarkdownFenceMarker(line);
31763
+ if (fenceMatch) {
31764
+ inFence ? fenceMatch.markerChar === fenceMarker && fenceMatch.markerLen >= fenceLen && /^\s*$/.test(fenceMatch.rest) && (inFence = !1, fenceMarker = "", fenceLen = 0) : (inFence = !0, fenceMarker = fenceMatch.markerChar, fenceLen = fenceMatch.markerLen);
31765
+ return;
31766
+ }
31767
+ if (inFence)
31768
+ return;
31769
+ let i = 0;
31770
+ for (; i < line.length; ) {
31771
+ if (inDollarBlock) {
31772
+ line.startsWith("$$", i) && !isEscapedDelimiterAt(line, i) ? (inDollarBlock = !1, i += 2) : i++;
31773
+ continue;
31774
+ }
31775
+ if (inBracketMath) {
31776
+ line.startsWith("\\]", i) && !isEscapedDelimiterAt(line, i) ? (inBracketMath = !1, i += 2) : i++;
31777
+ continue;
31778
+ }
31779
+ let ch = line[i];
31780
+ if (ch === "`") {
31781
+ let runLen = countRepeatedChar(line, i, "`"), closeIndex = findCodeSpanCloseIndex(line, i + runLen, runLen);
31782
+ if (closeIndex === -1)
31783
+ break;
31784
+ i = closeIndex + runLen;
31785
+ continue;
31786
+ }
31787
+ if (ch === "\\") {
31788
+ let next = line[i + 1];
31789
+ next === "[" && !isEscapedDelimiterAt(line, i) ? (inBracketMath = !0, i += 2) : (next === "]" && isEscapedDelimiterAt(line, i), i += 2);
31790
+ continue;
31791
+ }
31792
+ if (ch === "$") {
31793
+ if (line[i + 1] === "$" && !isEscapedDelimiterAt(line, i)) {
31794
+ inDollarBlock = !0, singleDollarOpen = !1, i += 2;
31795
+ continue;
31796
+ }
31797
+ if (singleDollarOpen) {
31798
+ singleDollarOpen = !1, i++;
31799
+ continue;
31800
+ }
31801
+ let after = line[i + 1];
31802
+ (after === void 0 || after !== " " && after !== " " && !/\d/.test(after)) && (singleDollarOpen = !0), i++;
31803
+ continue;
31804
+ }
31805
+ i++;
31806
+ }
31807
+ };
31808
+ return {
31809
+ scanTo: (target) => {
31810
+ for (; scanned < target; ) {
31811
+ let newlineIndex = source.indexOf(`
31812
+ `, scanned), lineEndRaw = newlineIndex === -1 || newlineIndex >= target ? target : newlineIndex, lineEnd$2 = lineEndRaw > scanned && source[lineEndRaw - 1] === "\r" ? lineEndRaw - 1 : lineEndRaw;
31813
+ if (processLine(source.slice(scanned, lineEnd$2), scanned), newlineIndex === -1 || newlineIndex >= target) {
31814
+ scanned = target;
31815
+ break;
31816
+ }
31817
+ singleDollarOpen = !1, scanned = newlineIndex + 1;
31818
+ }
31819
+ },
31820
+ inMath: () => inDollarBlock || inBracketMath || singleDollarOpen
31821
+ };
31822
+ }
31823
+ function transformStreamingSafeMarkdown(source, isFinal, md, options) {
31824
+ let safeMarkdown = source.replace(/([^\\])\r(ight|ho)/g, "$1\\r$2"), latexSplitMathScanner = createLatexSplitMathScanner(safeMarkdown);
31825
+ if (safeMarkdown = safeMarkdown.replace(/([^\\])\r?\n(abla|eq|ot|exists)/g, (full, before, cmd, offset) => {
31826
+ latexSplitMathScanner.scanTo(offset + 1);
31827
+ let shouldReconstruct = latexSplitMathScanner.inMath();
31828
+ return latexSplitMathScanner.scanTo(offset + full.length), shouldReconstruct ? `${before}\\n${cmd}` : full;
31829
+ }), isFinal || (safeMarkdown.endsWith("- *") && (safeMarkdown = safeMarkdown.replace(/- \*$/, "- \\*")), /(?:^|\n)\s*-\s*$/.test(safeMarkdown) ? safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*-\s*$/, (m) => m.startsWith(`
31723
31830
  `) ? `
31724
31831
  ` : "") : /(?:^|\n)\s*--\s*$/.test(safeMarkdown) ? safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*--\s*$/, (m) => m.startsWith(`
31725
31832
  `) ? `
@@ -31731,7 +31838,7 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
31731
31838
  ` : "")) : /(?:^|\n)\s*\d+[.)]\s+\*{1,3}\s*$/.test(safeMarkdown) ? safeMarkdown = safeMarkdown.replace(/((?:^|\n)\s*\d+[.)]\s+)(\*{1,3})\s*$/, (_, prefix, stars) => `${prefix}${stars.split("").map(() => "\\*").join("")}`) : /(?:^|\n)\s*\d+[.)]\s*$/.test(safeMarkdown) ? safeMarkdown = safeMarkdown.replace(/(?:^|\n)\s*\d+[.)]\s*$/, (m) => m.startsWith(`
31732
31839
  `) ? `
31733
31840
  ` : "") : /\n[[(]\n*$/.test(safeMarkdown) && (safeMarkdown = safeMarkdown.replace(/(\n\[|\n\()+\n*$/g, `
31734
- `)), safeMarkdown = stripPendingExplicitMathTail(safeMarkdown, md), safeMarkdown = getStreamingAdmonitionOpenTailReplacement(safeMarkdown, options.customHtmlTags) ?? safeMarkdown), options.customHtmlTags?.length && safeMarkdown.includes("<")) {
31841
+ `)), safeMarkdown = getStreamingAdmonitionOpenTailReplacement(safeMarkdown, options.customHtmlTags) ?? safeMarkdown), options.customHtmlTags?.length && safeMarkdown.includes("<")) {
31735
31842
  let tags = normalizeCustomHtmlTags(options.customHtmlTags);
31736
31843
  if (tags.length && (safeMarkdown = ensureBlankLineBeforeInlineMultilineCustomHtmlBlocks(safeMarkdown, tags), safeMarkdown = normalizeCustomHtmlOpeningTagSameLine(safeMarkdown, tags), safeMarkdown = ensureBlankLineBeforeCustomHtmlBlocks(safeMarkdown, tags), safeMarkdown = ensureBlankLineAfterCustomHtmlCloseBeforeBlockMarkerSameLine(safeMarkdown, tags), safeMarkdown.includes("</")))
31737
31844
  for (let tag of tags) {
@@ -31739,7 +31846,26 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
31739
31846
  safeMarkdown = safeMarkdown.replace(re, "$1$2$2");
31740
31847
  }
31741
31848
  }
31742
- isFinal || (safeMarkdown = stripDanglingHtmlLikeTail(safeMarkdown));
31849
+ return isFinal || (safeMarkdown = stripDanglingHtmlLikeTail(safeMarkdown)), safeMarkdown;
31850
+ }
31851
+ function getSafeMarkdown(md, sourceMarkdown, isFinal, options) {
31852
+ let owner = md, mode = `${isFinal ? "final" : "stream"}:${(options.customHtmlTags ?? []).join(",")}`, previous = safeMarkdownCache.get(owner), safeMarkdown;
31853
+ if (!isFinal && !options.customHtmlTags?.length && previous && previous.mode === mode && sourceMarkdown.length >= previous.source.length && sourceMarkdown.startsWith(previous.source)) {
31854
+ let windowStart = Math.max(0, previous.source.length - SAFE_MARKDOWN_WINDOW_MARGIN - SAFE_MARKDOWN_WINDOW_OVERLAP), transformed = transformStreamingSafeMarkdown(sourceMarkdown.slice(windowStart), isFinal, md, options), overlapLength = previous.source.length - windowStart;
31855
+ safeMarkdown = transformed.length >= overlapLength && transformed.slice(0, overlapLength) === previous.safeMarkdown.slice(-overlapLength) ? previous.safeMarkdown.slice(0, previous.safeMarkdown.length - overlapLength) + transformed : transformStreamingSafeMarkdown(sourceMarkdown, isFinal, md, options);
31856
+ } else
31857
+ safeMarkdown = transformStreamingSafeMarkdown(sourceMarkdown, isFinal, md, options);
31858
+ return isFinal || (safeMarkdown = stripPendingExplicitMathTail(safeMarkdown, md)), safeMarkdownCache.set(owner, {
31859
+ source: sourceMarkdown,
31860
+ safeMarkdown,
31861
+ mode
31862
+ }), safeMarkdown;
31863
+ }
31864
+ function parseMarkdownToStructure(markdown, md, options = {}) {
31865
+ let timing = getParseTiming(options), parseStartedAt = timing ? getParserNow() : 0, isFinal = !!options.final, sourceMarkdown = (markdown ?? "").toString();
31866
+ shouldResetTopLevelStreamCacheForFinalAutoParse(md, options) && (md.stream.reset(), clearTolerantMathBoundaryStreamCache(md), safeMarkdownCache.delete(md));
31867
+ let safeMarkdown = getSafeMarkdown(md, sourceMarkdown, isFinal, options);
31868
+ timing && addTiming(timing, "safeMarkdownMs", getParserNow() - parseStartedAt);
31743
31869
  let standaloneHtmlDocument = parseStandaloneHtmlDocument(safeMarkdown);
31744
31870
  if (standaloneHtmlDocument) {
31745
31871
  if (options.includeSourceMap) {
@@ -31756,8 +31882,8 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
31756
31882
  }
31757
31883
  return finishParsedNodes(standaloneHtmlDocument, options, timing, parseStartedAt);
31758
31884
  }
31759
- let tokens = parseTopLevelTokens(md, safeMarkdown, { __markstreamFinal: isFinal }, options);
31760
- if (!tokens || !Array.isArray(tokens))
31885
+ let tokenizeStartedAt = timing ? getParserNow() : 0, tokens = parseTopLevelTokens(md, safeMarkdown, { __markstreamFinal: isFinal }, options);
31886
+ if (timing && addTiming(timing, "tokenizeMs", getParserNow() - tokenizeStartedAt), !tokens || !Array.isArray(tokens))
31761
31887
  return finishParsedNodes([], options, timing, parseStartedAt);
31762
31888
  let pre = options.preTransformTokens, post = options.postTransformTokens, transformedTokens = tokens;
31763
31889
  pre && typeof pre == "function" && (transformedTokens = pre(transformedTokens) || transformedTokens);
@@ -31779,7 +31905,11 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
31779
31905
  }, timing) : result = postResult;
31780
31906
  }
31781
31907
  }
31782
- if (hasTopLevelHtmlBlock(result) && (result = mergeSplitTopLevelHtmlBlocks(result, isFinal, safeMarkdown, internalOptions), result = combineStructuredDetailsHtmlBlocks(result, safeMarkdown, md, internalOptions, isFinal)[0], result = structureGenericHtmlBlockChildren(result, md, internalOptions, isFinal)), isFinal) {
31908
+ if (hasTopLevelHtmlBlock(result)) {
31909
+ let htmlPassesStartedAt = timing ? getParserNow() : 0;
31910
+ result = mergeSplitTopLevelHtmlBlocks(result, isFinal, safeMarkdown, internalOptions), result = combineStructuredDetailsHtmlBlocks(result, safeMarkdown, md, internalOptions, isFinal)[0], result = structureGenericHtmlBlockChildren(result, md, internalOptions, isFinal), timing && addTiming(timing, "htmlBlockPassesMs", getParserNow() - htmlPassesStartedAt);
31911
+ }
31912
+ if (isFinal) {
31783
31913
  let seen = /* @__PURE__ */ new WeakSet(), finalizeHtmlBlockLoading = (value) => {
31784
31914
  if (!value || typeof value != "object" || seen.has(value))
31785
31915
  return;
@@ -31800,7 +31930,11 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
31800
31930
  function processTokens(tokens, options) {
31801
31931
  if (!tokens || !Array.isArray(tokens))
31802
31932
  return [];
31803
- let result = [], linkifyContext = createLinkifyDemotionContextTracker(options), includeSourceMap = options?.includeSourceMap === !0, i = 0;
31933
+ let result = [], linkifyContext = createLinkifyDemotionContextTracker(options), seedRaws = options?.__linkifyDemotionSeed;
31934
+ if (Array.isArray(seedRaws) && seedRaws.length)
31935
+ for (let raw of seedRaws)
31936
+ linkifyContext.remember(String(raw ?? ""));
31937
+ let includeSourceMap = options?.includeSourceMap === !0, i = 0;
31804
31938
  for (; i < tokens.length; ) {
31805
31939
  let handled = parseCommonBlockToken(tokens, i, linkifyContext.options(), containerTokenHandlers);
31806
31940
  if (handled) {
@@ -33531,11 +33665,60 @@ function mergeStyle11(base, overlay) {
33531
33665
  let merged = Object.freeze({ ...base, ...overlay });
33532
33666
  return bucket.set(overlay, merged), merged;
33533
33667
  }
33534
- var activeMarkdownImageGraphics = /* @__PURE__ */ new WeakMap();
33668
+ var activeMarkdownImageGraphics = /* @__PURE__ */ new WeakMap(), markdownImageGraphicIdCache = /* @__PURE__ */ new WeakMap(), preparedMarkdownImageGraphicCache = /* @__PURE__ */ new WeakMap();
33535
33669
  function markdownImageGraphicId(segment, identity) {
33536
- return `md-image:${stableTerminalGraphicNumericId(
33670
+ let cachedIds = markdownImageGraphicIdCache.get(segment);
33671
+ cachedIds || (cachedIds = /* @__PURE__ */ new Map(), markdownImageGraphicIdCache.set(segment, cachedIds));
33672
+ let cached = cachedIds.get(identity);
33673
+ if (cached)
33674
+ return cached;
33675
+ let id = `md-image:${stableTerminalGraphicNumericId(
33537
33676
  `${identity}:${segment.src ?? segment.tex ?? ""}:${segment.displayWidth ?? 0}:${segment.displayHeight ?? 0}:${segment.base64 ?? ""}`
33538
33677
  )}`;
33678
+ return cachedIds.set(identity, id), id;
33679
+ }
33680
+ function prepareMarkdownImageGraphic(segment, identity, protocol, placement) {
33681
+ if (!segment.base64)
33682
+ return null;
33683
+ let preparedByVariant = preparedMarkdownImageGraphicCache.get(segment);
33684
+ preparedByVariant || (preparedByVariant = /* @__PURE__ */ new Map(), preparedMarkdownImageGraphicCache.set(segment, preparedByVariant));
33685
+ let cacheKey = `${identity}\0${protocol}\0${placement.width}\0${placement.height}\0${placement.sourceX ?? ""}\0${placement.sourceY ?? ""}\0${placement.sourceWidth ?? ""}\0${placement.sourceHeight ?? ""}`, cached = preparedByVariant.get(cacheKey);
33686
+ if (cached)
33687
+ return cached;
33688
+ let id = markdownImageGraphicId(segment, identity), imageId = stableTerminalGraphicNumericId(`image:${id}`), placementId = stableTerminalGraphicNumericId(`placement:${id}`), sequence = protocol === "kitty" ? createKittyGraphicsSequence(segment.base64, {
33689
+ imageId,
33690
+ placementId,
33691
+ columns: placement.width,
33692
+ rows: placement.height,
33693
+ sourceX: placement.sourceX,
33694
+ sourceY: placement.sourceY,
33695
+ sourceWidth: placement.sourceWidth,
33696
+ sourceHeight: placement.sourceHeight,
33697
+ zIndex: -1
33698
+ }) : protocol === "iterm2" ? createIterm2InlineImageSequence(segment.base64, {
33699
+ width: placement.width,
33700
+ height: placement.height,
33701
+ preserveAspectRatio: !0,
33702
+ doNotMoveCursor: !0
33703
+ }) : "";
33704
+ if (!sequence)
33705
+ return null;
33706
+ let prepared = Object.freeze({
33707
+ id,
33708
+ sequence,
33709
+ clearSequence: protocol === "kitty" ? createKittyDeleteGraphicsSequence({ imageId, placementId }) : void 0,
33710
+ resizeSequence: protocol === "kitty" ? createKittyPlacementSequence({
33711
+ imageId,
33712
+ placementId,
33713
+ columns: placement.width,
33714
+ rows: placement.height,
33715
+ sourceX: placement.sourceX,
33716
+ sourceY: placement.sourceY,
33717
+ sourceWidth: placement.sourceWidth,
33718
+ sourceHeight: placement.sourceHeight
33719
+ }) : void 0
33720
+ });
33721
+ return preparedByVariant.set(cacheKey, prepared), prepared;
33539
33722
  }
33540
33723
  function rememberMarkdownImageGraphic(terminal, id, rect) {
33541
33724
  let active = activeMarkdownImageGraphics.get(terminal);
@@ -33566,57 +33749,47 @@ function clearMarkdownImageGraphics(terminal, rect) {
33566
33749
  for (let [id, item] of active)
33567
33750
  rect && (item.x >= rect.x + rect.w || item.x + item.w <= rect.x || item.y >= rect.y + rect.h || item.y + item.h <= rect.y) || clearTrackedMarkdownImageGraphic(terminal, id);
33568
33751
  }
33569
- function queueMarkdownImageGraphic(terminal, segment, identity, rect) {
33752
+ function queueMarkdownImageGraphic(terminal, segment, identity, rect, placementOverride) {
33570
33753
  if (!segment.base64)
33571
33754
  return "unavailable";
33572
33755
  let output = getTerminalGraphicsOutput(terminal), protocol = output?.capabilities.preferredProtocol;
33573
33756
  if (!output?.capabilities.supported || !isTerminalGraphicsProtocol(protocol))
33574
33757
  return "unavailable";
33575
- let width = Math.max(1, Math.floor(segment.displayWidth ?? rect.w)), height = Math.max(1, Math.floor(segment.displayHeight ?? 1)), id = markdownImageGraphicId(segment, identity), imageId = stableTerminalGraphicNumericId(`image:${id}`), placementId = stableTerminalGraphicNumericId(`placement:${id}`), sequence = protocol === "kitty" ? createKittyGraphicsSequence(segment.base64, {
33576
- imageId,
33577
- placementId,
33578
- columns: width,
33579
- rows: height,
33580
- zIndex: -1
33581
- }) : protocol === "iterm2" ? createIterm2InlineImageSequence(segment.base64, {
33582
- width,
33583
- height,
33584
- preserveAspectRatio: !0,
33585
- doNotMoveCursor: !0
33586
- }) : "";
33587
- if (!sequence)
33758
+ let placement = placementOverride ?? {
33759
+ width: Math.max(1, Math.floor(segment.displayWidth ?? rect.w)),
33760
+ height: Math.max(1, Math.floor(segment.displayHeight ?? 1))
33761
+ }, prepared = prepareMarkdownImageGraphic(segment, identity, protocol, placement);
33762
+ if (!prepared)
33588
33763
  return "unavailable";
33589
- let clearSequence = protocol === "kitty" ? createKittyDeleteGraphicsSequence({
33590
- imageId,
33591
- placementId
33592
- }) : void 0, resizeSequence = protocol === "kitty" ? createKittyPlacementSequence({
33593
- imageId,
33594
- placementId,
33595
- columns: width,
33596
- rows: height
33597
- }) : void 0, accepted = output.queue({
33598
- id,
33764
+ let accepted = output.queue({
33765
+ id: prepared.id,
33599
33766
  x: rect.x,
33600
33767
  y: rect.y,
33601
- w: width,
33602
- h: height,
33768
+ w: placement.width,
33769
+ h: placement.height,
33603
33770
  protocol,
33604
- sequence,
33605
- resizeSequence,
33606
- clearSequence,
33771
+ sequence: prepared.sequence,
33772
+ resizeSequence: prepared.resizeSequence,
33773
+ clearSequence: prepared.clearSequence,
33774
+ placementMoveWithoutClear: protocol === "kitty",
33607
33775
  fallbackText: segment.alt ?? (segment.kind === "math" ? segment.raw ?? segment.tex ?? "math" : "image")
33608
33776
  });
33609
33777
  return markdownImageDebug(
33610
- `queue id=${id}`,
33778
+ `queue id=${prepared.id}`,
33611
33779
  `accepted=${accepted ? "true" : "false"}`,
33612
33780
  `x=${rect.x}`,
33613
33781
  `y=${rect.y}`,
33614
- `w=${width}`,
33615
- `h=${height}`,
33782
+ `w=${placement.width}`,
33783
+ `h=${placement.height}`,
33616
33784
  `visibleW=${rect.w}`,
33617
33785
  `displayW=${segment.displayWidth ?? ""}`,
33618
33786
  `displayH=${segment.displayHeight ?? ""}`
33619
- ), accepted && rememberMarkdownImageGraphic(terminal, id, { x: rect.x, y: rect.y, w: width, h: height }), accepted ? "queued" : "rejected";
33787
+ ), accepted && rememberMarkdownImageGraphic(terminal, prepared.id, {
33788
+ x: rect.x,
33789
+ y: rect.y,
33790
+ w: placement.width,
33791
+ h: placement.height
33792
+ }), accepted ? "queued" : "rejected";
33620
33793
  }
33621
33794
  function collectVisibleMarkdownImageGraphicIds(rows, options) {
33622
33795
  let keepIds = /* @__PURE__ */ new Set();
@@ -33632,7 +33805,7 @@ function collectVisibleMarkdownImageGraphicIds(rows, options) {
33632
33805
  let logicalX = 0;
33633
33806
  for (let [segmentIndex, segment] of row.segments.entries()) {
33634
33807
  let segmentStart = logicalX, segmentEnd = logicalX + segment.cells;
33635
- if (logicalX = segmentEnd, !segment.graphic || segmentEnd <= clipStart || segmentStart >= clipEnd || Math.max(segmentStart, clipStart) !== segmentStart)
33808
+ if (logicalX = segmentEnd, !segment.graphic || segmentEnd <= clipStart || segmentStart >= clipEnd)
33636
33809
  continue;
33637
33810
  let height = Math.max(1, Math.floor(segment.graphic.displayHeight ?? 1));
33638
33811
  if (rowIndex + height <= firstRow || rowIndex >= lastRow)
@@ -33648,10 +33821,74 @@ function collectVisibleMarkdownImageGraphicIds(rows, options) {
33648
33821
  }
33649
33822
  return keepIds;
33650
33823
  }
33824
+ function queueClippedVisibleMarkdownImageGraphics(terminal, rows, options) {
33825
+ let queuedIds = /* @__PURE__ */ new Set(), output = getTerminalGraphicsOutput(terminal);
33826
+ if (options.w <= 0 || options.h <= 0 || !output?.capabilities.supported || output.capabilities.preferredProtocol !== "kitty")
33827
+ return queuedIds;
33828
+ let clipStart = Math.max(0, Math.floor(options.clipStart)), firstRow = Math.min(rows.length, Math.max(0, Math.floor(options.rowOffset))), lastRow = Math.min(rows.length, firstRow + Math.max(0, Math.floor(options.h))), scanStart = firstRow;
33829
+ for (; scanStart > 0 && (rows[scanStart]?.segments.length ?? 0) === 0; )
33830
+ scanStart--;
33831
+ for (let rowIndex = scanStart; rowIndex < lastRow; rowIndex++) {
33832
+ let row = rows[rowIndex];
33833
+ if (!row)
33834
+ continue;
33835
+ let logicalX = 0;
33836
+ for (let [segmentIndex, segment] of row.segments.entries()) {
33837
+ let segmentStart = logicalX;
33838
+ if (logicalX += segment.cells, !segment.graphic?.base64)
33839
+ continue;
33840
+ let fullWidth = Math.max(1, Math.floor(segment.graphic.displayWidth ?? segment.cells)), fullHeight = Math.max(1, Math.floor(segment.graphic.displayHeight ?? 1)), fullRect = {
33841
+ x: options.x + segmentStart - clipStart,
33842
+ y: options.y + rowIndex - firstRow,
33843
+ w: fullWidth,
33844
+ h: fullHeight
33845
+ }, visibleRect = {
33846
+ x: Math.max(options.x, fullRect.x),
33847
+ y: Math.max(options.y, fullRect.y),
33848
+ w: Math.min(options.x + options.w, fullRect.x + fullRect.w) - Math.max(options.x, fullRect.x),
33849
+ h: Math.min(options.y + options.h, fullRect.y + fullRect.h) - Math.max(options.y, fullRect.y)
33850
+ };
33851
+ if (visibleRect.w <= 0 || visibleRect.h <= 0 || visibleRect.x === fullRect.x && visibleRect.y === fullRect.y && visibleRect.w === fullRect.w && visibleRect.h === fullRect.h || options.isGraphicCovered?.(visibleRect))
33852
+ continue;
33853
+ let naturalWidth = Math.floor(segment.graphic.naturalWidth ?? 0), naturalHeight = Math.floor(segment.graphic.naturalHeight ?? 0);
33854
+ if (naturalWidth <= 0 || naturalHeight <= 0)
33855
+ continue;
33856
+ let offsetX = visibleRect.x - fullRect.x, offsetY = visibleRect.y - fullRect.y, sourceX = Math.floor(offsetX * naturalWidth / fullWidth), sourceY = Math.floor(offsetY * naturalHeight / fullHeight), sourceRight = Math.max(
33857
+ sourceX + 1,
33858
+ Math.min(naturalWidth, Math.ceil((offsetX + visibleRect.w) * naturalWidth / fullWidth))
33859
+ ), sourceBottom = Math.max(
33860
+ sourceY + 1,
33861
+ Math.min(
33862
+ naturalHeight,
33863
+ Math.ceil((offsetY + visibleRect.h) * naturalHeight / fullHeight)
33864
+ )
33865
+ ), identity = `${row.key}:${segmentIndex}`;
33866
+ queueMarkdownImageGraphic(
33867
+ terminal,
33868
+ segment.graphic,
33869
+ identity,
33870
+ { x: visibleRect.x, y: visibleRect.y, w: visibleRect.w },
33871
+ {
33872
+ width: visibleRect.w,
33873
+ height: visibleRect.h,
33874
+ sourceX,
33875
+ sourceY,
33876
+ sourceWidth: sourceRight - sourceX,
33877
+ sourceHeight: sourceBottom - sourceY
33878
+ }
33879
+ ) === "queued" && queuedIds.add(markdownImageGraphicId(segment.graphic, identity));
33880
+ }
33881
+ }
33882
+ return queuedIds;
33883
+ }
33651
33884
  function paintMarkdownVisualRow(terminal, row, options) {
33652
33885
  let clipStart = Math.max(0, Math.floor(options.clipStart ?? 0)), clipEnd = clipStart + options.w;
33653
33886
  if (!row) {
33654
- options.clear !== !1 && (terminal.write(spaces(options.w), { x: options.x, y: options.y, style: options.baseStyle }), clearStaleMarkdownImageGraphicsForRow(terminal, options.y, /* @__PURE__ */ new Set(), options.keepGraphicIds));
33887
+ options.clear !== !1 && (terminal.write(spaces(options.w), {
33888
+ x: options.x,
33889
+ y: options.y,
33890
+ style: options.baseStyle
33891
+ }), clearStaleMarkdownImageGraphicsForRow(terminal, options.y, /* @__PURE__ */ new Set(), options.keepGraphicIds));
33655
33892
  return;
33656
33893
  }
33657
33894
  let logicalX = 0, used = 0, queuedGraphics = /* @__PURE__ */ new Set();
@@ -33682,12 +33919,12 @@ function paintMarkdownVisualRow(terminal, row, options) {
33682
33919
  y: options.y,
33683
33920
  w: Math.max(1, Math.floor(segment.graphic.displayWidth ?? visibleCells)),
33684
33921
  h: Math.max(1, Math.floor(segment.graphic.displayHeight ?? 1))
33685
- }, queueResult = !(options.isGraphicCovered?.(graphicRect) === !0) && visibleStart === segmentStart && visibleCells > 0 && queueMarkdownImageGraphic(terminal, segment.graphic, `${row.key}:${segmentIndex}`, {
33922
+ }, graphicCovered = options.isGraphicCovered?.(graphicRect) === !0, graphicId = markdownImageGraphicId(segment.graphic, `${row.key}:${segmentIndex}`), queueResult = options.prequeuedGraphicIds?.has(graphicId) === !0 ? "queued" : !graphicCovered && visibleStart === segmentStart && visibleCells > 0 && queueMarkdownImageGraphic(terminal, segment.graphic, `${row.key}:${segmentIndex}`, {
33686
33923
  x: cellX,
33687
33924
  y: options.y,
33688
33925
  w: visibleCells
33689
33926
  }), graphicAvailable = queueResult || canAttemptMarkdownImageGraphic(terminal, segment.graphic), queuedGraphic = queueResult === "queued", suppressFallback = queuedGraphic || queueResult === "rejected" || graphicAvailable === !0;
33690
- queuedGraphic && queuedGraphics.add(markdownImageGraphicId(segment.graphic, `${row.key}:${segmentIndex}`)), terminal.write(
33927
+ queuedGraphic && queuedGraphics.add(graphicId), terminal.write(
33691
33928
  suppressFallback ? spaces(visibleCells) : sliceByCellsRange(
33692
33929
  segment.fallbackText ?? segment.graphic.alt ?? (segment.graphic.kind === "math" ? segment.graphic.raw ?? segment.graphic.tex ?? "math" : "image"),
33693
33930
  0,
@@ -33768,23 +34005,36 @@ function markdownStyleSignature(style) {
33768
34005
  style.href ?? ""
33769
34006
  ].join("") : "";
33770
34007
  }
34008
+ var markdownRowSignatureCache = /* @__PURE__ */ new WeakMap(), markdownRowGraphicSignatureCache = /* @__PURE__ */ new WeakMap();
33771
34009
  function markdownRowSignature(row) {
33772
- return row ? [
34010
+ if (!row)
34011
+ return "";
34012
+ let cached = markdownRowSignatureCache.get(row);
34013
+ if (cached != null)
34014
+ return cached;
34015
+ let signature = [
33773
34016
  row.key,
33774
34017
  row.plainText,
33775
34018
  row.segments.map(
33776
34019
  (segment) => `${segment.text}${segment.cells}${markdownStyleSignature(segment.style)}${segment.graphic?.src ?? ""}${segment.graphic?.base64 ?? ""}${segment.fallbackText ?? ""}`
33777
34020
  ).join("")
33778
- ].join("") : "";
34021
+ ].join("");
34022
+ return markdownRowSignatureCache.set(row, signature), signature;
33779
34023
  }
33780
34024
  function getWheelScrollInput4(e) {
33781
34025
  let deltaY = Number(e.deltaY ?? 0), deltaMode = typeof e.deltaMode == "number" ? e.deltaMode : void 0;
33782
34026
  return Number.isInteger(deltaY) && deltaY !== 0 && Math.abs(deltaY) >= 100 && Math.abs(deltaY) % 100 === 0 && deltaMode == null ? { deltaY: deltaY / 100, mode: "line" } : deltaMode === 1 ? { deltaY, mode: "line" } : deltaMode === 0 ? { deltaY, mode: "pixel" } : { deltaY, mode: "auto" };
33783
34027
  }
33784
34028
  function rowGraphicSignature(row) {
33785
- return row ? row.segments.map(
33786
- (segment) => segment.graphic ? `${segment.graphic.kind}${segment.graphic.src}${segment.graphic.base64 ?? ""}` : ""
33787
- ).join("") : "";
34029
+ if (!row)
34030
+ return "";
34031
+ let cached = markdownRowGraphicSignatureCache.get(row);
34032
+ if (cached != null)
34033
+ return cached;
34034
+ let signature = row.segments.filter((segment) => segment.graphic).map(
34035
+ (segment) => `${segment.graphic.kind}${segment.graphic.src}${segment.graphic.base64 ?? ""}`
34036
+ ).join("");
34037
+ return markdownRowGraphicSignatureCache.set(row, signature), signature;
33788
34038
  }
33789
34039
  var TVirtualMarkdown = (0, import_vue33.defineComponent)({
33790
34040
  name: "TVirtualMarkdown",
@@ -33835,6 +34085,10 @@ var TVirtualMarkdown = (0, import_vue33.defineComponent)({
33835
34085
  imageOcclusionRects: {
33836
34086
  type: Array,
33837
34087
  default: void 0
34088
+ },
34089
+ rowScrollMode: {
34090
+ type: String,
34091
+ default: "off"
33838
34092
  }
33839
34093
  },
33840
34094
  emits: {
@@ -33848,7 +34102,16 @@ var TVirtualMarkdown = (0, import_vue33.defineComponent)({
33848
34102
  linkAction: (_payload) => !0
33849
34103
  },
33850
34104
  setup(props, { emit }) {
33851
- let instance = (0, import_vue33.getCurrentInstance)(), { terminal, defaultStyle, events, scheduler, selection, widthProvider } = useTerminal(), layout = useLayout(), { visible, rootProps } = useVisibility(), parentEventZ = (0, import_vue33.inject)(EventZIndexContextKey, (0, import_vue33.computed)(() => 0)), eventZ = (0, import_vue33.computed)(() => (parentEventZ.value ?? 0) + (props.zIndex ?? 0)), internalScrollTop = (0, import_vue33.ref)(0), documentVersion = (0, import_vue33.ref)(0), rows = (0, import_vue33.shallowRef)((0, import_vue33.markRaw)([])), pendingSelectionScrollFocusRemap = !1, wheelState = createWheelScrollState(), builtOnce = !1, rebuildVersion = 0, layoutCache, alive = !0, parser = (0, import_vue33.shallowRef)(
34105
+ let instance = (0, import_vue33.getCurrentInstance)(), {
34106
+ terminal,
34107
+ defaultStyle,
34108
+ events,
34109
+ scheduler,
34110
+ selection,
34111
+ widthProvider,
34112
+ render,
34113
+ rendererCapabilities
34114
+ } = useTerminal(), layout = useLayout(), { visible, rootProps } = useVisibility(), parentEventZ = (0, import_vue33.inject)(EventZIndexContextKey, (0, import_vue33.computed)(() => 0)), plane = (0, import_vue33.inject)(RenderPlaneContextKey, (0, import_vue33.ref)("default")), eventZ = (0, import_vue33.computed)(() => (parentEventZ.value ?? 0) + (props.zIndex ?? 0)), internalScrollTop = (0, import_vue33.ref)(0), documentVersion = (0, import_vue33.ref)(0), rows = (0, import_vue33.shallowRef)((0, import_vue33.markRaw)([])), pendingSelectionScrollFocusRemap = !1, wheelState = createWheelScrollState(), builtOnce = !1, rebuildVersion = 0, layoutCache, alive = !0, dirtyRowsHint, renderNodeId = null, parser = (0, import_vue33.shallowRef)(
33852
34115
  (0, import_vue33.markRaw)(
33853
34116
  createTuiMarkdownParser({
33854
34117
  streaming: props.streaming,
@@ -33923,7 +34186,16 @@ var TVirtualMarkdown = (0, import_vue33.defineComponent)({
33923
34186
  let nextRows = nextLayout.rows;
33924
34187
  rows.value = (0, import_vue33.markRaw)(nextRows), enqueuePendingMathImages(), reconcileScrollTop();
33925
34188
  let nextScrollTop = internalScrollTop.value, nextVisibleRows = visibleRowSignatures(nextRows, nextScrollTop), nextVisibleGraphics = visibleRowGraphics(nextRows, nextScrollTop), visibleChanged = prevVisibleRows.length !== nextVisibleRows.length || prevVisibleRows.some((row, index) => row !== nextVisibleRows[index]) || prevVisibleGraphics.some((row, index) => row !== nextVisibleGraphics[index]);
33926
- (!builtOnce || prevScrollTop !== nextScrollTop || visibleChanged) && (documentVersion.value++, selection.refresh());
34189
+ if (!builtOnce || prevScrollTop !== nextScrollTop || visibleChanged) {
34190
+ if (visibleChanged && prevScrollTop === nextScrollTop && prevVisibleGraphics.every((signature) => !signature) && nextVisibleGraphics.every((signature) => !signature)) {
34191
+ let rect = normalizedRect(), changedRows = [], count = Math.max(prevVisibleRows.length, nextVisibleRows.length);
34192
+ for (let index = 0; index < count; index++)
34193
+ prevVisibleRows[index] !== nextVisibleRows[index] && changedRows.push(rect.y + index);
34194
+ markRowsDirty(changedRows);
34195
+ } else
34196
+ markRowsDirty(viewportRows());
34197
+ documentVersion.value++, selection.refresh();
34198
+ }
33927
34199
  }
33928
34200
  function scheduleRebuild() {
33929
34201
  let currentVersion = ++rebuildVersion;
@@ -33980,16 +34252,60 @@ var TVirtualMarkdown = (0, import_vue33.defineComponent)({
33980
34252
  out.push(rowGraphicSignature(sourceRows[index]));
33981
34253
  return out;
33982
34254
  }
34255
+ function viewportRows() {
34256
+ let rect = normalizedRect(), result = [];
34257
+ for (let y = rect.y; y < rect.y + rect.h; y++)
34258
+ result.push(y);
34259
+ return result;
34260
+ }
34261
+ function exposedRowsForDelta2(y, height, delta) {
34262
+ let result = [];
34263
+ if (delta > 0)
34264
+ for (let offset = height - delta; offset < height; offset++)
34265
+ result.push(y + offset);
34266
+ else
34267
+ for (let offset = 0; offset < -delta; offset++)
34268
+ result.push(y + offset);
34269
+ return result;
34270
+ }
34271
+ function markRowsDirty(nextRows) {
34272
+ let rows2 = new Set(dirtyRowsHint);
34273
+ for (let y of nextRows)
34274
+ rows2.add(y);
34275
+ dirtyRowsHint = Array.from(rows2).sort((a, b) => a - b), renderNodeId && render.markDirtyRows(renderNodeId, dirtyRowsHint);
34276
+ }
34277
+ function visibleGraphicsAt(scrollTop) {
34278
+ let rect = normalizedRect(), { x: clipX, y: clipY } = clipOffsets();
34279
+ return collectVisibleMarkdownImageGraphicIds(rows.value, {
34280
+ x: rect.x,
34281
+ y: rect.y,
34282
+ w: rect.w,
34283
+ h: rect.h,
34284
+ rowOffset: scrollTop + clipY,
34285
+ clipStart: clipX
34286
+ }).size > 0;
34287
+ }
34288
+ function isClipped() {
34289
+ let rect = normalizedRect(), full = normalizedFullRect();
34290
+ return rect.x !== full.x || rect.y !== full.y || rect.w !== full.w || rect.h !== full.h;
34291
+ }
34292
+ function markScrollDamage(prevTop, nextTop) {
34293
+ let rect = normalizedRect(), delta = nextTop - prevTop;
34294
+ if (rect.h <= 0 || !delta)
34295
+ return;
34296
+ let size = terminal.size();
34297
+ props.rowScrollMode === "unsafe-full-row" && rendererCapabilities.value.scrollOperations && rect.x === 0 && rect.w >= size.cols && rect.y >= 0 && rect.y + rect.h <= size.rows && !isClipped() && Math.abs(delta) < rect.h && !dirtyRowsHint?.length && !visibleGraphicsAt(prevTop) ? (render.unsafeScrollPlaneRows(plane.value, rect.y, rect.y + rect.h, delta), markRowsDirty(exposedRowsForDelta2(rect.y, rect.h, delta))) : markRowsDirty(viewportRows());
34298
+ }
33983
34299
  function hasControlledScrollTop() {
33984
34300
  return Object.prototype.hasOwnProperty.call(instance?.vnode.props ?? {}, "scrollTop");
33985
34301
  }
33986
34302
  function applyControlledScrollTop(next, remapSelectionFocus = !1) {
33987
34303
  let desired = Math.floor(Number(next) || 0), clamped = clamp18(desired, 0, maxScrollTop()), changed = internalScrollTop.value !== clamped;
33988
- changed && (internalScrollTop.value = clamped), desired !== clamped && (emit("update:scrollTop", clamped), emit("scroll", clamped)), (changed || remapSelectionFocus) && selection.refresh(remapSelectionFocus ? { remapFocus: !0 } : void 0);
34304
+ changed && (markScrollDamage(internalScrollTop.value, clamped), internalScrollTop.value = clamped), desired !== clamped && (emit("update:scrollTop", clamped), emit("scroll", clamped)), (changed || remapSelectionFocus) && selection.refresh(remapSelectionFocus ? { remapFocus: !0 } : void 0);
33989
34305
  }
33990
34306
  function setScrollTop(next, emitChange = !0, refreshOptions) {
33991
34307
  let desired = Math.floor(Number(next) || 0), clamped = clamp18(desired, 0, maxScrollTop()), changed = internalScrollTop.value !== clamped;
33992
- changed && (internalScrollTop.value = clamped), emitChange && (changed || refreshOptions?.emitClampEvenIfUnchanged && desired !== clamped) && (emit("update:scrollTop", clamped), emit("scroll", clamped)), (changed || refreshOptions?.remapSelectionFocus) && selection.refresh(refreshOptions?.remapSelectionFocus ? { remapFocus: !0 } : void 0);
34308
+ changed && (markScrollDamage(internalScrollTop.value, clamped), internalScrollTop.value = clamped), emitChange && (changed || refreshOptions?.emitClampEvenIfUnchanged && desired !== clamped) && (emit("update:scrollTop", clamped), emit("scroll", clamped)), (changed || refreshOptions?.remapSelectionFocus) && selection.refresh(refreshOptions?.remapSelectionFocus ? { remapFocus: !0 } : void 0);
33993
34309
  }
33994
34310
  function reconcileScrollTop() {
33995
34311
  let desired = hasControlledScrollTop() ? Math.floor(Number(props.scrollTop) || 0) : internalScrollTop.value, clamped = clamp18(desired, 0, maxScrollTop());
@@ -34200,16 +34516,18 @@ var TVirtualMarkdown = (0, import_vue33.defineComponent)({
34200
34516
  keydown: onKeydown
34201
34517
  }
34202
34518
  }));
34203
- return (0, import_vue33.watchEffect)(() => {
34519
+ (0, import_vue33.watchEffect)(() => {
34204
34520
  if (!props.autoFocus || !visible.value)
34205
34521
  return;
34206
34522
  let manager = events.value, nodeId = eventNode.id.value;
34207
34523
  nodeId && manager && manager.getFocused() !== nodeId && manager.focus(nodeId);
34208
34524
  }), (0, import_vue33.onBeforeUnmount)(() => {
34209
34525
  alive = !1, rebuildVersion++, unsubscribeGraphicsOutput(), unsubscribeMathRenderer(), unsubscribeMathImage(), clearMarkdownImageGraphics(terminal, fullRect.value);
34210
- }), useRenderNode(() => ({
34526
+ });
34527
+ let renderNode = useRenderNode(() => ({
34211
34528
  zIndex: props.zIndex,
34212
34529
  rect: visible.value ? normalizedRect() : { x: 0, y: 0, w: 0, h: 0 },
34530
+ dirtyRowsHint,
34213
34531
  deps: [
34214
34532
  visible.value,
34215
34533
  absRect.value,
@@ -34222,13 +34540,25 @@ var TVirtualMarkdown = (0, import_vue33.defineComponent)({
34222
34540
  props.imageOcclusionRects
34223
34541
  ],
34224
34542
  paint: (dirtyRows) => {
34225
- withTextWidthProvider(widthProvider, () => {
34543
+ dirtyRowsHint = void 0, withTextWidthProvider(widthProvider, () => {
34226
34544
  if (!visible.value)
34227
34545
  return;
34228
34546
  let r = normalizedRect();
34229
34547
  if (r.w <= 0 || r.h <= 0)
34230
34548
  return;
34231
- let baseStyle = props.style ?? defaultStyle.value, { x: clipX, y: clipY } = clipOffsets(), isGraphicCovered = (rect) => props.imageOcclusionRects?.some((item) => intersectRect(rect, item)) === !0, keepGraphicIds = collectVisibleMarkdownImageGraphicIds(rows.value, {
34549
+ let baseStyle = props.style ?? defaultStyle.value, { x: clipX, y: clipY } = clipOffsets(), isGraphicCovered = (rect) => props.imageOcclusionRects?.some((item) => intersectRect(rect, item)) === !0, prequeuedGraphicIds = queueClippedVisibleMarkdownImageGraphics(
34550
+ terminal,
34551
+ rows.value,
34552
+ {
34553
+ x: r.x,
34554
+ y: r.y,
34555
+ w: r.w,
34556
+ h: r.h,
34557
+ rowOffset: internalScrollTop.value + clipY,
34558
+ clipStart: clipX,
34559
+ isGraphicCovered
34560
+ }
34561
+ ), keepGraphicIds = collectVisibleMarkdownImageGraphicIds(rows.value, {
34232
34562
  x: r.x,
34233
34563
  y: r.y,
34234
34564
  w: r.w,
@@ -34248,6 +34578,7 @@ var TVirtualMarkdown = (0, import_vue33.defineComponent)({
34248
34578
  baseStyle,
34249
34579
  clear: !0,
34250
34580
  keepGraphicIds,
34581
+ prequeuedGraphicIds,
34251
34582
  isGraphicCovered
34252
34583
  });
34253
34584
  };
@@ -34260,7 +34591,10 @@ var TVirtualMarkdown = (0, import_vue33.defineComponent)({
34260
34591
  paintRow(y);
34261
34592
  });
34262
34593
  }
34263
- })), () => (0, import_vue33.h)("span", rootProps);
34594
+ }));
34595
+ return (0, import_vue33.watchEffect)(() => {
34596
+ renderNodeId = renderNode.id.value;
34597
+ }), () => (0, import_vue33.h)("span", rootProps);
34264
34598
  }
34265
34599
  });
34266
34600