-
-
Notifications
You must be signed in to change notification settings - Fork 469
Description
Describe the issue
Summary
When confirming an IME composition inside brackets with bracketMatching() enabled (default afterCursor: true), text before the opening bracket visually disappears on Chrome. The document data remains intact, and the display recovers when the cursor moves to another line. This does not reproduce on Safari.
Environment
@codemirror/language6.12.2@codemirror/view6.40.0@codemirror/state6.6.0- Browser: Chrome (also Firefox; Safari is unaffected)
- Input method: IME (tested with Japanese and Chinese)
Steps to reproduce
- Enable
bracketMatching()with the defaultafterCursor: true - Type a line containing brackets, e.g.:
## Template (test) - Place the cursor inside the brackets:
## Template (|test) - Delete
testand re-type using IME; confirm with Enter or Space - After confirmation,
## Templatevisually disappears — only(confirmed text)is rendered
Expected: ## Template (confirmed text) displays correctly.
Actual: Everything before ( vanishes from the display. Document state is correct. Moving the cursor to a different line restores the missing text.
Analysis
The paused flag added in @codemirror/language 6.12.2 (for #1324) correctly defers bracket matching decoration updates while view.composing is true. However, once compositionend fires, view.composing immediately becomes false, and the very next update cycle synchronously recalculates bracket decorations with no post-composition delay.
On Chrome, the sequence is:
- IME confirmation →
compositionendfires synchronously view.composingdrops tofalse- DOM observer flushes, transaction is dispatched
bracketMatcher.update()runs, sees composition has ended, unpauses- With
afterCursor: true, cursor is at…(confirmed text|)—matchBracketsfinds)before the cursor and its matching(, appliesDecoration.mark(cm-matchingBracket) to both - The mark wrapping
(mutates the DOM before Chrome's rendering engine has settled its post-composition state, causing the preceding text node to drop from the render tree
Safari is unaffected because @codemirror/view delays compositionend dispatch by 20ms via setTimeout when Safari fires an insertText event during composition. This gives the browser time to finalize DOM changes before decorations are reapplied. Chrome receives no such delay.
Workaround
Disable the default bracketMatching() and re-add it with afterCursor: false. This prevents the cursor-before-bracket match that triggers the problematic decoration, but at the cost of losing bracket highlighting when the cursor is immediately before a bracket.
Suggested fix
Add a short post-composition guard to the bracketMatcher plugin, similar to the compositionEndedAt checks already used in @codemirror/view for Safari key handling. For example, after compositionend, keep the plugin paused for ~80ms before allowing decoration recalculation. This would give all browsers time to settle their post-composition DOM state.
Browser and platform
MacOS: 15.7.4(24G517, Google Chrome: v46.0.7680.154
Reproduction link
No response