arkham 0.1.0

A framework for CLI applications
Documentation
use indicatif::{HumanDuration, MultiProgress, ProgressBar, ProgressStyle};
use std::{
    sync::{Arc, Mutex},
    time::Instant,
};

#[derive(Clone)]
pub struct TaskGroup {
    mp: Arc<MultiProgress>,
}

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<Mutex<TaskState>>);

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,
}