дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
fix(vcs): keep Git Log rows painted while dragging the scrollbar (#1914)
Dragging the Git Log scrollbar through a long history stuttered and showed blank rows: the native scrollbar scrolls asynchronously in WebKit, so the virtual list rendered rows a frame or more after the new offset was painted. The list now uses a scrollbar drawn in the DOM (`Scrollbar` in `src/ui`) that sets the offset from pointer events and notifies scroll listeners at once, so the virtualizer renders the matching rows before the next paint. Rows are keyed by slot so a large jump updates the mounted rows instead of rebuilding them, overscan is lowered, and rows rendered mid-scroll draw their graph without edge hit targets, which come back once scrolling stops. Adds a `gitLogScrollbar` perf scenario with budgets.
Цей коміт міститься в:
1 джерело
159c2d6fd2
коміт
b99fe1704b
8 files changed
+414
-46
No files matched your search
@@ -51,6 +51,9 @@
|
||||
"gitLog.tbtMs": 50,
|
||||
"gitLog.arrowKeyP95Ms": 20,
|
||||
"gitLog.arrowKeyMissedFramePct": 5,
|
||||
"gitLogScrollbar.frameP95Ms": 17.5,
|
||||
"gitLogScrollbar.droppedFramesPct": 2,
|
||||
"gitLogScrollbar.tbtMs": 50,
|
||||
|
||||
"resizePanels.droppedFramesPct": 2,
|
||||
"resizePanels.bottomDroppedFramesPct": 2,
|
||||
|
||||
@@ -316,6 +316,52 @@ const gitLog: Scenario = {
|
||||
},
|
||||
};
|
||||
|
||||
/** Scrollbar-sized jumps across a loaded graph, rather than incremental wheel scrolling. */
|
||||
const gitLogScrollbar: Scenario = {
|
||||
id: "gitLogScrollbar",
|
||||
title: "Drag through a loaded 6k-commit Git Log",
|
||||
async run(h) {
|
||||
await h.page.evaluate(async () => {
|
||||
const probe = (
|
||||
window as never as {
|
||||
__openideaPerf: {
|
||||
fakeGitLog(n: number): void;
|
||||
runAction(id: string): Promise<boolean>;
|
||||
};
|
||||
}
|
||||
).__openideaPerf;
|
||||
probe.fakeGitLog(6000);
|
||||
await probe.runAction("vcs.showLog");
|
||||
});
|
||||
const list = h.page.getByRole("listbox", { name: "Commits" });
|
||||
await list.waitFor();
|
||||
await list.evaluate(async (element) => {
|
||||
for (let i = 0; i < 300 && element.scrollHeight < 6000 * 26; i++) {
|
||||
element.scrollTop = element.scrollHeight;
|
||||
await new Promise(requestAnimationFrame);
|
||||
}
|
||||
if (element.scrollHeight < 6000 * 26) throw new Error("Git Log did not finish loading");
|
||||
element.scrollTop = 0;
|
||||
});
|
||||
await h.page.waitForTimeout(200);
|
||||
const refresh = await h.refreshMs();
|
||||
const t0 = await h.now();
|
||||
await h.inPage((p) => p.startFrames());
|
||||
await list.evaluate(async (element) => {
|
||||
const max = element.scrollHeight - element.clientHeight;
|
||||
for (let i = 0; i < 180; i++) {
|
||||
element.scrollTop = ((i < 90 ? i : 180 - i) / 90) * max;
|
||||
await new Promise(requestAnimationFrame);
|
||||
}
|
||||
});
|
||||
const frames = await h.inPage((p) => p.stopFrames());
|
||||
return {
|
||||
...frameSummary(frames, refresh),
|
||||
tbtMs: totalBlockingTime(await h.longTasksSince(t0)),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Dragging the splitters with an editor, the Project tree and the Git Log
|
||||
* open: every pointer move resizes the islands, so each frame relays them out.
|
||||
@@ -555,6 +601,7 @@ export const SCENARIOS: Scenario[] = [
|
||||
completion,
|
||||
consoleOutput,
|
||||
gitLog,
|
||||
gitLogScrollbar,
|
||||
resizePanels,
|
||||
keyRepeat,
|
||||
scroll,
|
||||
|
||||
Reference in new issue
Заблокувати користувача