Skip to content

Commit 8ca0324

Browse files
committed
fix: center viewport on search match navigation
Use centerViewportOnCursor instead of syncViewportToCursor for search navigation to match hunk navigation behavior. Update CLAUDE.md with session learnings.
1 parent ad239a4 commit 8ca0324

2 files changed

Lines changed: 7 additions & 4 deletions

File tree

CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,6 @@ git diff → diff.ParseUnifiedDiff() → []DiffLine
7373
- Tab replacement happens at render time in `renderDiffLine`, not in diff parsing
7474
- `run()` resolves git repo root via `git rev-parse --show-toplevel` so revdiff works from any subdirectory
7575
- Help overlay uses `overlayCenter()` (ANSI-aware compositing via `charmbracelet/x/ansi.Cut`) to render on top of existing content; background (tree pane) remains visible at the edges
76+
- **ANSI nesting with lipgloss**: `lipgloss.Render()` emits `\033[0m` (full reset) which breaks outer style backgrounds. For styled substrings inside a lipgloss container (status bar separators, search highlights), use raw ANSI sequences via `ansiColor(hex, code)` — code 38 for fg, 48 for bg. Never use `lipgloss.NewStyle().Render()` for inline elements within a lipgloss-rendered parent.
77+
- Status bar mode icons (`▼ ◉ ↩ ≋`) are always rendered on the right side via `statusModeIcons()`. Active modes use `StatusFg`, inactive use `Muted` — both via raw ANSI fg sequences. Graceful degradation on narrow terminals drops left segments: search position first (`statusSegmentsNoSearch`), then hunk info (`statusSegmentsMinimal`), then truncates filename.
78+
- Search and hunk navigation both use `centerViewportOnCursor()` to center the target in the middle of the viewport. Use `syncViewportToCursor()` only for cursor movements that should keep the cursor barely visible (j/k scrolling).

ui/search.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func (m *Model) submitSearch() {
5656
m.searchCursor = i
5757
m.diffCursor = idx
5858
m.cursorOnAnnotation = false
59-
m.syncViewportToCursor()
59+
m.centerViewportOnCursor()
6060
return
6161
}
6262

@@ -68,7 +68,7 @@ func (m *Model) submitSearch() {
6868
m.searchCursor = i
6969
m.diffCursor = idx
7070
m.cursorOnAnnotation = false
71-
m.syncViewportToCursor()
71+
m.centerViewportOnCursor()
7272
return
7373
}
7474
}
@@ -92,7 +92,7 @@ func (m *Model) nextSearchMatch() {
9292
}
9393
m.diffCursor = m.searchMatches[m.searchCursor]
9494
m.cursorOnAnnotation = false
95-
m.syncViewportToCursor()
95+
m.centerViewportOnCursor()
9696
}
9797

9898
// prevSearchMatch moves to the previous search match with wrap-around.
@@ -117,7 +117,7 @@ func (m *Model) prevSearchMatch() {
117117
}
118118
m.diffCursor = m.searchMatches[m.searchCursor]
119119
m.cursorOnAnnotation = false
120-
m.syncViewportToCursor()
120+
m.centerViewportOnCursor()
121121
}
122122

123123
// cancelSearch exits searching mode without submitting.

0 commit comments

Comments
 (0)