text_selection: drag-autoscroll never moved a virtualized list - #2948
text_selection: drag-autoscroll never moved a virtualized list#2948kossoy wants to merge 1 commit into
Conversation
|
Thanks for chasing this down — the symptom you instrumented (726 deltas dispatched, The synthetic wheel does move a virtualized listThe repo already has
The reason is that gpui's So the participant notification is not replacing a dead path — it is running alongside a live one. Consequence: two timers drive the same listAfter this change a scrollable
Autoscroll therefore runs at roughly double its previous speed (the table above), and because one writer is relative-from-now and the other absolute-from-last-frame, they race across repaints: when the participant timer ticks twice between paints, the wheel's stale base snaps the list backwards. That is visible jitter, not just a speed change. The dispatch needs to be exclusive — notify the participant or send the wheel. The natural seam is the The delta uses the wrong rectangle for a self-scrolling participant
Concretely, a scrollable The participant notification should use Smaller things
On the original symptomNone of this explains your field repro, and I'd rather not see it papered over. The wheel path works in the harness, so something in your layout keeps the list's hitbox out of the hit-test set at the clamped synthetic position — another hitbox painted above it, or the list not present in the frame being hit-tested. Worth identifying before locking in a fix, since the exclusive-dispatch design above depends on knowing which participants can rely on the wheel at all. One note for whoever lands this: the test at 🤖 Review assisted by Claude Code |
…g auto-scroll `update_auto_scroll` synthesized a wheel event at a position clamped inside the anchor participant's content mask. For a scrollable `TextView` whose list ends inside that mask (vertical padding on the view, or any layout where the view does not reach its clipping ancestor's edge), the clamped position lands in the band between the list's bottom and the mask's bottom, the list hitbox is not in the hit-test set, and the wheel never scrolls it. Registrations now carry a `self_scroll` flag; `TextView` sets it when `scrollable`. Dispatch is exclusive: a self-scrolling participant is notified through `TextSelectionEvent::AutoScroll` with a delta measured against its own bounds (as `update_participant_auto_scroll` already did), and the synthetic wheel is reserved for participants that scroll through an ancestor. Exactly one timer writes the list. `update_auto_scroll` takes `&Window`; the anchor lookup is shared by `anchor_participant` / `anchor_registration`. Tests: the existing harness test asserts a magnitude bound (ticks x per-frame delta) so a second writer fails it; a new test reproduces the padded reader layout and fails on main.
c6e8e2f to
bee77ea
Compare
|
Thanks for the measurements. Reproduced your table and reworked the branch (force-pushed, now Measurement
The double-write was real; the mechanism I described in the PR body was wrong. Changes per point
Field reproFound. The reader in the field layout is a clipping row containing a Probe on New test Verified: |
update_auto_scrollnotifies the participant — which scrolls itself through itsown list API — only on the branch taken when no
Windowis available:A live drag always passes
Some(window), so the only branch a drag ever tookwas the synthetic-wheel one, and a synthetic
ScrollWheelEventnever reaches avirtualized list's scroll handler while the pointer is captured by the drag. The
working branch was dead code for the one flow that matters. Autoscroll computed
and dispatched a correct delta forever while the list stood still.
Reproduction
Open a long document in a scrollable
TextView. Anchor a selection near the topof the viewport, drag to the bottom edge and hold with small movements for
several seconds.
Instrumented: 726 events with
delta = Some(16.33 px)dispatched,px_offstays
0.0, selection captures only the visible viewport (≈ 2 KB of a 132 KBnote).
Fix
Notify the participant unconditionally, then keep the wheel dispatch for
participants that scroll through an ancestor container rather than a list of
their own — for a participant that handled the notification the wheel is a
no-op.
After: the same 8-second hold scrolls
px_off 0 → 5 382.8and the selectionextends to 38 KB.
crates/base/src/text_selection.rs, +14 lines, no gpui corechange.