Skip to main content

Crate nanospinner

Crate nanospinner 

Source
Expand description

A minimal, zero-dependency terminal spinner for Rust CLI applications.

nanospinner provides lightweight animated spinners for giving users feedback during long-running CLI operations. Run a single spinner or multiple concurrent spinners — each on a background thread so your main logic stays unblocked.

Built with only the Rust standard library — no transitive dependencies, fast compile times, and a tiny binary footprint.

§Quick start

use nanospinner::Spinner;
use std::thread;
use std::time::Duration;

let handle = Spinner::new("Loading...").start();
thread::sleep(Duration::from_secs(2));
handle.success();

§Usage

§Single spinner

§Finishing with success or failure

Use SpinnerHandle::success for a green ✔ or SpinnerHandle::fail for a red ✖. Both consume the handle and stop the animation.

let handle = Spinner::new("Deploying...").start();
thread::sleep(Duration::from_secs(1));
handle.fail(); // ✖ Deploying...

You can also replace the message at finalization:

let handle = Spinner::new("Compiling...").start();
thread::sleep(Duration::from_secs(2));
handle.success_with("Compiled in 2.1s"); // ✔ Compiled in 2.1s

§Updating the message mid-spin

let handle = Spinner::new("Step 1...").start();
thread::sleep(Duration::from_secs(1));
handle.update("Step 2...");
thread::sleep(Duration::from_secs(1));
handle.success_with("All steps complete");

§Custom writers

Write to stderr or any std::io::Write + Send target:

let handle = Spinner::with_writer("Processing...", std::io::stderr()).start();
thread::sleep(Duration::from_secs(1));
handle.success();

§TTY detection

When stdout is not a terminal (e.g. piped to a file), nanospinner automatically skips the animation and ANSI escape codes. The final result is printed as plain text:

$ my_tool | cat
✔ Done!

For custom writers you can force TTY behavior with Spinner::with_writer_tty.

§Multiple spinners

MultiSpinner renders several spinner lines at once, each independently updatable and finalizable. Use MultiSpinnerHandle::add to dynamically append new lines — even after the animation has started. Lines can be finished with SpinnerLineHandle::success / SpinnerLineHandle::fail, or silently dismissed with SpinnerLineHandle::clear — cleared lines disappear and the remaining lines collapse together with no gap.

use nanospinner::MultiSpinner;
use std::thread;
use std::time::Duration;

let handle = MultiSpinner::new().start();

let line1 = handle.add("Compiling crate A...");
let line2 = handle.add("Compiling crate B...");
let line3 = handle.add("Checking crate C...");

thread::sleep(Duration::from_secs(2));
line1.success();
line2.fail_with("Crate B had errors.");
line3.clear(); // silently dismissed — no output

handle.stop();

Each SpinnerLineHandle is Send, so you can move it to another thread and finalize or clear it from there. For custom output targets or explicit TTY control, see MultiSpinner::with_writer and MultiSpinner::with_writer_tty.

§Features

Structs§

MultiSpinner
A builder for a multi-spinner group that manages multiple concurrent spinners on separate terminal lines.
MultiSpinnerHandle
Handle returned by MultiSpinner::start for managing a running multi-spinner group.
Spinner
A builder for configuring and starting a terminal spinner.
SpinnerHandle
Handle for controlling a running spinner.
SpinnerLineHandle
Handle for controlling a single spinner line within a multi-spinner group.