Skip to content

Commit ca0c335

Browse files
committed
fix scroll bug when returning to the list view of commits
1 parent 1555885 commit ca0c335

2 files changed

Lines changed: 62 additions & 1 deletion

File tree

main.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,19 @@ func (m *model) clampCursor() {
367367
m.adjustScroll()
368368
}
369369

370+
// scroll applies a mouse-wheel step (delta of -1 up / +1 down) to whichever
371+
// scrollable view is active; other states ignore the wheel.
372+
func (m *model) scroll(delta int) {
373+
switch m.state {
374+
case stateList:
375+
m.cursor += delta
376+
m.clampCursor()
377+
case stateDiff:
378+
m.diffTop += delta * 3 // 3 lines per wheel notch, like a pager
379+
m.clampDiff()
380+
}
381+
}
382+
370383
func (m *model) visibleRows() int {
371384
return max(1, m.height-5) // minus header (2) + footer (3)
372385
}
@@ -450,6 +463,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
450463
return m, spinnerTickCmd()
451464
}
452465
return m, nil
466+
case tea.MouseMsg:
467+
// Handle the wheel ourselves so it scrolls the active view rather than
468+
// the terminal translating it into arrow-key bursts that leak between views.
469+
switch msg.Button {
470+
case tea.MouseButtonWheelUp:
471+
m.scroll(-1)
472+
case tea.MouseButtonWheelDown:
473+
m.scroll(1)
474+
}
475+
return m, nil
453476
case tea.KeyMsg:
454477
switch m.state {
455478
case stateList:
@@ -1201,7 +1224,7 @@ func main() {
12011224
fmt.Fprintln(os.Stderr, "git_pruner:", err)
12021225
os.Exit(1)
12031226
}
1204-
p := tea.NewProgram(m, tea.WithAltScreen())
1227+
p := tea.NewProgram(m, tea.WithAltScreen(), tea.WithMouseCellMotion())
12051228
if _, err := p.Run(); err != nil {
12061229
fmt.Fprintln(os.Stderr, "git_pruner:", err)
12071230
os.Exit(1)

main_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,44 @@ func TestRemoteMergedIndicator(t *testing.T) {
507507
}
508508
}
509509

510+
// Scrolling the diff view with the wheel must not disturb the list's cursor or
511+
// scroll position (regression: over-scrolling the diff jumped the list to the end).
512+
func TestWheelScrollDoesNotLeakBetweenViews(t *testing.T) {
513+
repo := setupRepo(t)
514+
chdir(t, repo)
515+
m, err := initialModel()
516+
if err != nil {
517+
t.Fatal(err)
518+
}
519+
520+
// Park the list cursor at a non-zero row.
521+
m.cursor = 2
522+
m.clampCursor()
523+
savedCursor, savedTop := m.cursor, m.top
524+
525+
// Enter the diff with scrollable content and scroll it hard past the bottom.
526+
m.state = stateDiff
527+
m.diffLines = make([]string, 200)
528+
m.diffTop = 0
529+
for range 500 {
530+
m.scroll(1)
531+
}
532+
if m.diffTop == 0 {
533+
t.Fatal("diff should have scrolled down")
534+
}
535+
if m.cursor != savedCursor || m.top != savedTop {
536+
t.Fatalf("diff scroll leaked into list: cursor %d->%d, top %d->%d",
537+
savedCursor, m.cursor, savedTop, m.top)
538+
}
539+
540+
// Back in the list, the wheel drives the cursor (routed via Update/MouseMsg).
541+
m.state = stateList
542+
nm, _ := m.Update(tea.MouseMsg{Button: tea.MouseButtonWheelDown, Action: tea.MouseActionPress})
543+
if got := nm.(model).cursor; got != savedCursor+1 {
544+
t.Fatalf("list wheel should move cursor to %d, got %d", savedCursor+1, got)
545+
}
546+
}
547+
510548
// The version string is well-formed even when VCS build info is absent.
511549
func TestVersionString(t *testing.T) {
512550
s := versionString()

0 commit comments

Comments
 (0)