use std::fmt::Display; #[allow(unused)] pub trait Stylize { fn red(self) -> Ansi where Self: Sized, { Ansi::new(self).red() } fn yellow(self) -> Ansi where Self: Sized, { Ansi::new(self).yellow() } fn cyan(self) -> Ansi where Self: Sized, { Ansi::new(self).cyan() } fn bold(self) -> Ansi where Self: Sized, { Ansi::new(self).bold() } } impl Stylize for T where T: Display {} #[derive(Clone, Copy)] #[repr(usize)] pub enum AnsiMode { Bold = 1, Red = 31, Yellow = 33, Cyan = 36, } pub struct Ansi { inner: T, modes: Vec, } impl Ansi { pub fn new(inner: T) -> Self { Self { inner, modes: Vec::new(), } } pub fn with(mut self, mode: AnsiMode) -> Self { self.modes.push(mode); self } } impl Ansi { fn red(self) -> Self where Self: Sized, { self.with(AnsiMode::Red) } fn yellow(self) -> Self where Self: Sized, { self.with(AnsiMode::Yellow) } fn cyan(self) -> Self where Self: Sized, { self.with(AnsiMode::Cyan) } fn bold(self) -> Self where Self: Sized, { self.with(AnsiMode::Bold) } } impl Extend for Ansi { fn extend>(&mut self, iter: I) { self.modes.extend(iter) } } impl Display for Ansi where T: Display, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("\x1b[")?; let mut sep = ""; for mode in &self.modes { f.write_str(sep)?; sep = ";"; write!(f, "{}", *mode as usize)?; } f.write_str("m")?; self.inner.fmt(f)?; f.write_str("\x1b[0m")?; Ok(()) } } #[macro_export] macro_rules! warning { ($($arg:tt)*) => {{ use $crate::report::Stylize; ::std::eprint!("{}: ", "warning".yellow().bold()); ::std::eprintln!($($arg)*); }}; } #[macro_export] macro_rules! error { ($($arg:tt)*) => {{ use $crate::report::Stylize; ::std::eprint!("{}: ", "error".red().bold()); ::std::eprintln!($($arg)*); }}; } #[macro_export] macro_rules! exit_with_error { ($($arg:tt)*) => {{ $crate::error!($($arg)*); ::std::process::exit(1); }}; }