Skip to main content

output_dynamic/
output_dynamic.rs

1//! Time-based and interactive output widgets: spinner, progress, multi-progress
2//! live display and pager. Run in a real terminal:
3//!
4//! `cargo run --example output_dynamic --features pager`
5//!
6//! Off-terminal (piped/redirected) the animations become no-ops and only the
7//! final state is printed; the pager prints its content directly.
8
9use std::thread::sleep;
10use std::time::Duration;
11
12use sparcli::prelude::*;
13use sparcli::{Live, MultiProgress, ProgressBar, Spinner};
14
15fn main() -> Result<()> {
16    spinner()?;
17    progress()?;
18    multi_progress()?;
19    live()?;
20    pager()?;
21    Ok(())
22}
23
24/// Animates a spinner for a moment, then finishes with a success marker.
25fn spinner() -> Result<()> {
26    let mut spinner = Spinner::new("working");
27    for _ in 0..12 {
28        spinner.tick()?;
29        sleep(Duration::from_millis(80));
30    }
31    spinner.finish(true, "done")
32}
33
34/// Fills a single progress bar from 0 to 100 %.
35fn progress() -> Result<()> {
36    let mut bar = ProgressBar::new().label("download").width(30);
37    for step in 0..=20 {
38        bar.draw(f64::from(step), 20.0)?;
39        sleep(Duration::from_millis(50));
40    }
41    bar.finish(20.0, 20.0)
42}
43
44/// Advances two bars together in a single block.
45fn multi_progress() -> Result<()> {
46    let mut multi = MultiProgress::new();
47    let downloads = multi.add(ProgressBar::new().label("downloads").width(20));
48    let installs = multi.add(ProgressBar::new().label("installs ").width(20));
49    for step in 0..=20 {
50        multi.update(downloads, f64::from(step), 20.0)?;
51        multi.update(installs, f64::from(step) * 0.6, 20.0)?;
52        sleep(Duration::from_millis(60));
53    }
54    multi.finish()
55}
56
57/// Redraws a panel in place a few times.
58fn live() -> Result<()> {
59    let mut live = Live::new();
60    for tick in 1..=8 {
61        let frame = Panel::new(format!("live tick {tick}"))
62            .title(Title::new("Live"))
63            .render(30);
64        live.update(&frame)?;
65        sleep(Duration::from_millis(120));
66    }
67    live.finish()
68}
69
70/// Pages a long block of lines (only with the `pager` feature).
71#[cfg(feature = "pager")]
72fn pager() -> Result<()> {
73    use sparcli::Pager;
74    let lines = (1..=200)
75        .map(|n| Line::raw(format!("line {n}")))
76        .collect::<Vec<_>>();
77    Pager::new().page(&Rendered::new(lines))
78}
79
80/// No-op when the `pager` feature is disabled.
81#[cfg(not(feature = "pager"))]
82fn pager() -> Result<()> {
83    Ok(())
84}