detached 955a9b7

tui: collapse double-blank between adjacent tool boxes

Each tool result owns its own box, but the assistant message that
batched the originating tool_use blocks now renders to nothing (the
box edges moved to the tool result). Build() was still emitting an
inter-message blank for that empty render, which compounded with
the blank from the next real message and produced two blank rows
between adjacent tool boxes \u2014 visible whenever the model batched
multiple tool calls without prose between them.

Skip the inter-message blank when a message rendered to zero lines
so an empty assistant message no longer contributes a separator
row. Adjacent tool boxes now sit one blank row apart, matching the
spacing between every other pair of chat blocks.
commit
955a9b703b73e3076d52ddd3285bee653d61b56e
author
patriceckhart · · 2026-04-27 13:59 UTC
parent
4b2bce3
signature
unsigned
refs
tag: v0.1.28
1 file · +9 -0
M internal/tui/view.go +9 -0
@@ -232,6 +232,15 @@ func (v *View) BuildWithAnchors(width int) ([]string, []MessageAnchor) {
232232 for idx := range v.Messages {
233233 anchors = append(anchors, MessageAnchor{MessageIdx: idx, Row: len(out)})
234234 out = append(out, rendered[idx]...)
235+ // Skip the inter-message blank for messages that rendered
236+ // to nothing. An assistant message whose only content is
237+ // ToolCallBlock(s) has no rendered output of its own (each
238+ // tool result owns its box now), so emitting a blank for it
239+ // would compound with the blank from the next real message
240+ // and produce two blank rows between adjacent tool boxes.
241+ if len(rendered[idx]) == 0 {
242+ continue
243+ }
235244 out = append(out, "")
236245 }
237246 // Only render the streaming header/body when there's actual
@@ -232,6 +232,15 @@ func (v *View) BuildWithAnchors(width int) ([]string, []MessageAnchor) {
232 for idx := range v.Messages {232 for idx := range v.Messages {
233 anchors = append(anchors, MessageAnchor{MessageIdx: idx, Row: len(out)})233 anchors = append(anchors, MessageAnchor{MessageIdx: idx, Row: len(out)})
234 out = append(out, rendered[idx]...)234 out = append(out, rendered[idx]...)
235+ // Skip the inter-message blank for messages that rendered
236+ // to nothing. An assistant message whose only content is
237+ // ToolCallBlock(s) has no rendered output of its own (each
238+ // tool result owns its box now), so emitting a blank for it
239+ // would compound with the blank from the next real message
240+ // and produce two blank rows between adjacent tool boxes.
241+ if len(rendered[idx]) == 0 {
242+ continue
243+ }
235 out = append(out, "")244 out = append(out, "")
236 }245 }
237 // Only render the streaming header/body when there's actual246 // Only render the streaming header/body when there's actual

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