lineWrapping: clicking past end of trailing wrapped segment places cursor on previous visual line #1693
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Describe the issue
When
EditorView.lineWrappingis enabled and a line wraps across multiple visual lines, clicking in the horizontal whitespace after the last character on the trailing visual line places the cursor at the equivalent x-position on the visual line above, rather than at the end of the logical line.Expected: the cursor lands at the end of the line (after the last character of the trailing wrapped segment), matching what the user clicked near.
Actual: the cursor lands mid-line on the previous visual row. Typing then inserts in the wrong place, which is jarring.
Browser and platform
Firefox 149.0 on Linux
Reproduction link
https://codemirror.net/try/#c=aW1wb3J0IHttaW5pbWFsU2V0dXAsIEVkaXRvclZpZXd9IGZyb20gImNvZGVtaXJyb3IiCgpuZXcgRWRpdG9yVmlldyh7CiAgZG9jOiAiVEhJUyBMSU5FIElTIExPTkcuIFRISVMgTElORSBJUyBMT05HLiBUSElTIExJTkUgSVMgTE9ORy4gVEhJUyBMSU5FIElTIExPTkcuIFRISVMgTElORSBJUyBMT05HLiBUSElTIExJTkUgSVMgTE9ORy4gVEhJUyBMSU5FIElTIExPTkcuIFRISVMgTElORSBJUyBMT05HLiBUSElTIExJTkUgSVMgTE9ORy4gVEhJUyBMSU5FIElTIExPTkcuIFRISVMgTElORSBJUyBMT05HLiBUSElTIExJTkUgSVMgTE9ORy4gVEhJUyBMSU5FIElTIExPTkcuIFRISVMgTElORSBJUyBMT05HLiBUSElTIExJTkUgSVMgTE9ORy5cblxuQSBOZXcgTGluZS4iLAogIGV4dGVuc2lvbnM6IFsKICAgIEVkaXRvclZpZXcubGluZVdyYXBwaW5nCiAgXSwKICBwYXJlbnQ6IGRvY3VtZW50LmJvZHkKfSkK
I cannot reproduce this. Attached patch adds a test, but it's passing on all browsers (including Firefox Linux) that I have access to. Are you sure this problem still exists in @codemirror/view 6.41.0?
Weird. I'm able to repro it reliably in FF 149.0 on Linux using the link in the description. However Chrome on linux seems to work correctly, as does FF 149 on Windows.
Here's what I see on FF in linux:
https://github.com/user-attachments/assets/017b5b1c-04ea-4212-abbc-31c577e54e27
(My setup probably represents a vanishingly small number of real users, to be fair)
I was able to trace the behavior I'm seeing to this check in
cursor.ts:github.com/codemirror/view@59b1fed1f0/src/cursor.ts (L333-L340)I think there's some weird subpixel rendering artifacts in FF's font rendering (at least in my environment).
above.bottomturns out to be some fraction of a pixel lower thanclosestRect.top, so the scan nudges me into the row above.One thought might be to gate the check on overlaps >= 1 px (e.g.
above && above.bottom - closestRect.top >= 1) to guard against such subpixel weirdness. I just don't know well enough whether this would break the case that the check was designed to catch in the first place.Edit to add: I also was able to reproduce a similar issue (with I believe the same root cause) in Chrome (Linux; still no repro on Windows), if the line above included a lint diagnostic. It adds
paddingBottom: "0.7px"which extends theaboverow's rects into closestRect by 0.7px, and results in the same issue during cursor scan. Reproduction (just make sure LINT appears on the second-to-last visual line).Very odd. I guess you're getting a different font or font library than I am getting, leading to different rectangles being returned by
getClientRects, which somehow throws off that code. I tried installing nightly, but still cannot reproduce this. Could you maybe see whatclosestIandclosestRectare when that condition you linked is triggered? Maybe that would make the problem obvious enough to try to fix it blindly.I added some debugging to cursor.ts. Here's what I see in firefox:
If I add a lint diagnostic to something on the line above it's more exaggerated.
In chrome, with the lint example I get:
closestRectseems reasonable though. That's the end of the line. I failed to ask for the value ofabove, which is actually the relevant rectangle determining the decision to recurse into the line above. Any chance you can repeat the experiment and include that too?