fix: only emit style ops for ranges where marks actually changed - #82
Open
frioux wants to merge 1 commit into
Open
fix: only emit style ops for ranges where marks actually changed#82frioux wants to merge 1 commit into
frioux wants to merge 1 commit into
Conversation
updateLoroText re-applied every run's mark attributes over the entire text on every change, including explicit null unmarks for every mark key that appeared anywhere in the text. Loro records each of those mark/unmark ops even when they don't change the visible styles (they still carry meaning under concurrent editing), so a single keystroke of plain typing grew the document by two style ops, and the style anchors they leave behind permanently slow down every styled read of the container. Diff the styles the LoroText holds after the text edit against the ones ProseMirror wants and only apply marks over the ranges that differ. Typing, deleting, and plain pastes now emit no style ops at all; mark changes emit ops covering just the changed ranges.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On any text change — a single typed character —
updateLoroTextre-applies every run's mark attributes over the entire text length viaapplyDelta, including explicitnullunmarks over every plain range for every mark key that appears anywhere in the text.Loro records each of those mark/unmark ops even when they don't change the visible styles (and it can't do otherwise: a redundant-looking unmark still has meaning under concurrent editing). So a keystroke of styled typing produced 3 CRDT ops instead of 1, and every one of those redundant style ops leaves a permanent style anchor in the container state that every later styled read (
toDelta) has to pay for. On heavily edited paragraphs we measured styled reads degrading from ~5µs to multiple milliseconds — felt as per-keystroke typing lag — plus snapshots bloated by the accumulated anchors (135KB for 4KB of visible text on a real page).Fix
After the (unchanged) minimal text diff, diff the styles the LoroText now holds against the ones ProseMirror wants, run by run, and apply marks only over the ranges that differ:
configTextStyle;Validation
Added
tests/update-loro-text.test.ts, which asserts the exact op stream viaexportJsonUpdates:nonemark extended by PM) still get repaired, over just the inserted rangepnpm test,pnpm lint, andpnpm check-formatall pass.Complementary to #81: that PR stops PM and Loro from disagreeing about default-inclusive mark boundaries; this one stops the binding from emitting redundant style ops whether or not they disagree. Either merges cleanly without the other.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KQw7nfh6KaUhQy6ZQUZwMm