fix: prevent IME double-resync from stripping list bullet after Enter#722
Open
tfkci wants to merge 1 commit into
Open
fix: prevent IME double-resync from stripping list bullet after Enter#722tfkci wants to merge 1 commit into
tfkci wants to merge 1 commit into
Conversation
When the user presses Enter at the end of a list item, checkForParagraphs creates a new paragraph and inserts its startText (e.g. "• " or "1. ") into tempTextFieldValue. Some IMEs (Samsung keyboard and others) respond to this programmatic insertion by sending one or more removal callbacks that remove exactly those startText characters from the new, still-empty paragraph. These are NOT user Backspaces — they are the IME reconciling its internal buffer. The previous code had no guard for this. Each resync was treated as a real deletion, demoting the paragraph type to DefaultParagraph and losing the bullet/number formatting. Fix: - Add `justInsertedListParagraph` flag, armed by checkForParagraphs whenever it inserts a non-empty startText for a new list paragraph. - In handleRemovingCharacters, compute `isComposeResync` by checking all of: the flag is set, the paragraph is a list type, the paragraph body is still empty, the removal count equals exactly the startText length, and the removal starts exactly at the startText position. - On resync detection: restore the startText into tempTextFieldValue (so updateAnnotatedString sees no net change) and do NOT clear the flag — repeated resyncs from persistent IMEs are handled identically. - The flag is cleared on the first real user action (any non-resync removal, or the next character addition). Adds three regression tests: single resync, double resync on unordered list, and double resync on ordered list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Problem
When the user presses Enter at the end of a list item,
checkForParagraphscreates a new paragraph and inserts itsstartText(e.g."• "or"1. ") programmatically intotempTextFieldValue. Some IMEs — in particular Samsung Keyboard on Galaxy devices — respond to this insertion by sending one or more removal callbacks that remove exactly thosestartTextcharacters from the new, still-empty paragraph.These callbacks go through
TextFieldKeyInput(dispatchKeyEvent) rather than the standard IME composition protocol, so they arrive as normalonValueChangecalls. Without a guard, each one is treated as a user Backspace, demoting the paragraph type toDefaultParagraphand losing the bullet/number formatting.The issue is especially visible with Samsung's word-prediction keyboard, which tends to send the resync twice (double-resync). A single-shot boolean guard (armed once, cleared on first resync) would leave the second resync unprotected.
Fix
justInsertedListParagraphflag — armed bycheckForParagraphsimmediately after it inserts a non-emptystartTextfor a new list paragraph.isComposeResyncpositional check inhandleRemovingCharacters— fires when ALL of the following are true:justInsertedListParagraphis setstartTextexists, nothing typed yet)startTextlengthstartTextpositionOn resync detection: restore the
startTextintotempTextFieldValue(soupdateAnnotatedStringsees no net change) and do NOT clear the flag — every subsequent identical resync is handled the same way. The flag is cleared on the first real user action (non-resync removal, or next character typed).Tests
Three new regression tests in
RichTextStateIMETest:testSingleResyncAfterEnter_unorderedListtestDoubleResyncAfterEnter_unorderedListtestDoubleResyncAfterEnter_orderedListAll existing tests continue to pass.
Affected devices
Samsung Galaxy A-series, M-series, and other Samsung devices with Samsung Keyboard word suggestions enabled. Potentially any IME that routes certain operations through
dispatchKeyEvent.