Skip to content

Sync every style field of the configuration in updateNSView - #164

Open
paulscan wants to merge 1 commit into
nodes-app:mainfrom
paulscan:fix/sync-theme-in-updateNSView
Open

Sync every style field of the configuration in updateNSView#164
paulscan wants to merge 1 commit into
nodes-app:mainfrom
paulscan:fix/sync-theme-in-updateNSView

Conversation

@paulscan

@paulscan paulscan commented Aug 31, 2026

Copy link
Copy Markdown

updateNSView copies only a few MarkdownEditorConfiguration fields into the coordinator. It syncs heightBehavior, rawSourceMode, lists, and it syncs services, extensions, and directives when a fingerprint changes. Every other field stays at whatever value makeCoordinator captured on first mount. That includes theme, paragraph, link, markers, codeBlock, inlineCode, taskCheckbox, blockquote, headings, imageEmbed, blockLatex, inlineLatex, thematicBreak, and cursorFollowsSpanInk.

An embedder that swaps configurations at runtime sees nothing change on screen. A palette change from light to dark, a change to heading metrics, or a new link color never reaches the styler. Each rebuild paints the original values back on top of the fresh storage.

What's fixed

updateNSView compares these fields with an internal styleSignature. When any of them differ, it copies them across and clears didInitialFormatting so the rebuild path further down runs and the new values reach text storage. The existing fingerprint checks for services, extensions, and directives keep their behavior. A configuration whose style fields did not change pays only a struct compare.

The style sub-structs (MarkdownEditorTheme, MarkerStyle, HeadingStyle, LinkStyle, ParagraphStyle, and the rest) now conform to Equatable, so the signature compare is a synthesized member check. InlineLatexStyle has a hand-written == because its stored Void placeholder cannot be synthesized.

Tests

Tests/MarkdownEngineTests/ConfigurationStyleSyncTests.swift covers:

  • The signature changes when any style field changes, and stays the
    same for grammar, service, and lifecycle fields.
  • adoptStyleFields copies exactly the style fields and leaves the
    rest alone.
  • After swapping the theme, a rebuild paints body text in the new
    color instead of the one captured on first mount.

swift build and swift test are green.

`updateNSView` used to copy only a handful of `MarkdownEditorConfiguration`
fields — `heightBehavior`, `rawSourceMode`, `lists`, and the
fingerprint-gated `services` / `extensions` / `directives`. Everything
else — `theme`, `paragraph`, `link`, `markers`, `codeBlock`, `inlineCode`,
`taskCheckbox`, `blockquote`, `headings`, `imageEmbed`, `blockLatex`,
`inlineLatex`, `thematicBreak`, `cursorFollowsSpanInk` — was captured
once in `makeCoordinator` and never refreshed, so an embedder flipping
between two configurations (a light/dark palette toggle, a heading-metric
change, a link-ink update) kept whatever those fields were at first mount:
the styler kept reading them off a stale snapshot, and each `[StyledRange]`
rebuild painted the old colors and metrics back over the fresh storage.

The reconcile in `updateNSView` compares the pure-style fields via an
internal `styleSignature`, copies them across when they differ, and
flips `didInitialFormatting` off so the rebuild path below runs and the
new palette / metrics reach text storage. The fingerprint-gated paths
above stay as they were — services and grammar changes still restyle
through their own branches — and a configuration whose style fields are
unchanged pays only a struct compare.

Value-typed configuration sub-structs (`MarkdownEditorTheme`,
`MarkerStyle`, `HeadingStyle`, `LinkStyle`, `ParagraphStyle`, and the
rest) now conform to `Equatable` so the signature compare is a
synthesized member-by-member check. `InlineLatexStyle` has a hand-written
`==` because its stored `Void` placeholder can't be synthesized against.

`Tests/MarkdownEngineTests/ConfigurationStyleSyncTests.swift` pins the
three pieces the fix relies on: the signature flips on every pure-style
field and stays put for grammar/service/lifecycle fields, `adoptStyleFields`
copies exactly the style fields and leaves the rest alone, and a rebuild
after swapping the theme paints body text with the new color rather than
the one captured at first mount.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LNvrf6TPFQ571njp1G98wt
@paulscan
paulscan marked this pull request as ready for review August 31, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant