use std::io::{IsTerminal, stdout};
use std::time::Duration;
use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle};
pub struct Progress {
live: Option<Live>,
}
struct Live {
multi: MultiProgress,
lines: Vec<ProgressBar>,
}
impl Progress {
pub fn new(names: &[&str]) -> Self {
if !stdout().is_terminal() {
return Self { live: None };
}
let multi = MultiProgress::with_draw_target(ProgressDrawTarget::stdout());
let waiting = ProgressStyle::with_template("· {msg}").expect("valid template");
let lines = names
.iter()
.map(|name| {
multi.add(
ProgressBar::new_spinner()
.with_style(waiting.clone())
.with_message((*name).to_owned()),
)
})
.collect();
Self {
live: Some(Live { multi, lines }),
}
}
pub fn start(&self, i: usize) {
if let Some(live) = &self.live {
let line = &live.lines[i];
line.set_style(
ProgressStyle::with_template("{spinner} {msg}").expect("valid template"),
);
line.enable_steady_tick(Duration::from_millis(80));
}
}
pub fn finish(&self, i: usize, mark: &str) {
if let Some(live) = &self.live {
let line = &live.lines[i];
line.set_style(
ProgressStyle::with_template(&format!("{mark} {{msg}}")).expect("valid template"),
);
line.finish();
}
}
pub fn report(&self, i: usize, text: &str) {
match &self.live {
Some(live) => {
live.lines[i].finish_and_clear();
live.multi.remove(&live.lines[i]);
let _ = live.multi.println(text);
}
None => println!("{text}"),
}
}
}