You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add synchronized spinner API with direct tea.Program integration (#4351)
## Problem
The previous `cmdio.Spinner()` API returned immediately on
`close(spinner)` without waiting for the spinner to terminate. Callers
had no way to ensure the spinner fully stopped before proceeding. This
potentially races with log statements or program termination (failing to
restore cursor state). As of #4336 we perform synchronization on program
termination, but this addresses the symptom not the cause.
```go
spinner := cmdio.Spinner(ctx)
spinner <- "Processing..."
close(spinner) // Returns immediately - spinner still running!
```
## Solution
New `NewSpinner()` API with synchronous `Close()` that blocks until
tea.Program terminates:
```go
sp := cmdio.NewSpinner(ctx)
sp.Update("Processing...")
sp.Close() // Blocks until spinner fully stopped
```
**Changes:**
- `sp.Update()` sends directly to tea.Program (no bridge goroutines)
- `sp.Close()` blocks until cleanup completes (guaranteed termination)
- Race-free concurrent `Close()` calls (context cancellation + explicit)
- Old API wraps new implementation (100% backward compatible)
Refactored 9 manual usages. All tests pass with race detector.
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
0 commit comments