From 6956102cf7f8c043d45371998bcea00d4cf59c31 Mon Sep 17 00:00:00 2001 From: kami Date: Tue, 2 Jun 2026 23:39:38 +0400 Subject: [PATCH] fix(tui): clamp diff scroll offset to last full page The diff overlay incremented diffScrollOffset on every down-key with no upper bound; the render clamped only the displayed offset, so the stored value grew unbounded and the up-key appeared dead for N presses. Clamp the increment against a new diffMaxScroll() (len(lines) - body height), shared with the render path via diffBodyHeight(). --- apps/tui-go/internal/app/overlays.go | 28 ++++++++++++++++++++++------ apps/tui-go/internal/app/update.go | 4 +++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/apps/tui-go/internal/app/overlays.go b/apps/tui-go/internal/app/overlays.go index 7acad342..6cecf2a9 100644 --- a/apps/tui-go/internal/app/overlays.go +++ b/apps/tui-go/internal/app/overlays.go @@ -94,20 +94,36 @@ func (m Model) renderApproval(base string) string { return m.center(modal) } -func (m Model) diffModal() string { - t := m.theme - w := m.modalWidth() +// diffBodyHeight is the number of diff lines visible in the diff modal body. +func (m Model) diffBodyHeight() int { h := m.height * 70 / 100 if h < 8 { h = 8 } - bodyH := h - 6 + return h - 6 +} + +// diffMaxScroll is the largest scroll offset that still fills the body with +// diff lines, keeping the last page anchored to the bottom of the modal. +func (m Model) diffMaxScroll() int { + lines := strings.Split(strings.TrimRight(m.currentDiff(), "\n"), "\n") + max := len(lines) - m.diffBodyHeight() + if max < 0 { + max = 0 + } + return max +} + +func (m Model) diffModal() string { + t := m.theme + w := m.modalWidth() + bodyH := m.diffBodyHeight() diff := m.currentDiff() lines := strings.Split(strings.TrimRight(diff, "\n"), "\n") off := m.diffScrollOffset - if off > len(lines)-1 { - off = len(lines) - 1 + if off > m.diffMaxScroll() { + off = m.diffMaxScroll() } if off < 0 { off = 0 diff --git a/apps/tui-go/internal/app/update.go b/apps/tui-go/internal/app/update.go index c6e2e026..b2f04b9f 100644 --- a/apps/tui-go/internal/app/update.go +++ b/apps/tui-go/internal/app/update.go @@ -332,7 +332,9 @@ func (m Model) handleOverlayKey(k tea.KeyMsg) (tea.Model, tea.Cmd) { m.diffScrollOffset-- } case k.Type == tea.KeyDown || runeIs(k, "j"): - m.diffScrollOffset++ + if m.diffScrollOffset < m.diffMaxScroll() { + m.diffScrollOffset++ + } case k.Type == tea.KeyCtrlX: m.overlay = OverlayNone }