Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-startup-file-window.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"hunkdiff": patch
---

Fill the review stream on first paint instead of leaving it blank until the user scrolls.
14 changes: 14 additions & 0 deletions src/ui/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ export function App({
const layoutToggleScrollTopRef = useRef<number | null>(null);
const cancelCopySelectionRef = useRef<(() => void) | null>(null);
const [layoutToggleRequestId, setLayoutToggleRequestId] = useState(0);
const [scrollEdgeRequest, setScrollEdgeRequest] = useState<{
id: number;
edge: "top" | "bottom";
}>({ id: 0, edge: "top" });
const [transientNoticeText, setTransientNoticeText] = useState<string | null>(null);
const [layoutMode, setLayoutMode] = useState<LayoutMode>(bootstrap.initialMode);
const [themeId, setThemeId] = useState(
Expand Down Expand Up @@ -1395,6 +1399,15 @@ export function App({
delta: number,
unit: "step" | "viewport" | "content" | "half" = "viewport",
) => {
if (unit === "content") {
if (delta !== 0) {
setScrollEdgeRequest((current) => ({
id: current.id + 1,
edge: delta > 0 ? "bottom" : "top",
}));
}
return;
}
if (unit === "half") {
const scrollBox = diffScrollRef.current;
if (!scrollBox) return;
Expand Down Expand Up @@ -2407,6 +2420,7 @@ export function App({
wrapToggleScrollTop={wrapToggleScrollTopRef.current}
layoutToggleScrollTop={layoutToggleScrollTopRef.current}
layoutToggleRequestId={layoutToggleRequestId}
scrollEdgeRequest={scrollEdgeRequest}
selectedFileTopAlignRequestId={review.selectedFileTopAlignRequestId}
selectedHunkRevealRequestId={review.selectedHunkRevealRequestId}
cursorLine={cursorLine}
Expand Down
43 changes: 43 additions & 0 deletions src/ui/AppHost.interactions.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,14 @@ async function flush(setup: Awaited<ReturnType<typeof testRender>>) {
});
}

/** Let initial viewport measurement enable row windowing before testing imperative scroll jumps. */
async function settleViewportMeasurement(setup: Awaited<ReturnType<typeof testRender>>) {
await act(async () => {
await Bun.sleep(32);
await setup.renderOnce();
});
}

/** Let wrap-toggle renders and follow-up layout retries settle before asserting on the frame. */
async function settleWrapToggle(setup: Awaited<ReturnType<typeof testRender>>) {
await flush(setup);
Expand Down Expand Up @@ -2462,6 +2470,7 @@ describe("App interactions", () => {

try {
await flush(setup);
await settleViewportMeasurement(setup);
let frame = setup.captureCharFrame();
expect(frame).toContain("line01 = 1001");

Expand All @@ -2485,6 +2494,39 @@ describe("App interactions", () => {
}
});

test("G supersedes a pending selected-hunk reveal", async () => {
const setup = await testRender(
<AppHost bootstrap={createCrossFileHunkNavigationBootstrap()} />,
{
width: 120,
height: 16,
},
);

try {
await flush(setup);
await settleViewportMeasurement(setup);
await pressHunkNavigationKey(setup, "]", 1);

await act(async () => {
await setup.mockInput.pressKey("g", { shift: true });
});
await flush(setup);
await act(async () => {
await Bun.sleep(160);
await setup.renderOnce();
});

const frame = setup.captureCharFrame();
expect(frame).toContain("export const mid = 4;");
expect(frame).not.toContain("line 021 changed");
} finally {
await act(async () => {
setup.renderer.destroy();
});
}
});

test("pager mode also supports G and g top/bottom jumps", async () => {
const before =
Array.from(
Expand Down Expand Up @@ -2525,6 +2567,7 @@ describe("App interactions", () => {

try {
await flush(setup);
await settleViewportMeasurement(setup);
let frame = setup.captureCharFrame();
expect(frame).toContain("line01 = 1001");

Expand Down
Loading
Loading