SIGN IN SIGN UP

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