use crate::{styled_write, Ansi};
use std::io::{self, IsTerminal};
use std::fmt;
use std::cell::Cell;
use super::{AnsiPreference, AnsiWrite};
static mut ANSIOUT: Cell<Option<Ansi>> = Cell::new(None);
static mut ANSIERR: Cell<Option<Ansi>> = Cell::new(None);
pub struct Ansiout(io::StdoutLock<'static>);
pub struct Ansierr(io::StderrLock<'static>);
pub fn ansiout() -> Ansiout { Ansiout(io::stdout().lock()) }
pub fn ansierr() -> Ansierr { Ansierr(io::stderr().lock()) }
impl Ansiout {
#[inline]
#[doc(hidden)]
pub fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
io::Write::write_fmt(self, fmt)
}
}
impl Ansierr {
#[inline]
#[doc(hidden)]
pub fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
io::Write::write_fmt(self, fmt)
}
}
impl AnsiWrite for Ansiout {
fn ansi(&self) -> Ansi {
#[allow(static_mut_refs)]
unsafe {
match ANSIOUT.get() {
None => {
let ansi: Ansi = self.preferred_ansi();
ANSIOUT.set(Some(ansi));
ansi
},
Some(ansi) => ansi,
}
}
}
fn set_ansi(&mut self, ansi: Ansi) {
#[allow(static_mut_refs)]
unsafe { ANSIOUT.set(Some(ansi)); }
}
}
impl AnsiWrite for Ansierr {
fn ansi(&self) -> Ansi {
#[allow(static_mut_refs)]
unsafe {
match ANSIERR.get() {
None => {
let ansi: Ansi = self.preferred_ansi();
ANSIERR.set(Some(ansi));
ansi
},
Some(ansi) => ansi,
}
}
}
fn set_ansi(&mut self, ansi: Ansi) {
#[allow(static_mut_refs)]
unsafe { ANSIERR.set(Some(ansi)); }
}
}
impl AnsiPreference for Ansiout {
fn is_ansi_preferred(&self) -> bool { self.0.is_terminal() }
}
impl AnsiPreference for Ansierr {
fn is_ansi_preferred(&self) -> bool { self.0.is_terminal() }
}
impl io::Write for Ansiout {
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
if ! self.ansi().is_empty() {
styled_write!(self.0, self.ansi(), "{}", fmt)
} else {
self.0.write_fmt(fmt)
}
}
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
fn flush(&mut self) -> io::Result<()> { self.0.flush() }
}
impl io::Write for Ansierr {
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
if ! self.ansi().is_empty() {
styled_write!(self.0, self.ansi(), "{}", fmt)
} else {
self.0.write_fmt(fmt)
}
}
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
fn flush(&mut self) -> io::Result<()> { self.0.flush() }
}