1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! 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
//!
//! ```no_run
//! 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.
//!
//! ```no_run
//! # use nanospinner::Spinner;
//! # use std::thread;
//! # use std::time::Duration;
//! let handle = Spinner::new("Deploying...").start();
//! thread::sleep(Duration::from_secs(1));
//! handle.fail(); // ✖ Deploying...
//! ```
//!
//! You can also replace the message at finalization:
//!
//! ```no_run
//! # use nanospinner::Spinner;
//! # use std::thread;
//! # use std::time::Duration;
//! 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
//!
//! ```no_run
//! # use nanospinner::Spinner;
//! # use std::thread;
//! # use std::time::Duration;
//! 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:
//!
//! ```no_run
//! # use nanospinner::Spinner;
//! # use std::thread;
//! # use std::time::Duration;
//! 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:
//!
//! ```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.
//!
//! ```no_run
//! 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
//!
//! - Zero dependencies — only `std`
//! - Braille-dot animation (`⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`) on a single line
//! - Multiple concurrent spinners via [`MultiSpinner`] — each line
//! independently updatable and finalizable, or silently dismissible
//! via [`SpinnerLineHandle::clear`]
//! - Update the message while spinning via [`SpinnerHandle::update`]
//! - Finish with [`SpinnerHandle::success`] (✔) or [`SpinnerHandle::fail`] (✖)
//! - Replacement messages via [`SpinnerHandle::success_with`] / [`SpinnerHandle::fail_with`]
//! - Pluggable writer for testing or custom output targets
//! - Automatic TTY detection — ANSI codes and animation are skipped when
//! output is piped or redirected
//! - Clean shutdown via [`Drop`] — no thread leaks if you forget to stop
pub use ;
pub use ;