use indicatif::{ProgressBar, ProgressStyle};
use std::env;
use std::io::IsTerminal;
use tabled::{Table, Tabled, settings::Style as TableStyle};
fn should_use_colors() -> bool {
if env::var("NO_COLOR").is_ok() {
return false;
}
if let Ok(term) = env::var("TERM")
&& term == "dumb"
{
return false;
}
std::io::stderr().is_terminal()
}
const RED: &str = "\x1b[31m";
const YELLOW: &str = "\x1b[33m";
const GREEN: &str = "\x1b[32m";
const CYAN: &str = "\x1b[36m";
const RESET: &str = "\x1b[0m";
pub fn success(msg: &str) {
if should_use_colors() {
eprintln!("{}✓{} {}", GREEN, RESET, msg);
} else {
eprintln!("✓ {}", msg);
}
}
pub fn error(msg: &str) {
if should_use_colors() {
eprintln!("{}✗{} {}", RED, RESET, msg);
} else {
eprintln!("✗ {}", msg);
}
}
pub fn warn(msg: &str) {
if should_use_colors() {
eprintln!("{}⚠{} {}", YELLOW, RESET, msg);
} else {
eprintln!("⚠ {}", msg);
}
}
pub fn info(msg: &str) {
if should_use_colors() {
eprintln!("{}→{} {}", CYAN, RESET, msg);
} else {
eprintln!("→ {}", msg);
}
}
pub fn print_table<T: Tabled>(data: &[T]) {
if data.is_empty() {
return;
}
let mut table = Table::new(data);
table.with(TableStyle::modern());
println!("{}", table);
}
pub fn format_size(bytes: u64) -> String {
const KB: u64 = 1024;
const MB: u64 = KB * 1024;
const GB: u64 = MB * 1024;
if bytes >= GB {
format!("{:.2} GB", bytes as f64 / GB as f64)
} else if bytes >= MB {
format!("{:.2} MB", bytes as f64 / MB as f64)
} else if bytes >= KB {
format!("{:.2} KB", bytes as f64 / KB as f64)
} else {
format!("{} B", bytes)
}
}
pub fn spinner(msg: &str) -> ProgressBar {
let spinner = ProgressBar::new_spinner();
if should_use_colors() {
spinner.set_style(
ProgressStyle::default_spinner()
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
.template("{spinner} {msg}")
.unwrap(),
);
} else {
spinner.set_style(
ProgressStyle::default_spinner()
.tick_chars("/-\\|")
.template("{spinner} {msg}")
.unwrap(),
);
}
spinner.set_message(msg.to_string());
spinner.enable_steady_tick(std::time::Duration::from_millis(100));
spinner
}
pub fn format_duration(seconds: u64) -> String {
if seconds < 60 {
format!("{}s", seconds)
} else {
let mins = seconds / 60;
let secs = seconds % 60;
format!("{}m {}s", mins, secs)
}
}