Fix typing over RTL selection requiring two keypresses - #331077
Fix typing over RTL selection requiring two keypresses#331077jibin jose (jibin7jose) wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Updates the TextAreaWrapper selection accessors to return the textarea’s raw selectionStart/selectionEnd values instead of swapping based on selectionDirection.
Changes:
- Simplified
getSelectionStart()to always returnthis._actual.selectionStart. - Simplified
getSelectionEnd()to always returnthis._actual.selectionEnd.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
||
| public getSelectionStart(): number { | ||
| return this._actual.selectionDirection === 'backward' ? this._actual.selectionEnd : this._actual.selectionStart; | ||
| return this._actual.selectionStart; |
There was a problem hiding this comment.
This change is the correct fix for this input pipeline.
TextAreaState and the input diffing engine (deduceInput) assume standard, normalized selection boundaries (selectionStart <= selectionEnd). Standard browsers also do not support setting a selection range where selectionStart > selectionEnd (doing so collapses the selection).
Swapping selectionStart and selectionEnd for backward/RTL selections violates these assumptions, leading to a state mismatch where the native selection is collapsed and replacePrevCharCnt is incorrectly computed as 1 instead of 0 on the first keypress.
Since the hidden textarea is only used for IME/input bridging and not direct user selection interaction, returning normalized boundaries here is safe and correctly aligns the native state with TextAreaState expectations, solving the double-keypress bug without breaking caret logic.
|
|
||
| public getSelectionEnd(): number { | ||
| return this._actual.selectionDirection === 'backward' ? this._actual.selectionStart : this._actual.selectionEnd; | ||
| return this._actual.selectionEnd; |
There was a problem hiding this comment.
This change is the correct fix for this input pipeline.
TextAreaState and the input diffing engine (deduceInput) assume standard, normalized selection boundaries (selectionStart <= selectionEnd). Standard browsers also do not support setting a selection range where selectionStart > selectionEnd (doing so collapses the selection).
Swapping selectionStart and selectionEnd for backward/RTL selections violates these assumptions, leading to a state mismatch where the native selection is collapsed and replacePrevCharCnt is incorrectly computed as 1 instead of 0 on the first keypress.
Since the hidden textarea is only used for IME/input bridging and not direct user selection interaction, returning normalized boundaries here is safe and correctly aligns the native state with TextAreaState expectations, solving the double-keypress bug without breaking caret logic.
Fixes microsoft/monaco-editor#5448
Description of Proposed Changes
This PR resolves an input bug in the legacy
<textarea>input pipeline (the path used wheneditContextis disabled, such as natively in Safari).TextAreaStateexpects standard, normalized selection bounds (selectionStart <= selectionEnd). However, thegetSelectionStart()andgetSelectionEnd()methods inTextAreaWrapperwere flipping these values for backward/RTL selections. This causedselectionStart > selectionEndto be written and read, which violated native browser behavior (browsers automatically clamp/collapse native selections where start > end) and resulted in a state diff mismatch insidededuceInput(computingreplacePrevCharCnt = 1instead of0).TextAreaWrapper.getSelectionStartandgetSelectionEndto always return standard LTR range bounds, aligning with the expected format inTextAreaStateand maintaining selection synchronization.How to Test
editContext: falseconfigured (or open in Safari with default options).const U = 19.05;).Shift+ArrowLeftonce to select the;character backwards.akey once.;is immediately replaced withaon the first keypress, resulting inconst U = 19.05a.