Module conciliator::spin
source · Expand description
Spinner
animations
A couple of different Animation
s are provided, but you can also define your own using Animation::new
or by implementing Animate
.
Check out the example binary to see the provided Animation
s in action!
Because the animation requires terminal escape codes to work it can’t always be displayed.
To keep it simple, the Spinner
reuses the determination that the Stream
made on whether to emit color escape codes to decide whether to display the animation.
This means there is no way (for the user) to disable color output without also disabling the animation (and vice versa).
Obviously, the Spinner
takes care of this for you: it’s not an error to use any of it’s methods when the animation isn’t being displayed.
§Output Stream
The Spinner
animation is printed to the stderr
output stream instead of stdout
.
This makes no difference in normal operation since the terminal emulator will merge the two back together, but it means that the user can still see the animation when they redirect (“pipe”) the standard output into another program (i.e. with |
) or into a file (>>
).
Of course, it’s also possible (though far less common) to redirect the stderr
stream (with 2>>
, for example).
In this case, the animation (probably) won’t be rendered for the user, so no escape codes are emitted.
In fact, not even the Spinner
Message
s will be printed, only output from using the Conciliator
methods will be written (to stdout
, as normal).
§Hidden Cursor
While the Spinner
is active, the cursor is hidden.
Since it would jump around or cover parts of the animation, it looks better that way.
Unfortunately, the terminal will not automatically un-hide the cursor when the program ends, which means the cursor might stay hidden when your program crashes, or is killed / interrupted (i.e. Ctrl+C
) while spinning.
You can mitigate this by implementing orderly shutdown and ensuring that destructors get run as the program ends.
Of course, there’s nothing your program can do if it gets SIGKILL
’d, but if you avoid std::process::exit
and install a signal handler for SIGINT
, you probably have most situations covered.
Even if your program panics, the Rust panic handler will (try to) run every destructor before exiting, and the escape code for showing the cursor will get printed by one of them.
If all else fails, you can usually still fix your terminal manually using the reset
command.
§Output while spinning
The animation is printed to the terminal using control characters (and \r
) to stay in the same line and always overwrite the last frame of the animation.
Because of this, access to the output needs to be synchronized: whenever there’s something to be printed, the line with the animation needs to be erased first, then the thing is printed, and then the animation put back.
The Spinner
takes care of this, but it can only do that when you go through its Conciliator
methods – instead of the Claw
’s.
So, to prevent this from happening accidentally, the Spinner
holds a mutable reference to the Claw
.
Of course, you can still mess it up by going to the standard output directly, i.e. using std::io::Stdout
, println
, dbg
, eprint
and so on.
You could create multiple Claw
s, too.
Don’t.
§Async
By default, creating a Spinner
will spawn a new thread to do the animation.
Then, when it is dropped, finished, or cleared, the “main” thread will block until the other thread returns.
While these blocks should resolve very quickly, it could still be an issue when used within a runtime / async
executor, because while a thread is blocking, the runtime can’t schedule something else on it.
Because of this, there is another implementation of the Spinner
, specifically for use with the Tokio runtime.
It spawns a Tokio task instead of a thread, and it uses Tokio message queues instead of std::sync::mpsc
.
To use this implementation instead, enable the tokio
crate feature.
When you enable the tokio
feature, Spinner::clear
and Spinner::finish
will become async
, and you need to make sure to call one of them, as explained below.
§Dropping the Spinner
Only the synchronous Spinner
should ever be dropped implicitly (that is, without calling Spinner::clear
or Spinner::finish
).
This means: if you enable the tokio
feature (which is off by default), you have to make sure to call and await Spinner::clear
or Spinner::finish
when you’re done with it!
If you don’t explicitly drop it using one of these methods, the destructor for it has to clean it up, and it may do a worse job.
Because destructors cannot be async
, the task will be aborted instead of joined, which should still work, but it could cause one or two lines of output being mangled.
Again, this is only an issue if you drop the Spinner
without calling either Spinner::clear
or Spinner::finish
, and the tokio
feature is enabled.
For the default, thread-based implementation, dropping the Spinner
is exactly the same as calling Spinner::clear
explicitly.
§Example
Creating a Spinner
with the DOT
Animation
(taken from FGRibreau/spinners).
use conciliator::{Conciliator, Spinner};
use conciliator::spin::DOT;
// `mut` so that the Spinner can get an exclusive (mutable) reference
let mut con = conciliator::init();
con.status("Starting process");
let sp = Spinner::new(&mut con, DOT, "Downloading thing...");
// < download the thing >
sp.status("Download complete");
sp.message("Unpacking thing...");
// < unpack the thing >
sp.status("Thing unpacked");
sp.message("Process finished");
sp.finish().await; // without the tokio feature, this is not async
// you can only use the Claw after the Spinner is finished
con.info("Doing other thing");
Structs§
- A simple animation that cycles through a series of frames
- Show that something is ongoing with an animated tag & message
Constants§
- 3-wide Braille character animation, two opposing groups of dots looping
- Narrow spinner animation using Braille characters
- Spinner animation using Braille characters, wider version of
DOT
- Same as
LOOP
, but even wider, Braille dots go all the way to the edge - Narrow spinner animation using half-filled square characters
- Narrow spinner animation using triangle characters
Traits§
- Define a custom animation