use indicatif::{MultiProgress, MultiProgressAlignment, ProgressBar, ProgressStyle};
use std::sync::{Arc, LazyLock};
pub static MULTI_PROGRESS: LazyLock<Arc<MultiProgress>> = LazyLock::new(|| {
let mp = MultiProgress::new();
mp.set_alignment(MultiProgressAlignment::Top);
Arc::new(mp)
});
pub static CHECKMARK: LazyLock<String> =
LazyLock::new(|| format!("{}", console::style("✓").green()));
pub static ERROR_MARK: LazyLock<String> =
LazyLock::new(|| format!("{}", console::style("✗").red()));
pub static TICK_STRINGS: LazyLock<[&str; 11]> =
LazyLock::new(|| ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", &CHECKMARK]);
pub static ERROR_TICK_STRINGS: LazyLock<[&str; 2]> = LazyLock::new(|| ["⠏", &ERROR_MARK]);
pub fn is_interactive_terminal() -> bool {
let stdin_is_tty = unsafe { libc::isatty(libc::STDIN_FILENO) == 1 };
let stdout_is_tty = unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 };
let is_tty = stdin_is_tty && stdout_is_tty;
let has_term = std::env::var("TERM").is_ok();
if is_tty && !has_term {
tracing::debug!("detected TTY without TERM environment variable");
}
is_tty
}
pub fn is_ansi_interactive_terminal() -> bool {
is_interactive_terminal() && !std::env::var("TERM").unwrap_or_default().contains("dumb")
}
pub fn create_spinner(
message: String,
insert_at_position: Option<usize>,
len: Option<u64>,
) -> ProgressBar {
let pb = if let Some(len) = len {
ProgressBar::new(len)
} else {
ProgressBar::new_spinner()
};
let pb = if let Some(pos) = insert_at_position {
MULTI_PROGRESS.insert(pos, pb)
} else {
MULTI_PROGRESS.add(pb)
};
let style = if let Some(_) = len {
ProgressStyle::with_template("{spinner} {msg} {pos:.bold} / {len:.dim}")
.unwrap()
.tick_strings(&*TICK_STRINGS)
} else {
ProgressStyle::with_template("{spinner} {msg}")
.unwrap()
.tick_strings(&*TICK_STRINGS)
};
pb.set_style(style);
pb.set_message(message);
pb.enable_steady_tick(std::time::Duration::from_millis(80));
pb
}
pub fn finish_with_error(pb: &ProgressBar) {
let style = ProgressStyle::with_template("{spinner} {msg}")
.unwrap()
.tick_strings(&*ERROR_TICK_STRINGS);
pb.set_style(style);
pb.finish();
}