use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::OnceLock;
use std::time::Duration;
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use owo_colors::OwoColorize;
static JSON_MODE: AtomicBool = AtomicBool::new(false);
static NO_COLOR: AtomicBool = AtomicBool::new(false);
pub fn set_json_mode(enabled: bool) {
JSON_MODE.store(enabled, Ordering::Relaxed);
}
pub fn is_json_mode() -> bool {
JSON_MODE.load(Ordering::Relaxed)
}
pub fn set_no_color(enabled: bool) {
NO_COLOR.store(enabled, Ordering::Relaxed);
}
fn use_color() -> bool {
static C: OnceLock<bool> = OnceLock::new();
*C.get_or_init(|| {
!NO_COLOR.load(Ordering::Relaxed)
&& std::env::var_os("NO_COLOR").is_none()
&& supports_color::on(supports_color::Stream::Stdout).is_some()
})
}
pub fn warn(msg: &str) {
if is_json_mode() {
return;
}
if use_color() {
eprintln!("{} {}", "Warning:".yellow(), msg);
} else {
eprintln!("Warning: {}", msg);
}
}
pub fn success(msg: &str) {
if is_json_mode() {
return;
}
if use_color() {
eprintln!("{}", msg.green());
} else {
eprintln!("{}", msg);
}
}
pub fn info(msg: &str) {
if is_json_mode() {
return;
}
if use_color() {
eprintln!("{}", msg.bold());
} else {
eprintln!("{}", msg);
}
}
pub fn detail(msg: &str) {
if is_json_mode() {
return;
}
if use_color() {
eprintln!("{}", msg.dimmed());
} else {
eprintln!("{}", msg);
}
}
pub fn notice(msg: &str) {
if is_json_mode() {
return;
}
if use_color() {
eprintln!("{}", msg.yellow());
} else {
eprintln!("{}", msg);
}
}
pub fn status(msg: &str) {
if is_json_mode() {
return;
}
eprintln!("{}", msg);
}
pub fn check_pass(label: &str) {
if is_json_mode() {
return;
}
if use_color() {
eprintln!(" {} {}", "✓".green(), label.dimmed());
} else {
eprintln!(" ✓ {}", label);
}
}
pub fn check_fail(label: &str, detail: &str) {
if is_json_mode() {
return;
}
if use_color() {
eprintln!(" {} {} — {}", "✗".red().bold(), label, detail);
} else {
eprintln!(" ✗ {} — {}", label, detail);
}
}
pub fn check_warn(label: &str, detail: &str) {
if is_json_mode() {
return;
}
if use_color() {
eprintln!(" {} {} — {}", "⚠".yellow(), label, detail);
} else {
eprintln!(" ⚠ {} — {}", label, detail);
}
}
pub fn create_spinner() -> ProgressBar {
let pb = ProgressBar::new_spinner();
if is_json_mode() {
pb.set_draw_target(ProgressDrawTarget::hidden());
} else {
pb.set_style(
ProgressStyle::with_template(" {spinner:.green} {msg}")
.unwrap()
.tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", "✓"]),
);
pb.enable_steady_tick(Duration::from_millis(80));
}
pb
}
pub mod style {
use super::*;
pub fn bold(s: &str) -> String {
if use_color() {
s.bold().to_string()
} else {
s.to_string()
}
}
pub fn yellow(s: &str) -> String {
if use_color() {
s.yellow().to_string()
} else {
s.to_string()
}
}
pub fn green(s: &str) -> String {
if use_color() {
s.green().to_string()
} else {
s.to_string()
}
}
pub fn red(s: &str) -> String {
if use_color() {
s.red().to_string()
} else {
s.to_string()
}
}
pub fn green_bold(s: &str) -> String {
if use_color() {
s.green().bold().to_string()
} else {
s.to_string()
}
}
pub fn red_bold(s: &str) -> String {
if use_color() {
s.red().bold().to_string()
} else {
s.to_string()
}
}
pub fn dim(s: &str) -> String {
if use_color() {
s.dimmed().to_string()
} else {
s.to_string()
}
}
}