use std::env;
use console::{Term, style};
use dialoguer::Password;
use indicatif::{ProgressBar, ProgressStyle};
use miette::{Result, miette};
fn ci_mode() -> bool {
env::var("MAKIATTO_CI_MODE").is_ok() || env::var("CI").is_ok()
}
pub fn status(msg: &str) {
println!("{} {}", style("==>").green().bold(), msg);
}
pub fn info(msg: &str) {
println!("{} {}", style("::").blue().bold(), style(msg).dim());
}
pub fn warn(msg: &str) {
println!("{} {}", style("!!").yellow().bold(), style(msg).yellow());
}
pub fn text(msg: &str) {
println!("{msg}");
}
pub fn command(cmd: &str) {
println!(" {}", style(cmd).dim());
}
pub fn field(key: &str, value: &str) {
println!(" {}: {}", style(key).dim(), value);
}
pub fn header(title: &str) {
println!("{} {}", style("::").blue().bold(), style(title).bold());
}
pub fn action(msg: &str) {
println!(" {} {}", style("->").blue(), msg);
}
pub fn password(prompt: &str) -> Result<String> {
Password::new()
.with_prompt(prompt)
.interact()
.map_err(|e| miette!("Failed to read input: {}", e))
}
pub fn separator() {
let term = Term::stdout();
let width = term.size().1 as usize;
let line = "─".repeat(width.min(80));
println!("{}", style(line).dim());
}
pub enum Progress {
Real(ProgressBar),
Mock,
}
impl Progress {
pub fn finish_with_message(&self, msg: impl Into<String>) {
match self {
Self::Real(pb) => pb.finish_with_message(msg.into()),
Self::Mock => println!("{}", msg.into()),
}
}
pub fn finish(&self) {
match self {
Self::Real(pb) => pb.finish(),
Self::Mock => {}
}
}
pub fn set_message(&self, msg: impl Into<String>) {
match self {
Self::Real(pb) => pb.set_message(msg.into()),
Self::Mock => {}
}
}
pub fn inc(&self, delta: u64) {
match self {
Self::Real(pb) => pb.inc(delta),
Self::Mock => {}
}
}
pub fn set_position(&self, pos: u64) {
match self {
Self::Real(pb) => pb.set_position(pos),
Self::Mock => {}
}
}
pub fn enable_steady_tick(&self, duration: std::time::Duration) {
match self {
Self::Real(pb) => pb.enable_steady_tick(duration),
Self::Mock => {}
}
}
}
#[must_use]
pub fn spinner(msg: &str) -> Progress {
if ci_mode() {
println!("{msg}");
Progress::Mock
} else {
let spinner = ProgressBar::new_spinner();
spinner.set_style(
ProgressStyle::default_spinner()
.template("{spinner:.green} {msg}")
.expect("Spinner template is invalid"),
);
spinner.set_message(msg.to_string());
spinner.enable_steady_tick(std::time::Duration::from_millis(100));
Progress::Real(spinner)
}
}
#[must_use]
pub fn progress_bar(total_bytes: u64, msg: &str) -> Progress {
if ci_mode() {
println!("{msg}");
Progress::Mock
} else {
let pb = ProgressBar::new(total_bytes);
pb.set_style(
ProgressStyle::default_bar()
.template("{spinner:.green} {msg} [{wide_bar:.cyan/blue}] {bytes}/{total_bytes}")
.expect("Progress bar template is invalid")
.progress_chars("#>-"),
);
pb.set_message(msg.to_string());
Progress::Real(pb)
}
}