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