use indicatif::{ProgressBar, ProgressStyle};
use std::time::Duration;
pub fn spinner(message: &str, quiet: bool) -> Option<ProgressBar> {
if quiet {
return None;
}
let pb = ProgressBar::new_spinner();
pb.set_style(
ProgressStyle::default_spinner()
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
.template("{spinner:.cyan} {msg}")
.expect("Invalid spinner template"),
);
pb.set_message(message.to_string());
pb.enable_steady_tick(Duration::from_millis(100));
Some(pb)
}
#[allow(dead_code)]
pub fn progress_bar(total: u64, message: &str, quiet: bool) -> Option<ProgressBar> {
if quiet {
return None;
}
let pb = ProgressBar::new(total);
pb.set_style(
ProgressStyle::default_bar()
.template("{msg} [{bar:40.cyan/blue}] {pos}/{len} ({percent}%)")
.expect("Invalid progress bar template")
.progress_chars("█▓░"),
);
pb.set_message(message.to_string());
Some(pb)
}
#[allow(dead_code)]
pub fn bytes_bar(total: u64, message: &str, quiet: bool) -> Option<ProgressBar> {
if quiet {
return None;
}
let pb = ProgressBar::new(total);
pb.set_style(
ProgressStyle::default_bar()
.template("{msg} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec})")
.expect("Invalid bytes bar template")
.progress_chars("█▓░"),
);
pb.set_message(message.to_string());
Some(pb)
}
pub fn finish_spinner(pb: Option<ProgressBar>, message: &str) {
if let Some(pb) = pb {
pb.set_style(
ProgressStyle::default_spinner()
.template("{prefix:.green} {msg}")
.expect("Invalid finish template"),
);
pb.set_prefix("✓");
pb.finish_with_message(message.to_string());
}
}
pub fn finish_spinner_warn(pb: Option<ProgressBar>, message: &str) {
if let Some(pb) = pb {
pb.set_style(
ProgressStyle::default_spinner()
.template("{prefix:.yellow} {msg}")
.expect("Invalid warn template"),
);
pb.set_prefix("!");
pb.finish_with_message(message.to_string());
}
}
#[allow(dead_code)]
pub fn finish_spinner_error(pb: Option<ProgressBar>, message: &str) {
if let Some(pb) = pb {
pb.set_style(
ProgressStyle::default_spinner()
.template("{prefix:.red} {msg}")
.expect("Invalid error template"),
);
pb.set_prefix("✗");
pb.finish_with_message(message.to_string());
}
}
#[allow(dead_code)]
pub fn finish_progress(pb: Option<ProgressBar>) {
if let Some(pb) = pb {
pb.finish_and_clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_spinner_quiet_returns_none() {
let pb = spinner("test", true);
assert!(pb.is_none());
}
#[test]
fn test_spinner_not_quiet_returns_some() {
let pb = spinner("test", false);
assert!(pb.is_some());
if let Some(pb) = pb {
pb.finish();
}
}
#[test]
fn test_progress_bar_quiet_returns_none() {
let pb = progress_bar(100, "test", true);
assert!(pb.is_none());
}
#[test]
fn test_finish_spinner_handles_none() {
finish_spinner(None, "done");
finish_spinner_warn(None, "warning");
finish_spinner_error(None, "error");
}
#[test]
fn test_finish_progress_handles_none() {
finish_progress(None);
}
}