feat(ui): add comma and period shortcuts to move between files#280
feat(ui): add comma and period shortcuts to move between files#280mvanhorn wants to merge 1 commit intomodem-dev:mainfrom
Conversation
Greptile SummaryAdds
Confidence Score: 5/5Safe to merge — the change adds a purely additive keyboard shortcut with no risk to existing navigation paths. The implementation is self-contained: No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant useKeyboard
participant handleFilterShortcut
participant handleAppShortcut
participant moveToFile
participant selectFile
User->>useKeyboard: press "," or "."
useKeyboard->>handleFilterShortcut: key event
alt filter is focused
handleFilterShortcut-->>useKeyboard: return true (consumed)
else filter not focused
handleFilterShortcut-->>useKeyboard: return false
useKeyboard->>handleAppShortcut: key event
handleAppShortcut->>moveToFile: moveToFile(-1) or moveToFile(+1)
moveToFile->>moveToFile: findIndex in visibleFiles
alt no selected file or boundary reached
moveToFile-->>handleAppShortcut: no-op (return early)
else valid next file
moveToFile->>selectFile: selectFile(nextFile.id, 0, alignFileHeaderTop: true)
selectFile-->>moveToFile: selection updated
end
end
Reviews (1): Last reviewed commit: "feat(ui): add , and . shortcuts to move ..." | Re-trigger Greptile |
Summary
Adds keyboard shortcuts to move between files in the current diff --
,for previous file,.for next file. Mirrors how[/]walks hunks, but at the file level.Why this matters
Per #212 your suggestion: "If the purpose is to just scroll up/down on the file list, what if I just added a keyboard shortcut for file up/down?" This PR ships exactly that -- a global shortcut that works from the diff pane without needing a sidebar-focus state machine.
moveToAnnotatedFile(useReviewController.ts:238) was the architecturally analogous existing function -- it walksannotatedFilesand callsselectFile. This PR addsmoveToFilenext to it. Two deliberate divergences vs.moveToAnnotatedFile:visibleFiles(all files, not just annotated). The whole point of the shortcut is to reach every file.moveToAnnotatedFile.selectFile(nextFile.id, 0, { alignFileHeaderTop: true })so the diff pane aligns the file header to the top, matching the mouse-click behavior the original issue described asjumpToFile(fileId, 0, { alignFileHeaderTop: true }).Key binding choice
Picked
,and.because bothfandj/kare already taken (page-down and step-down/up respectively per keyboard.ts:13-35). The comma/period pair is unbound and reads naturally as prev/next in many TUIs.If you'd prefer a different pair, let me know -- changing the binding is a one-line tweak.
Changes
src/ui/hooks/useReviewController.ts: newmoveToFile(delta)method. Clamps to[0, visibleFiles.length - 1]; no-op at boundaries (no re-fire ofselectFile).src/ui/hooks/useAppKeyboardShortcuts.ts: binds,→moveToFile(-1)and.→moveToFile(1)insidehandleAppShortcut, so the filter-area short-circuit at lines 228-240 automatically prevents firing while typing in the filter.src/ui/App.tsx: threadsmoveToFilefrom the review controller into the keyboard shortcuts hook (mirrorsmoveToHunk).src/ui/components/chrome/HelpDialog.tsx: new row[", / ."]→"previous / next file", placed next to the existing[ / ]hunk row.src/ui/hooks/useReviewController.test.tsx: unit tests covering mid-list step, clamp at first file (no-op), clamp at last file (no-op), and thatselectFileis called withalignFileHeaderTop: true.src/ui/AppHost.interactions.test.tsx: integration test that exercises the key bindings end-to-end through the renderer.Testing
bun run typecheck-- cleanbun run format:check-- cleanbun run lint-- clean (0 warnings)bun test ./src/ui/hooks/useReviewController.test.tsx ./src/ui/AppHost.interactions.test.tsx-- 48 pass, 0 fail,and.are not bound anywhere inkeyboard.tsoruseAppKeyboardShortcuts.ts. Existing shortcuts[/],j/k,f,Space, etc. behave unchanged.Existing CONTRIBUTING.md rule honored: "Selecting a file should jump within the main stream, not collapse the review to one file." This PR jumps within the main stream (no view-mode change).
Fixes #255
AI was used for assistance.