1 #[cfg(all(feature = "color", not(target_os = "windows")))]
2 use ansi_term::ANSIString;
3 
4 #[cfg(all(feature = "color", not(target_os = "windows")))]
5 use ansi_term::Colour::{Green, Red, Yellow};
6 
7 #[cfg(feature = "color")]
8 use atty;
9 use std::env;
10 use std::fmt;
11 
12 #[doc(hidden)]
13 #[derive(Debug, Copy, Clone, PartialEq)]
14 pub enum ColorWhen {
15     Auto,
16     Always,
17     Never,
18 }
19 
20 #[cfg(feature = "color")]
is_a_tty(stderr: bool) -> bool21 pub fn is_a_tty(stderr: bool) -> bool {
22     debugln!("is_a_tty: stderr={:?}", stderr);
23     let stream = if stderr {
24         atty::Stream::Stderr
25     } else {
26         atty::Stream::Stdout
27     };
28     atty::is(stream)
29 }
30 
31 #[cfg(not(feature = "color"))]
is_a_tty(_: bool) -> bool32 pub fn is_a_tty(_: bool) -> bool {
33     debugln!("is_a_tty;");
34     false
35 }
36 
is_term_dumb() -> bool37 pub fn is_term_dumb() -> bool {
38     env::var("TERM").ok() == Some(String::from("dumb"))
39 }
40 
41 #[doc(hidden)]
42 pub struct ColorizerOption {
43     pub use_stderr: bool,
44     pub when: ColorWhen,
45 }
46 
47 #[doc(hidden)]
48 pub struct Colorizer {
49     when: ColorWhen,
50 }
51 
52 macro_rules! color {
53     ($_self:ident, $c:ident, $m:expr) => {
54         match $_self.when {
55             ColorWhen::Auto => Format::$c($m),
56             ColorWhen::Always => Format::$c($m),
57             ColorWhen::Never => Format::None($m),
58         }
59     };
60 }
61 
62 impl Colorizer {
new(option: ColorizerOption) -> Colorizer63     pub fn new(option: ColorizerOption) -> Colorizer {
64         let is_a_tty = is_a_tty(option.use_stderr);
65         let is_term_dumb = is_term_dumb();
66         Colorizer {
67             when: match option.when {
68                 ColorWhen::Auto if is_a_tty && !is_term_dumb => ColorWhen::Auto,
69                 ColorWhen::Auto => ColorWhen::Never,
70                 when => when,
71             },
72         }
73     }
74 
good<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str>,75     pub fn good<T>(&self, msg: T) -> Format<T>
76     where
77         T: fmt::Display + AsRef<str>,
78     {
79         debugln!("Colorizer::good;");
80         color!(self, Good, msg)
81     }
82 
warning<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str>,83     pub fn warning<T>(&self, msg: T) -> Format<T>
84     where
85         T: fmt::Display + AsRef<str>,
86     {
87         debugln!("Colorizer::warning;");
88         color!(self, Warning, msg)
89     }
90 
error<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str>,91     pub fn error<T>(&self, msg: T) -> Format<T>
92     where
93         T: fmt::Display + AsRef<str>,
94     {
95         debugln!("Colorizer::error;");
96         color!(self, Error, msg)
97     }
98 
none<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str>,99     pub fn none<T>(&self, msg: T) -> Format<T>
100     where
101         T: fmt::Display + AsRef<str>,
102     {
103         debugln!("Colorizer::none;");
104         Format::None(msg)
105     }
106 }
107 
108 impl Default for Colorizer {
default() -> Self109     fn default() -> Self {
110         Colorizer::new(ColorizerOption {
111             use_stderr: true,
112             when: ColorWhen::Auto,
113         })
114     }
115 }
116 
117 /// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow,
118 /// and Good=Green
119 #[derive(Debug)]
120 #[doc(hidden)]
121 pub enum Format<T> {
122     /// Defines the style used for errors, defaults to Red
123     Error(T),
124     /// Defines the style used for warnings, defaults to Yellow
125     Warning(T),
126     /// Defines the style used for good values, defaults to Green
127     Good(T),
128     /// Defines no formatting style
129     None(T),
130 }
131 
132 #[cfg(all(feature = "color", not(target_os = "windows")))]
133 impl<T: AsRef<str>> Format<T> {
format(&self) -> ANSIString134     fn format(&self) -> ANSIString {
135         match *self {
136             Format::Error(ref e) => Red.bold().paint(e.as_ref()),
137             Format::Warning(ref e) => Yellow.paint(e.as_ref()),
138             Format::Good(ref e) => Green.paint(e.as_ref()),
139             Format::None(ref e) => ANSIString::from(e.as_ref()),
140         }
141     }
142 }
143 
144 #[cfg(any(not(feature = "color"), target_os = "windows"))]
145 #[cfg_attr(feature = "lints", allow(match_same_arms))]
146 impl<T: fmt::Display> Format<T> {
format(&self) -> &T147     fn format(&self) -> &T {
148         match *self {
149             Format::Error(ref e) => e,
150             Format::Warning(ref e) => e,
151             Format::Good(ref e) => e,
152             Format::None(ref e) => e,
153         }
154     }
155 }
156 
157 #[cfg(all(feature = "color", not(target_os = "windows")))]
158 impl<T: AsRef<str>> fmt::Display for Format<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result159     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160         write!(f, "{}", &self.format())
161     }
162 }
163 
164 #[cfg(any(not(feature = "color"), target_os = "windows"))]
165 impl<T: fmt::Display> fmt::Display for Format<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result166     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167         write!(f, "{}", &self.format())
168     }
169 }
170 
171 #[cfg(all(test, feature = "color", not(target_os = "windows")))]
172 mod test {
173     use super::Format;
174     use ansi_term::ANSIString;
175     use ansi_term::Colour::{Green, Red, Yellow};
176 
177     #[test]
colored_output()178     fn colored_output() {
179         let err = Format::Error("error");
180         assert_eq!(
181             &*format!("{}", err),
182             &*format!("{}", Red.bold().paint("error"))
183         );
184         let good = Format::Good("good");
185         assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
186         let warn = Format::Warning("warn");
187         assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
188         let none = Format::None("none");
189         assert_eq!(
190             &*format!("{}", none),
191             &*format!("{}", ANSIString::from("none"))
192         );
193     }
194 }
195