fix(editor): prevent syntax highlight color flicker on state recreation (#2304)#2457
fix(editor): prevent syntax highlight color flicker on state recreation (#2304)#2457Elitex07 wants to merge 3 commits into
Conversation
Greptile SummaryThis PR caches the resolved CodeMirror language extension on each
Confidence Score: 4/5Safe to merge; the caching logic is sound and cache invalidation is handled correctly on mode changes and signature mismatches. The fix correctly addresses the flicker by pre-populating the language extension cache. The only notable concern is that dispatchLanguageExtension writes both cache fields before calling targetEditor.dispatch(), so a dispatch failure leaves the cache populated while markLanguageReady was never called. The existing hasLanguageSupport check in shouldApplyLanguage mitigates this in practice, but the ordering is a subtle invariant worth tightening. The cache-write ordering inside dispatchLanguageExtension in src/lib/editorManager.js is the one spot worth a second look. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant F as EditorFile
participant EM as EditorManager
participant CM as CodeMirror
Note over F,CM: First activation (cold)
EM->>EM: resolveLanguageExtension(file, sig)
EM->>EM: cache miss → langExtFn()
alt Async language load
EM-->>CM: return [] (placeholder)
CM->>CM: "EditorState.create(exts=[])"
Note over CM: Renders with no syntax highlighting
EM->>EM: promise.then(ext)
EM->>F: "__cmCachedLanguageExtension = ext"
EM->>F: "__cmCachedLanguageSignature = sig"
EM->>CM: dispatchLanguageExtension(ext)
Note over CM: Syntax highlights applied (flicker)
else Sync language load
EM-->>CM: return ext
EM->>F: "__cmCachedLanguageExtension = ext"
EM->>F: "__cmCachedLanguageSignature = sig"
CM->>CM: "EditorState.create(exts=[ext])"
end
Note over F,CM: Subsequent activation (warm, same sig)
EM->>EM: resolveLanguageExtension(file, sig)
EM->>F: cache check → HIT
EM->>EM: markLanguageReady(true)
EM-->>CM: return __cmCachedLanguageExtension
CM->>CM: "EditorState.create(exts=[cachedExt])"
Note over CM: Syntax highlights applied immediately, no flicker
Note over F,CM: setMode() invalidation
F->>F: "__cmCachedLanguageExtension = null"
F->>F: "__cmCachedLanguageSignature = null"
Note over F: Forces fresh load on next activation
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant F as EditorFile
participant EM as EditorManager
participant CM as CodeMirror
Note over F,CM: First activation (cold)
EM->>EM: resolveLanguageExtension(file, sig)
EM->>EM: cache miss → langExtFn()
alt Async language load
EM-->>CM: return [] (placeholder)
CM->>CM: "EditorState.create(exts=[])"
Note over CM: Renders with no syntax highlighting
EM->>EM: promise.then(ext)
EM->>F: "__cmCachedLanguageExtension = ext"
EM->>F: "__cmCachedLanguageSignature = sig"
EM->>CM: dispatchLanguageExtension(ext)
Note over CM: Syntax highlights applied (flicker)
else Sync language load
EM-->>CM: return ext
EM->>F: "__cmCachedLanguageExtension = ext"
EM->>F: "__cmCachedLanguageSignature = sig"
CM->>CM: "EditorState.create(exts=[ext])"
end
Note over F,CM: Subsequent activation (warm, same sig)
EM->>EM: resolveLanguageExtension(file, sig)
EM->>F: cache check → HIT
EM->>EM: markLanguageReady(true)
EM-->>CM: return __cmCachedLanguageExtension
CM->>CM: "EditorState.create(exts=[cachedExt])"
Note over CM: Syntax highlights applied immediately, no flicker
Note over F,CM: setMode() invalidation
F->>F: "__cmCachedLanguageExtension = null"
F->>F: "__cmCachedLanguageSignature = null"
Note over F: Forces fresh load on next activation
|
Cached resolved language extensions (
file.__cmCachedLanguageExtensionandfile.__cmCachedLanguageSignature) on theEditorFileinstance. WhenresolveLanguageExtensionruns for a file whose language signature matches the cache, it synchronously returns the cached extension immediately.