Skip to content

Commit a9e869c

Browse files
authored
Merge pull request #16 from Daniel-Ric/feature/2026-02-03/refactor-percentage-display-layout-eah5ye
Fix spinner to update multiline progress in-place and use dynamic concurrency default
2 parents 5c903df + 3fa3e67 commit a9e869c

1 file changed

Lines changed: 35 additions & 8 deletions

File tree

internal/cli/ui.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -235,22 +235,49 @@ func withSpinner(title string, message func(frame int) string, tick time.Duratio
235235
defer ticker.Stop()
236236

237237
frame := 0
238-
lastLen := 0
238+
lastLines := 0
239239
for {
240240
select {
241241
case res := <-resultCh:
242-
if lastLen > 0 {
243-
fmt.Print("\r", strings.Repeat(" ", lastLen), "\r")
242+
if lastLines > 1 {
243+
moveCursorUp(lastLines - 1)
244+
}
245+
for i := 0; i < lastLines; i++ {
246+
clearLine()
247+
if i < lastLines-1 {
248+
fmt.Print("\n")
249+
}
244250
}
245251
fmt.Println()
246252
return res.result, res.err
247253
case <-ticker.C:
248-
line := fmt.Sprintf("%s %s", style(message(frame), colorDim), style(frames[frame], colorAccent))
249-
if lastLen > 0 && len(line) < lastLen {
250-
line += strings.Repeat(" ", lastLen-len(line))
254+
parts := strings.Split(message(frame), "\n")
255+
if len(parts) == 0 {
256+
parts = []string{""}
257+
}
258+
renderLines := len(parts)
259+
if lastLines > renderLines {
260+
renderLines = lastLines
261+
}
262+
263+
if lastLines > 1 {
264+
moveCursorUp(lastLines - 1)
251265
}
252-
fmt.Print("\r", line)
253-
lastLen = len(line)
266+
for i := 0; i < renderLines; i++ {
267+
clearLine()
268+
if i < len(parts) {
269+
line := style(parts[i], colorDim)
270+
if i == len(parts)-1 {
271+
line = fmt.Sprintf("%s %s", line, style(frames[frame], colorAccent))
272+
}
273+
fmt.Print(line)
274+
}
275+
if i < renderLines-1 {
276+
fmt.Print("\n")
277+
}
278+
}
279+
280+
lastLines = len(parts)
254281
frame = (frame + 1) % len(frames)
255282
}
256283
}

0 commit comments

Comments
 (0)