mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 14:52:33 +00:00
65c2350aa3
Color are now only used when outputting to a termainal/TTY. There are three new settings as well which can be used to control color output, they are: * `AppSettings::ColorAuto`: The default, and will only output color when outputting to a terminal or TTY * `AppSettings::ColorAlways`: Outputs color no matter where the output is going * `AppSettings::ColorNever`: Never colors output This now allows one to use things like command line options, or environmental variables to turn colored output on/off. Closes #512
147 lines
3.8 KiB
Text
147 lines
3.8 KiB
Text
use std::fmt;
|
|
|
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
|
use ansi_term::Colour::{Green, Red, Yellow};
|
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
|
use ansi_term::ANSIString;
|
|
|
|
#[cfg(color)]
|
|
use libc;
|
|
|
|
#[cfg(color)]
|
|
const STDERR: i32 = libc::STDERR_FILENO;
|
|
#[cfg(color)]
|
|
const STDOUT: i32 = libc::STDOUT_FILENO;
|
|
#[cfg(not(color))]
|
|
const STDERR: i32 = 0;
|
|
#[cfg(not(color))]
|
|
const STDOUT: i32 = 0;
|
|
|
|
#[doc(hidden)]
|
|
#[derive(Debug, PartialEq)]
|
|
pub enum ColorWhen {
|
|
Auto, // Default
|
|
Always,
|
|
Never
|
|
}
|
|
|
|
#[cfg(color)]
|
|
pub fn is_a_tty(stderr: bool) -> bool {
|
|
let fd = if stderr { STDERR } else { STDOUT };
|
|
unsafe { libc::isatty(fd) != 0 }
|
|
}
|
|
|
|
#[cfg(not(color))]
|
|
pub fn is_a_tty(stderr: bool) -> bool {
|
|
false
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub struct Colorizer {
|
|
use_stderr: bool,
|
|
when: ColorWhen
|
|
}
|
|
|
|
macro_rules! color {
|
|
($_self:ident, $c:ident, $m:expr) => {
|
|
match $_self.when {
|
|
ColorWhen::Auto => if is_a_tty($_self.use_stderr) {
|
|
Format::$c($m)
|
|
} else {
|
|
$m
|
|
},
|
|
ColorWhen::Always => Format::$c($m),
|
|
ColorWhen::Never => $m,
|
|
}
|
|
};
|
|
}
|
|
|
|
impl Colorizer {
|
|
pub fn good<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
|
|
use Format::Good;
|
|
color!(self, Good, msg)
|
|
}
|
|
pub fn warning<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
|
|
use Format::Warning;
|
|
color!(self, Warning, msg)
|
|
}
|
|
pub fn error<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
|
|
use Format::Error;
|
|
color!(self, Error, msg)
|
|
}
|
|
}
|
|
|
|
impl Default for Colorizer {
|
|
fn default() -> Self {
|
|
Colorizer {
|
|
use_stderr: true,
|
|
when: ColorWhen::Auto
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow,
|
|
/// and Good=Green
|
|
#[derive(Debug)]
|
|
#[doc(hidden)]
|
|
pub enum Format<T> {
|
|
/// Defines the style used for errors, defaults to Red
|
|
Error(T),
|
|
/// Defines the style used for warnings, defaults to Yellow
|
|
Warning(T),
|
|
/// Defines the style used for good values, defaults to Green
|
|
Good(T),
|
|
}
|
|
|
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
|
impl<T: AsRef<str>> Format<T> {
|
|
fn format(&self) -> ANSIString {
|
|
match *self {
|
|
Format::Error(ref e) => Red.bold().paint(e.as_ref()),
|
|
Format::Warning(ref e) => Yellow.paint(e.as_ref()),
|
|
Format::Good(ref e) => Green.paint(e.as_ref()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
|
impl<T: AsRef<str>> fmt::Display for Format<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{}", &self.format())
|
|
}
|
|
}
|
|
|
|
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
|
impl<T: fmt::Display> Format<T> {
|
|
fn format(&self) -> &T {
|
|
match *self {
|
|
Format::Error(ref e) => e,
|
|
Format::Warning(ref e) => e,
|
|
Format::Good(ref e) => e,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
|
impl<T: fmt::Display> fmt::Display for Format<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{}", &self.format())
|
|
}
|
|
}
|
|
|
|
#[cfg(all(test, feature = "color", not(target_os = "windows")))]
|
|
mod test {
|
|
use super::Format;
|
|
use ansi_term::Colour::{Green, Red, Yellow};
|
|
|
|
#[test]
|
|
fn colored_output() {
|
|
let err = Format::Error("error");
|
|
assert_eq!(&*format!("{}", err),
|
|
&*format!("{}", Red.bold().paint("error")));
|
|
let good = Format::Good("good");
|
|
assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
|
|
let warn = Format::Warning("warn");
|
|
assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
|
|
}
|
|
}
|