use std::{fmt::Display, sync::OnceLock};
pub static NO_DECORATION: OnceLock<bool> = OnceLock::new();
pub static DEBUG: OnceLock<bool> = OnceLock::new();
#[macro_export]
macro_rules! log_context {
($($name:ident => $value:expr),* $(,)?) => {{
use heck::ToTitleCase;
let ctx = file!()
.split('/')
.last()
.unwrap_or("unknown")
.split('.')
.next()
.unwrap_or("unknown")
.to_title_case();
println!("{}", ctx);
let last = [$(stringify!($name)),*].last().unwrap();
let maxlen = [$(stringify!($name)),*].iter().map(|s| s.len()).max().unwrap_or(0) + 1;
$(
let marker = if stringify!($name) == *last { '╰' } else { '├' };
println!(
"{} {:width$}: {:?}",
marker,
stringify!($name),
$value,
width = maxlen
);
)*
println!();
}};
}
#[macro_export]
macro_rules! debug {
($fmt:expr) => {{
if *$crate::log::DEBUG.get().unwrap_or(&false) {
println!($fmt);
}
}};
($fmt:expr, $($arg:tt)*) => {{
if *$crate::log::DEBUG.get().unwrap_or(&false) {
println!($fmt, $($arg)*);
}
}};
}
#[allow(dead_code)]
pub trait Ansi {
fn fg(&self, color: u8) -> String;
fn bg(&self, color: u8) -> String;
fn bold(&self) -> String;
fn link(&self, url: &str) -> String;
}
impl<T: Display> Ansi for T {
fn fg(&self, color: u8) -> String {
if *NO_DECORATION.get().unwrap_or(&false) {
return self.to_string();
}
format!("\x1b[38;5;{}m{}\x1b[39m", color, self)
}
fn bg(&self, color: u8) -> String {
if *NO_DECORATION.get().unwrap_or(&false) {
return self.to_string();
}
format!("\x1b[48;5;{}m{}\x1b[49m", color, self)
}
fn bold(&self) -> String {
if *NO_DECORATION.get().unwrap_or(&false) {
return self.to_string();
}
format!("\x1b[1m{}\x1b[22m", self)
}
fn link(&self, url: &str) -> String {
if *NO_DECORATION.get().unwrap_or(&false) {
return self.to_string();
}
format!("\x1b]8;;{}\x1b\\{}\x1b]8;;\x1b\\", url, self)
}
}