concolor_control/color/
mod.rsmod choice;
mod lazy;
use choice::AtomicChoice;
#[derive(Clone, Debug)]
pub struct Color {
flags: InternalFlags,
choice: crate::ColorChoice,
stream: crate::Stream,
}
impl Color {
pub fn color(&self) -> bool {
match self.choice {
crate::ColorChoice::Auto => self.flags.color(self.stream),
crate::ColorChoice::AlwaysAnsi => true,
crate::ColorChoice::Always => true,
crate::ColorChoice::Never => false,
}
}
#[cfg(not(windows))]
pub fn ansi_color(&self) -> bool {
match self.choice {
crate::ColorChoice::Auto => self.flags.ansi_color(self.stream),
crate::ColorChoice::AlwaysAnsi => true,
crate::ColorChoice::Always => true,
crate::ColorChoice::Never => false,
}
}
#[cfg(windows)]
pub fn ansi_color(&self) -> bool {
match self.choice {
crate::ColorChoice::Auto => self.flags.ansi_color(self.stream),
crate::ColorChoice::AlwaysAnsi => true,
crate::ColorChoice::Always => self.flags.intersects(InternalFlags::ANSI_ANY),
crate::ColorChoice::Never => false,
}
}
pub fn truecolor(&self) -> bool {
self.ansi_color() && self.flags.contains(InternalFlags::TRUECOLOR)
}
}
static FLAGS: lazy::Lazy = lazy::Lazy::new();
static USER: AtomicChoice = AtomicChoice::new();
pub fn get(stream: crate::Stream) -> Color {
let flags = FLAGS.get_or_init(init);
Color {
flags: InternalFlags::from_bits(flags).unwrap(),
choice: USER.get(),
stream,
}
}
#[cfg(feature = "api_unstable")]
pub fn set(choice: crate::ColorChoice) {
USER.set(choice)
}
fn init() -> usize {
let mut flags = InternalFlags::empty();
#[cfg(feature = "clicolor")]
{
if concolor_query::clicolor() {
flags |= InternalFlags::CLICOLOR;
}
if concolor_query::clicolor_force() {
flags |= InternalFlags::CLICOLOR_FORCE;
}
}
#[cfg(not(feature = "clicolor"))]
{
flags |= InternalFlags::CLICOLOR;
}
#[cfg(feature = "no_color")]
if concolor_query::no_color() {
flags |= InternalFlags::NO_COLOR;
}
#[cfg(feature = "term")]
{
if concolor_query::term_supports_color() {
flags |= InternalFlags::TERM_SUPPORT;
}
if concolor_query::term_supports_ansi_color() {
flags |= InternalFlags::ANSI_SUPPORT;
}
if concolor_query::truecolor() {
flags |= InternalFlags::TRUECOLOR;
}
}
#[cfg(feature = "interactive")]
{
if atty::is(atty::Stream::Stdout) {
flags |= InternalFlags::TTY_STDOUT;
}
if atty::is(atty::Stream::Stderr) {
flags |= InternalFlags::TTY_STDERR;
}
}
#[cfg(feature = "windows")]
if concolor_query::windows::enable_ansi_colors().unwrap_or(false) {
flags |= InternalFlags::ANSI_WIN;
}
flags.bits()
}
bitflags::bitflags! {
struct InternalFlags: usize {
const CLICOLOR = 0b00000000001;
const CLICOLOR_FORCE = 0b00000000010;
const NO_COLOR = 0b00000000100;
const TERM_SUPPORT = 0b00000001000;
const ANSI_SUPPORT = 0b00000010000;
const ANSI_WIN = 0b00000100000;
const ANSI_ANY = 0b00000110000;
const TRUECOLOR = 0b00001000000;
const TTY_STDOUT = 0b00010000000;
const TTY_STDERR = 0b00100000000;
const TTY_ANY = 0b00110000000;
}
}
impl InternalFlags {
fn color(self, stream: crate::Stream) -> bool {
(self.is_interactive(stream)
&& self.contains(Self::TERM_SUPPORT)
&& self.contains(Self::CLICOLOR)
&& !self.contains(Self::NO_COLOR))
|| self.contains(Self::CLICOLOR_FORCE)
}
fn ansi_color(self, stream: crate::Stream) -> bool {
(self.is_interactive(stream)
&& self.contains(Self::TERM_SUPPORT)
&& self.intersects(Self::ANSI_ANY)
&& self.contains(Self::CLICOLOR)
&& !self.contains(Self::NO_COLOR))
|| self.contains(Self::CLICOLOR_FORCE)
}
fn is_interactive(self, stream: crate::Stream) -> bool {
self.contains(stream.flags())
}
}
impl crate::Stream {
fn flags(self) -> InternalFlags {
match self {
Self::Stdout => InternalFlags::TTY_STDOUT,
Self::Stderr => InternalFlags::TTY_STDERR,
Self::Either => InternalFlags::TTY_ANY,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn is_interactive() {
let flags = InternalFlags::empty();
assert!(!flags.is_interactive(crate::Stream::Stdout));
assert!(!flags.is_interactive(crate::Stream::Stderr));
assert!(!flags.is_interactive(crate::Stream::Either));
let flags = InternalFlags::TTY_STDOUT;
assert!(flags.is_interactive(crate::Stream::Stdout));
assert!(!flags.is_interactive(crate::Stream::Stderr));
assert!(!flags.is_interactive(crate::Stream::Either));
let flags = InternalFlags::TTY_STDERR;
assert!(!flags.is_interactive(crate::Stream::Stdout));
assert!(flags.is_interactive(crate::Stream::Stderr));
assert!(!flags.is_interactive(crate::Stream::Either));
let flags = InternalFlags::TTY_STDOUT | InternalFlags::TTY_STDERR;
assert!(flags.is_interactive(crate::Stream::Stdout));
assert!(flags.is_interactive(crate::Stream::Stderr));
assert!(flags.is_interactive(crate::Stream::Either));
}
}