Skip to content

fix: prevent syntax highlighting from disappearing after initial display#562

Merged
batonogov merged 2 commits intomainfrom
fix/556-syntax-highlight-disappears
Mar 25, 2026
Merged

fix: prevent syntax highlighting from disappearing after initial display#562
batonogov merged 2 commits intomainfrom
fix/556-syntax-highlight-disappears

Conversation

@batonogov
Copy link
Copy Markdown
Owner

Summary

Fixes #556 — syntax highlighting shows correctly when a file is first opened, then disappears after a short time.

Root cause: A cascading re-highlight cycle during makeNSView:

  1. textView.string = text fired textDidChange (delegate was already set before text assignment)
  2. textDidChange wrote parent.textupdateContentcachedHighlightResult = nil, contentVersion++
  3. Synchronous highlight applied colors successfully (colors visible briefly)
  4. SwiftUI re-render → updateNSViewupdateContentIfNeeded saw textChanged = true (from contentVersion bump) AND languageChanged = true (lastLanguage was "")
  5. textView.string = text (same text!) stripped all highlight attributes since isRichText = false
  6. Re-highlight attempted but could be delayed or overwritten by further cycles

Fixes applied:

  • Defer delegate assignment in makeNSView until after text and highlighting are configured, preventing textDidChange from firing during initial setup
  • Initialize lastLanguage/lastFileName from parent in Coordinator.init, eliminating false languageChanged on first updateNSView
  • Guard textView.string = text with textView.string != text to avoid stripping attributes when contentVersion bumps but text content is identical
  • Skip cached highlight result when language changed (stale grammar matches from old language)

Test plan

  • New HighlightPersistenceTests (8 tests) covering:
    • Coordinator initializes lastLanguage/lastFileName from parent
    • First updateNSView skips unnecessary update when language matches
    • Same-content version bump preserves highlight colors
    • Different content correctly replaces text
    • Language change triggers fresh highlight (not stale cache)
    • Delegate set after text does not fire textDidChange
    • Delegate after text preserves highlight attributes
    • cancelPendingHighlight increments generation
  • Updated CodeEditorStaticTests.coordinatorInitialState for new init behavior
  • All existing coordinator, highlight cache, async highlight, and concurrent highlight tests pass
  • SwiftLint clean on all changed files

…lay (#556)

The root cause was a cascading re-highlight cycle during makeNSView:

1. textView.string = text fired textDidChange (delegate was already set)
2. textDidChange wrote parent.text → updateContent → cachedHighlightResult = nil,
   contentVersion++
3. Synchronous highlight applied colors successfully
4. SwiftUI re-render → updateNSView → updateContentIfNeeded saw textChanged = true
   (from contentVersion bump) AND languageChanged = true (lastLanguage was "")
5. textView.string = text (same text!) stripped all highlight attributes
6. Re-highlight attempted but could fail or be delayed

Three fixes:
- Defer textView.delegate assignment in makeNSView until AFTER text and
  highlighting are configured, preventing textDidChange from firing during setup
- Initialize Coordinator.lastLanguage/lastFileName from parent in init,
  eliminating the false languageChanged detection on first updateNSView
- Guard textView.string = text with textView.string != text to avoid
  stripping attributes when contentVersion bumps but text is identical
- Skip cached highlight result when language changed (stale grammar matches)
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 25, 2026

✅ Code Coverage: 73.3%

Threshold: 70%

Coverage is above the minimum threshold.

Generated by CI — see job summary for detailed file-level breakdown.

@batonogov batonogov merged commit f8cc976 into main Mar 25, 2026
13 checks passed
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.

bug: syntax highlighting disappears after initially appearing

1 participant