From c5786a8913951cc296e41e41702bc51036ec16bb Mon Sep 17 00:00:00 2001 From: JK Date: Mon, 18 May 2026 18:41:47 +0200 Subject: [PATCH] fix lazy multiline latex in callout leads to corrupt live preview --- .../equations/live-preview-equations.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/features/equations/live-preview-equations.ts b/src/features/equations/live-preview-equations.ts index ef994f1..cf4ac03 100644 --- a/src/features/equations/live-preview-equations.ts +++ b/src/features/equations/live-preview-equations.ts @@ -4,7 +4,7 @@ import { editorInfoField } from 'obsidian'; import LatexReferencer from 'main'; import { CONVERTER, getEqNumberPrefix } from 'utils/format'; import type { PluginSettings } from "features/settings/settings"; -import { getCalloutPrefix, isStructuralCalloutLine } from "utils/parse"; +import { CALLOUT_PREFIX_REGEX, getCalloutPrefix, isStructuralCalloutLine } from "utils/parse"; /** @@ -51,6 +51,26 @@ function findMathBlocks(state: EditorState): readonly { from: number; to: number const mathRegex = /\$\$(.*?)\$\$/gs; let mathMatch: RegExpExecArray | null; while ((mathMatch = mathRegex.exec(text)) !== null) { + // Guard against lazy-continuation callout math blocks. + // When the opening $$ is on a callout line (e.g. "> $$") but the closing + // $$ is NOT (lazy continuation), the tag manager would corrupt the document + // by reconstructing the closing with the opening's prefix. + // Only skip blocks with MISMATCHED prefixes; properly-formed callout + // equations (where both $$ share the same prefix) are fine. + const openPos = mathMatch.index; + const openLineStart = text.lastIndexOf('\n', openPos - 1) + 1; + const openPrefix = text.substring(openLineStart, openPos); + + const closePos = mathMatch.index + mathMatch[0].length - 2; // position of closing $$ + const closeLineStart = text.lastIndexOf('\n', closePos - 1) + 1; + const closePrefix = text.substring(closeLineStart, closePos); + + const openCallout = (openPrefix.match(CALLOUT_PREFIX_REGEX) || [''])[0]; + const closeCallout = (closePrefix.match(CALLOUT_PREFIX_REGEX) || [''])[0]; + if (openCallout !== closeCallout) { + continue; + } + mathBlockRanges.push({ from: mathMatch.index, to: mathMatch.index + mathMatch[0].length }); }