blob: 2ab75be6ca2a9210c7c0fe7e1a5f0ad5069f6495 [file] [log] [blame] [edit]
use lazy_static::lazy_static;
use std::io::{Result, Write};
use std::sync::{Mutex, MutexGuard, PoisonError};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream as Stream, WriteColor};
lazy_static! {
static ref TERM: Mutex<Term> = Mutex::new(Term::new());
}
pub fn lock() -> MutexGuard<'static, Term> {
TERM.lock().unwrap_or_else(PoisonError::into_inner)
}
pub fn bold() {
lock().set_color(ColorSpec::new().set_bold(true));
}
pub fn color(color: Color) {
lock().set_color(ColorSpec::new().set_fg(Some(color)));
}
pub fn bold_color(color: Color) {
lock().set_color(ColorSpec::new().set_bold(true).set_fg(Some(color)));
}
pub fn reset() {
lock().reset();
}
#[deny(unused_macros)]
macro_rules! print {
($($args:tt)*) => {{
use std::io::Write;
let _ = std::write!($crate::term::lock(), $($args)*);
}};
}
#[deny(unused_macros)]
macro_rules! println {
($($args:tt)*) => {{
use std::io::Write;
let _ = std::writeln!($crate::term::lock(), $($args)*);
}};
}
pub struct Term {
spec: ColorSpec,
stream: Stream,
start_of_line: bool,
}
impl Term {
fn new() -> Self {
Term {
spec: ColorSpec::new(),
stream: Stream::stderr(ColorChoice::Auto),
start_of_line: true,
}
}
fn set_color(&mut self, spec: &ColorSpec) {
if self.spec != *spec {
self.spec = spec.clone();
self.start_of_line = true;
}
}
fn reset(&mut self) {
self.spec = ColorSpec::new();
let _ = self.stream.reset();
}
}
impl Write for Term {
// Color one line at a time because Travis does not preserve color setting
// across output lines.
fn write(&mut self, mut buf: &[u8]) -> Result<usize> {
if self.spec.is_none() {
return self.stream.write(buf);
}
let len = buf.len();
while !buf.is_empty() {
if self.start_of_line {
let _ = self.stream.set_color(&self.spec);
}
match buf.iter().position(|byte| *byte == b'\n') {
Some(line_len) => {
self.stream.write_all(&buf[..line_len + 1])?;
self.start_of_line = true;
buf = &buf[line_len + 1..];
}
None => {
self.stream.write_all(buf)?;
self.start_of_line = false;
break;
}
}
}
Ok(len)
}
fn flush(&mut self) -> Result<()> {
self.stream.flush()
}
}