Expand description
strides is an async-first crate to support building command line tools which display progress to the user. The purpose is similar to that of the widely used indicatif crate but focuses on integrating with async futures and streams and drive progress animations based on polling state.
Instead of integrating progress bar and spinner UI elements along an asynchronous program,
strides provides utilities to integrate these elements as part of the Future and
Stream abstractions.
§Spinners
A spinner is a UI element that represents ongoing work. It is usually iconified as a circular
motion but anything that streams Unicode characters can be used. To create a spinner, import
the Spinner struct and pass it a string slice:
let abc = strides::spinner::Spinner::new("abc");The ticks() method returns an infinite stream that cycles
through the characters of the string slice. The rate at which characters are cycled is set to
every 80ms and can be changed with the
with_interval() function.
The spinner::styles module provides a few pre-defined spinner
styles.
§Bars
A Bar renders fractional progress as a strip of characters. It is
defined by two characters, one for the empty portion and one for the filled portion. Create
one with Bar::new() or pick a pre-defined variant from
bar::styles:
let bar = strides::bar::styles::THIN_LINE
.with_border("[", "]")
.with_filled_style(owo_colors::Style::new().bright_purple());Borders, an optional in-between separator, and per-portion colors are configured via the
builder methods on Bar. The bar is attached to a Theme with
with_bar(); width defaults to the terminal size and can be
overridden with with_bar_width().
§Themes
A Theme bundles a Spinner and a Bar
into a single configuration object that can be passed to both the futures and streams
progress APIs:
let theme = strides::Theme::new()
.with_bar(strides::bar::styles::PARALLELOGRAM)
.with_spinner(strides::spinner::styles::DOTS_3);A bare Spinner can also be passed directly wherever a
Theme is expected.
§Futures
Import the FutureExt extension trait and call
progress() on any Future to obtain a
ProgressBuilder. Capabilities compose freely:
with_message sets a static message,
with_messages installs a
Stream whose values replace the displayed message as they arrive,
and with_fraction drives the progress bar
from a Stream<Item = f64>.
use strides::future::FutureExt;
use strides::spinner::styles::DOTS_3;
use std::time::Duration;
std::pin::pin!(async {
// Simulate work by waiting for three seconds.
futures_timer::Delay::new(Duration::from_secs(3)).await;
})
.progress(DOTS_3)
.with_message("this will take some time")
.await;For multiple concurrent futures use future::Group, which renders one line per task
with optional per-task progress bars and dynamic messages.
§Streams
Import the StreamExt extension trait and call
progress() with a fraction closure. The closure
receives the monotonically increasing item number (starting at 1) and a reference to the
item, so the fraction can be derived from a known total or from the item itself (e.g.
accumulated bytes / Content-Length). The returned
StreamProgressBuilder accepts a
with_messages stream for
dynamic text.
use futures_lite::{StreamExt as _, stream};
use strides::stream::StreamExt;
use strides::Theme;
use strides::{bar, spinner};
let theme = Theme::new()
.with_spinner(spinner::styles::DOTS_3)
.with_bar(bar::styles::SHADED);
let total = 100;
stream::iter(0..total)
.progress(theme, move |i, _| i as f64 / total as f64)
.for_each(|_| {})
.await;§Output
strides currently renders all progress output to stdout. A renderer abstraction (for
tests or TUI embedding) is intentionally out of scope for 1.0 in favor of simplicity.
Re-exports§
pub use theme::Theme;