use colored::Colorize;
use indicatif::{ProgressBar, ProgressStyle};
fn prefix() -> String {
"[mvm]".bold().cyan().to_string()
}
pub fn info(msg: &str) {
println!("{} {}", prefix(), msg);
}
pub fn success(msg: &str) {
println!("{} {}", prefix(), msg.green());
}
pub fn error(msg: &str) {
eprintln!("{} {}", "[mvm]".bold().red(), msg.red());
}
pub fn warn(msg: &str) {
println!("{} {}", prefix(), msg.yellow());
}
pub fn step(n: u32, total: u32, msg: &str) {
println!(
"\n{} {} {}",
prefix(),
format!("Step {}/{}:", n, total).bold().yellow(),
msg,
);
}
pub fn banner(lines: &[&str]) {
let width = lines.iter().map(|l| l.len()).max().unwrap_or(0) + 4;
let rule = "=".repeat(width);
println!();
println!("{}", rule.bold().green());
for line in lines {
let pad = width - line.len() - 4;
println!(
"{}",
format!(" {}{} ", line, " ".repeat(pad)).bold().green()
);
}
println!("{}", rule.bold().green());
println!();
}
pub fn status_header() {
println!("{}", "mvmctl status".bold());
println!("{}", "-------------".dimmed());
}
pub fn status_line(label: &str, value: &str) {
let colored_value = if value.starts_with("Running") {
value.green().to_string()
} else if value == "Stopped" {
value.yellow().to_string()
} else if value.starts_with("Not ") || value == "-" {
value.dimmed().to_string()
} else if value.starts_with("Starting") {
value.yellow().to_string()
} else {
value.to_string()
};
println!("{} {}", format!("{:<14}", label).bold(), colored_value);
}
pub fn confirm(msg: &str) -> bool {
inquire::Confirm::new(msg)
.with_default(false)
.prompt()
.unwrap_or(false)
}
pub fn spinner(msg: &str) -> ProgressBar {
let pb = ProgressBar::new_spinner();
pb.set_style(
ProgressStyle::default_spinner()
.tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"])
.template("{spinner:.cyan} {msg}")
.expect("invalid spinner template"),
);
pb.set_message(msg.to_string());
pb.enable_steady_tick(std::time::Duration::from_millis(80));
pb
}