Major refactor (#2)
This commit is contained in:
commit
0a38760780
|
@ -2,7 +2,7 @@
|
||||||
name = "spinoff"
|
name = "spinoff"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
author = "ad4m"
|
authors = ["ad4m"]
|
||||||
description = "🔨 Simple to use Rust library for displaying spinners in the terminal."
|
description = "🔨 Simple to use Rust library for displaying spinners in the terminal."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
homepage = "https://github.com/ad4mx/spinoff"
|
homepage = "https://github.com/ad4mx/spinoff"
|
||||||
|
@ -13,8 +13,8 @@ categories = ["command-line-interface"]
|
||||||
include = ["src/**/*", "README.md"]
|
include = ["src/**/*", "README.md"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lazy_static = "1.4.0"
|
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
yansi = "0.5.1"
|
yansi = "0.5.1"
|
||||||
strum = { version = "0.24.0", features = ["derive"] }
|
strum = { version = "0.24.0", features = ["derive"] }
|
||||||
|
once_cell = "1.13.0"
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use spinoff::Spinners;
|
use spinoff::{Spinner, Spinners};
|
||||||
use std::thread::sleep;
|
use std::{thread::sleep, time::Duration};
|
||||||
use std::time::Duration;
|
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut spin = spinoff::new(Spinners::Dots, "Spinning...", None);
|
let mut spin = Spinner::new(Spinners::Dots, "", None);
|
||||||
for spinner in Spinners::iter() {
|
for spinner in Spinners::iter() {
|
||||||
spin = spin.update(spinner, "Spinning...", None);
|
spin.update(spinner, format!("Spinners::{}", spinner), None);
|
||||||
sleep(Duration::from_secs(1));
|
sleep(Duration::from_secs(2));
|
||||||
}
|
}
|
||||||
println!("Done!");
|
spin.stop_with_message("Done!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use spinoff::Spinners;
|
use spinoff::{Spinner, Spinners};
|
||||||
use std::thread::sleep;
|
use std::{thread::sleep, time::Duration};
|
||||||
use std::time::Duration;
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let sp = spinoff::new(Spinners::Dots, "Loading...", None);
|
let sp = Spinner::new(Spinners::Dots, "Loading...", None);
|
||||||
sleep(Duration::from_millis(800));
|
sleep(Duration::from_millis(8000));
|
||||||
sp.success("Success!");
|
sp.success("Success!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use spinoff::Spinners;
|
use spinoff::{Spinner, Spinners};
|
||||||
use std::thread::sleep;
|
use std::{thread::sleep, time::Duration};
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let sp = spinoff::new(Spinners::Dots, "Loading...", None);
|
let sp = Spinner::new(Spinners::Dots, "Loading...", None);
|
||||||
sleep(Duration::from_secs(5));
|
sleep(Duration::from_secs(5));
|
||||||
sp.stop_and_persist("🍕", "Pizza!");
|
sp.stop_and_persist("🍕", "Pizza!");
|
||||||
}
|
}
|
||||||
|
|
557
src/lib.rs
557
src/lib.rs
|
@ -1,287 +1,340 @@
|
||||||
//! ## spinoff
|
//! ## spinoff
|
||||||
//!
|
//!
|
||||||
//! `spinoff` is a simple library for displaying spinners in the terminal.
|
//! `spinoff` is a simple library for displaying spinners in the terminal.
|
||||||
|
//!
|
||||||
//! ### Usage
|
//! ### Usage
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```
|
||||||
//! use spinoff::Spinners;
|
//! # use spinoff::*;
|
||||||
//! use std::thread::sleep;
|
//! # use std::thread::sleep;
|
||||||
//! use std::time::Duration;
|
//! # use std::time::Duration;
|
||||||
//!
|
//! #
|
||||||
//! let sp = spinoff::new(Spinners::Dots, "Loading...", None);
|
//! let sp = Spinner::new(Spinners::Dots, "Loading...", None);
|
||||||
//! sleep(Duration::from_millis(800));
|
//! sleep(Duration::from_millis(800));
|
||||||
//! sp.success("Success!");
|
//! sp.success("Success!");
|
||||||
//!
|
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
//! ### Spinners
|
//! ### Spinners
|
||||||
//! There are over 80+ spinners available in the `Spinners` enum.
|
//!
|
||||||
|
//! There are over 80+ spinners available in the [`Spinners`] enum.
|
||||||
//!
|
//!
|
||||||
//! ### Colors
|
//! ### Colors
|
||||||
//! You can also color your spinners without any hassle. Simply pass a color to the `color` option.
|
|
||||||
//! There are 6 colors available: `blue`, `green`, `red`, `yellow`, `cyan`, `white`.
|
|
||||||
//! Don't want any of that? Simply pass `None` to the `color` option.
|
|
||||||
//!
|
//!
|
||||||
#![allow(clippy::needless_return)]
|
//! You can also color your spinners without any hassle. Simply pass a color to the `color` option.
|
||||||
mod utils;
|
//! There are 6 colors available: blue, green, red, yellow, cyan, white.
|
||||||
use crate::utils::printer::{delete_last_line, init_color};
|
//! Don't want any of that? Simply pass `None` to the `color` option.
|
||||||
use crate::utils::spinner_data::SPINNER_FRAMES;
|
|
||||||
pub use crate::utils::spinner_enum::Spinners;
|
use std::borrow::Cow;
|
||||||
use std::io::{stdout, Write};
|
use std::io::{stdout, Write};
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::{atomic::AtomicBool, Arc};
|
||||||
use std::sync::Arc;
|
use std::thread::{self, JoinHandle};
|
||||||
use std::thread;
|
|
||||||
// Using this type for better readability.
|
/// Using this type for better readability.
|
||||||
type StringLiteral = &'static str;
|
type StringLiteral = &'static str;
|
||||||
|
|
||||||
/// All methods for the spinner are implemented in this struct.
|
mod printer;
|
||||||
/// This struct has an `Arc<AtomicBool>` field, which is later used in the `stop` type methods to stop the thread printing the spinner.
|
mod spinner_data;
|
||||||
/// The `msg` field is needed for the `clear` and `stop` methods for knowing how many spaces to print to clean up the previous spinner.
|
mod spinner_enum;
|
||||||
|
|
||||||
|
use printer::{delete_last_line, init_color};
|
||||||
|
use spinner_data::SPINNER_FRAMES;
|
||||||
|
pub use spinner_enum::Spinners;
|
||||||
|
|
||||||
|
/// Terminal spinner.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Spinner {
|
pub struct Spinner {
|
||||||
|
thread_handle: Option<JoinHandle<()>>,
|
||||||
|
|
||||||
|
/// This struct has an `Arc<AtomicBool>` field, which is later used in the `stop` type methods to stop the thread printing the spinner.
|
||||||
still_spinning: Arc<AtomicBool>,
|
still_spinning: Arc<AtomicBool>,
|
||||||
msg: StringLiteral,
|
|
||||||
|
msg: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
/// Create a new spinner.
|
|
||||||
///
|
/// Color for spinner.
|
||||||
/// # Arguments
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||||
/// * `spinner_type` - The spinner to use.
|
#[non_exhaustive]
|
||||||
/// * `msg` - The message to display.
|
pub enum Color {
|
||||||
/// * `color` - The color of the spinner.
|
Blue,
|
||||||
///
|
Green,
|
||||||
/// # Example
|
Red,
|
||||||
/// ```rust
|
Yellow,
|
||||||
/// use spinoff::Spinners;
|
Cyan,
|
||||||
/// use std::thread::sleep;
|
White,
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// let sp = spinoff::new(Spinners::Dots, "Hello", "blue".into()); // Color can also be `None` or `Some("blue")`
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp.clear();
|
|
||||||
/// ```
|
|
||||||
/// # Panics
|
|
||||||
/// * `Invalid color` - If the color is not one of the following: `blue`, `green`, `red`, `yellow`, `cyan`, `white` or `None`.
|
|
||||||
/// * `Invalid spinner` - If the spinner is not one of those belonging to the `Spinners` enum.
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
/// * The spinner immediately starts spinning upon creation.
|
|
||||||
pub fn new(spinner_type: Spinners, msg: StringLiteral, color: Option<StringLiteral>) -> Spinner {
|
|
||||||
let still_spinning = Arc::new(AtomicBool::new(true));
|
|
||||||
// Clone the atomic bool so that we can use it in the thread and return the original one later.
|
|
||||||
let still_spinning_cloned = still_spinning.clone();
|
|
||||||
// We use atomic bools to make the thread stop itself when the `spinner.stop()` method is called.
|
|
||||||
thread::spawn(move || {
|
|
||||||
let spinner_data = SPINNER_FRAMES.get(&spinner_type).unwrap();
|
|
||||||
let mut stdout = stdout();
|
|
||||||
// Iterate over all the frames of the spinner while the atomic bool is true.
|
|
||||||
let iterator = spinner_data
|
|
||||||
.frames
|
|
||||||
.iter()
|
|
||||||
.cycle()
|
|
||||||
.take_while(|_| still_spinning_cloned.load(std::sync::atomic::Ordering::Relaxed));
|
|
||||||
for frame in iterator {
|
|
||||||
let text = format!("\r{} {}", init_color(color, frame.to_string()), msg);
|
|
||||||
stdout.write_all(text.as_bytes()).unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
thread::sleep(std::time::Duration::from_millis(
|
|
||||||
spinner_data.interval as u64,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Return a Spinner struct so we can implement methods on it instead of `spinoff::stop()` etc.
|
|
||||||
let spinner = Spinner {
|
|
||||||
still_spinning,
|
|
||||||
msg,
|
|
||||||
};
|
|
||||||
return spinner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spinner {
|
impl Spinner {
|
||||||
/// Stop the spinner.
|
/// Create a new spinner.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `spinner_type` - The spinner to use.
|
||||||
|
/// * `msg` - The message to display.
|
||||||
|
/// * `color` - The color of the spinner.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
|
||||||
/// use spinoff::Spinners;
|
|
||||||
/// use std::thread::sleep;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
///
|
||||||
/// let sp = spinoff::new(Spinners::Dots, "Hello", None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp.stop();
|
|
||||||
/// ```
|
/// ```
|
||||||
/// # Notes
|
/// # use spinoff::*;
|
||||||
/// * The spinner will be deleted after this method is called, the message will remain though.
|
/// # use std::thread::sleep;
|
||||||
/// * This method also sets the `still_spinning` atomic bool to `false`, which stops the spinner thread.
|
/// # use std::time::Duration;
|
||||||
/// * This method cannot be called if the spinner is already stopped.
|
/// #
|
||||||
///
|
/// let sp = Spinner::new(Spinners::Dots, "Hello", Some(Color::Blue));
|
||||||
pub fn stop(self) {
|
|
||||||
self.still_spinning
|
|
||||||
.store(false, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
print!("\r");
|
|
||||||
println!("{} ", self.msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stops the spinner and prints a message on a new line.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use spinoff::Spinners;
|
|
||||||
/// use std::thread::sleep;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// let sp = spinoff::new(Spinners::Dots, "Hello", None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp.stop_with_message("Bye");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// * The method will panic if the color is not one of the following: `blue`, `green`, `red`, `yellow`, `cyan`, `white` or `None`.
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
/// * This method cannot be called if the spinner is already stopped.
|
|
||||||
///
|
|
||||||
pub fn stop_with_message(self, msg: StringLiteral) {
|
|
||||||
self.stop();
|
|
||||||
println!("{}", &msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the spinner and message and prints a new line with a symbol and message.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use spinoff::Spinners;
|
|
||||||
/// use std::thread::sleep;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// let sp = spinoff::new(Spinners::Dots, "Hello", None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp.stop_and_persist("🍕", "Pizza!");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// * The method will panic if the color is not one of the following: `blue`, `green`, `red`, `yellow`, `cyan`, `white` or `None`.
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
/// * This method will delete the last line of the terminal, so it is recommended to not print anything in between the spinner and the success message.
|
|
||||||
/// * This method cannot be called if the spinner is already stopped.
|
|
||||||
pub fn stop_and_persist(self, symbol: StringLiteral, msg: StringLiteral) {
|
|
||||||
self.clear();
|
|
||||||
println!("{} {}", &symbol, &msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the last line of the terminal and prints a success symbol with a message.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use spinoff::Spinners;
|
|
||||||
/// use std::thread::sleep;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// let sp = spinoff::new(Spinners::Dots, "Hello", None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp.success("Success!");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
/// * This method cannot be called if the spinner is already stopped.
|
|
||||||
/// * This method will delete the last line of the terminal, so it is recommended to not print anything in between the spinner and the success message.
|
|
||||||
pub fn success(self, msg: StringLiteral) {
|
|
||||||
self.clear();
|
|
||||||
println!("{} {}", init_color(Some("green"), "✔".to_string()), &msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the last line of the terminal and prints a failure symbol with a message.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use spinoff::Spinners;
|
|
||||||
/// use std::thread::sleep;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// let sp = spinoff::new(Spinners::Dots, "Hello", None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp.fail("Failed!");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
/// * This method will delete the last line of the terminal, so it is recommended to not print anything in between the spinner and the failure message.
|
|
||||||
/// * This method cannot be called if the spinner is already stopped.
|
|
||||||
///
|
|
||||||
pub fn fail(self, msg: StringLiteral) {
|
|
||||||
self.clear();
|
|
||||||
println!("{} {}", init_color(Some("red"), "✖".to_string()), &msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the last line of the terminal and prints a warning symbol with a message.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use spinoff::Spinners;
|
|
||||||
/// use std::thread::sleep;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// let sp = spinoff::new(Spinners::Dots, "Hello", None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp.warn("Look out!");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
/// * This method will delete the last line of the terminal, so it is recommended to not print anything in between the spinner and the warning message.
|
|
||||||
/// * This method cannot be called if the spinner is already stopped.
|
|
||||||
pub fn warn(self, msg: StringLiteral) {
|
|
||||||
self.clear();
|
|
||||||
println!("{} {}", init_color(Some("yellow"), "⚠".to_string()), &msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the last line of the terminal and prints a new spinner.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use spinoff::Spinners;
|
|
||||||
/// use std::thread::sleep;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// let mut sp = spinoff::new(Spinners::Dots, "Hello", None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp = sp.update(Spinners::Dots2, "Goodbye".into(), None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
|
||||||
/// sp.stop();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
/// * This method will delete the last line of the terminal, so it is recommended to not print anything in between the spinner and the new spinner instance.
|
|
||||||
/// * This method cannot be called if the spinner is already stopped.
|
|
||||||
///
|
|
||||||
pub fn update(
|
|
||||||
self,
|
|
||||||
spinner: Spinners,
|
|
||||||
msg: StringLiteral,
|
|
||||||
color: Option<StringLiteral>,
|
|
||||||
) -> Spinner {
|
|
||||||
self.still_spinning
|
|
||||||
.store(false, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
delete_last_line(self.msg);
|
|
||||||
self::new(spinner, msg, color)
|
|
||||||
}
|
|
||||||
/// Deletes the last line of the terminal.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use spinoff::Spinners;
|
|
||||||
/// use std::thread::sleep;
|
|
||||||
/// use std::time::Duration;
|
|
||||||
///
|
|
||||||
/// let mut sp = spinoff::new(Spinners::Dots, "Hello", None);
|
|
||||||
/// sleep(Duration::from_millis(800));
|
/// sleep(Duration::from_millis(800));
|
||||||
/// sp.clear();
|
/// sp.clear();
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Notes
|
/// # Notes
|
||||||
/// * This method will delete the last line of the terminal, so it is recommended to not print anything in between the spinner and the `delete` method call.
|
///
|
||||||
/// * This method cannot be called if the spinner is already stopped.
|
/// * The spinner immediately starts spinning upon creation.
|
||||||
pub fn clear(self) {
|
///
|
||||||
|
pub fn new<T>(spinner_type: Spinners, msg: T, color: Option<Color>) -> Self
|
||||||
|
where
|
||||||
|
T: Into<Cow<'static, str>>,
|
||||||
|
{
|
||||||
|
let still_spinning = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
// Gain ownership of the message for the thread to use
|
||||||
|
let msg = msg.into();
|
||||||
|
|
||||||
|
// We use atomic bools to make the thread stop itself when the `spinner.stop()` method is called.
|
||||||
|
let handle = thread::spawn({
|
||||||
|
// Clone the atomic bool so that we can use it in the thread and return the original one later.
|
||||||
|
let still_spinning = Arc::clone(&still_spinning);
|
||||||
|
|
||||||
|
let msg = msg.clone();
|
||||||
|
|
||||||
|
move || {
|
||||||
|
let spinner_data = SPINNER_FRAMES.get(&spinner_type).unwrap();
|
||||||
|
|
||||||
|
let stdout = stdout();
|
||||||
|
|
||||||
|
// Iterate over all the frames of the spinner while the atomic bool is true.
|
||||||
|
let frames = spinner_data
|
||||||
|
.frames
|
||||||
|
.iter()
|
||||||
|
.cycle()
|
||||||
|
.take_while(|_| still_spinning.load(std::sync::atomic::Ordering::Relaxed));
|
||||||
|
|
||||||
|
let mut last_length = 0;
|
||||||
|
|
||||||
|
for frame in frames {
|
||||||
|
// This is dependant on the stdout attached is a terminal that respects \r
|
||||||
|
let mut stdout_lock = stdout.lock();
|
||||||
|
let frame_str = format!(" {} {}", init_color(color, frame.to_string()), msg);
|
||||||
|
delete_last_line(last_length);
|
||||||
|
last_length = frame_str.bytes().len();
|
||||||
|
write!(stdout_lock, "{}", frame_str).unwrap();
|
||||||
|
stdout_lock.flush().unwrap();
|
||||||
|
drop(stdout_lock);
|
||||||
|
|
||||||
|
thread::sleep(std::time::Duration::from_millis(
|
||||||
|
spinner_data.interval as u64,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_last_line(last_length);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return a Spinner struct so we can implement methods on it instead of `spinoff::stop()` etc.
|
||||||
|
Self {
|
||||||
|
thread_handle: Some(handle),
|
||||||
|
still_spinning,
|
||||||
|
msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stop the spinner.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use spinoff::{Spinners, Spinner};
|
||||||
|
/// # use std::thread::sleep;
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// #
|
||||||
|
/// let sp = Spinner::new(Spinners::Dots, "Hello", None);
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
/// sp.stop();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// * The spinner will be dropped after this method is called, the message will remain though.
|
||||||
|
///
|
||||||
|
pub fn stop(mut self) {
|
||||||
|
self.stop_spinner_thread();
|
||||||
|
|
||||||
|
// print message
|
||||||
|
println!("{}", self.msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stops the spinner and prints a message on a new line.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use spinoff::{Spinners, Spinner};
|
||||||
|
/// # use std::thread::sleep;
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// #
|
||||||
|
/// let sp = Spinner::new(Spinners::Dots, "Hello", None);
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
/// sp.stop_with_message("Bye");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn stop_with_message(mut self, msg: &str) {
|
||||||
|
self.stop_spinner_thread();
|
||||||
|
|
||||||
|
// put the message over the spinner
|
||||||
|
println!("{}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the spinner and message and prints a new line with a symbol and message.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use spinoff::{Spinners, Spinner};
|
||||||
|
/// # use std::thread::sleep;
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// #
|
||||||
|
/// let sp = Spinner::new(Spinners::Dots, "Hello", None);
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
/// sp.stop_and_persist("🍕", "Pizza!");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn stop_and_persist(mut self, symbol: &str, msg: &str) {
|
||||||
|
self.stop_spinner_thread();
|
||||||
|
|
||||||
|
println!("{} {}", symbol, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the last line of the terminal and prints a success symbol with a message.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use spinoff::{Spinners, Spinner};
|
||||||
|
/// # use std::thread::sleep;
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// #
|
||||||
|
/// let sp = Spinner::new(Spinners::Dots, "Hello", None);
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
/// sp.success("Success!");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn success(mut self, msg: StringLiteral) {
|
||||||
|
self.stop_spinner_thread();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{} {}",
|
||||||
|
init_color(Some(Color::Green), "✔".to_string()),
|
||||||
|
&msg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the last line of the terminal and prints a failure symbol with a message.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use spinoff::{Spinners, Spinner};
|
||||||
|
/// # use std::thread::sleep;
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// #
|
||||||
|
/// let sp = Spinner::new(Spinners::Dots, "Hello", None);
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
/// sp.fail("Failed!");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn fail(mut self, msg: StringLiteral) {
|
||||||
|
self.stop_spinner_thread();
|
||||||
|
|
||||||
|
println!("{} {}", init_color(Some(Color::Red), "✖".to_string()), &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the last line of the terminal and prints a warning symbol with a message.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use spinoff::{Spinners, Spinner};
|
||||||
|
/// # use std::thread::sleep;
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// #
|
||||||
|
/// let sp = Spinner::new(Spinners::Dots, "Hello", None);
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
/// sp.warn("Look out!");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn warn(mut self, msg: StringLiteral) {
|
||||||
|
self.stop_spinner_thread();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{} {}",
|
||||||
|
init_color(Some(Color::Yellow), "⚠".to_string()),
|
||||||
|
&msg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the last line of the terminal and prints a new spinner.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use spinoff::*;
|
||||||
|
/// # use std::thread::sleep;
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// #
|
||||||
|
/// let mut sp = Spinner::new(Spinners::Dots, "Hello", None);
|
||||||
|
///
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
/// sp.update(Spinners::Dots2, "Goodbye", None);
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
///
|
||||||
|
/// sp.stop();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn update<T>(&mut self, spinner: Spinners, msg: T, color: Option<Color>)
|
||||||
|
where
|
||||||
|
T: Into<Cow<'static, str>>,
|
||||||
|
{
|
||||||
|
self.stop_spinner_thread();
|
||||||
|
|
||||||
|
let _ = std::mem::replace(self, Self::new(spinner, msg, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the last line of the terminal.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use spinoff::{Spinners, Spinner};
|
||||||
|
/// # use std::thread::sleep;
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// #
|
||||||
|
/// let mut sp = Spinner::new(Spinners::Dots, "Hello", None);
|
||||||
|
/// sleep(Duration::from_millis(800));
|
||||||
|
/// sp.clear();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn clear(mut self) {
|
||||||
|
self.stop_spinner_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stop the spinner thread and wait for it.
|
||||||
|
fn stop_spinner_thread(&mut self) {
|
||||||
|
// set flag to signal thread to stop
|
||||||
self.still_spinning
|
self.still_spinning
|
||||||
.store(false, std::sync::atomic::Ordering::Relaxed);
|
.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||||
delete_last_line(self.msg);
|
|
||||||
|
// wait for the thread to actually stop
|
||||||
|
self.thread_handle
|
||||||
|
.take()
|
||||||
|
.expect("Stopping the spinner thread should only happen once.")
|
||||||
|
.join()
|
||||||
|
.expect("Thread to join.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
28
src/printer.rs
Normal file
28
src/printer.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use crate::Color;
|
||||||
|
use std::io::{stdout, Write};
|
||||||
|
use yansi::Paint;
|
||||||
|
|
||||||
|
pub fn delete_last_line(clear_length: usize) {
|
||||||
|
let mut stdout_lock = stdout().lock();
|
||||||
|
|
||||||
|
write!(stdout_lock, "\r").unwrap();
|
||||||
|
for _ in 0..clear_length {
|
||||||
|
write!(stdout_lock, " ").unwrap();
|
||||||
|
}
|
||||||
|
write!(stdout_lock, "\r").unwrap();
|
||||||
|
|
||||||
|
drop(stdout_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accepts a color option and spinner, returns a Paint<String> object (e.g. `Paint::green(spinner)`)
|
||||||
|
pub fn init_color(color: Option<Color>, spinner: String) -> Paint<String> {
|
||||||
|
match color {
|
||||||
|
Some(Color::Blue) => Paint::blue(spinner),
|
||||||
|
Some(Color::Green) => Paint::green(spinner),
|
||||||
|
Some(Color::Red) => Paint::red(spinner),
|
||||||
|
Some(Color::Yellow) => Paint::yellow(spinner),
|
||||||
|
Some(Color::Cyan) => Paint::cyan(spinner),
|
||||||
|
Some(Color::White) => Paint::new(spinner),
|
||||||
|
None => Paint::new(spinner),
|
||||||
|
}
|
||||||
|
}
|
1189
src/spinner_data.rs
Normal file
1189
src/spinner_data.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,17 @@
|
||||||
use strum::EnumIter;
|
use strum::EnumIter;
|
||||||
|
|
||||||
/// An enum of all the available spinners.
|
/// An enum of all the available spinners.
|
||||||
|
///
|
||||||
/// Contains around 80+ spinners.
|
/// Contains around 80+ spinners.
|
||||||
|
/// It is recommended to use the `all_spinners` example to view each spinner's animation.
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// cargo run --example all_spinners
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// Each variant in this enum is assigned to a HashMap holding it's frames and interval count.
|
/// Each variant in this enum is assigned to a HashMap holding it's frames and interval count.
|
||||||
#[derive(Debug, Eq, Hash, PartialEq, EnumIter)]
|
///
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, EnumIter, strum::Display)]
|
||||||
pub enum Spinners {
|
pub enum Spinners {
|
||||||
Dots,
|
Dots,
|
||||||
Dots2,
|
Dots2,
|
|
@ -1,3 +0,0 @@
|
||||||
pub mod printer;
|
|
||||||
pub mod spinner_data;
|
|
||||||
pub mod spinner_enum;
|
|
|
@ -1,25 +0,0 @@
|
||||||
use yansi::Paint;
|
|
||||||
|
|
||||||
use crate::StringLiteral;
|
|
||||||
|
|
||||||
pub fn delete_last_line(msg: StringLiteral) {
|
|
||||||
print!("\r");
|
|
||||||
for _ in 0..(msg.len() + 30) {
|
|
||||||
print!(" ");
|
|
||||||
}
|
|
||||||
print!("\r");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Accepts a color option and spinner, returns a Paint<String> object (e.g. `Paint::green(spinner)`)
|
|
||||||
pub fn init_color(color: Option<&str>, spinner: String) -> Paint<String> {
|
|
||||||
match color {
|
|
||||||
Some("blue") => Paint::blue(spinner),
|
|
||||||
Some("green") => Paint::green(spinner),
|
|
||||||
Some("red") => Paint::red(spinner),
|
|
||||||
Some("yellow") => Paint::yellow(spinner),
|
|
||||||
Some("cyan") => Paint::cyan(spinner),
|
|
||||||
Some("white") => Paint::new(spinner),
|
|
||||||
None => Paint::new(spinner),
|
|
||||||
_ => panic!("invalid color: expected one of the following: blue, green, red, yellow, cyan, white or None"),
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue