detached 47257c8

Add separator before truncated tool footers

commit
47257c8a544bc7f86a215f446167282e4be4bd97
author
patriceckhart · · 2026-05-22 15:12 UTC
parent
14ffdb6
signature
unsigned
2 files · +17 -2
M internal/agent/tools/read.go +3 -0
@@ -131,6 +131,9 @@ func (t *ReadTool) Execute(ctx context.Context, raw json.RawMessage, progress fu
131131 sb.WriteString(line)
132132 sb.WriteByte('\n')
133133 }
134+ if truncLines || truncBytes {
135+ sb.WriteString("\n")
136+ }
134137 if truncLines {
135138 sb.WriteString(fmt.Sprintf("... [truncated at %d lines]\n", maxReadLines))
136139 }
@@ -131,6 +131,9 @@ func (t *ReadTool) Execute(ctx context.Context, raw json.RawMessage, progress fu
131 sb.WriteString(line)131 sb.WriteString(line)
132 sb.WriteByte('\n')132 sb.WriteByte('\n')
133 }133 }
134+ if truncLines || truncBytes {
135+ sb.WriteString("\n")
136+ }
134 if truncLines {137 if truncLines {
135 sb.WriteString(fmt.Sprintf("... [truncated at %d lines]\n", maxReadLines))138 sb.WriteString(fmt.Sprintf("... [truncated at %d lines]\n", maxReadLines))
136 }139 }
M internal/tui/view.go +14 -2
@@ -1113,7 +1113,9 @@ func (v *View) collapseToolBody(lines []string, hasImage bool) []string {
11131113 total := len(lines)
11141114 footer := fmt.Sprintf(" ... (%d more lines, %d total, ctrl+o to expand)", hidden, total)
11151115 footer = v.Theme.FG256(v.Theme.Muted, footer)
1116- return append(append([]string(nil), kept...), footer)
1116+ out := append([]string(nil), kept...)
1117+ out = append(out, "")
1118+ return append(out, footer)
11171119 }
11181120
11191121 // renderToolText renders a text block inside a tool result. If the
@@ -1179,6 +1181,11 @@ func (v *View) renderToolText(text string, width, defaultColor int, sourcePath s
11791181 out = append(out, " "+v.Theme.FG256(v.Theme.Muted, l))
11801182 continue
11811183 }
1184+ if inDiff && strings.TrimSpace(l) == "..." {
1185+ out = append(out, "")
1186+ out = append(out, " "+v.Theme.FG256(v.Theme.Muted, "..."))
1187+ continue
1188+ }
11821189 if inDiff && len(l) > 0 {
11831190 switch l[0] {
11841191 case '+':
@@ -1716,7 +1723,9 @@ func (v *View) renderRawFile(text, sourcePath string, startLine int) []string {
17161723 lines = lines[:n-1]
17171724 }
17181725 // Split code from trailing footer lines ("... [truncated ...]")
1719- // so we don't number the footer.
1726+ // so we don't number the footer. A single blank separator line
1727+ // immediately before the footer is also pulled out so the
1728+ // gutter doesn't render a phantom number for it.
17201729 codeEnd := len(lines)
17211730 for i := len(lines) - 1; i >= 0; i-- {
17221731 if strings.HasPrefix(lines[i], "...") {
@@ -1725,6 +1734,9 @@ func (v *View) renderRawFile(text, sourcePath string, startLine int) []string {
17251734 }
17261735 break
17271736 }
1737+ if codeEnd > 0 && codeEnd < len(lines) && lines[codeEnd-1] == "" {
1738+ codeEnd--
1739+ }
17281740 code := lines[:codeEnd]
17291741 footer := lines[codeEnd:]
17301742
@@ -1113,7 +1113,9 @@ func (v *View) collapseToolBody(lines []string, hasImage bool) []string {
1113 total := len(lines)1113 total := len(lines)
1114 footer := fmt.Sprintf(" ... (%d more lines, %d total, ctrl+o to expand)", hidden, total)1114 footer := fmt.Sprintf(" ... (%d more lines, %d total, ctrl+o to expand)", hidden, total)
1115 footer = v.Theme.FG256(v.Theme.Muted, footer)1115 footer = v.Theme.FG256(v.Theme.Muted, footer)
1116- return append(append([]string(nil), kept...), footer)1116+ out := append([]string(nil), kept...)
1117+ out = append(out, "")
1118+ return append(out, footer)
1117 }1119 }
1118 1120
1119 // renderToolText renders a text block inside a tool result. If the1121 // renderToolText renders a text block inside a tool result. If the
@@ -1179,6 +1181,11 @@ func (v *View) renderToolText(text string, width, defaultColor int, sourcePath s
1179 out = append(out, " "+v.Theme.FG256(v.Theme.Muted, l))1181 out = append(out, " "+v.Theme.FG256(v.Theme.Muted, l))
1180 continue1182 continue
1181 }1183 }
1184+ if inDiff && strings.TrimSpace(l) == "..." {
1185+ out = append(out, "")
1186+ out = append(out, " "+v.Theme.FG256(v.Theme.Muted, "..."))
1187+ continue
1188+ }
1182 if inDiff && len(l) > 0 {1189 if inDiff && len(l) > 0 {
1183 switch l[0] {1190 switch l[0] {
1184 case '+':1191 case '+':
@@ -1716,7 +1723,9 @@ func (v *View) renderRawFile(text, sourcePath string, startLine int) []string {
1716 lines = lines[:n-1]1723 lines = lines[:n-1]
1717 }1724 }
1718 // Split code from trailing footer lines ("... [truncated ...]")1725 // Split code from trailing footer lines ("... [truncated ...]")
1719- // so we don't number the footer.1726+ // so we don't number the footer. A single blank separator line
1727+ // immediately before the footer is also pulled out so the
1728+ // gutter doesn't render a phantom number for it.
1720 codeEnd := len(lines)1729 codeEnd := len(lines)
1721 for i := len(lines) - 1; i >= 0; i-- {1730 for i := len(lines) - 1; i >= 0; i-- {
1722 if strings.HasPrefix(lines[i], "...") {1731 if strings.HasPrefix(lines[i], "...") {
@@ -1725,6 +1734,9 @@ func (v *View) renderRawFile(text, sourcePath string, startLine int) []string {
1725 }1734 }
1726 break1735 break
1727 }1736 }
1737+ if codeEnd > 0 && codeEnd < len(lines) && lines[codeEnd-1] == "" {
1738+ codeEnd--
1739+ }
1728 code := lines[:codeEnd]1740 code := lines[:codeEnd]
1729 footer := lines[codeEnd:]1741 footer := lines[codeEnd:]
1730 1742

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