use crossterm::style::Stylize;
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use std::time::Duration;
pub fn header(cmd: &str) {
eprintln!();
eprintln!(" {}", cmd.cyan().bold());
eprintln!(" {}", "─".repeat(40).dim());
eprintln!();
}
pub fn spinner(message: &str) -> ProgressBar {
let pb = ProgressBar::new_spinner();
pb.set_draw_target(ProgressDrawTarget::stderr());
pb.set_style(
ProgressStyle::default_spinner()
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
.template(" {spinner:.cyan} {msg} {elapsed:.dim}")
.unwrap(),
);
pb.set_message(message.to_string());
pb.enable_steady_tick(Duration::from_millis(80));
pb
}
pub fn spinner_done(pb: &ProgressBar, detail: Option<&str>) {
let msg = pb.message();
pb.finish_and_clear();
phase_ok(&msg, detail);
}
pub fn phase_ok(msg: &str, detail: Option<&str>) {
let suffix = detail
.map(|d| format!(" · {}", d.dim()))
.unwrap_or_default();
eprintln!(" {} {msg}{suffix}", "✓".green().bold());
}
pub fn warn(msg: &str) {
eprintln!(" {} {}", "⚠".yellow().bold(), msg.yellow());
}
pub fn info(msg: &str) {
eprintln!(" {} {}", "ℹ".cyan(), msg.dim());
}
pub fn error(msg: &str) {
eprintln!(" {} {}", "✗".red().bold(), msg.red());
}
pub fn tree_item(text: &str, is_last: bool) {
let connector = if is_last { "└─" } else { "├─" };
eprintln!(" {} {}", connector.dim(), text);
}