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::fmt;
10 use std::env;
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 { env::var("TERM").ok() == Some(String::from("dumb")) }
38
39 #[doc(hidden)]
40 pub struct ColorizerOption {
41 pub use_stderr: bool,
42 pub when: ColorWhen,
43 }
44
45 #[doc(hidden)]
46 pub struct Colorizer {
47 when: ColorWhen,
48 }
49
50 macro_rules! color {
51 ($_self:ident, $c:ident, $m:expr) => {
52 match $_self.when {
53 ColorWhen::Auto => Format::$c($m),
54 ColorWhen::Always => Format::$c($m),
55 ColorWhen::Never => Format::None($m),
56 }
57 };
58 }
59
60 impl Colorizer {
new(option: ColorizerOption) -> Colorizer61 pub fn new(option: ColorizerOption) -> Colorizer {
62 let is_a_tty = is_a_tty(option.use_stderr);
63 let is_term_dumb = is_term_dumb();
64 Colorizer {
65 when: if is_a_tty && !is_term_dumb {
66 option.when
67 } else {
68 ColorWhen::Never
69 },
70 }
71 }
72
good<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str>,73 pub fn good<T>(&self, msg: T) -> Format<T>
74 where
75 T: fmt::Display + AsRef<str>,
76 {
77 debugln!("Colorizer::good;");
78 color!(self, Good, msg)
79 }
80
warning<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str>,81 pub fn warning<T>(&self, msg: T) -> Format<T>
82 where
83 T: fmt::Display + AsRef<str>,
84 {
85 debugln!("Colorizer::warning;");
86 color!(self, Warning, msg)
87 }
88
error<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str>,89 pub fn error<T>(&self, msg: T) -> Format<T>
90 where
91 T: fmt::Display + AsRef<str>,
92 {
93 debugln!("Colorizer::error;");
94 color!(self, Error, msg)
95 }
96
none<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str>,97 pub fn none<T>(&self, msg: T) -> Format<T>
98 where
99 T: fmt::Display + AsRef<str>,
100 {
101 debugln!("Colorizer::none;");
102 Format::None(msg)
103 }
104 }
105
106 impl Default for Colorizer {
default() -> Self107 fn default() -> Self {
108 Colorizer::new(ColorizerOption {
109 use_stderr: true,
110 when: ColorWhen::Auto,
111 })
112 }
113 }
114
115 /// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow,
116 /// and Good=Green
117 #[derive(Debug)]
118 #[doc(hidden)]
119 pub enum Format<T> {
120 /// Defines the style used for errors, defaults to Red
121 Error(T),
122 /// Defines the style used for warnings, defaults to Yellow
123 Warning(T),
124 /// Defines the style used for good values, defaults to Green
125 Good(T),
126 /// Defines no formatting style
127 None(T),
128 }
129
130 #[cfg(all(feature = "color", not(target_os = "windows")))]
131 impl<T: AsRef<str>> Format<T> {
format(&self) -> ANSIString132 fn format(&self) -> ANSIString {
133 match *self {
134 Format::Error(ref e) => Red.bold().paint(e.as_ref()),
135 Format::Warning(ref e) => Yellow.paint(e.as_ref()),
136 Format::Good(ref e) => Green.paint(e.as_ref()),
137 Format::None(ref e) => ANSIString::from(e.as_ref()),
138 }
139 }
140 }
141
142 #[cfg(any(not(feature = "color"), target_os = "windows"))]
143 #[cfg_attr(feature = "lints", allow(match_same_arms))]
144 impl<T: fmt::Display> Format<T> {
format(&self) -> &T145 fn format(&self) -> &T {
146 match *self {
147 Format::Error(ref e) => e,
148 Format::Warning(ref e) => e,
149 Format::Good(ref e) => e,
150 Format::None(ref e) => e,
151 }
152 }
153 }
154
155
156 #[cfg(all(feature = "color", not(target_os = "windows")))]
157 impl<T: AsRef<str>> fmt::Display for Format<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result158 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) }
159 }
160
161 #[cfg(any(not(feature = "color"), target_os = "windows"))]
162 impl<T: fmt::Display> fmt::Display for Format<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) }
164 }
165
166 #[cfg(all(test, feature = "color", not(target_os = "windows")))]
167 mod test {
168 use ansi_term::ANSIString;
169 use ansi_term::Colour::{Green, Red, Yellow};
170 use super::Format;
171
172 #[test]
colored_output()173 fn colored_output() {
174 let err = Format::Error("error");
175 assert_eq!(
176 &*format!("{}", err),
177 &*format!("{}", Red.bold().paint("error"))
178 );
179 let good = Format::Good("good");
180 assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
181 let warn = Format::Warning("warn");
182 assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
183 let none = Format::None("none");
184 assert_eq!(
185 &*format!("{}", none),
186 &*format!("{}", ANSIString::from("none"))
187 );
188 }
189 }
190