use std::io::{IsTerminal, Write};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use yansi::Paint;
pub const INDENT: &str = " ";
pub const DETAIL_INDENT: &str = " ";
pub const LABEL_WIDTH: usize = 20;
pub fn pass() -> yansi::Painted<&'static str> {
"\u{2713}".green()
}
pub fn fail() -> yansi::Painted<&'static str> {
"\u{2717}".red()
}
pub fn warn() -> yansi::Painted<&'static str> {
"\u{26a0}".yellow()
}
pub fn error(msg: &str) {
eprintln!("error: {msg}");
}
pub fn warning(msg: &str) {
eprintln!("warning: {msg}");
}
pub fn blank() {
eprintln!();
}
pub fn heading(label: &str, value: &str) {
eprintln!("{INDENT}{label}{value}");
}
pub fn item(label: &str, value: &str) {
eprintln!(
"{DETAIL_INDENT}{:<width$} {value}",
label,
width = LABEL_WIDTH
);
}
pub fn info(msg: &str) {
eprintln!("{INDENT}{msg}");
}
pub fn detail(msg: &str) {
eprintln!("{DETAIL_INDENT}{msg}");
}
pub fn hint(msg: &str) {
eprintln!("{INDENT}hint: {msg}");
}
pub fn check_line(symbol: &str, label: &str) {
eprintln!("{DETAIL_INDENT}{symbol} {label}");
}
pub fn summary_counts(valid: usize, total: usize) {
eprintln!("{valid}/{total} valid");
}
pub fn print(msg: &str) {
eprintln!("{msg}");
}
pub fn is_tty() -> bool {
std::io::stderr().is_terminal()
}
pub fn pending(index: usize, total: usize, display: &str) {
if is_tty() {
eprint!("{INDENT}[{}/{}] > {display}", index + 1, total);
} else {
eprintln!("{INDENT}> {display}");
}
}
pub fn pending_non_tty(display: &str) {
eprintln!("{INDENT}> {display}");
}
pub fn spin_while<F, T>(display: &str, f: F) -> T
where
F: FnOnce() -> T,
{
if !is_tty() || !yansi::is_enabled() {
eprintln!("{INDENT}> {display}");
return f();
}
const FRAMES: &[&str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
let running = Arc::new(AtomicBool::new(true));
let stop = Arc::clone(&running);
let label = display.to_string();
let handle = std::thread::spawn(move || {
let mut i = 0usize;
while stop.load(Ordering::Relaxed) {
eprint!("\r{INDENT}{} {label}", FRAMES[i % FRAMES.len()]);
let _ = std::io::stderr().flush();
std::thread::sleep(std::time::Duration::from_millis(80));
i += 1;
}
});
let result = f();
running.store(false, Ordering::Relaxed);
let _ = handle.join();
eprint!("\r\x1b[K");
result
}