Skip to content

Commit 6686128

Browse files
committed
refactor(review): keep gap toggle selection in controller
1 parent 124d3e2 commit 6686128

3 files changed

Lines changed: 57 additions & 21 deletions

File tree

src/ui/App.tsx

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import {
1818
maxFileCodeLineWidth,
1919
resolveCodeViewportWidth,
2020
} from "./diff/codeColumns";
21-
import { selectGapForKeyboardToggle } from "./diff/expandCollapsedRows";
22-
import { trailingCollapsedLines } from "./diff/pierre";
2321
import { useAppKeyboardShortcuts } from "./hooks/useAppKeyboardShortcuts";
2422
import { useHunkSessionBridge } from "./hooks/useHunkSessionBridge";
2523
import { useMenuController } from "./hooks/useMenuController";
@@ -337,24 +335,6 @@ export function App({
337335
[review.selectHunk],
338336
);
339337

340-
/** Toggle the leading gap of the selected hunk, scanning forward to the next
341-
* available gap (or the trailing gap) when nothing is reachable above. */
342-
const toggleGapForSelectedHunk = useCallback(() => {
343-
const file = selectedFile;
344-
if (!file?.sourceFetcher) {
345-
return;
346-
}
347-
348-
const target = selectGapForKeyboardToggle(
349-
file.metadata.hunks,
350-
selectedHunkIndex,
351-
trailingCollapsedLines(file.metadata) > 0,
352-
);
353-
if (target) {
354-
review.toggleGap(file.id, target);
355-
}
356-
}, [review, selectedFile, selectedHunkIndex]);
357-
358338
const canRefreshCurrentInput = canReloadInput(bootstrap.input);
359339
const watchEnabled = Boolean(bootstrap.input.options.watch && canRefreshCurrentInput);
360340

@@ -582,7 +562,7 @@ export function App({
582562
switchMenu,
583563
toggleAgentNotes,
584564
toggleFocusArea,
585-
toggleGapForSelectedHunk,
565+
toggleGapForSelectedHunk: review.toggleSelectedHunkGap,
586566
toggleHelp,
587567
toggleHunkHeaders,
588568
toggleLineNumbers,

src/ui/hooks/useReviewController.test.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,41 @@ describe("useReviewController", () => {
438438
}
439439
});
440440

441+
test("toggleSelectedHunkGap expands the nearest gap for the current selection", async () => {
442+
const beforeLines = Array.from({ length: 30 }, (_, index) => `line ${index + 1}`);
443+
const afterLines = [...beforeLines];
444+
afterLines[4] = "line 5 changed";
445+
const after = lines(...afterLines);
446+
const sourceFetcher = createTestSourceFetcher((side) => (side === "new" ? after : null));
447+
const file = createTestDiffFile({
448+
after,
449+
before: lines(...beforeLines),
450+
context: 3,
451+
id: "alpha",
452+
path: "alpha.ts",
453+
sourceFetcher,
454+
});
455+
456+
const { controllerRef, setup } = await renderReviewController([file]);
457+
458+
try {
459+
await flush(setup);
460+
461+
await act(async () => {
462+
expectValue(controllerRef.current).toggleSelectedHunkGap();
463+
});
464+
await flush(setup);
465+
466+
const expanded = expectValue(controllerRef.current).expandedGapsByFileId["alpha"];
467+
expect(expanded?.has("before:0")).toBe(true);
468+
expect(sourceFetcher.calls).toEqual(["new"]);
469+
} finally {
470+
await act(async () => {
471+
setup.renderer.destroy();
472+
});
473+
}
474+
});
475+
441476
test("toggleGap surfaces an error status when the fetcher resolves null", async () => {
442477
const failingFetcher = createTestSourceFetcher(() => null);
443478

src/ui/hooks/useReviewController.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import type {
3434
SessionLiveCommentSummary,
3535
} from "../../hunk-session/types";
3636
import type { FileSourceStatus } from "../diff/expandCollapsedRows";
37+
import { selectGapForKeyboardToggle } from "../diff/expandCollapsedRows";
38+
import { trailingCollapsedLines } from "../diff/pierre";
3739
import { findNextHunkCursor } from "../lib/hunks";
3840
import {
3941
buildReviewState,
@@ -94,6 +96,7 @@ export interface ReviewController {
9496
sidebarEntries: ReviewState["sidebarEntries"];
9597
sourceStatusByFileId: Record<string, FileSourceStatus>;
9698
toggleGap: (fileId: string, gapKey: string) => void;
99+
toggleSelectedHunkGap: () => void;
97100
visibleFiles: DiffFile[];
98101
addLiveComment: (
99102
input: CommentToolInput,
@@ -404,6 +407,23 @@ export function useReviewController({ files }: { files: DiffFile[] }): ReviewCon
404407
[allFiles],
405408
);
406409

410+
/** Toggle the collapsed gap nearest to the current hunk selection. */
411+
const toggleSelectedHunkGap = useCallback(() => {
412+
const file = selectedFile;
413+
if (!file?.sourceFetcher) {
414+
return;
415+
}
416+
417+
const target = selectGapForKeyboardToggle(
418+
file.metadata.hunks,
419+
selectedHunkIndex,
420+
trailingCollapsedLines(file.metadata) > 0,
421+
);
422+
if (target) {
423+
toggleGap(file.id, target);
424+
}
425+
}, [selectedFile, selectedHunkIndex, toggleGap]);
426+
407427
/** Resolve one session-daemon navigation request against the current review state and select it. */
408428
const navigateToLocation = useCallback(
409429
(input: NavigateToHunkToolInput): NavigatedSelectionResult => {
@@ -652,6 +672,7 @@ export function useReviewController({ files }: { files: DiffFile[] }): ReviewCon
652672
sidebarEntries,
653673
sourceStatusByFileId,
654674
toggleGap,
675+
toggleSelectedHunkGap,
655676
visibleFiles,
656677
addLiveComment,
657678
addLiveCommentBatch,

0 commit comments

Comments
 (0)