virtual_list: Measure the sample item at the viewport width for vertical lists (#2774)
## Summary - Fixes phantom horizontal scrolling in vertical lists: when the sample item used for size measurement (by default the first row) contains a long non-wrapping text (e.g. `.truncate()`), measuring it with `AvailableSpace::MinContent` reports the full untruncated text width. That width becomes the list's horizontal scroll content size (`content_size.width`), while the visible rows are actually laid out at the viewport width — so the list can be scrolled sideways into blank space. - Record the content bounds size (excluding padding and border) in `VirtualListScrollHandleState` during prepaint, and pass it as a definite width constraint to `measure_item` for vertical lists. Relative widths (`flex_1`, `w_1_4`, …) and text truncation then resolve exactly the same way as for the visible rows, so the measured width matches the real layout. - Items that are genuinely wider than the viewport (e.g. via `min_w`) still measure larger than the definite constraint and keep their horizontal scroll range. Horizontal lists are unchanged. On the first frame (no recorded size yet) the old `MinContent` behavior is used and the measurement converges on the next frame. Observed in Longbridge's watchlist list mode: a long stock name in the first row made the whole list horizontally scrollable with a blank area on the right, even though the name itself was properly truncated with an ellipsis. ## Related PRs - Regression surfaced by #2571: before it, `VirtualList` always measured flattened item `0` — for `List` that is the (often empty) section-header entry, so `content_size.width` was ~0 and the phantom scroll range never appeared. #2571 correctly routes the real first data row into the measurement (needed for the completion menu's intrinsic width), which exposed the unconstrained `MinContent` measurement fixed here. This PR keeps #2571's behavior intact — `ListSizingBehavior::Infer` still measures intrinsic width on the first frame, and the completion popover constraints are unchanged. ## Test plan - [x] `cargo test -p gpui-base` (369 tests, including the `virtual_list` visible-range/deferred-scroll tests) - [x] Verified in the Longbridge desktop app via a path patch: with a long name in the first watchlist row, the list no longer scrolls horizontally and no blank area appears; truncation still shows the ellipsis - [ ] Verify a vertical list whose rows are intentionally wider than the viewport still scrolls horizontally - [ ] Verify the editor completion menu still sizes to its longest row (#2571's scenario) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Y
Ylin committed
ddba2ef356d637392c08ef773fe1bbf3dd536deb
Parent: ea5fc0c
Committed by GitHub <noreply@github.com>
on 8/20/2026, 3:22:46 AM