From 94018de3e803d6a7098d41e51998ca7bf95a824e Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 8 Aug 2026 18:57:12 +0200 Subject: [PATCH] Route all view origin writes through SetOriginX and SetOriginY Several methods assigned v.ox and v.oy directly: SetOrigin, CopyContent, the wrap/autoscroll branches in draw, FocusPoint, and Scroll{Up,Down,Left,Right}. Funnelling them all through SetOriginX and SetOriginY gives a single place to observe (or set a breakpoint on) every change to a view's scroll position, which makes debugging scroll behaviour much easier. This means those call sites now also get the setters' `< 0` clamps, but that is behaviour-preserving in every case: each assigned value is already >= 0. calculateNewOrigin never returns a negative number; CopyContent copies origins that are themselves always >= 0; and the draw and scroll writes are all guarded (or fed only non-negative amounts) so the result can't go below zero. Co-Authored-By: Claude Opus 5 (1M context) --- pkg/gocui/view.go | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/pkg/gocui/view.go b/pkg/gocui/view.go index 787d11475..81ab0acab 100644 --- a/pkg/gocui/view.go +++ b/pkg/gocui/view.go @@ -402,7 +402,7 @@ func (v *View) FocusPoint(cx int, cy int, scrollIntoView bool) { if scrollIntoView { height := v.InnerHeight() - v.oy = calculateNewOrigin(cy, v.oy, lineCount, height) + v.SetOriginY(calculateNewOrigin(cy, v.oy, lineCount, height)) } v.cx = cx @@ -707,15 +707,8 @@ func (v *View) CursorY() int { // implement Horizontal and Vertical scrolling with just incrementing // or decrementing ox and oy. func (v *View) SetOrigin(x, y int) { - if x < 0 { - x = 0 - } - if y < 0 { - y = 0 - } - - v.ox = x - v.oy = y + v.SetOriginX(x) + v.SetOriginY(y) } func (v *View) SetOriginX(x int) { @@ -1166,8 +1159,8 @@ func (v *View) CopyContent(from *View) { // their contents. v.lines = slices.Clone(from.lines) v.viewLines = slices.Clone(from.viewLines) - v.ox = from.ox - v.oy = from.oy + v.SetOriginX(from.ox) + v.SetOriginY(from.oy) v.cx = from.cx v.cy = from.cy } @@ -1335,14 +1328,14 @@ func (v *View) draw(isWindowFocused bool) { if maxX == 0 { return } - v.ox = 0 + v.SetOriginX(0) } v.refreshViewLinesIfNeeded() visibleViewLinesHeight := v.viewLineLengthIgnoringTrailingBlankLines() if v.Autoscroll && visibleViewLinesHeight > maxY { - v.oy = visibleViewLinesHeight - maxY + v.SetOriginY(visibleViewLinesHeight - maxY) } if len(v.viewLines) == 0 { @@ -1989,7 +1982,7 @@ func (v *View) ScrollUp(amount int) { } if amount != 0 { - v.oy -= amount + v.SetOriginY(v.oy - amount) v.cy += amount v.clearHover() @@ -2001,7 +1994,7 @@ func (v *View) ScrollUp(amount int) { func (v *View) ScrollDown(amount int) { adjustedAmount := v.adjustDownwardScrollAmount(amount) if adjustedAmount > 0 { - v.oy += adjustedAmount + v.SetOriginY(v.oy + adjustedAmount) v.cy -= adjustedAmount v.clearHover() @@ -2015,7 +2008,7 @@ func (v *View) ScrollLeft(amount int) { newOx = 0 } if newOx != v.ox { - v.ox = newOx + v.SetOriginX(newOx) v.clearHover() } @@ -2023,7 +2016,7 @@ func (v *View) ScrollLeft(amount int) { // not applying any limits to this func (v *View) ScrollRight(amount int) { - v.ox += amount + v.SetOriginX(v.ox + amount) v.clearHover() }