extern crate yansi;
use std::fmt::Display;
use std::io::{stdout, Write};
use std::ops::FnOnce;
use yansi::Paint;
const DEFAULT_PADDING: usize = 12;
pub struct Progress<'a> {
action: &'a str,
description: &'a str,
padding: usize,
value: u8,
}
impl<'a> Progress<'a> {
pub fn new(action: &'a str, description: &'a str, padding: usize) -> Progress<'a> {
Progress {
action,
description,
padding,
value: 0,
}
}
pub fn initialize(&mut self) {
self.set_from(0, 100, 0);
}
pub fn set(&mut self, value: usize) {
self.set_from(0, 100, value)
}
pub fn increment(&mut self, offset: usize) {
self.set(self.value as usize + offset);
}
pub fn set_from(&mut self, min: usize, max: usize, value: usize) {
self.value = (((value - min) * 100) / (max - min)) as u8;
print!(
"\r{:>3$} [{:>3}%] {:<4$}",
Paint::yellow(self.action),
self.value,
self.description,
self.padding,
self.description.len()
);
stdout().flush().unwrap_or_default();
}
fn ok<R>(&mut self, result: &R)
where
R: Display,
{
self.value = 100;
println!(
"\r{:>3$} [{:>3}%] {:<4$}",
Paint::green(self.action),
self.value,
result,
self.padding,
self.description.len()
);
}
fn err<E>(&mut self, error: &E)
where
E: Display,
{
println!(
"\r{:>3$} [{:>3}%] {:<4$}",
Paint::red(self.action),
self.value,
error,
self.padding,
self.description.len()
);
}
}
pub fn proceed<F, R, D, E>(action: &str, description: &str, function: F) -> Result<R, E>
where
F: FnOnce(&mut Progress) -> Result<(R, D), E>,
D: Display,
E: Display,
{
proceed_padded(action, description, function, DEFAULT_PADDING)
}
pub fn proceed_padded<F, R, D, E>(
action: &str,
description: &str,
function: F,
padding: usize,
) -> Result<R, E>
where
F: FnOnce(&mut Progress) -> Result<(R, D), E>,
D: Display,
E: Display,
{
let mut progress = Progress::new(action, description, padding);
progress.initialize();
match function(&mut progress) {
Ok(result) => {
progress.ok(&result.1);
Ok(result.0)
}
Err(error) => {
progress.err(&error);
Err(error)
}
}
}
pub fn success(action: &str, description: &str) {
success_padded(action, description, DEFAULT_PADDING);
}
pub fn success_padded(action: &str, description: &str, padding: usize) {
println!("\r{:>2$} {:}", Paint::green(action), description, padding);
}
pub fn error(action: &str, description: &str) {
error_padded(action, description, DEFAULT_PADDING);
}
pub fn error_padded(action: &str, description: &str, padding: usize) {
println!("\r{:>2$} {:}", Paint::red(action), description, padding);
}
pub fn warning(action: &str, description: &str) {
warning_padded(action, description, DEFAULT_PADDING);
}
pub fn warning_padded(action: &str, description: &str, padding: usize) {
println!("\r{:>2$} {:}", Paint::yellow(action), description, padding);
}
pub fn info(action: &str, description: &str) {
info_padded(action, description, DEFAULT_PADDING);
}
pub fn info_padded(action: &str, description: &str, padding: usize) {
println!("\r{:>2$} {:}", Paint::cyan(action), description, padding);
}