use std::fmt;
use style::{Style, Property};
use color::Color;
#[derive(Default, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
pub struct Paint<T> {
item: T,
style: Style,
}
macro_rules! constructors_for {
($T:ty, $($name:ident: $color:ident),*) => ($(
#[doc = concat!(
"Constructs a new `Paint` structure encapsulating `item` with the foreground color\n",
"set to ", stringify!($name), ".\n",
"```rust\n",
"use yansi::Paint;\n",
"\n",
"println!(\"This is going to be ", stringify!($name),
": {}\", Paint::", stringify!($name), "(\"yay!\"));\n",
"```\n"
)]
#[inline]
pub fn $name(item: $T) -> Paint<$T> {
Paint::new(item).fg(Color::$color)
}
)*)
}
impl<T> Paint<T> {
#[inline]
pub fn new(item: T) -> Paint<T> {
Paint { item, style: Style::default() }
}
#[inline]
pub fn default(item: T) -> Paint<T> {
Paint::new(item).fg(Color::Default).bg(Color::Default)
}
#[inline]
pub fn masked(item: T) -> Paint<T> {
Paint::new(item).mask()
}
#[inline]
pub fn wrapping(item: T) -> Paint<T> {
Paint::new(item).wrap()
}
#[inline]
pub fn rgb(r: u8, g: u8, b: u8, item: T) -> Paint<T> {
Paint::new(item).fg(Color::RGB(r, g, b))
}
#[inline]
pub fn fixed(color: u8, item: T) -> Paint<T> {
Paint::new(item).fg(Color::Fixed(color))
}
constructors_for!(T, black: Black, red: Red, green: Green, yellow: Yellow,
blue: Blue, magenta: Magenta, cyan: Cyan, white: White);
#[inline]
pub fn style(&self) -> Style {
self.style
}
#[inline]
pub fn inner(&self) -> &T {
&self.item
}
#[inline]
pub fn with_style(mut self, style: Style) -> Paint<T> {
self.style = style;
self
}
#[inline]
pub fn mask(mut self) -> Paint<T> {
self.style.masked = true;
self
}
#[inline]
pub fn wrap(mut self) -> Paint<T> {
self.style.wrap = true;
self
}
#[inline]
pub fn fg(mut self, color: Color) -> Paint<T> {
self.style.foreground = color;
self
}
#[inline]
pub fn bg(mut self, color: Color) -> Paint<T> {
self.style.background = color;
self
}
style_builder_for!(Paint<T>, |paint| paint.style.properties,
bold: BOLD, dimmed: DIMMED, italic: ITALIC,
underline: UNDERLINE, blink: BLINK, invert: INVERT,
hidden: HIDDEN, strikethrough: STRIKETHROUGH);
}
macro_rules! impl_fmt_trait {
($trait:ident, $fmt:expr) => (
impl<T: fmt::$trait> fmt::$trait for Paint<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if Paint::is_enabled() && self.style.wrap {
let mut prefix = String::new();
prefix.push_str("\x1B[0m");
self.style.fmt_prefix(&mut prefix)?;
self.style.fmt_prefix(f)?;
let item = format!($fmt, self.item).replace("\x1B[0m", &prefix);
fmt::$trait::fmt(&item, f)?;
self.style.fmt_suffix(f)
} else if Paint::is_enabled() {
self.style.fmt_prefix(f)?;
fmt::$trait::fmt(&self.item, f)?;
self.style.fmt_suffix(f)
} else if !self.style.masked {
fmt::$trait::fmt(&self.item, f)
} else {
Ok(())
}
}
}
)
}
impl_fmt_trait!(Display, "{}");
impl_fmt_trait!(Debug, "{:?}");
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
static ENABLED: AtomicBool = AtomicBool::new(true);
impl Paint<()> {
pub fn disable() {
ENABLED.store(false, Ordering::Release);
}
pub fn enable() {
ENABLED.store(true, Ordering::Release);
}
pub fn is_enabled() -> bool {
ENABLED.load(Ordering::Acquire)
}
#[inline]
pub fn enable_windows_ascii() -> bool {
::windows::enable_ascii_colors()
}
}