💫 Easy to use, robust Rust library for displaying spinners in the terminal

Overview

spinoff

an easy to use, robust library for displaying spinners in the terminal

Version Downloads Docs License Actions

🔨 Install

Add as a dependency to your Cargo.toml:

[dependencies]
spinoff = "0.7.0"

Usage

use spinoff::{Spinner, spinners, Color};
use std::thread::sleep;
use std::time::Duration;

let spinner = Spinner::new(spinners::Dots, "Loading...", Color::Blue); 
sleep(Duration::from_secs(3));
spinner.success("Done!");

Update a spinner

use spinoff::{Spinner, spinners, Color};
use std::thread::sleep;
use std::time::Duration;

let mut spinner = Spinner::new(spinners::Aesthetic, "Loading...", Color::Red); 
sleep(Duration::from_secs(3));
spinner.update(Spinners::Dots2, "Retrying...", None);
sleep(Duration::from_secs(3));
spinner.stop()

Specify an output stream

use spinoff::{Spinner, spinners, Color, Streams};
use std::thread::sleep;
use std::time::Duration;

let spinner = Spinner::new_with_stream(spinners::Line, "Loading...", Color::Yellow, Streams::Stderr);
sleep(Duration::from_secs(3));
spinner.stop_and_persist("📜", "Task done.");

💫 Spinners

spinoff includes over 80+ spinner variants out of the box. All spinner variants are treated as features that can be enabled or disabled. By default, all of them are enabled for ease of use. To disable/enable variants, you will have to edit your cargo.toml file:

[dependencies]
spinoff = { version = "0.7.0", features = ["dots", "arc", "line"] }

Any suggestions for new spinner variants are welcome.

Creating your own spinner

You can create your own spinner using the spinner! macro:

use spinoff::*;
use std::thread::sleep;
use std::time::Duration;

let frames = spinner!([">", ">>", ">>>"], 100);
let sp = Spinner::new(frames, "Hello World!", None);
sleep(Duration::from_millis(800));
sp.stop();

Note for Windows Users

For colors to work properly, you need to add a few extra lines to your code:

use colored::control
control::enable_virtual_terminal(true).unwrap();

📖 Documentation

⚙ Examples

cargo run --example simple
cargo run --example stream
cargo run --example stop_and_persist

Other examples can be found in the documentation.

🚧 Contributing

Any contributions to this crate are highly appreciated. If you have any ideas/suggestions/bug fixes, please open an issue or a pull request. If you like the project, star this project on GitHub.

📑 License

This crate is licensed under the MIT license.

Comments
  • Colours not working in Windows

    Colours not working in Windows

    Describe the bug In a Windows command line terminal, colours are not correctly displayed, instead random letters and symbols are (which I assume is the supposed syntax for the colour). This seems to be a problem with the colored crate but I would suggest to at least when using the None option for the colours to add no such syntax at all and just the spinner with the text (looking on how its done in the source code).

    To Reproduce Steps to reproduce the behavior:

    1. Create any spinner with any color (includine the None option)
    2. Open the created binary on a windows command line terminal (not the new Windows Terminal)
    3. See error

    Expected behavior A colour should be displayed (again, probably an error with the colored crate)

    Desktop:

    • OS: Windows

    Additional info This might not be able to be fixed by you (see above with the colored crate) but I like your crate so the suggested fix would be nice, so I can use the spinners without the colours :)

    bug 
    opened by RubyBit 14
  • Provide an easy way to define an updated text when creating a spinner

    Provide an easy way to define an updated text when creating a spinner

    Is your feature request related to a problem? Please describe. I want to display a spinner while my application is making a blocking IO call. When the call takes longer than expected (say 2 seconds) I would like to update the spinner text. In single-threaded code this is not possible because there is no way of keeping track of the elapsed time and calling the update_text() method on the spinner.

    Describe the solution you'd like The spinner itself is able to keep track of the elapsed time. When creating the spinner you pass it a starting text, a duration and an updated text that will be displayed once the duration has passed. Alternatively it could be a sequence of updated texts that it will loop through or even another data structure with multiple texts and for how long they will be displayed.

    Describe alternatives you've considered Spawning a separate thread for the blocking IO call so I can keep track of the time and update the spinner manually. The proposed solution would be more convenient though.

    enhancement 
    opened by avsaase 5
  • Add .rustfmt.toml

    Add .rustfmt.toml

    Before starting work on https://github.com/ad4mx/spinoff/issues/15, I saw that there was inconsistent formatting applied to the source code, so I added a .rustfmt.toml file and ran cargo fmt. This PR only contains automatically fixed formatting changes.

    This was to make sure that any future PRs will contain less formatting "noise" and that all contributors get the same output when we run "cargo fmt"

    opened by DrPoppyseed 3
  • Automatic spinner animation data.

    Automatic spinner animation data.

    Hey!

    I stumbled across this crate on reddit. I have pretty much the same crate: https://github.com/mainrs/terminal-spinners-rs. I do have a repository that automatically updates spinner definitions based on sindresorphus spinner library.

    https://github.com/mainrs/terminal-spinner-data-rs

    If you need anything additionally api wise, feel free to open an issue.

    Cheers!

    opened by mainrs 3
  • Split each spinner into a feature

    Split each spinner into a feature

    Most people only need one or two spinners. Instead of having the user install all 80+ spinners, we can use features so that they only need to install the specific spinner they want.

    With this change, iterating over all spinner variants will not be supported out of the box and, instead, will need to be implemented by the user. People installing all 80+ spinners will also have a slightly larger crate to install (due to the individual implementations for each spinner). Still, this crate will be able to drop maplit and strum as dependencies, as they will no longer be necessary.

    However, this change has a delightful side effect of allowing SpinnerFrames data to be decoupled with the core of the crate itself. Users, if they so wish to, will now be able to implement and run their custom spinner using a macro provided by this crate while still reaping the ergonomics that this crate offers, allowing for much more extensibility.

    We can easily achieve this without changing the interface by using macros and tweaking the library just a bit; We can also have the default feature set to all to ease the transition.

    An example of what it could look like:

    // The generated code (from the macro) could have an empty struct, a way to
    // convert the struct into `SpinnerFrames`, and the actual static value itself.
    pub struct Dots;
    
    impl From<Dots> for SpinnerFrames {
        fn from(_: Dots) -> SpinnerFrames {
            DOTS_SPINNER.clone()
        }
    }
    
    static DOTS_SPINNER: Lazy<SpinnerFrames> = Lazy::new(|| SpinnerFrames {
        frames: vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
        interval: 80
    });
    
    // If a user has the `dots` feature enabled, a new spinner could be created 
    // with the same interface as the current one
    Spinner::new(Spinners::Dots, "Hello world!", None);
    

    What do you think? I already have a fork for https://github.com/FGRibreau/spinners implementing this change, so adjusting it and porting it to this crate should be easy. If you don't have any fundamental objections, I would like to submit a PR, though, I fully understand if you don't want this.

    enhancement 
    opened by DrPoppyseed 2
  • Implement Copy trait

    Implement Copy trait

    Is your feature request related to a problem? Please describe.

    Cannot implement Facade pattern because there is no implementation of the Copy trait 🤕

    Describe the solution you'd like

    implement copy/clone (I'm new to rust, please forgive me if it doesn't makes sense 🙏 )

    Describe alternatives you've considered

    using spinners lib for facade (it worked ✅ )

    Additional context

    use spinoff::{spinners, Color, Spinner as LibSpinner};
    
    pub struct Spinner {
        msg: String,
        sp: LibSpinner,
    }
    
    impl Spinner {
        pub fn new(msg: &String) -> Self {
            Self {
                msg: msg.clone(),
                sp: create_standard_spinner(&msg),
            }
        }
    
        pub fn success(&mut self) {
            self.sp.success(&self.msg);
        }
    }
    
    fn create_standard_spinner(msg: &String) -> LibSpinner {
        LibSpinner::new(spinners::Dots2, msg.clone(), Color::Blue)
    }
    
    pub fn create_spinner(msg: &String) -> Spinner {
        Spinner::new(msg)
    }
    
    

    but it results in the following error

    error[E0507]: cannot move out of `self.sp` which is behind a mutable reference
      --> shared/commands-helper/src/lib.rs:23:13
       |
    23 |             self.sp.success(&self.msg);
       |             ^^^^^^^ move occurs because `self.sp` has type `spinoff::Spinner`, which does not implement the `Copy` trait
    
    For more information about this error, try `rustc --explain E0507`.
                     ^^^^
    
    enhancement 
    opened by EdgardoArriagada 1
  • Split each spinner into individual features

    Split each spinner into individual features

    This PR is a rough suggestion of how the proposed changes outlined in #15 could be implemented.

    The main difference this PR introduces is moving away from the current implementation of keeping all spinner data in a Hashmap and looking them up by their key, and instead, defining featured gated empty structs which implement a common trait that lets it convert itself into spinner data. This allows users only to include the spinners they want to use via features and allows users to define custom spinners and use them with this crate.

    However, in this implementation, the API will change in three non-trivial ways.

    1. Iterating through all spinners is not provided out of the box. Users will have to create their own vectors to iterate over.
    2. The Spinners enum is replaced with the spinners module, so crate-supplied spinners will now be imported as spinners::Spinner instead of Spinners::Spinner
    3. Only the dots spinner is included by default. If you want to use all spinners provided by the crate, you have to now use the all features on import.
    #! Cargo.toml
    spinoff = { version = "*", features = ["all"] }
    
    opened by DrPoppyseed 1
  • Allow persisting spinner at end of terminal

    Allow persisting spinner at end of terminal

    Is your feature request related to a problem? Please describe. I'm using this crate in a program I'm building, and I'd like to be able to have the spinner stay at the bottom while a command is running and printing out to stdout. Currently, the command being ran and the spinner end up "z-fighting" in a way.

    Describe the solution you'd like The spinner would stay at the bottom of the terminal, while the command streams to stdout above the spinner.

    Describe alternatives you've considered I have not found any alternatives at this point.

    opened by pupbrained 1
  • fix: add support for locking behind mutex

    fix: add support for locking behind mutex

    Fairly new to rust so not sure if this change is appropriate, or if there would be an appetite for it. Currently we are using the library with some work that is happening in a spawned thread. It would be nice if we could share the spinner instance with the thread - as work gets done we can update the text on the fly. Because several function do not take self as a reference this makes it not possible to send the instance to the spawned thread.

    opened by cschear 0
  • Displaying two spinners together

    Displaying two spinners together

    Hi there!

    I'm currently building a project where I need to show two spinners for two different long-running tasks.

    Is there a way to achieve this?

    Thanks in advance for your help!

    enhancement help wanted good first issue 
    opened by ClementNerma 5
Releases(v0.7.0)
  • v0.7.0(Jan 29, 2023)

    What's Changed

    • Features introduced in place of the spinner enum
    • Users can now create their own spinners
    • Added spinner segment to readme
    • Changed documentation

    Full Changelog: https://github.com/ad4mx/spinoff/compare/v0.6.0...v0.7.0

    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Jan 2, 2023)

  • v0.5.4(Sep 11, 2022)

    What's Changed

    • Colors not working in windows by https://github.com/ad4mx/spinoff/pull/7

    Full Changelog: https://github.com/ad4mx/spinoff/compare/v0.5.3...v0.5.4

    Source code(tar.gz)
    Source code(zip)
  • v0.5.3(Jul 31, 2022)

  • v0.5.2(Jul 30, 2022)

  • v0.5.1(Jul 28, 2022)

    What's new

    • New update_text function added, works like update, but only limited to text
    • Documentation added for update_text
    • Changed code examples in the readme
    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Jul 27, 2022)

    What's Changed

    • New ::new_with_stream function has been added to give users more control over output
    • New example has been added to illustrate use of the ::new_with_stream function
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Jul 19, 2022)

    What's new

    • No need for using Some(Color) anymore thanks to a generic type
    • Improved documentation
    • Calling .fail() now prints to stderr instead of stdout

    Full Changelog: https://github.com/ad4mx/spinoff/compare/v0.3.0...v0.4.0

    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Jul 18, 2022)

    What's new

    • More colors added to the Color enum
    • Better documentation examples
    • Better README.md styling
    • More comments

    Full Changelog: https://github.com/ad4mx/spinoff/compare/v0.2.0...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jul 17, 2022)

    What's Changed

    • Full code refactor by @konnorandrews in https://github.com/ad4mx/spinoff/pull/1

    Full Changelog: https://github.com/ad4mx/spinoff/compare/v0.1.1...v0.2.0

    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Jul 16, 2022)

    Updates

    • Rewrote the logic for threads, it is now based on iterators
    • Removed unnecessary color arguments in stop_and_persist and stop_with_message methods
    • Touch ups to the README.md

    Full Changelog: https://github.com/ad4mx/spinoff/commits/v0.1.1

    Source code(tar.gz)
    Source code(zip)
Owner
ad4m
rust/typescript programmer that loves the terminal
ad4m
🛎 60+ Elegant terminal spinners for Rust

Spinners - ?? 60+ Elegant terminal spinners for Rust ❤️ Shameless plug Charts, simple as a URL. No more server-side rendering pain, 1 url = 1 chart Lo

Francois-Guillaume Ribreau 435 Dec 26, 2022
A robust, customizable, blazingly-fast, efficient and easy-to-use command line application to uwu'ify your text!

uwuifyy A robust, customizable, blazingly-fast, efficient and easy-to-use command line application to uwu'ify your text! Logo Credits: Jade Nelson Tab

Hamothy 43 Dec 12, 2022
Multi-threaded CLI torrent scraper for displaying searched for magnet links; tailored for use with plex & ssh.

magnetfinder Multi-threaded CLI torrent aggregator; scrapes torrent results from multiple websites and delivers them into a table in your terminal! Su

Ryan 59 Dec 10, 2022
Multi-threaded CLI torrent scraper for displaying searched for magnet links; tailored for use with plex & ssh.

magnetfinder Multi-threaded CLI torrent aggregator; scrapes torrent results from multiple websites and delivers them into a table in your terminal! Su

null 59 Dec 10, 2022
😎 A CLI tool for fetching data and displaying it nicely

?? A CLI tool for fetching data and displaying it nicely. (The neofetch for remote data fetching)

Milo 6 Aug 24, 2022
CLI tool for displaying table

tv Format json into table display $ cat test.json [ { "name": "test", "age": 10, "lang": "ja" }, { "name": "uzimaru", "age":

uzimaru0000 322 Jan 7, 2023
Failed experiment in downloading random cat image, turning it into ascii and displaying it in Neovim.

cat.nvim Failed experiment in downloading random cat image, turning it into ascii and displaying it in Neovim. Failed as I realized far too late, that

James Vero 4 Aug 5, 2022
Leptos Query - a robust asynchronous state management library for Leptos,

Leptos Query is a robust asynchronous state management library for Leptos, providing simplified data fetching, integrated reactivity, server-side rendering support, and intelligent cache management.

Nico Burniske 5 Jul 24, 2023
A library that creates a terminal-like window with feature-packed drawing of text and easy input handling. MIRROR.

BearLibTerminal provides a pseudoterminal window with a grid of character cells and a simple yet powerful API for flexible textual output and uncompli

Tommy Ettinger 43 Oct 31, 2022
An easy to use library for pretty print tables of Rust structs and enums.

tabled An easy to use library for pretty printing tables of Rust structs and enums. Table of Contents Usage Settings Style Themes ASCII Psql Github Ma

Maxim Zhiburt 1.3k Jan 9, 2023
An easy-to-use SocketCAN library for Python and C++, built in Rust.

JCAN An easy-to-use SocketCAN library for Python and C++, built in Rust, using cxx-rs and pyo3. Warning: I have never used Rust before and I don't kno

Leigh Oliver 4 Feb 9, 2023
Rustato: A powerful, thread-safe global state management library for Rust applications, offering type-safe, reactive state handling with an easy-to-use macro-based API.

Rustato State Manager A generical thread-safe global state manager for Rust Introduction • Features • Installation • Usage • Advanced Usage • Api Refe

BiteCraft 8 Sep 16, 2024
Experimental language build in Rust to make it fast and robust

Reg-lang Experimental language build with Rust. Its aim is : To be simple to help learning programmation with, and in a second hand, to be robust enou

Gipson62 1 Dec 29, 2022
A fast and robust MLOps tool for managing data and pipelines

xvc A Fast and Robust MLOps Swiss-Army Knife in Rust ⌛ When to use xvc? Machine Learning Engineers: When you manage large quantities of unstructured d

Emre Sahin 6 Dec 15, 2022
zigfi is an open-source stocks, commodities and cryptocurrencies price monitoring CLI app, written fully in Rust, where you can organize assets you're watching easily into watchlists for easy access on your terminal.

zigfi zigfi is an open-source stocks, commodities and cryptocurrencies price monitoring CLI app, written fully in Rust, where you can organize assets

Aldrin Zigmund Cortez Velasco 18 Oct 24, 2022
Workflows make it easy to browse, search, execute and share commands (or a series of commands)--without needing to leave your terminal.

Workflows The repo for all public Workflows that appear within Warp and within commands.dev. To learn how to create local or repository workflows, see

Warp 369 Jan 2, 2023
Workflows make it easy to browse, search, execute and share commands (or a series of commands)--without needing to leave your terminal.

Workflows The repo for all public Workflows that appear within Warp and within commands.dev. To learn how to create local or repository workflows, see

Warp 227 Jun 1, 2022
An easy, fast and lightweight tool to create notes in terminal.

An easy and lightweight tool to create notes in terminal. Features Make notes faster. Manage your notes directly in terminal. Lightweight and fast. Ea

Konstantin Zhigaylo 5 May 24, 2023
Bookmark directories for easy directory-hopping in the terminal

markd Bookmark directories for easy directory-hopping in the terminal. All it takes is one command markd to bookmark your current directory, or use th

Maaz Ahmed 10 Jul 10, 2023