| 294 | } |
| 295 | |
| 296 | func (w *ttyWriter) printWithDimensions(terminalWidth, terminalHeight int) { |
| 297 | w.mtx.Lock() |
| 298 | defer w.mtx.Unlock() |
| 299 | if len(w.tasks) == 0 { |
| 300 | return |
| 301 | } |
| 302 | |
| 303 | up := w.numLines + 1 |
| 304 | if !w.repeated { |
| 305 | up-- |
| 306 | w.repeated = true |
| 307 | } |
| 308 | b := aec.NewBuilder( |
| 309 | aec.Hide, // Hide the cursor while we are printing |
| 310 | aec.Up(uint(up)), |
| 311 | aec.Column(0), |
| 312 | ) |
| 313 | _, _ = fmt.Fprint(w.out, b.ANSI) |
| 314 | defer func() { |
| 315 | _, _ = fmt.Fprint(w.out, aec.Show) |
| 316 | }() |
| 317 | |
| 318 | firstLine := fmt.Sprintf("[+] %s %d/%d", w.operation, numDone(w.tasks), len(w.tasks)) |
| 319 | _, _ = fmt.Fprintln(w.out, firstLine) |
| 320 | |
| 321 | // Collect parent tasks in original order |
| 322 | allTasks := slices.Collect(w.parentTasks()) |
| 323 | |
| 324 | // Available lines: terminal height - 2 (header line + potential "more" line) |
| 325 | maxLines := max(terminalHeight-2, 1) |
| 326 | |
| 327 | showMore := len(allTasks) > maxLines |
| 328 | tasksToShow := allTasks |
| 329 | if showMore { |
| 330 | tasksToShow = allTasks[:maxLines-1] // Reserve one line for "more" message |
| 331 | } |
| 332 | |
| 333 | // collect line data and compute timerLen |
| 334 | lines := make([]lineData, len(tasksToShow)) |
| 335 | var timerLen int |
| 336 | for i, t := range tasksToShow { |
| 337 | lines[i] = w.prepareLineData(t) |
| 338 | if len(lines[i].timer) > timerLen { |
| 339 | timerLen = len(lines[i].timer) |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | // pad timers so they all have the same visible width |
| 344 | for i := range lines { |
| 345 | l := &lines[i] |
| 346 | if l.timer == "" { |
| 347 | continue |
| 348 | } |
| 349 | timerWidth := utf8.RuneCountInString(l.timer) |
| 350 | if timerWidth < timerLen { |
| 351 | // Left-pad so the timer's right edge stays aligned on the terminal. |
| 352 | // This also prevents stale suffix characters from visually “sticking” |
| 353 | // when a previously-rendered timer was wider (e.g. "10.6s" -> "0.0s"). |