Skip to main content

Crate strides

Crate strides 

Source
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;

Modules§

bar
Progress bar UI element.
future
Spinner integration for futures.
spinner
Spinner UI element.
stream
Progress bar extension for streams.
term
Terminal helpers.
theme
Shared progress theme configuration.