@@ -1051,7 +1051,9 @@ func (m *Model) renderToolBlock(block DisplayBlock) string {
10511051
10521052func (m * Model ) renderToolState (tool * ToolState , isActive bool ) string {
10531053 var b strings.Builder
1054+ w := m .width
10541055
1056+ // Status indicator
10551057 var dot string
10561058 var nameStyle lipgloss.Style
10571059 switch tool .Status {
@@ -1069,49 +1071,179 @@ func (m *Model) renderToolState(tool *ToolState, isActive bool) string {
10691071 nameStyle = lipgloss .NewStyle ().Bold (true )
10701072 }
10711073
1074+ // Header line: ⏺ ToolName(args)
10721075 name := nameStyle .Render (tool .Name )
10731076 args := ""
10741077 if tool .InputStr != "" {
10751078 args = theme .MutedStyle .Render ("(" + truncate (tool .InputStr , 80 ) + ")" )
10761079 }
10771080 b .WriteString (fmt .Sprintf (" %s %s%s\n " , dot , name , args ))
10781081
1082+ // Running indicator
10791083 if tool .Status == "running" && isActive {
10801084 b .WriteString (" " + theme .MutedStyle .Render ("Running..." ) + "\n " )
10811085 }
10821086
1083- if tool .Status == "done" && ! tool .EndTime .IsZero () {
1084- dur := tool .EndTime .Sub (tool .StartTime )
1085- if dur > time .Second {
1086- b .WriteString (" " + theme .DimText .Render (fmt .Sprintf ("(%s)" , formatDuration (dur ))) + "\n " )
1087+ // Output section — tool-specific rendering
1088+ if tool .Output != "" {
1089+ expanded := m .transcriptMode || tool .Expanded
1090+ b .WriteString (m .renderToolOutput (tool , expanded , w ))
1091+ }
1092+
1093+ // Error
1094+ if tool .Error != "" {
1095+ errLines := strings .Split (tool .Error , "\n " )
1096+ for i , line := range errLines {
1097+ if i >= 5 {
1098+ b .WriteString (" " + theme .ErrorStyle .Render (fmt .Sprintf ("... +%d more error lines" , len (errLines )- 5 )) + "\n " )
1099+ break
1100+ }
1101+ b .WriteString (" " + theme .ErrorStyle .Render (truncate (line , w - 8 )) + "\n " )
10871102 }
10881103 }
10891104
1090- // Tool output
1091- if tool .Output != "" && (m .transcriptMode || tool .Expanded ) {
1092- outputLines := strings .Split (tool .Output , "\n " )
1093- maxLines := 20
1094- if len (outputLines ) > maxLines {
1095- for _ , line := range outputLines [:maxLines ] {
1096- b .WriteString (" " + theme .DimText .Render (truncate (line , m .width - 8 )) + "\n " )
1105+ return b .String ()
1106+ }
1107+
1108+ func (m * Model ) renderToolOutput (tool * ToolState , expanded bool , w int ) string {
1109+ var b strings.Builder
1110+ output := tool .Output
1111+ lines := strings .Split (output , "\n " )
1112+ totalLines := len (lines )
1113+
1114+ // How many lines to show when collapsed
1115+ collapsedMax := 3
1116+ expandedMax := 30
1117+
1118+ switch tool .Name {
1119+ case "Read" :
1120+ // For Read tool: show line count summary
1121+ if ! expanded {
1122+ b .WriteString (fmt .Sprintf (" ⎿ %d lines\n " , totalLines ))
1123+ } else {
1124+ maxShow := expandedMax
1125+ if totalLines < maxShow {
1126+ maxShow = totalLines
1127+ }
1128+ for i := 0 ; i < maxShow ; i ++ {
1129+ b .WriteString (" " + theme .DimText .Render (truncate (lines [i ], w - 8 )) + "\n " )
1130+ }
1131+ if totalLines > maxShow {
1132+ b .WriteString (" " + theme .DimText .Render (fmt .Sprintf ("... +%d lines" , totalLines - maxShow )) + "\n " )
1133+ }
1134+ }
1135+
1136+ case "Bash" :
1137+ // For Bash: show output, stderr-aware
1138+ maxShow := collapsedMax
1139+ if expanded {
1140+ maxShow = expandedMax
1141+ }
1142+ if totalLines <= maxShow {
1143+ for _ , line := range lines {
1144+ b .WriteString (" " + theme .DimText .Render (truncate (line , w - 8 )) + "\n " )
10971145 }
1098- b .WriteString (" " + theme .DimText .Render (fmt .Sprintf ("... +%d lines (ctrl+o to expand)" , len (outputLines )- maxLines )) + "\n " )
10991146 } else {
1100- for _ , line := range outputLines {
1101- b .WriteString (" " + theme .DimText .Render (truncate (line , m . width - 8 )) + "\n " )
1147+ for i := 0 ; i < maxShow ; i ++ {
1148+ b .WriteString (" " + theme .DimText .Render (truncate (lines [ i ], w - 8 )) + "\n " )
11021149 }
1150+ b .WriteString (" " + theme .DimText .Render (fmt .Sprintf ("... +%d lines (ctrl+o to expand)" , totalLines - maxShow )) + "\n " )
11031151 }
1104- } else if tool .Output != "" {
1105- lines := strings .Count (tool .Output , "\n " ) + 1
1106- firstLine := strings .SplitN (tool .Output , "\n " , 2 )[0 ]
1107- b .WriteString (" ⎿ " + theme .DimText .Render (truncate (firstLine , m .width - 10 )) + "\n " )
1108- if lines > 1 {
1109- b .WriteString (" " + theme .DimText .Render (fmt .Sprintf (" ... +%d lines (ctrl+o to expand)" , lines - 1 )) + "\n " )
1152+
1153+ case "Edit" :
1154+ // For Edit: show what was changed
1155+ if ! expanded {
1156+ b .WriteString (" ⎿ " + theme .SuccessText .Render ("file updated" ) + "\n " )
1157+ } else {
1158+ maxShow := expandedMax
1159+ if totalLines < maxShow {
1160+ maxShow = totalLines
1161+ }
1162+ for i := 0 ; i < maxShow ; i ++ {
1163+ line := lines [i ]
1164+ if strings .HasPrefix (line , "+" ) {
1165+ b .WriteString (" " + theme .SuccessText .Render (truncate (line , w - 8 )) + "\n " )
1166+ } else if strings .HasPrefix (line , "-" ) {
1167+ b .WriteString (" " + theme .ErrorStyle .Render (truncate (line , w - 8 )) + "\n " )
1168+ } else {
1169+ b .WriteString (" " + theme .DimText .Render (truncate (line , w - 8 )) + "\n " )
1170+ }
1171+ }
1172+ if totalLines > maxShow {
1173+ b .WriteString (" " + theme .DimText .Render (fmt .Sprintf ("... +%d lines" , totalLines - maxShow )) + "\n " )
1174+ }
11101175 }
1111- }
11121176
1113- if tool .Error != "" {
1114- b .WriteString (" " + theme .ErrorStyle .Render ("⎿ Error: " + truncate (tool .Error , m .width - 12 )) + "\n " )
1177+ case "Write" :
1178+ // For Write: show file created/written
1179+ if ! expanded {
1180+ b .WriteString (" ⎿ " + theme .SuccessText .Render ("file written" ) + "\n " )
1181+ } else {
1182+ maxShow := expandedMax
1183+ if totalLines < maxShow {
1184+ maxShow = totalLines
1185+ }
1186+ for i := 0 ; i < maxShow ; i ++ {
1187+ b .WriteString (" " + theme .DimText .Render (truncate (lines [i ], w - 8 )) + "\n " )
1188+ }
1189+ if totalLines > maxShow {
1190+ b .WriteString (" " + theme .DimText .Render (fmt .Sprintf ("... +%d lines" , totalLines - maxShow )) + "\n " )
1191+ }
1192+ }
1193+
1194+ case "Glob" :
1195+ // Show file list
1196+ maxShow := 8
1197+ if expanded {
1198+ maxShow = 30
1199+ }
1200+ if totalLines <= maxShow {
1201+ for _ , line := range lines {
1202+ b .WriteString (" " + theme .DimText .Render (truncate (line , w - 8 )) + "\n " )
1203+ }
1204+ } else {
1205+ for i := 0 ; i < maxShow ; i ++ {
1206+ b .WriteString (" " + theme .DimText .Render (truncate (lines [i ], w - 8 )) + "\n " )
1207+ }
1208+ b .WriteString (" " + theme .DimText .Render (fmt .Sprintf ("... +%d files" , totalLines - maxShow )) + "\n " )
1209+ }
1210+
1211+ case "Grep" :
1212+ // Show search results
1213+ maxShow := 5
1214+ if expanded {
1215+ maxShow = 30
1216+ }
1217+ if totalLines <= maxShow {
1218+ for _ , line := range lines {
1219+ b .WriteString (" " + theme .DimText .Render (truncate (line , w - 8 )) + "\n " )
1220+ }
1221+ } else {
1222+ for i := 0 ; i < maxShow ; i ++ {
1223+ b .WriteString (" " + theme .DimText .Render (truncate (lines [i ], w - 8 )) + "\n " )
1224+ }
1225+ b .WriteString (" " + theme .DimText .Render (fmt .Sprintf ("... +%d matches" , totalLines - maxShow )) + "\n " )
1226+ }
1227+
1228+ default :
1229+ // Generic: show first few lines
1230+ maxShow := collapsedMax
1231+ if expanded {
1232+ maxShow = expandedMax
1233+ }
1234+ if totalLines <= maxShow {
1235+ for _ , line := range lines {
1236+ if line != "" {
1237+ b .WriteString (" ⎿ " + theme .DimText .Render (truncate (line , w - 10 )) + "\n " )
1238+ }
1239+ }
1240+ } else {
1241+ firstLine := lines [0 ]
1242+ b .WriteString (" ⎿ " + theme .DimText .Render (truncate (firstLine , w - 10 )) + "\n " )
1243+ if totalLines > 1 {
1244+ b .WriteString (" " + theme .DimText .Render (fmt .Sprintf (" ... +%d lines (ctrl+o to expand)" , totalLines - 1 )) + "\n " )
1245+ }
1246+ }
11151247 }
11161248
11171249 return b .String ()
0 commit comments