use indicatif::{HumanDuration, MultiProgress, ProgressBar, ProgressStyle}; use std::{ sync::{Arc, Mutex}, time::Instant, }; #[derive(Clone)] pub struct TaskGroup { mp: Arc, } impl TaskGroup { pub fn new() -> Self { Self { mp: Arc::new(MultiProgress::new()), } } pub fn start_task(&self, desc: &str) -> Task { let pb = self.mp.add(ProgressBar::new(1)); let spinner_style = ProgressStyle::default_spinner() .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ ") .template("{prefix:.bold.dim} {spinner} {wide_msg}"); pb.set_style(spinner_style); Task::new(TaskState { pb, desc: desc.into(), started_at: Instant::now(), }) } pub fn join(&self) { self.mp.join().unwrap(); } } #[derive(Clone)] pub struct Task(Arc>); impl Task { pub fn new(state: TaskState) -> Self { Self(Arc::new(Mutex::new(state))) } pub fn tick(&self) { let state = self.0.lock().unwrap(); state.pb.set_message(&format!( "{} [{}]", state.desc, style(HumanDuration(state.started_at.elapsed())).yellow() )); state.pb.tick(); } pub fn complete(&self) { self.0.lock().unwrap().pb.finish_with_message("OK"); } } pub struct TaskState { pb: ProgressBar, desc: String, started_at: Instant, }