Show progress without corrupting CI logs¶
Wrap the slow part in a spinner¶
use rtb_tui::Spinner;
let mut spinner = Spinner::new("resolving dependencies…");
let manifest = resolve().await?;
spinner.set_message("downloading…");
let archive = download(&manifest).await?;
spinner.finish();
println!("installed {} packages", manifest.len());
Spinner::new draws the first frame immediately, so the user sees the
message as soon as the work starts rather than after the first stage
finishes.
Do nothing special for CI¶
There is no --quiet to thread through and no is_ci() check to
write. Spinner::new asks whether stderr is a terminal, and when it is
not — a CI job log, a redirect to a file, a tool speaking a protocol
over stdio — every method becomes a no-op that writes nothing at all.
That check happens once, in the constructor. Constructing the spinner before you decide whether the operation is long enough to need one is still cheap.
Give the spinner something to say¶
Nothing advances the spinner on a timer. The glyph is a single ⠋ and
it is redrawn only when you call set_message, so a spinner that goes
thirty seconds between messages shows a frozen line for thirty seconds.
The fix is more stages, not a faster animation:
If you genuinely need a moving indicator during one indivisible await, this crate will not give you one — see Why the spinner does not animate.
Clear the line before printing anything else¶
finish clears the spinner's line and leaves the cursor at column 0.
Print your result after that, or the spinner text and your output
share a line.
Dropping the spinner does the same cleanup, so an early return or a
? in the middle of the work still leaves a clean terminal — the
Drop impl runs on the way out.
What finish does not do is print a completion message. If you want
"done", print it yourself.
Keep the spinner off stdout¶
The spinner writes to stderr only. That is what lets a caller pipe your
stdout into jq while a human still sees progress, and it is why the
spinner and a --output json flag can be on at the same time without
corrupting the JSON.
Do not mirror progress to stdout to make it more visible. That is the one change that breaks every consumer of the command.
Next¶
- Spinner reference — exactly what is
written, and what
finishandDropeach do.