detached 43da5e5

tui: reset auto-follow baseline on new turn to stop viewport jump

startTurnWithImages clears the previous turn's tool-call overlay and
pins scrollOffset to 0. Without also resetting prevChatLen/prevChatCols,
the auto-follow guard on the next render sees a synthetic negative
delta equal to the number of overlay rows that were cleared, and
nudges scrollOffset by that amount. On terminals that mirror zot's
chat-pane scroll into their native scrollbar this is visible as a
viewport jump the instant the user presses enter on a follow-up
prompt.

Zero them out in the same locked block so the guard short-circuits
on the very next render, the same way it already does on column
resize. The legitimate "user scrolled up while content streams in"
case is unaffected because prevChatLen is repopulated on that first
post-submit render.
commit
43da5e5249e11af0609bfbde8a4fd33c03754bd8
author
patriceckhart · · 2026-05-12 18:43 UTC
parent
1030ae5
signature
unsigned
refs
tag: v0.1.77
1 file · +11 -1
M internal/agent/modes/interactive.go +11 -1
@@ -3167,7 +3167,17 @@ func (i *Interactive) startTurnWithImages(parent context.Context, prompt string,
31673167 i.toolCalls = map[string]*tui.ToolCallView{}
31683168 i.toolOrder = nil
31693169 i.scrollOffset = 0 // jump back to the bottom on new turn
3170- i.parkedTurn = 0 // starting a turn clears the /jump parked state
3170+ // Reset the auto-follow baseline so the very next render at
3171+ // interactive.go:1053 doesn't see a synthetic shrink between
3172+ // "last frame had the previous turn's tool overlay" and
3173+ // "this frame had it cleared above". Without this, the guard
3174+ // reads delta = -(rows in cleared overlay) and decrements
3175+ // scrollOffset, which on terminals that mirror zot's pane
3176+ // scroll into the host scrollbar visibly yanks the viewport.
3177+ // See autofollow_shrink_test.go for the exact arithmetic.
3178+ i.prevChatLen = 0
3179+ i.prevChatCols = 0
3180+ i.parkedTurn = 0 // starting a turn clears the /jump parked state
31713181 i.parkedTotal = 0
31723182 i.helpBlock = nil // hide the help block once the user asks something
31733183 i.mu.Unlock()
@@ -3167,7 +3167,17 @@ func (i *Interactive) startTurnWithImages(parent context.Context, prompt string,
3167 i.toolCalls = map[string]*tui.ToolCallView{}3167 i.toolCalls = map[string]*tui.ToolCallView{}
3168 i.toolOrder = nil3168 i.toolOrder = nil
3169 i.scrollOffset = 0 // jump back to the bottom on new turn3169 i.scrollOffset = 0 // jump back to the bottom on new turn
3170- i.parkedTurn = 0 // starting a turn clears the /jump parked state3170+ // Reset the auto-follow baseline so the very next render at
3171+ // interactive.go:1053 doesn't see a synthetic shrink between
3172+ // "last frame had the previous turn's tool overlay" and
3173+ // "this frame had it cleared above". Without this, the guard
3174+ // reads delta = -(rows in cleared overlay) and decrements
3175+ // scrollOffset, which on terminals that mirror zot's pane
3176+ // scroll into the host scrollbar visibly yanks the viewport.
3177+ // See autofollow_shrink_test.go for the exact arithmetic.
3178+ i.prevChatLen = 0
3179+ i.prevChatCols = 0
3180+ i.parkedTurn = 0 // starting a turn clears the /jump parked state
3171 i.parkedTotal = 03181 i.parkedTotal = 0
3172 i.helpBlock = nil // hide the help block once the user asks something3182 i.helpBlock = nil // hide the help block once the user asks something
3173 i.mu.Unlock()3183 i.mu.Unlock()

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close