Fix diagrams disappearing after switching tabs#4
Conversation
renderMermaidBlocks() and renderVegaBlocks() mark blocks with a data-*-claimed attribute to keep concurrent passes from racing on the same <pre>, but the attribute was never removed. The block selector excludes claimed blocks, so any block left marked is skipped forever. When a render is cancelled mid-loop -- which the MarkdownView effect does on every content or theme change via its cleanup -- the remaining blocks keep the claim. The next pass finds nothing to render and the diagram stays a plain code block. This is why diagrams render on first open but vanish after switching tabs: the initial render completes uninterrupted, while a tab switch changes renderedHTML (and often theme right after), cancelling the in-flight render partway through. Release the claim in a finally block for every block that was not replaced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Please hold off on merging this — I no longer think it's the right fix, and I'd rather say so than let it land. First, what I got wrong: I never verified this in a running build. The comparison I based it on turned out to be invalid — both binaries I was comparing contained the patch, so the "before" case was never actually observed. More importantly, the
The blocks end up unclaimed, unrendered, and with no further pass to pick them up. The diagram stays a plain code block until something changes Two other things surfaced while digging, both independent of this PR:
Rather than patch the claim protocol further, I'd like to try removing the need for it: render Mermaid and Vega into the HTML string inside the I'll close this or replace it with that once I have it verified in a real build. Sorry for the noise. |
|
Closing in favour of #5, which removes the need for the claim protocol rather than patching it. The race described above goes away with it, along with the cancellation plumbing and the revert-then-rerender path. |
Problem
Mermaid and Vega diagrams render on first open, but after switching to
another tab and back they stay as plain code blocks.
Cause
renderMermaidBlocks()marks blocks withdata-mermaid-claimedso twoconcurrent passes cannot race on the same
<pre>:The attribute is never removed, and the block selector excludes claimed
blocks:
'code.language-mermaid:not([data-mermaid-rendered]):not([data-mermaid-claimed])'So a block left marked is skipped by every later pass.
The
MarkdownVieweffect cancels its render on eachrenderedHTMLorthemechange via the cleanup. When the cancel lands inside the loop —after the claim, before
host.replaceWith(wrapper)— the remaining blockskeep the claim forever.
That is exactly the tab-switch path: the first open renders uninterrupted,
while switching tabs changes
renderedHTML(and oftenthemeright after),cancelling the in-flight render partway through.
Note the related inconsistency: the early-exit query (
initial) does notexclude claimed blocks, so the function does not bail out at the
initial.length === 0guard — it proceeds and then finds nothing to do.Fix
Release the claim in a
finallyblock for every block that was not replaced.vega.tshas the identical bug withdata-vega-claimedand is fixed thesame way.
Verification
Reproduced and fixed under Linux (AppImage build, MarkView 1.0.5) with
vouchers.mdandpayments.md, both containing mermaid flowcharts.I also covered the mermaid path with a unit test that drives
renderMermaidBlocks()with a cancel firing inside the loop, then runs asecond pass. It fails against the current code (block stuck in
data-mermaid-claimed, no SVG on the second pass) and passes with thischange. Happy to include it if you want to add a test setup — the project
has none today, so I left it out of this PR.
The
vega.tschange is the same pattern, reviewed by reading rather thanexecuted.
Investigated, fixed and tested with Claude Opus 4.8 (Anthropic) in an
AI-assisted session. I reviewed the diagnosis and verified the fix locally
before opening this PR. The commit carries a
Co-Authored-Bytrailer forthe same reason.