Files
tolaria/docs/adr/0037-codemirror-language-markdown-highlighting.md
lucaronin 4eca9ca8fd fix: prevent infinite render loop when creating notes
updateEntry's .map() always returned a new array even when no entry matched,
causing unnecessary state changes. During note creation, addEntry uses
startTransition (deferred) while markContentPending calls updateEntry
synchronously — the entry doesn't exist yet, so the no-op .map() produced a
new reference that cascaded into "Maximum update depth exceeded" (which
surfaced as React error #185 in the production WKWebView build).

The fix makes updateEntry bail out (return prev) when no entry was changed,
preventing the spurious state update. Also removes the defensive try-catch
from the previous fix attempt and cleans up an unnecessary setToastMessage
dependency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 10:33:40 +02:00

2.6 KiB

type, id, title, status, date
type id title status date
ADR 0037 Language-based markdown syntax highlighting in raw editor active 2026-04-01

Context

The raw editor (CodeMirror 6, introduced in ADR-0022) initially had a custom frontmatterHighlight extension that used regex-based decoration for YAML frontmatter and headings. Markdown body content had no syntax highlighting at all, making the raw editor feel like a plain textarea despite being a full CodeMirror instance.

Extending the custom regex-based approach to cover all markdown syntax (bold, italic, links, lists, blockquotes, code) would have been brittle and hard to maintain.

Decision

Replace the custom heading decoration in frontmatterHighlight.ts with @codemirror/lang-markdown (the official CodeMirror language package). A custom HighlightStyle maps CodeMirror highlight tags to visual styles for headings, bold, italic, strikethrough, links, lists, blockquotes, and inline code. The frontmatter YAML plugin is retained for YAML-specific colouring but its heading decoration is removed in favour of the language parser.

Options considered

  • Option A (chosen): @codemirror/lang-markdown with custom HighlightStyle — uses the official, maintained language parser; future highlight rules are one CSS declaration. Downside: adds a new npm dependency; the custom frontmatter plugin must be kept separately.
  • Option B: Extend the custom regex plugin to cover all markdown — no new dependency. Downside: regex-based tokenisation is fragile (e.g., nested formatting), already proving hard to maintain after the heading/frontmatter overlap bug.
  • Option C: Switch to a markdown-aware editor (e.g., Milkdown, Monaco) — full-featured. Downside: major migration, breaks the dual-editor architecture in ADR-0022, significant scope.

Consequences

  • @codemirror/lang-markdown added to package.json — this is the only new runtime dependency introduced by this change.
  • frontmatterHighlight.ts is simplified (heading decoration removed); markdownHighlight.ts is the new extension responsible for body highlighting.
  • The two extensions are composed in useCodeMirror.ts — YAML frontmatter block is still styled by the custom plugin; everything else by the language parser.
  • Future syntax highlighting changes (e.g., task lists, tables) can be added by extending the HighlightStyle without modifying the parser.
  • Re-evaluate if @codemirror/lang-markdown conflicts with the custom frontmatter YAML handling as the editor evolves (e.g., if frontmatter block needs to be parsed as a code block rather than decorated text).