Breadcrumbs: fix clipped-item reveal and avoid redundant aligned scroll updates#315385
Breadcrumbs: fix clipped-item reveal and avoid redundant aligned scroll updates#315385
Conversation
Co-authored-by: dmitrivMS <9581278+dmitrivMS@users.noreply.github.com>
|
@copilot See my comment above |
Co-authored-by: dmitrivMS <9581278+dmitrivMS@users.noreply.github.com>
Addressed in cafaf5a. I replaced the selection-specific change with a root-cause fix in I also rewrote the tests to avoid private-field fakes and now cover left-clipped, right-clipped, fully-visible (no scroll), plus non-minimal behavior via |
Updated review — much better, with one suggested additionThe new revision addresses essentially every concern from my previous comment:
Couple of small notes on this PR by itself:
Relationship to #315384#315384 takes a different angle: it's a perf fix — early-return from They conflict textually — both edit the same
So #315384's perf benefit is real and not covered by #315385 alone — specifically for the Recommendation: take #315385 as the base, fold in #315384's optimization, close #315384The cleanest combined shape is to extend export function getBreadcrumbScrollLeft(scrollLeft: number, width: number, itemOffsetLeft: number, itemWidth: number, minimal: boolean): number | undefined {
const itemEnd = itemOffsetLeft + itemWidth;
let target: number;
if (!minimal) {
target = itemOffsetLeft;
} else if (itemOffsetLeft < scrollLeft) {
target = itemOffsetLeft;
} else if (itemEnd > scrollLeft + width) {
target = itemEnd - width;
} else {
return undefined; // already fully visible
}
return target === scrollLeft ? undefined : target; // no-op if already aligned
}And add one more unit test mirroring #315384's intent: Drop #315384's test entirely — it has the same Conflict logisticsWhichever PR lands second will need a trivial rebase against the other. Combining into one PR (this one) is cleaner: single |
|
@copilot See my comment above |
Co-authored-by: dmitrivMS <9581278+dmitrivMS@users.noreply.github.com>
Addressed in 195c069. I updated |
|
Latest revision ( This PR now supersedes #315384 — closing that one in favor of this. The UX concern from #168824 is preserved: |
setItems re-renders the DOM synchronously, but DomScrollableElement only refreshes its cached scrollWidth via a deferred scanDomNode (double-RAF) inside _updateScrollbar. The reveal call that follows setItems on the cursor-update path could therefore clamp setScrollPosition against a stale scrollWidth, leaving the new last crumb right-clipped depending on the previous scroll state. Call scanDomNode() at the start of _reveal so dimensions are current before computing the target. Also switch reveal(item) to minimal reveal so cursor-update doesn't reset the user's manual horizontal scroll when the target is already visible. revealLast() keeps its existing pin-to-left semantics.
There was a problem hiding this comment.
Pull request overview
Fixes breadcrumbs horizontal reveal behavior so items are fully revealed when partially clipped (especially right-clipped cases in narrow editor groups), and avoids redundant scroll updates when the reveal target is already aligned.
Changes:
- Introduces
getBreadcrumbScrollLeft(...)to compute minimal vs non-minimal reveal targets and returnundefinedfor no-op scrolls. - Updates
BreadcrumbsWidgetreveal/select paths to use minimal reveal by default and skip redundant scroll position churn. - Adds focused unit tests covering left/right clipping, fully visible, and aligned no-op cases.
Show a summary per file
| File | Description |
|---|---|
| src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts | Centralizes reveal math in getBreadcrumbScrollLeft and updates reveal/selection to use minimal scrolling and avoid redundant scroll updates. |
| src/vs/base/test/browser/ui/breadcrumbs/breadcrumbsWidget.test.ts | Adds unit tests validating reveal target calculations for clipped/visible/aligned scenarios. |
Copilot's findings
- Files reviewed: 2/2 changed files
- Comments generated: 1
| * @param itemOffsetLeft The item's left offset in the breadcrumbs strip. | ||
| * @param itemWidth The item's width. | ||
| * @param minimal Whether to use minimal scrolling semantics. | ||
| * Returns `undefined` when no scrolling is required. |
Description
In narrow editor groups, breadcrumb items could remain partially visible when their left edge was inside the viewport but their right edge was clipped. This change fixes reveal calculation at the source and now also avoids redundant scroll updates when the computed reveal target is already aligned with the current scroll position.
Behavior change
BreadcrumbsWidget._revealcomputes minimal horizontal scrolling for both clipping cases:itemOffsetLeft < scrollLeft)itemOffsetLeft + itemWidth > scrollLeft + width)_selectuses minimal reveal behavior (_reveal(selectedIndex, true)) to avoid click-induced left-edge pinning regressions.minimal === falsestill targets the item's left edge).getBreadcrumbScrollLeft(...)now returnsundefinedwhen the computed target equals the currentscrollLeft, so_revealskips redundantsetScrollPosition/setRevealOnScrollchurn.Scope
getBreadcrumbScrollLeft(...).Coverage
Testing
npm run transpile-clientnode test/unit/browser/index.js --run src/vs/base/test/browser/ui/breadcrumbs/breadcrumbsWidget.test.ts --browser chromiumFixes #187463
Fixes #168824