Summary
With agent notes attached, the next/prev-comment keybinding (and the equivalent hunk session navigate --next-comment / --prev-comment API) appears to "stop working" — pressing it teleports the user backward to the first comment instead of advancing to the next one. Repros in vanilla 0.10.0 once the user has scrolled (or otherwise moved selection) off any of the annotated hunks.
Repro
hunk diff <range> on a multi-file diff
- Attach agent notes to a few hunks
- Press next-comment a couple of times to advance
- Scroll a little (or press next-hunk) so the centered selection lands on a non-annotated hunk
- Press next-comment again → viewport jumps back to the first comment instead of advancing to the next one
It's reliably reproducible because viewport-centered selection (findViewportCenteredHunkTarget → onViewportCenteredHunkChange) keeps shifting selectedHunkIndex to whichever hunk is centered as the user scrolls. That hunk is frequently not annotated, so the next press of next/prev-comment hits the no-exact-match fallback path.
Root cause
src/ui/lib/hunks.ts:findNextHunkCursor:
const currentIndex = cursors.findIndex(
(cursor) => cursor.fileId === currentFileId && cursor.hunkIndex === currentHunkIndex,
);
const nextIndex =
currentIndex >= 0
? Math.min(Math.max(currentIndex + delta, 0), cursors.length - 1)
: delta >= 0
? 0
: cursors.length - 1;
When (currentFileId, currentHunkIndex) isn't an exact match in the (filtered) cursor list — which is the common case for annotated-cursor navigation, since the user's selection lives on the full hunk stream — the fallback unconditionally returns the first or last cursor regardless of where the user actually is. Often that's backwards from their position.
Suggested fix
Resolve the relative position from the cursor list itself instead of falling back to first/last:
- Files appear in stream order in the cursor list, and within a file
hunkIndex is ascending.
- The first appearance of each file in the cursor list gives a stable per-file stream rank.
- For a non-matching
(currentFileId, currentHunkIndex):
- delta ≥ 0 → first cursor whose stream rank is strictly greater than the current position.
- delta < 0 → last cursor whose stream rank is strictly less than the current position.
- Only fall back to start/end when the current file has no cursors at all (file with no annotations) or when the search exhausts the list.
The existing test cases at src/ui/lib/hunks.test.ts:160-170 happen to coincide with the "first/last cursor" answer because they exercise a single-cursor list, so they don't catch the regression — worth adding regression tests for non-annotated current with a multi-cursor list.
Related
Summary
With agent notes attached, the next/prev-comment keybinding (and the equivalent
hunk session navigate --next-comment/--prev-commentAPI) appears to "stop working" — pressing it teleports the user backward to the first comment instead of advancing to the next one. Repros in vanilla 0.10.0 once the user has scrolled (or otherwise moved selection) off any of the annotated hunks.Repro
hunk diff <range>on a multi-file diffIt's reliably reproducible because viewport-centered selection (
findViewportCenteredHunkTarget→onViewportCenteredHunkChange) keeps shiftingselectedHunkIndexto whichever hunk is centered as the user scrolls. That hunk is frequently not annotated, so the next press of next/prev-comment hits the no-exact-match fallback path.Root cause
src/ui/lib/hunks.ts:findNextHunkCursor:When
(currentFileId, currentHunkIndex)isn't an exact match in the (filtered) cursor list — which is the common case for annotated-cursor navigation, since the user's selection lives on the full hunk stream — the fallback unconditionally returns the first or last cursor regardless of where the user actually is. Often that's backwards from their position.Suggested fix
Resolve the relative position from the cursor list itself instead of falling back to first/last:
hunkIndexis ascending.(currentFileId, currentHunkIndex):The existing test cases at
src/ui/lib/hunks.test.ts:160-170happen to coincide with the "first/last cursor" answer because they exercise a single-cursor list, so they don't catch the regression — worth adding regression tests for non-annotated current with a multi-cursor list.Related