• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2 This crate provides a cross platform abstraction for writing colored text to
3 a terminal. Colors are written using either ANSI escape sequences or by
4 communicating with a Windows console. Much of this API was motivated by use
5 inside command line applications, where colors or styles can be configured
6 by the end user and/or the environment.
7 
8 This crate also provides platform independent support for writing colored text
9 to an in memory buffer. While this is easy to do with ANSI escape sequences
10 (because they are in the buffer themselves), it is trickier to do with the
11 Windows console API, which requires synchronous communication.
12 
13 # Organization
14 
15 The `WriteColor` trait extends the `io::Write` trait with methods for setting
16 colors or resetting them.
17 
18 `StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are
19 analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr`
20 and `std::io::StderrLock`.
21 
22 `Buffer` is an in memory buffer that supports colored text. In a parallel
23 program, each thread might write to its own buffer. A buffer can be printed to
24 using a `BufferWriter`. The advantage of this design is that each thread can
25 work in parallel on a buffer without having to synchronize access to global
26 resources such as the Windows console. Moreover, this design also prevents
27 interleaving of buffer output.
28 
29 `Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of
30 `io::Write`. These types are useful when you know exactly what you need. An
31 analogous type for the Windows console is not provided since it cannot exist.
32 
33 # Example: using `StandardStream`
34 
35 The `StandardStream` type in this crate works similarly to `std::io::Stdout`,
36 except it is augmented with methods for coloring by the `WriteColor` trait.
37 For example, to write some green text:
38 
39 ```rust,no_run
40 # fn test() -> Result<(), Box<::std::error::Error>> {
41 use std::io::Write;
42 use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
43 
44 let mut stdout = StandardStream::stdout(ColorChoice::Always);
45 stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
46 writeln!(&mut stdout, "green text!")?;
47 # Ok(()) }
48 ```
49 
50 Note that any text written to the terminal now will be colored
51 green when using ANSI escape sequences, even if it is written via
52 stderr, and even if stderr had previously been set to `Color::Red`.
53 Users will need to manage any color changes themselves by calling
54 [`WriteColor::set_color`](trait.WriteColor.html#tymethod.set_color), and this
55 may include calling [`WriteColor::reset`](trait.WriteColor.html#tymethod.reset)
56 before the program exits to a shell.
57 
58 # Example: using `BufferWriter`
59 
60 A `BufferWriter` can create buffers and write buffers to stdout or stderr. It
61 does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer`
62 implements `io::Write` and `io::WriteColor`.
63 
64 This example shows how to print some green text to stderr.
65 
66 ```rust,no_run
67 # fn test() -> Result<(), Box<::std::error::Error>> {
68 use std::io::Write;
69 use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
70 
71 let mut bufwtr = BufferWriter::stderr(ColorChoice::Always);
72 let mut buffer = bufwtr.buffer();
73 buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
74 writeln!(&mut buffer, "green text!")?;
75 bufwtr.print(&buffer)?;
76 # Ok(()) }
77 ```
78 
79 # Detecting presence of a terminal
80 
81 In many scenarios when using color, one often wants to enable colors
82 automatically when writing to a terminal and disable colors automatically when
83 writing to anything else. The typical way to achieve this in Unix environments
84 is via libc's
85 [`isatty`](https://man7.org/linux/man-pages/man3/isatty.3.html)
86 function.
87 Unfortunately, this notoriously does not work well in Windows environments. To
88 work around that, the currently recommended solution is to use the
89 [`atty`](https://crates.io/crates/atty)
90 crate, which goes out of its way to get this as right as possible in Windows
91 environments.
92 
93 For example, in a command line application that exposes a `--color` flag,
94 your logic for how to enable colors might look like this:
95 
96 ```rust,ignore
97 use atty;
98 use termcolor::{ColorChoice, StandardStream};
99 
100 let preference = argv.get_flag("color").unwrap_or("auto");
101 let mut choice = preference.parse::<ColorChoice>()?;
102 if choice == ColorChoice::Auto && !atty::is(atty::Stream::Stdout) {
103     choice = ColorChoice::Never;
104 }
105 let stdout = StandardStream::stdout(choice);
106 // ... write to stdout
107 ```
108 
109 Currently, `termcolor` does not provide anything to do this for you.
110 */
111 
112 #![deny(missing_debug_implementations, missing_docs)]
113 
114 // #[cfg(doctest)]
115 // use doc_comment::doctest;
116 // #[cfg(doctest)]
117 // doctest!("../README.md");
118 
119 use std::env;
120 use std::error;
121 use std::fmt;
122 use std::io::{self, Write};
123 use std::str::FromStr;
124 use std::sync::atomic::{AtomicBool, Ordering};
125 #[cfg(windows)]
126 use std::sync::{Mutex, MutexGuard};
127 
128 #[cfg(windows)]
129 use winapi_util::console as wincon;
130 
131 /// This trait describes the behavior of writers that support colored output.
132 pub trait WriteColor: io::Write {
133     /// Returns true if and only if the underlying writer supports colors.
supports_color(&self) -> bool134     fn supports_color(&self) -> bool;
135 
136     /// Set the color settings of the writer.
137     ///
138     /// Subsequent writes to this writer will use these settings until either
139     /// `reset` is called or new color settings are set.
140     ///
141     /// If there was a problem setting the color settings, then an error is
142     /// returned.
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>143     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()>;
144 
145     /// Reset the current color settings to their original settings.
146     ///
147     /// If there was a problem resetting the color settings, then an error is
148     /// returned.
reset(&mut self) -> io::Result<()>149     fn reset(&mut self) -> io::Result<()>;
150 
151     /// Returns true if and only if the underlying writer must synchronously
152     /// interact with an end user's device in order to control colors. By
153     /// default, this always returns `false`.
154     ///
155     /// In practice, this should return `true` if the underlying writer is
156     /// manipulating colors using the Windows console APIs.
157     ///
158     /// This is useful for writing generic code (such as a buffered writer)
159     /// that can perform certain optimizations when the underlying writer
160     /// doesn't rely on synchronous APIs. For example, ANSI escape sequences
161     /// can be passed through to the end user's device as is.
is_synchronous(&self) -> bool162     fn is_synchronous(&self) -> bool {
163         false
164     }
165 }
166 
167 impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T {
supports_color(&self) -> bool168     fn supports_color(&self) -> bool {
169         (&**self).supports_color()
170     }
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>171     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
172         (&mut **self).set_color(spec)
173     }
reset(&mut self) -> io::Result<()>174     fn reset(&mut self) -> io::Result<()> {
175         (&mut **self).reset()
176     }
is_synchronous(&self) -> bool177     fn is_synchronous(&self) -> bool {
178         (&**self).is_synchronous()
179     }
180 }
181 
182 impl<T: ?Sized + WriteColor> WriteColor for Box<T> {
supports_color(&self) -> bool183     fn supports_color(&self) -> bool {
184         (&**self).supports_color()
185     }
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>186     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
187         (&mut **self).set_color(spec)
188     }
reset(&mut self) -> io::Result<()>189     fn reset(&mut self) -> io::Result<()> {
190         (&mut **self).reset()
191     }
is_synchronous(&self) -> bool192     fn is_synchronous(&self) -> bool {
193         (&**self).is_synchronous()
194     }
195 }
196 
197 /// ColorChoice represents the color preferences of an end user.
198 ///
199 /// The `Default` implementation for this type will select `Auto`, which tries
200 /// to do the right thing based on the current environment.
201 ///
202 /// The `FromStr` implementation for this type converts a lowercase kebab-case
203 /// string of the variant name to the corresponding variant. Any other string
204 /// results in an error.
205 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
206 pub enum ColorChoice {
207     /// Try very hard to emit colors. This includes emitting ANSI colors
208     /// on Windows if the console API is unavailable.
209     Always,
210     /// AlwaysAnsi is like Always, except it never tries to use anything other
211     /// than emitting ANSI color codes.
212     AlwaysAnsi,
213     /// Try to use colors, but don't force the issue. If the console isn't
214     /// available on Windows, or if TERM=dumb, or if `NO_COLOR` is defined, for
215     /// example, then don't use colors.
216     Auto,
217     /// Never emit colors.
218     Never,
219 }
220 
221 /// The default is `Auto`.
222 impl Default for ColorChoice {
default() -> ColorChoice223     fn default() -> ColorChoice {
224         ColorChoice::Auto
225     }
226 }
227 
228 impl FromStr for ColorChoice {
229     type Err = ColorChoiceParseError;
230 
from_str(s: &str) -> Result<ColorChoice, ColorChoiceParseError>231     fn from_str(s: &str) -> Result<ColorChoice, ColorChoiceParseError> {
232         match s.to_lowercase().as_str() {
233             "always" => Ok(ColorChoice::Always),
234             "always-ansi" => Ok(ColorChoice::AlwaysAnsi),
235             "never" => Ok(ColorChoice::Never),
236             "auto" => Ok(ColorChoice::Auto),
237             unknown => Err(ColorChoiceParseError {
238                 unknown_choice: unknown.to_string(),
239             }),
240         }
241     }
242 }
243 
244 impl ColorChoice {
245     /// Returns true if we should attempt to write colored output.
should_attempt_color(&self) -> bool246     fn should_attempt_color(&self) -> bool {
247         match *self {
248             ColorChoice::Always => true,
249             ColorChoice::AlwaysAnsi => true,
250             ColorChoice::Never => false,
251             ColorChoice::Auto => self.env_allows_color(),
252         }
253     }
254 
255     #[cfg(not(windows))]
env_allows_color(&self) -> bool256     fn env_allows_color(&self) -> bool {
257         match env::var_os("TERM") {
258             // If TERM isn't set, then we are in a weird environment that
259             // probably doesn't support colors.
260             None => return false,
261             Some(k) => {
262                 if k == "dumb" {
263                     return false;
264                 }
265             }
266         }
267         // If TERM != dumb, then the only way we don't allow colors at this
268         // point is if NO_COLOR is set.
269         if env::var_os("NO_COLOR").is_some() {
270             return false;
271         }
272         true
273     }
274 
275     #[cfg(windows)]
env_allows_color(&self) -> bool276     fn env_allows_color(&self) -> bool {
277         // On Windows, if TERM isn't set, then we shouldn't automatically
278         // assume that colors aren't allowed. This is unlike Unix environments
279         // where TERM is more rigorously set.
280         if let Some(k) = env::var_os("TERM") {
281             if k == "dumb" {
282                 return false;
283             }
284         }
285         // If TERM != dumb, then the only way we don't allow colors at this
286         // point is if NO_COLOR is set.
287         if env::var_os("NO_COLOR").is_some() {
288             return false;
289         }
290         true
291     }
292 
293     /// Returns true if this choice should forcefully use ANSI color codes.
294     ///
295     /// It's possible that ANSI is still the correct choice even if this
296     /// returns false.
297     #[cfg(windows)]
should_ansi(&self) -> bool298     fn should_ansi(&self) -> bool {
299         match *self {
300             ColorChoice::Always => false,
301             ColorChoice::AlwaysAnsi => true,
302             ColorChoice::Never => false,
303             ColorChoice::Auto => {
304                 match env::var("TERM") {
305                     Err(_) => false,
306                     // cygwin doesn't seem to support ANSI escape sequences
307                     // and instead has its own variety. However, the Windows
308                     // console API may be available.
309                     Ok(k) => k != "dumb" && k != "cygwin",
310                 }
311             }
312         }
313     }
314 }
315 
316 /// An error that occurs when parsing a `ColorChoice` fails.
317 #[derive(Clone, Debug)]
318 pub struct ColorChoiceParseError {
319     unknown_choice: String,
320 }
321 
322 impl std::error::Error for ColorChoiceParseError {}
323 
324 impl fmt::Display for ColorChoiceParseError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result325     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
326         write!(
327             f,
328             "unrecognized color choice '{}': valid choices are: \
329              always, always-ansi, never, auto",
330             self.unknown_choice,
331         )
332     }
333 }
334 
335 /// `std::io` implements `Stdout` and `Stderr` (and their `Lock` variants) as
336 /// separate types, which makes it difficult to abstract over them. We use
337 /// some simple internal enum types to work around this.
338 
339 enum StandardStreamType {
340     Stdout,
341     Stderr,
342     StdoutBuffered,
343     StderrBuffered,
344 }
345 
346 #[derive(Debug)]
347 enum IoStandardStream {
348     Stdout(io::Stdout),
349     Stderr(io::Stderr),
350     StdoutBuffered(io::BufWriter<io::Stdout>),
351     StderrBuffered(io::BufWriter<io::Stderr>),
352 }
353 
354 impl IoStandardStream {
new(sty: StandardStreamType) -> IoStandardStream355     fn new(sty: StandardStreamType) -> IoStandardStream {
356         match sty {
357             StandardStreamType::Stdout => {
358                 IoStandardStream::Stdout(io::stdout())
359             }
360             StandardStreamType::Stderr => {
361                 IoStandardStream::Stderr(io::stderr())
362             }
363             StandardStreamType::StdoutBuffered => {
364                 let wtr = io::BufWriter::new(io::stdout());
365                 IoStandardStream::StdoutBuffered(wtr)
366             }
367             StandardStreamType::StderrBuffered => {
368                 let wtr = io::BufWriter::new(io::stderr());
369                 IoStandardStream::StderrBuffered(wtr)
370             }
371         }
372     }
373 
lock(&self) -> IoStandardStreamLock<'_>374     fn lock(&self) -> IoStandardStreamLock<'_> {
375         match *self {
376             IoStandardStream::Stdout(ref s) => {
377                 IoStandardStreamLock::StdoutLock(s.lock())
378             }
379             IoStandardStream::Stderr(ref s) => {
380                 IoStandardStreamLock::StderrLock(s.lock())
381             }
382             IoStandardStream::StdoutBuffered(_)
383             | IoStandardStream::StderrBuffered(_) => {
384                 // We don't permit this case to ever occur in the public API,
385                 // so it's OK to panic.
386                 panic!("cannot lock a buffered standard stream")
387             }
388         }
389     }
390 }
391 
392 impl io::Write for IoStandardStream {
393     #[inline(always)]
write(&mut self, b: &[u8]) -> io::Result<usize>394     fn write(&mut self, b: &[u8]) -> io::Result<usize> {
395         match *self {
396             IoStandardStream::Stdout(ref mut s) => s.write(b),
397             IoStandardStream::Stderr(ref mut s) => s.write(b),
398             IoStandardStream::StdoutBuffered(ref mut s) => s.write(b),
399             IoStandardStream::StderrBuffered(ref mut s) => s.write(b),
400         }
401     }
402 
403     #[inline(always)]
flush(&mut self) -> io::Result<()>404     fn flush(&mut self) -> io::Result<()> {
405         match *self {
406             IoStandardStream::Stdout(ref mut s) => s.flush(),
407             IoStandardStream::Stderr(ref mut s) => s.flush(),
408             IoStandardStream::StdoutBuffered(ref mut s) => s.flush(),
409             IoStandardStream::StderrBuffered(ref mut s) => s.flush(),
410         }
411     }
412 }
413 
414 // Same rigmarole for the locked variants of the standard streams.
415 
416 #[derive(Debug)]
417 enum IoStandardStreamLock<'a> {
418     StdoutLock(io::StdoutLock<'a>),
419     StderrLock(io::StderrLock<'a>),
420 }
421 
422 impl<'a> io::Write for IoStandardStreamLock<'a> {
423     #[inline(always)]
write(&mut self, b: &[u8]) -> io::Result<usize>424     fn write(&mut self, b: &[u8]) -> io::Result<usize> {
425         match *self {
426             IoStandardStreamLock::StdoutLock(ref mut s) => s.write(b),
427             IoStandardStreamLock::StderrLock(ref mut s) => s.write(b),
428         }
429     }
430 
431     #[inline(always)]
flush(&mut self) -> io::Result<()>432     fn flush(&mut self) -> io::Result<()> {
433         match *self {
434             IoStandardStreamLock::StdoutLock(ref mut s) => s.flush(),
435             IoStandardStreamLock::StderrLock(ref mut s) => s.flush(),
436         }
437     }
438 }
439 
440 /// Satisfies `io::Write` and `WriteColor`, and supports optional coloring
441 /// to either of the standard output streams, stdout and stderr.
442 #[derive(Debug)]
443 pub struct StandardStream {
444     wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
445 }
446 
447 /// `StandardStreamLock` is a locked reference to a `StandardStream`.
448 ///
449 /// This implements the `io::Write` and `WriteColor` traits, and is constructed
450 /// via the `Write::lock` method.
451 ///
452 /// The lifetime `'a` refers to the lifetime of the corresponding
453 /// `StandardStream`.
454 #[derive(Debug)]
455 pub struct StandardStreamLock<'a> {
456     wtr: LossyStandardStream<WriterInnerLock<'a, IoStandardStreamLock<'a>>>,
457 }
458 
459 /// Like `StandardStream`, but does buffered writing.
460 #[derive(Debug)]
461 pub struct BufferedStandardStream {
462     wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
463 }
464 
465 /// WriterInner is a (limited) generic representation of a writer. It is
466 /// limited because W should only ever be stdout/stderr on Windows.
467 #[derive(Debug)]
468 enum WriterInner<W> {
469     NoColor(NoColor<W>),
470     Ansi(Ansi<W>),
471     #[cfg(windows)]
472     Windows {
473         wtr: W,
474         console: Mutex<wincon::Console>,
475     },
476 }
477 
478 /// WriterInnerLock is a (limited) generic representation of a writer. It is
479 /// limited because W should only ever be stdout/stderr on Windows.
480 #[derive(Debug)]
481 enum WriterInnerLock<'a, W> {
482     NoColor(NoColor<W>),
483     Ansi(Ansi<W>),
484     /// What a gross hack. On Windows, we need to specify a lifetime for the
485     /// console when in a locked state, but obviously don't need to do that
486     /// on Unix, which makes the `'a` unused. To satisfy the compiler, we need
487     /// a PhantomData.
488     #[allow(dead_code)]
489     Unreachable(::std::marker::PhantomData<&'a ()>),
490     #[cfg(windows)]
491     Windows {
492         wtr: W,
493         console: MutexGuard<'a, wincon::Console>,
494     },
495 }
496 
497 impl StandardStream {
498     /// Create a new `StandardStream` with the given color preferences that
499     /// writes to standard output.
500     ///
501     /// On Windows, if coloring is desired and a Windows console could not be
502     /// found, then ANSI escape sequences are used instead.
503     ///
504     /// The specific color/style settings can be configured when writing via
505     /// the `WriteColor` trait.
stdout(choice: ColorChoice) -> StandardStream506     pub fn stdout(choice: ColorChoice) -> StandardStream {
507         let wtr = WriterInner::create(StandardStreamType::Stdout, choice);
508         StandardStream { wtr: LossyStandardStream::new(wtr) }
509     }
510 
511     /// Create a new `StandardStream` with the given color preferences that
512     /// writes to standard error.
513     ///
514     /// On Windows, if coloring is desired and a Windows console could not be
515     /// found, then ANSI escape sequences are used instead.
516     ///
517     /// The specific color/style settings can be configured when writing via
518     /// the `WriteColor` trait.
stderr(choice: ColorChoice) -> StandardStream519     pub fn stderr(choice: ColorChoice) -> StandardStream {
520         let wtr = WriterInner::create(StandardStreamType::Stderr, choice);
521         StandardStream { wtr: LossyStandardStream::new(wtr) }
522     }
523 
524     /// Lock the underlying writer.
525     ///
526     /// The lock guard returned also satisfies `io::Write` and
527     /// `WriteColor`.
528     ///
529     /// This method is **not reentrant**. It may panic if `lock` is called
530     /// while a `StandardStreamLock` is still alive.
lock(&self) -> StandardStreamLock<'_>531     pub fn lock(&self) -> StandardStreamLock<'_> {
532         StandardStreamLock::from_stream(self)
533     }
534 }
535 
536 impl<'a> StandardStreamLock<'a> {
537     #[cfg(not(windows))]
from_stream(stream: &StandardStream) -> StandardStreamLock<'_>538     fn from_stream(stream: &StandardStream) -> StandardStreamLock<'_> {
539         let locked = match *stream.wtr.get_ref() {
540             WriterInner::NoColor(ref w) => {
541                 WriterInnerLock::NoColor(NoColor(w.0.lock()))
542             }
543             WriterInner::Ansi(ref w) => {
544                 WriterInnerLock::Ansi(Ansi(w.0.lock()))
545             }
546         };
547         StandardStreamLock { wtr: stream.wtr.wrap(locked) }
548     }
549 
550     #[cfg(windows)]
from_stream(stream: &StandardStream) -> StandardStreamLock551     fn from_stream(stream: &StandardStream) -> StandardStreamLock {
552         let locked = match *stream.wtr.get_ref() {
553             WriterInner::NoColor(ref w) => {
554                 WriterInnerLock::NoColor(NoColor(w.0.lock()))
555             }
556             WriterInner::Ansi(ref w) => {
557                 WriterInnerLock::Ansi(Ansi(w.0.lock()))
558             }
559             #[cfg(windows)]
560             WriterInner::Windows { ref wtr, ref console } => {
561                 WriterInnerLock::Windows {
562                     wtr: wtr.lock(),
563                     console: console.lock().unwrap(),
564                 }
565             }
566         };
567         StandardStreamLock { wtr: stream.wtr.wrap(locked) }
568     }
569 }
570 
571 impl BufferedStandardStream {
572     /// Create a new `BufferedStandardStream` with the given color preferences
573     /// that writes to standard output via a buffered writer.
574     ///
575     /// On Windows, if coloring is desired and a Windows console could not be
576     /// found, then ANSI escape sequences are used instead.
577     ///
578     /// The specific color/style settings can be configured when writing via
579     /// the `WriteColor` trait.
stdout(choice: ColorChoice) -> BufferedStandardStream580     pub fn stdout(choice: ColorChoice) -> BufferedStandardStream {
581         let wtr =
582             WriterInner::create(StandardStreamType::StdoutBuffered, choice);
583         BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
584     }
585 
586     /// Create a new `BufferedStandardStream` with the given color preferences
587     /// that writes to standard error via a buffered writer.
588     ///
589     /// On Windows, if coloring is desired and a Windows console could not be
590     /// found, then ANSI escape sequences are used instead.
591     ///
592     /// The specific color/style settings can be configured when writing via
593     /// the `WriteColor` trait.
stderr(choice: ColorChoice) -> BufferedStandardStream594     pub fn stderr(choice: ColorChoice) -> BufferedStandardStream {
595         let wtr =
596             WriterInner::create(StandardStreamType::StderrBuffered, choice);
597         BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
598     }
599 }
600 
601 impl WriterInner<IoStandardStream> {
602     /// Create a new inner writer for a standard stream with the given color
603     /// preferences.
604     #[cfg(not(windows))]
create( sty: StandardStreamType, choice: ColorChoice, ) -> WriterInner<IoStandardStream>605     fn create(
606         sty: StandardStreamType,
607         choice: ColorChoice,
608     ) -> WriterInner<IoStandardStream> {
609         if choice.should_attempt_color() {
610             WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
611         } else {
612             WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
613         }
614     }
615 
616     /// Create a new inner writer for a standard stream with the given color
617     /// preferences.
618     ///
619     /// If coloring is desired and a Windows console could not be found, then
620     /// ANSI escape sequences are used instead.
621     #[cfg(windows)]
create( sty: StandardStreamType, choice: ColorChoice, ) -> WriterInner<IoStandardStream>622     fn create(
623         sty: StandardStreamType,
624         choice: ColorChoice,
625     ) -> WriterInner<IoStandardStream> {
626         let mut con = match sty {
627             StandardStreamType::Stdout => wincon::Console::stdout(),
628             StandardStreamType::Stderr => wincon::Console::stderr(),
629             StandardStreamType::StdoutBuffered => wincon::Console::stdout(),
630             StandardStreamType::StderrBuffered => wincon::Console::stderr(),
631         };
632         let is_console_virtual = con
633             .as_mut()
634             .map(|con| con.set_virtual_terminal_processing(true).is_ok())
635             .unwrap_or(false);
636         if choice.should_attempt_color() {
637             if choice.should_ansi() || is_console_virtual {
638                 WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
639             } else if let Ok(console) = con {
640                 WriterInner::Windows {
641                     wtr: IoStandardStream::new(sty),
642                     console: Mutex::new(console),
643                 }
644             } else {
645                 WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
646             }
647         } else {
648             WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
649         }
650     }
651 }
652 
653 impl io::Write for StandardStream {
654     #[inline]
write(&mut self, b: &[u8]) -> io::Result<usize>655     fn write(&mut self, b: &[u8]) -> io::Result<usize> {
656         self.wtr.write(b)
657     }
658 
659     #[inline]
flush(&mut self) -> io::Result<()>660     fn flush(&mut self) -> io::Result<()> {
661         self.wtr.flush()
662     }
663 }
664 
665 impl WriteColor for StandardStream {
666     #[inline]
supports_color(&self) -> bool667     fn supports_color(&self) -> bool {
668         self.wtr.supports_color()
669     }
670 
671     #[inline]
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>672     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
673         self.wtr.set_color(spec)
674     }
675 
676     #[inline]
reset(&mut self) -> io::Result<()>677     fn reset(&mut self) -> io::Result<()> {
678         self.wtr.reset()
679     }
680 
681     #[inline]
is_synchronous(&self) -> bool682     fn is_synchronous(&self) -> bool {
683         self.wtr.is_synchronous()
684     }
685 }
686 
687 impl<'a> io::Write for StandardStreamLock<'a> {
688     #[inline]
write(&mut self, b: &[u8]) -> io::Result<usize>689     fn write(&mut self, b: &[u8]) -> io::Result<usize> {
690         self.wtr.write(b)
691     }
692 
693     #[inline]
flush(&mut self) -> io::Result<()>694     fn flush(&mut self) -> io::Result<()> {
695         self.wtr.flush()
696     }
697 }
698 
699 impl<'a> WriteColor for StandardStreamLock<'a> {
700     #[inline]
supports_color(&self) -> bool701     fn supports_color(&self) -> bool {
702         self.wtr.supports_color()
703     }
704 
705     #[inline]
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>706     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
707         self.wtr.set_color(spec)
708     }
709 
710     #[inline]
reset(&mut self) -> io::Result<()>711     fn reset(&mut self) -> io::Result<()> {
712         self.wtr.reset()
713     }
714 
715     #[inline]
is_synchronous(&self) -> bool716     fn is_synchronous(&self) -> bool {
717         self.wtr.is_synchronous()
718     }
719 }
720 
721 impl io::Write for BufferedStandardStream {
722     #[inline]
write(&mut self, b: &[u8]) -> io::Result<usize>723     fn write(&mut self, b: &[u8]) -> io::Result<usize> {
724         self.wtr.write(b)
725     }
726 
727     #[inline]
flush(&mut self) -> io::Result<()>728     fn flush(&mut self) -> io::Result<()> {
729         self.wtr.flush()
730     }
731 }
732 
733 impl WriteColor for BufferedStandardStream {
734     #[inline]
supports_color(&self) -> bool735     fn supports_color(&self) -> bool {
736         self.wtr.supports_color()
737     }
738 
739     #[inline]
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>740     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
741         if self.is_synchronous() {
742             self.wtr.flush()?;
743         }
744         self.wtr.set_color(spec)
745     }
746 
747     #[inline]
reset(&mut self) -> io::Result<()>748     fn reset(&mut self) -> io::Result<()> {
749         self.wtr.reset()
750     }
751 
752     #[inline]
is_synchronous(&self) -> bool753     fn is_synchronous(&self) -> bool {
754         self.wtr.is_synchronous()
755     }
756 }
757 
758 impl<W: io::Write> io::Write for WriterInner<W> {
759     #[inline(always)]
write(&mut self, buf: &[u8]) -> io::Result<usize>760     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
761         match *self {
762             WriterInner::NoColor(ref mut wtr) => wtr.write(buf),
763             WriterInner::Ansi(ref mut wtr) => wtr.write(buf),
764             #[cfg(windows)]
765             WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf),
766         }
767     }
768 
769     #[inline(always)]
flush(&mut self) -> io::Result<()>770     fn flush(&mut self) -> io::Result<()> {
771         match *self {
772             WriterInner::NoColor(ref mut wtr) => wtr.flush(),
773             WriterInner::Ansi(ref mut wtr) => wtr.flush(),
774             #[cfg(windows)]
775             WriterInner::Windows { ref mut wtr, .. } => wtr.flush(),
776         }
777     }
778 }
779 
780 impl<W: io::Write> WriteColor for WriterInner<W> {
supports_color(&self) -> bool781     fn supports_color(&self) -> bool {
782         match *self {
783             WriterInner::NoColor(_) => false,
784             WriterInner::Ansi(_) => true,
785             #[cfg(windows)]
786             WriterInner::Windows { .. } => true,
787         }
788     }
789 
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>790     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
791         match *self {
792             WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
793             WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec),
794             #[cfg(windows)]
795             WriterInner::Windows { ref mut wtr, ref console } => {
796                 wtr.flush()?;
797                 let mut console = console.lock().unwrap();
798                 spec.write_console(&mut *console)
799             }
800         }
801     }
802 
reset(&mut self) -> io::Result<()>803     fn reset(&mut self) -> io::Result<()> {
804         match *self {
805             WriterInner::NoColor(ref mut wtr) => wtr.reset(),
806             WriterInner::Ansi(ref mut wtr) => wtr.reset(),
807             #[cfg(windows)]
808             WriterInner::Windows { ref mut wtr, ref mut console } => {
809                 wtr.flush()?;
810                 console.lock().unwrap().reset()?;
811                 Ok(())
812             }
813         }
814     }
815 
is_synchronous(&self) -> bool816     fn is_synchronous(&self) -> bool {
817         match *self {
818             WriterInner::NoColor(_) => false,
819             WriterInner::Ansi(_) => false,
820             #[cfg(windows)]
821             WriterInner::Windows { .. } => true,
822         }
823     }
824 }
825 
826 impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> {
write(&mut self, buf: &[u8]) -> io::Result<usize>827     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
828         match *self {
829             WriterInnerLock::Unreachable(_) => unreachable!(),
830             WriterInnerLock::NoColor(ref mut wtr) => wtr.write(buf),
831             WriterInnerLock::Ansi(ref mut wtr) => wtr.write(buf),
832             #[cfg(windows)]
833             WriterInnerLock::Windows { ref mut wtr, .. } => wtr.write(buf),
834         }
835     }
836 
flush(&mut self) -> io::Result<()>837     fn flush(&mut self) -> io::Result<()> {
838         match *self {
839             WriterInnerLock::Unreachable(_) => unreachable!(),
840             WriterInnerLock::NoColor(ref mut wtr) => wtr.flush(),
841             WriterInnerLock::Ansi(ref mut wtr) => wtr.flush(),
842             #[cfg(windows)]
843             WriterInnerLock::Windows { ref mut wtr, .. } => wtr.flush(),
844         }
845     }
846 }
847 
848 impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
supports_color(&self) -> bool849     fn supports_color(&self) -> bool {
850         match *self {
851             WriterInnerLock::Unreachable(_) => unreachable!(),
852             WriterInnerLock::NoColor(_) => false,
853             WriterInnerLock::Ansi(_) => true,
854             #[cfg(windows)]
855             WriterInnerLock::Windows { .. } => true,
856         }
857     }
858 
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>859     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
860         match *self {
861             WriterInnerLock::Unreachable(_) => unreachable!(),
862             WriterInnerLock::NoColor(ref mut wtr) => wtr.set_color(spec),
863             WriterInnerLock::Ansi(ref mut wtr) => wtr.set_color(spec),
864             #[cfg(windows)]
865             WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
866                 wtr.flush()?;
867                 spec.write_console(console)
868             }
869         }
870     }
871 
reset(&mut self) -> io::Result<()>872     fn reset(&mut self) -> io::Result<()> {
873         match *self {
874             WriterInnerLock::Unreachable(_) => unreachable!(),
875             WriterInnerLock::NoColor(ref mut wtr) => wtr.reset(),
876             WriterInnerLock::Ansi(ref mut wtr) => wtr.reset(),
877             #[cfg(windows)]
878             WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
879                 wtr.flush()?;
880                 console.reset()?;
881                 Ok(())
882             }
883         }
884     }
885 
is_synchronous(&self) -> bool886     fn is_synchronous(&self) -> bool {
887         match *self {
888             WriterInnerLock::Unreachable(_) => unreachable!(),
889             WriterInnerLock::NoColor(_) => false,
890             WriterInnerLock::Ansi(_) => false,
891             #[cfg(windows)]
892             WriterInnerLock::Windows { .. } => true,
893         }
894     }
895 }
896 
897 /// Writes colored buffers to stdout or stderr.
898 ///
899 /// Writable buffers can be obtained by calling `buffer` on a `BufferWriter`.
900 ///
901 /// This writer works with terminals that support ANSI escape sequences or
902 /// with a Windows console.
903 ///
904 /// It is intended for a `BufferWriter` to be put in an `Arc` and written to
905 /// from multiple threads simultaneously.
906 #[derive(Debug)]
907 pub struct BufferWriter {
908     stream: LossyStandardStream<IoStandardStream>,
909     printed: AtomicBool,
910     separator: Option<Vec<u8>>,
911     color_choice: ColorChoice,
912     #[cfg(windows)]
913     console: Option<Mutex<wincon::Console>>,
914 }
915 
916 impl BufferWriter {
917     /// Create a new `BufferWriter` that writes to a standard stream with the
918     /// given color preferences.
919     ///
920     /// The specific color/style settings can be configured when writing to
921     /// the buffers themselves.
922     #[cfg(not(windows))]
create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter923     fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
924         BufferWriter {
925             stream: LossyStandardStream::new(IoStandardStream::new(sty)),
926             printed: AtomicBool::new(false),
927             separator: None,
928             color_choice: choice,
929         }
930     }
931 
932     /// Create a new `BufferWriter` that writes to a standard stream with the
933     /// given color preferences.
934     ///
935     /// If coloring is desired and a Windows console could not be found, then
936     /// ANSI escape sequences are used instead.
937     ///
938     /// The specific color/style settings can be configured when writing to
939     /// the buffers themselves.
940     #[cfg(windows)]
create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter941     fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
942         let mut con = match sty {
943             StandardStreamType::Stdout => wincon::Console::stdout(),
944             StandardStreamType::Stderr => wincon::Console::stderr(),
945             StandardStreamType::StdoutBuffered => wincon::Console::stdout(),
946             StandardStreamType::StderrBuffered => wincon::Console::stderr(),
947         }
948         .ok();
949         let is_console_virtual = con
950             .as_mut()
951             .map(|con| con.set_virtual_terminal_processing(true).is_ok())
952             .unwrap_or(false);
953         // If we can enable ANSI on Windows, then we don't need the console
954         // anymore.
955         if is_console_virtual {
956             con = None;
957         }
958         let stream = LossyStandardStream::new(IoStandardStream::new(sty));
959         BufferWriter {
960             stream,
961             printed: AtomicBool::new(false),
962             separator: None,
963             color_choice: choice,
964             console: con.map(Mutex::new),
965         }
966     }
967 
968     /// Create a new `BufferWriter` that writes to stdout with the given
969     /// color preferences.
970     ///
971     /// On Windows, if coloring is desired and a Windows console could not be
972     /// found, then ANSI escape sequences are used instead.
973     ///
974     /// The specific color/style settings can be configured when writing to
975     /// the buffers themselves.
stdout(choice: ColorChoice) -> BufferWriter976     pub fn stdout(choice: ColorChoice) -> BufferWriter {
977         BufferWriter::create(StandardStreamType::Stdout, choice)
978     }
979 
980     /// Create a new `BufferWriter` that writes to stderr with the given
981     /// color preferences.
982     ///
983     /// On Windows, if coloring is desired and a Windows console could not be
984     /// found, then ANSI escape sequences are used instead.
985     ///
986     /// The specific color/style settings can be configured when writing to
987     /// the buffers themselves.
stderr(choice: ColorChoice) -> BufferWriter988     pub fn stderr(choice: ColorChoice) -> BufferWriter {
989         BufferWriter::create(StandardStreamType::Stderr, choice)
990     }
991 
992     /// If set, the separator given is printed between buffers. By default, no
993     /// separator is printed.
994     ///
995     /// The default value is `None`.
separator(&mut self, sep: Option<Vec<u8>>)996     pub fn separator(&mut self, sep: Option<Vec<u8>>) {
997         self.separator = sep;
998     }
999 
1000     /// Creates a new `Buffer` with the current color preferences.
1001     ///
1002     /// A `Buffer` satisfies both `io::Write` and `WriteColor`. A `Buffer` can
1003     /// be printed using the `print` method.
1004     #[cfg(not(windows))]
buffer(&self) -> Buffer1005     pub fn buffer(&self) -> Buffer {
1006         Buffer::new(self.color_choice)
1007     }
1008 
1009     /// Creates a new `Buffer` with the current color preferences.
1010     ///
1011     /// A `Buffer` satisfies both `io::Write` and `WriteColor`. A `Buffer` can
1012     /// be printed using the `print` method.
1013     #[cfg(windows)]
buffer(&self) -> Buffer1014     pub fn buffer(&self) -> Buffer {
1015         Buffer::new(self.color_choice, self.console.is_some())
1016     }
1017 
1018     /// Prints the contents of the given buffer.
1019     ///
1020     /// It is safe to call this from multiple threads simultaneously. In
1021     /// particular, all buffers are written atomically. No interleaving will
1022     /// occur.
print(&self, buf: &Buffer) -> io::Result<()>1023     pub fn print(&self, buf: &Buffer) -> io::Result<()> {
1024         if buf.is_empty() {
1025             return Ok(());
1026         }
1027         let mut stream = self.stream.wrap(self.stream.get_ref().lock());
1028         if let Some(ref sep) = self.separator {
1029             if self.printed.load(Ordering::SeqCst) {
1030                 stream.write_all(sep)?;
1031                 stream.write_all(b"\n")?;
1032             }
1033         }
1034         match buf.0 {
1035             BufferInner::NoColor(ref b) => stream.write_all(&b.0)?,
1036             BufferInner::Ansi(ref b) => stream.write_all(&b.0)?,
1037             #[cfg(windows)]
1038             BufferInner::Windows(ref b) => {
1039                 // We guarantee by construction that we have a console here.
1040                 // Namely, a BufferWriter is the only way to produce a Buffer.
1041                 let console_mutex = self
1042                     .console
1043                     .as_ref()
1044                     .expect("got Windows buffer but have no Console");
1045                 let mut console = console_mutex.lock().unwrap();
1046                 b.print(&mut *console, &mut stream)?;
1047             }
1048         }
1049         self.printed.store(true, Ordering::SeqCst);
1050         Ok(())
1051     }
1052 }
1053 
1054 /// Write colored text to memory.
1055 ///
1056 /// `Buffer` is a platform independent abstraction for printing colored text to
1057 /// an in memory buffer. When the buffer is printed using a `BufferWriter`, the
1058 /// color information will be applied to the output device (a tty on Unix and a
1059 /// console on Windows).
1060 ///
1061 /// A `Buffer` is typically created by calling the `BufferWriter.buffer`
1062 /// method, which will take color preferences and the environment into
1063 /// account. However, buffers can also be manually created using `no_color`,
1064 /// `ansi` or `console` (on Windows).
1065 #[derive(Debug)]
1066 pub struct Buffer(BufferInner);
1067 
1068 /// BufferInner is an enumeration of different buffer types.
1069 #[derive(Debug)]
1070 enum BufferInner {
1071     /// No coloring information should be applied. This ignores all coloring
1072     /// directives.
1073     NoColor(NoColor<Vec<u8>>),
1074     /// Apply coloring using ANSI escape sequences embedded into the buffer.
1075     Ansi(Ansi<Vec<u8>>),
1076     /// Apply coloring using the Windows console APIs. This buffer saves
1077     /// color information in memory and only interacts with the console when
1078     /// the buffer is printed.
1079     #[cfg(windows)]
1080     Windows(WindowsBuffer),
1081 }
1082 
1083 impl Buffer {
1084     /// Create a new buffer with the given color settings.
1085     #[cfg(not(windows))]
new(choice: ColorChoice) -> Buffer1086     fn new(choice: ColorChoice) -> Buffer {
1087         if choice.should_attempt_color() {
1088             Buffer::ansi()
1089         } else {
1090             Buffer::no_color()
1091         }
1092     }
1093 
1094     /// Create a new buffer with the given color settings.
1095     ///
1096     /// On Windows, one can elect to create a buffer capable of being written
1097     /// to a console. Only enable it if a console is available.
1098     ///
1099     /// If coloring is desired and `console` is false, then ANSI escape
1100     /// sequences are used instead.
1101     #[cfg(windows)]
new(choice: ColorChoice, console: bool) -> Buffer1102     fn new(choice: ColorChoice, console: bool) -> Buffer {
1103         if choice.should_attempt_color() {
1104             if !console || choice.should_ansi() {
1105                 Buffer::ansi()
1106             } else {
1107                 Buffer::console()
1108             }
1109         } else {
1110             Buffer::no_color()
1111         }
1112     }
1113 
1114     /// Create a buffer that drops all color information.
no_color() -> Buffer1115     pub fn no_color() -> Buffer {
1116         Buffer(BufferInner::NoColor(NoColor(vec![])))
1117     }
1118 
1119     /// Create a buffer that uses ANSI escape sequences.
ansi() -> Buffer1120     pub fn ansi() -> Buffer {
1121         Buffer(BufferInner::Ansi(Ansi(vec![])))
1122     }
1123 
1124     /// Create a buffer that can be written to a Windows console.
1125     #[cfg(windows)]
console() -> Buffer1126     pub fn console() -> Buffer {
1127         Buffer(BufferInner::Windows(WindowsBuffer::new()))
1128     }
1129 
1130     /// Returns true if and only if this buffer is empty.
is_empty(&self) -> bool1131     pub fn is_empty(&self) -> bool {
1132         self.len() == 0
1133     }
1134 
1135     /// Returns the length of this buffer in bytes.
len(&self) -> usize1136     pub fn len(&self) -> usize {
1137         match self.0 {
1138             BufferInner::NoColor(ref b) => b.0.len(),
1139             BufferInner::Ansi(ref b) => b.0.len(),
1140             #[cfg(windows)]
1141             BufferInner::Windows(ref b) => b.buf.len(),
1142         }
1143     }
1144 
1145     /// Clears this buffer.
clear(&mut self)1146     pub fn clear(&mut self) {
1147         match self.0 {
1148             BufferInner::NoColor(ref mut b) => b.0.clear(),
1149             BufferInner::Ansi(ref mut b) => b.0.clear(),
1150             #[cfg(windows)]
1151             BufferInner::Windows(ref mut b) => b.clear(),
1152         }
1153     }
1154 
1155     /// Consume this buffer and return the underlying raw data.
1156     ///
1157     /// On Windows, this unrecoverably drops all color information associated
1158     /// with the buffer.
into_inner(self) -> Vec<u8>1159     pub fn into_inner(self) -> Vec<u8> {
1160         match self.0 {
1161             BufferInner::NoColor(b) => b.0,
1162             BufferInner::Ansi(b) => b.0,
1163             #[cfg(windows)]
1164             BufferInner::Windows(b) => b.buf,
1165         }
1166     }
1167 
1168     /// Return the underlying data of the buffer.
as_slice(&self) -> &[u8]1169     pub fn as_slice(&self) -> &[u8] {
1170         match self.0 {
1171             BufferInner::NoColor(ref b) => &b.0,
1172             BufferInner::Ansi(ref b) => &b.0,
1173             #[cfg(windows)]
1174             BufferInner::Windows(ref b) => &b.buf,
1175         }
1176     }
1177 
1178     /// Return the underlying data of the buffer as a mutable slice.
as_mut_slice(&mut self) -> &mut [u8]1179     pub fn as_mut_slice(&mut self) -> &mut [u8] {
1180         match self.0 {
1181             BufferInner::NoColor(ref mut b) => &mut b.0,
1182             BufferInner::Ansi(ref mut b) => &mut b.0,
1183             #[cfg(windows)]
1184             BufferInner::Windows(ref mut b) => &mut b.buf,
1185         }
1186     }
1187 }
1188 
1189 impl io::Write for Buffer {
1190     #[inline]
write(&mut self, buf: &[u8]) -> io::Result<usize>1191     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1192         match self.0 {
1193             BufferInner::NoColor(ref mut w) => w.write(buf),
1194             BufferInner::Ansi(ref mut w) => w.write(buf),
1195             #[cfg(windows)]
1196             BufferInner::Windows(ref mut w) => w.write(buf),
1197         }
1198     }
1199 
1200     #[inline]
flush(&mut self) -> io::Result<()>1201     fn flush(&mut self) -> io::Result<()> {
1202         match self.0 {
1203             BufferInner::NoColor(ref mut w) => w.flush(),
1204             BufferInner::Ansi(ref mut w) => w.flush(),
1205             #[cfg(windows)]
1206             BufferInner::Windows(ref mut w) => w.flush(),
1207         }
1208     }
1209 }
1210 
1211 impl WriteColor for Buffer {
1212     #[inline]
supports_color(&self) -> bool1213     fn supports_color(&self) -> bool {
1214         match self.0 {
1215             BufferInner::NoColor(_) => false,
1216             BufferInner::Ansi(_) => true,
1217             #[cfg(windows)]
1218             BufferInner::Windows(_) => true,
1219         }
1220     }
1221 
1222     #[inline]
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>1223     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1224         match self.0 {
1225             BufferInner::NoColor(ref mut w) => w.set_color(spec),
1226             BufferInner::Ansi(ref mut w) => w.set_color(spec),
1227             #[cfg(windows)]
1228             BufferInner::Windows(ref mut w) => w.set_color(spec),
1229         }
1230     }
1231 
1232     #[inline]
reset(&mut self) -> io::Result<()>1233     fn reset(&mut self) -> io::Result<()> {
1234         match self.0 {
1235             BufferInner::NoColor(ref mut w) => w.reset(),
1236             BufferInner::Ansi(ref mut w) => w.reset(),
1237             #[cfg(windows)]
1238             BufferInner::Windows(ref mut w) => w.reset(),
1239         }
1240     }
1241 
1242     #[inline]
is_synchronous(&self) -> bool1243     fn is_synchronous(&self) -> bool {
1244         false
1245     }
1246 }
1247 
1248 /// Satisfies `WriteColor` but ignores all color options.
1249 #[derive(Debug)]
1250 pub struct NoColor<W>(W);
1251 
1252 impl<W: Write> NoColor<W> {
1253     /// Create a new writer that satisfies `WriteColor` but drops all color
1254     /// information.
new(wtr: W) -> NoColor<W>1255     pub fn new(wtr: W) -> NoColor<W> {
1256         NoColor(wtr)
1257     }
1258 
1259     /// Consume this `NoColor` value and return the inner writer.
into_inner(self) -> W1260     pub fn into_inner(self) -> W {
1261         self.0
1262     }
1263 
1264     /// Return a reference to the inner writer.
get_ref(&self) -> &W1265     pub fn get_ref(&self) -> &W {
1266         &self.0
1267     }
1268 
1269     /// Return a mutable reference to the inner writer.
get_mut(&mut self) -> &mut W1270     pub fn get_mut(&mut self) -> &mut W {
1271         &mut self.0
1272     }
1273 }
1274 
1275 impl<W: io::Write> io::Write for NoColor<W> {
1276     #[inline]
write(&mut self, buf: &[u8]) -> io::Result<usize>1277     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1278         self.0.write(buf)
1279     }
1280 
1281     #[inline]
flush(&mut self) -> io::Result<()>1282     fn flush(&mut self) -> io::Result<()> {
1283         self.0.flush()
1284     }
1285 }
1286 
1287 impl<W: io::Write> WriteColor for NoColor<W> {
1288     #[inline]
supports_color(&self) -> bool1289     fn supports_color(&self) -> bool {
1290         false
1291     }
1292 
1293     #[inline]
set_color(&mut self, _: &ColorSpec) -> io::Result<()>1294     fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
1295         Ok(())
1296     }
1297 
1298     #[inline]
reset(&mut self) -> io::Result<()>1299     fn reset(&mut self) -> io::Result<()> {
1300         Ok(())
1301     }
1302 
1303     #[inline]
is_synchronous(&self) -> bool1304     fn is_synchronous(&self) -> bool {
1305         false
1306     }
1307 }
1308 
1309 /// Satisfies `WriteColor` using standard ANSI escape sequences.
1310 #[derive(Debug)]
1311 pub struct Ansi<W>(W);
1312 
1313 impl<W: Write> Ansi<W> {
1314     /// Create a new writer that satisfies `WriteColor` using standard ANSI
1315     /// escape sequences.
new(wtr: W) -> Ansi<W>1316     pub fn new(wtr: W) -> Ansi<W> {
1317         Ansi(wtr)
1318     }
1319 
1320     /// Consume this `Ansi` value and return the inner writer.
into_inner(self) -> W1321     pub fn into_inner(self) -> W {
1322         self.0
1323     }
1324 
1325     /// Return a reference to the inner writer.
get_ref(&self) -> &W1326     pub fn get_ref(&self) -> &W {
1327         &self.0
1328     }
1329 
1330     /// Return a mutable reference to the inner writer.
get_mut(&mut self) -> &mut W1331     pub fn get_mut(&mut self) -> &mut W {
1332         &mut self.0
1333     }
1334 }
1335 
1336 impl<W: io::Write> io::Write for Ansi<W> {
1337     #[inline]
write(&mut self, buf: &[u8]) -> io::Result<usize>1338     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1339         self.0.write(buf)
1340     }
1341 
1342     // Adding this method here is not required because it has a default impl,
1343     // but it seems to provide a perf improvement in some cases when using
1344     // a `BufWriter` with lots of writes.
1345     //
1346     // See https://github.com/BurntSushi/termcolor/pull/56 for more details
1347     // and a minimized example.
1348     #[inline]
write_all(&mut self, buf: &[u8]) -> io::Result<()>1349     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1350         self.0.write_all(buf)
1351     }
1352 
1353     #[inline]
flush(&mut self) -> io::Result<()>1354     fn flush(&mut self) -> io::Result<()> {
1355         self.0.flush()
1356     }
1357 }
1358 
1359 impl<W: io::Write> WriteColor for Ansi<W> {
1360     #[inline]
supports_color(&self) -> bool1361     fn supports_color(&self) -> bool {
1362         true
1363     }
1364 
1365     #[inline]
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>1366     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1367         if spec.reset {
1368             self.reset()?;
1369         }
1370         if spec.bold {
1371             self.write_str("\x1B[1m")?;
1372         }
1373         if spec.dimmed {
1374             self.write_str("\x1B[2m")?;
1375         }
1376         if spec.italic {
1377             self.write_str("\x1B[3m")?;
1378         }
1379         if spec.underline {
1380             self.write_str("\x1B[4m")?;
1381         }
1382         if spec.strikethrough {
1383             self.write_str("\x1B[9m")?;
1384         }
1385         if let Some(ref c) = spec.fg_color {
1386             self.write_color(true, c, spec.intense)?;
1387         }
1388         if let Some(ref c) = spec.bg_color {
1389             self.write_color(false, c, spec.intense)?;
1390         }
1391         Ok(())
1392     }
1393 
1394     #[inline]
reset(&mut self) -> io::Result<()>1395     fn reset(&mut self) -> io::Result<()> {
1396         self.write_str("\x1B[0m")
1397     }
1398 
1399     #[inline]
is_synchronous(&self) -> bool1400     fn is_synchronous(&self) -> bool {
1401         false
1402     }
1403 }
1404 
1405 impl<W: io::Write> Ansi<W> {
write_str(&mut self, s: &str) -> io::Result<()>1406     fn write_str(&mut self, s: &str) -> io::Result<()> {
1407         self.write_all(s.as_bytes())
1408     }
1409 
write_color( &mut self, fg: bool, c: &Color, intense: bool, ) -> io::Result<()>1410     fn write_color(
1411         &mut self,
1412         fg: bool,
1413         c: &Color,
1414         intense: bool,
1415     ) -> io::Result<()> {
1416         macro_rules! write_intense {
1417             ($clr:expr) => {
1418                 if fg {
1419                     self.write_str(concat!("\x1B[38;5;", $clr, "m"))
1420                 } else {
1421                     self.write_str(concat!("\x1B[48;5;", $clr, "m"))
1422                 }
1423             };
1424         }
1425         macro_rules! write_normal {
1426             ($clr:expr) => {
1427                 if fg {
1428                     self.write_str(concat!("\x1B[3", $clr, "m"))
1429                 } else {
1430                     self.write_str(concat!("\x1B[4", $clr, "m"))
1431                 }
1432             };
1433         }
1434         macro_rules! write_var_ansi_code {
1435             ($pre:expr, $($code:expr),+) => {{
1436                 // The loop generates at worst a literal of the form
1437                 // '255,255,255m' which is 12-bytes.
1438                 // The largest `pre` expression we currently use is 7 bytes.
1439                 // This gives us the maximum of 19-bytes for our work buffer.
1440                 let pre_len = $pre.len();
1441                 assert!(pre_len <= 7);
1442                 let mut fmt = [0u8; 19];
1443                 fmt[..pre_len].copy_from_slice($pre);
1444                 let mut i = pre_len - 1;
1445                 $(
1446                     let c1: u8 = ($code / 100) % 10;
1447                     let c2: u8 = ($code / 10) % 10;
1448                     let c3: u8 = $code % 10;
1449                     let mut printed = false;
1450 
1451                     if c1 != 0 {
1452                         printed = true;
1453                         i += 1;
1454                         fmt[i] = b'0' + c1;
1455                     }
1456                     if c2 != 0 || printed {
1457                         i += 1;
1458                         fmt[i] = b'0' + c2;
1459                     }
1460                     // If we received a zero value we must still print a value.
1461                     i += 1;
1462                     fmt[i] = b'0' + c3;
1463                     i += 1;
1464                     fmt[i] = b';';
1465                 )+
1466 
1467                 fmt[i] = b'm';
1468                 self.write_all(&fmt[0..i+1])
1469             }}
1470         }
1471         macro_rules! write_custom {
1472             ($ansi256:expr) => {
1473                 if fg {
1474                     write_var_ansi_code!(b"\x1B[38;5;", $ansi256)
1475                 } else {
1476                     write_var_ansi_code!(b"\x1B[48;5;", $ansi256)
1477                 }
1478             };
1479 
1480             ($r:expr, $g:expr, $b:expr) => {{
1481                 if fg {
1482                     write_var_ansi_code!(b"\x1B[38;2;", $r, $g, $b)
1483                 } else {
1484                     write_var_ansi_code!(b"\x1B[48;2;", $r, $g, $b)
1485                 }
1486             }};
1487         }
1488         if intense {
1489             match *c {
1490                 Color::Black => write_intense!("8"),
1491                 Color::Blue => write_intense!("12"),
1492                 Color::Green => write_intense!("10"),
1493                 Color::Red => write_intense!("9"),
1494                 Color::Cyan => write_intense!("14"),
1495                 Color::Magenta => write_intense!("13"),
1496                 Color::Yellow => write_intense!("11"),
1497                 Color::White => write_intense!("15"),
1498                 Color::Ansi256(c) => write_custom!(c),
1499                 Color::Rgb(r, g, b) => write_custom!(r, g, b),
1500                 Color::__Nonexhaustive => unreachable!(),
1501             }
1502         } else {
1503             match *c {
1504                 Color::Black => write_normal!("0"),
1505                 Color::Blue => write_normal!("4"),
1506                 Color::Green => write_normal!("2"),
1507                 Color::Red => write_normal!("1"),
1508                 Color::Cyan => write_normal!("6"),
1509                 Color::Magenta => write_normal!("5"),
1510                 Color::Yellow => write_normal!("3"),
1511                 Color::White => write_normal!("7"),
1512                 Color::Ansi256(c) => write_custom!(c),
1513                 Color::Rgb(r, g, b) => write_custom!(r, g, b),
1514                 Color::__Nonexhaustive => unreachable!(),
1515             }
1516         }
1517     }
1518 }
1519 
1520 impl WriteColor for io::Sink {
supports_color(&self) -> bool1521     fn supports_color(&self) -> bool {
1522         false
1523     }
1524 
set_color(&mut self, _: &ColorSpec) -> io::Result<()>1525     fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
1526         Ok(())
1527     }
1528 
reset(&mut self) -> io::Result<()>1529     fn reset(&mut self) -> io::Result<()> {
1530         Ok(())
1531     }
1532 }
1533 
1534 /// An in-memory buffer that provides Windows console coloring.
1535 ///
1536 /// This doesn't actually communicate with the Windows console. Instead, it
1537 /// acts like a normal buffer but also saves the color information associated
1538 /// with positions in the buffer. It is only when the buffer is written to the
1539 /// console that coloring is actually applied.
1540 ///
1541 /// This is roughly isomorphic to the ANSI based approach (i.e.,
1542 /// `Ansi<Vec<u8>>`), except with ANSI, the color information is embedded
1543 /// directly into the buffer.
1544 ///
1545 /// Note that there is no way to write something generic like
1546 /// `WindowsConsole<W: io::Write>` since coloring on Windows is tied
1547 /// specifically to the console APIs, and therefore can't work on arbitrary
1548 /// writers.
1549 #[cfg(windows)]
1550 #[derive(Clone, Debug)]
1551 struct WindowsBuffer {
1552     /// The actual content that should be printed.
1553     buf: Vec<u8>,
1554     /// A sequence of position oriented color specifications. Namely, each
1555     /// element is a position and a color spec, where the color spec should
1556     /// be applied at the position inside of `buf`.
1557     ///
1558     /// A missing color spec implies the underlying console should be reset.
1559     colors: Vec<(usize, Option<ColorSpec>)>,
1560 }
1561 
1562 #[cfg(windows)]
1563 impl WindowsBuffer {
1564     /// Create a new empty buffer for Windows console coloring.
new() -> WindowsBuffer1565     fn new() -> WindowsBuffer {
1566         WindowsBuffer { buf: vec![], colors: vec![] }
1567     }
1568 
1569     /// Push the given color specification into this buffer.
1570     ///
1571     /// This has the effect of setting the given color information at the
1572     /// current position in the buffer.
push(&mut self, spec: Option<ColorSpec>)1573     fn push(&mut self, spec: Option<ColorSpec>) {
1574         let pos = self.buf.len();
1575         self.colors.push((pos, spec));
1576     }
1577 
1578     /// Print the contents to the given stream handle, and use the console
1579     /// for coloring.
print( &self, console: &mut wincon::Console, stream: &mut LossyStandardStream<IoStandardStreamLock>, ) -> io::Result<()>1580     fn print(
1581         &self,
1582         console: &mut wincon::Console,
1583         stream: &mut LossyStandardStream<IoStandardStreamLock>,
1584     ) -> io::Result<()> {
1585         let mut last = 0;
1586         for &(pos, ref spec) in &self.colors {
1587             stream.write_all(&self.buf[last..pos])?;
1588             stream.flush()?;
1589             last = pos;
1590             match *spec {
1591                 None => console.reset()?,
1592                 Some(ref spec) => spec.write_console(console)?,
1593             }
1594         }
1595         stream.write_all(&self.buf[last..])?;
1596         stream.flush()
1597     }
1598 
1599     /// Clear the buffer.
clear(&mut self)1600     fn clear(&mut self) {
1601         self.buf.clear();
1602         self.colors.clear();
1603     }
1604 }
1605 
1606 #[cfg(windows)]
1607 impl io::Write for WindowsBuffer {
1608     #[inline]
write(&mut self, buf: &[u8]) -> io::Result<usize>1609     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1610         self.buf.extend_from_slice(buf);
1611         Ok(buf.len())
1612     }
1613 
1614     #[inline]
flush(&mut self) -> io::Result<()>1615     fn flush(&mut self) -> io::Result<()> {
1616         Ok(())
1617     }
1618 }
1619 
1620 #[cfg(windows)]
1621 impl WriteColor for WindowsBuffer {
1622     #[inline]
supports_color(&self) -> bool1623     fn supports_color(&self) -> bool {
1624         true
1625     }
1626 
1627     #[inline]
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>1628     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1629         self.push(Some(spec.clone()));
1630         Ok(())
1631     }
1632 
1633     #[inline]
reset(&mut self) -> io::Result<()>1634     fn reset(&mut self) -> io::Result<()> {
1635         self.push(None);
1636         Ok(())
1637     }
1638 
1639     #[inline]
is_synchronous(&self) -> bool1640     fn is_synchronous(&self) -> bool {
1641         false
1642     }
1643 }
1644 
1645 /// A color specification.
1646 #[derive(Clone, Debug, Eq, PartialEq)]
1647 pub struct ColorSpec {
1648     fg_color: Option<Color>,
1649     bg_color: Option<Color>,
1650     bold: bool,
1651     intense: bool,
1652     underline: bool,
1653     dimmed: bool,
1654     italic: bool,
1655     reset: bool,
1656     strikethrough: bool,
1657 }
1658 
1659 impl Default for ColorSpec {
default() -> ColorSpec1660     fn default() -> ColorSpec {
1661         ColorSpec {
1662             fg_color: None,
1663             bg_color: None,
1664             bold: false,
1665             intense: false,
1666             underline: false,
1667             dimmed: false,
1668             italic: false,
1669             reset: true,
1670             strikethrough: false,
1671         }
1672     }
1673 }
1674 
1675 impl ColorSpec {
1676     /// Create a new color specification that has no colors or styles.
new() -> ColorSpec1677     pub fn new() -> ColorSpec {
1678         ColorSpec::default()
1679     }
1680 
1681     /// Get the foreground color.
fg(&self) -> Option<&Color>1682     pub fn fg(&self) -> Option<&Color> {
1683         self.fg_color.as_ref()
1684     }
1685 
1686     /// Set the foreground color.
set_fg(&mut self, color: Option<Color>) -> &mut ColorSpec1687     pub fn set_fg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1688         self.fg_color = color;
1689         self
1690     }
1691 
1692     /// Get the background color.
bg(&self) -> Option<&Color>1693     pub fn bg(&self) -> Option<&Color> {
1694         self.bg_color.as_ref()
1695     }
1696 
1697     /// Set the background color.
set_bg(&mut self, color: Option<Color>) -> &mut ColorSpec1698     pub fn set_bg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1699         self.bg_color = color;
1700         self
1701     }
1702 
1703     /// Get whether this is bold or not.
1704     ///
1705     /// Note that the bold setting has no effect in a Windows console.
bold(&self) -> bool1706     pub fn bold(&self) -> bool {
1707         self.bold
1708     }
1709 
1710     /// Set whether the text is bolded or not.
1711     ///
1712     /// Note that the bold setting has no effect in a Windows console.
set_bold(&mut self, yes: bool) -> &mut ColorSpec1713     pub fn set_bold(&mut self, yes: bool) -> &mut ColorSpec {
1714         self.bold = yes;
1715         self
1716     }
1717 
1718     /// Get whether this is dimmed or not.
1719     ///
1720     /// Note that the dimmed setting has no effect in a Windows console.
dimmed(&self) -> bool1721     pub fn dimmed(&self) -> bool {
1722         self.dimmed
1723     }
1724 
1725     /// Set whether the text is dimmed or not.
1726     ///
1727     /// Note that the dimmed setting has no effect in a Windows console.
set_dimmed(&mut self, yes: bool) -> &mut ColorSpec1728     pub fn set_dimmed(&mut self, yes: bool) -> &mut ColorSpec {
1729         self.dimmed = yes;
1730         self
1731     }
1732 
1733     /// Get whether this is italic or not.
1734     ///
1735     /// Note that the italic setting has no effect in a Windows console.
italic(&self) -> bool1736     pub fn italic(&self) -> bool {
1737         self.italic
1738     }
1739 
1740     /// Set whether the text is italicized or not.
1741     ///
1742     /// Note that the italic setting has no effect in a Windows console.
set_italic(&mut self, yes: bool) -> &mut ColorSpec1743     pub fn set_italic(&mut self, yes: bool) -> &mut ColorSpec {
1744         self.italic = yes;
1745         self
1746     }
1747 
1748     /// Get whether this is underline or not.
1749     ///
1750     /// Note that the underline setting has no effect in a Windows console.
underline(&self) -> bool1751     pub fn underline(&self) -> bool {
1752         self.underline
1753     }
1754 
1755     /// Set whether the text is underlined or not.
1756     ///
1757     /// Note that the underline setting has no effect in a Windows console.
set_underline(&mut self, yes: bool) -> &mut ColorSpec1758     pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec {
1759         self.underline = yes;
1760         self
1761     }
1762 
1763     /// Get whether this is strikethrough or not.
1764     ///
1765     /// Note that the strikethrough setting has no effect in a Windows console.
strikethrough(&self) -> bool1766     pub fn strikethrough(&self) -> bool {
1767         self.strikethrough
1768     }
1769 
1770     /// Set whether the text is strikethrough or not.
1771     ///
1772     /// Note that the strikethrough setting has no effect in a Windows console.
set_strikethrough(&mut self, yes: bool) -> &mut ColorSpec1773     pub fn set_strikethrough(&mut self, yes: bool) -> &mut ColorSpec {
1774         self.strikethrough = yes;
1775         self
1776     }
1777 
1778     /// Get whether reset is enabled or not.
1779     ///
1780     /// reset is enabled by default. When disabled and using ANSI escape
1781     /// sequences, a "reset" code will be emitted every time a `ColorSpec`'s
1782     /// settings are applied.
1783     ///
1784     /// Note that the reset setting has no effect in a Windows console.
reset(&self) -> bool1785     pub fn reset(&self) -> bool {
1786         self.reset
1787     }
1788 
1789     /// Set whether to reset the terminal whenever color settings are applied.
1790     ///
1791     /// reset is enabled by default. When disabled and using ANSI escape
1792     /// sequences, a "reset" code will be emitted every time a `ColorSpec`'s
1793     /// settings are applied.
1794     ///
1795     /// Typically this is useful if callers have a requirement to more
1796     /// scrupulously manage the exact sequence of escape codes that are emitted
1797     /// when using ANSI for colors.
1798     ///
1799     /// Note that the reset setting has no effect in a Windows console.
set_reset(&mut self, yes: bool) -> &mut ColorSpec1800     pub fn set_reset(&mut self, yes: bool) -> &mut ColorSpec {
1801         self.reset = yes;
1802         self
1803     }
1804 
1805     /// Get whether this is intense or not.
1806     ///
1807     /// On Unix-like systems, this will output the ANSI escape sequence
1808     /// that will print a high-intensity version of the color
1809     /// specified.
1810     ///
1811     /// On Windows systems, this will output the ANSI escape sequence
1812     /// that will print a brighter version of the color specified.
intense(&self) -> bool1813     pub fn intense(&self) -> bool {
1814         self.intense
1815     }
1816 
1817     /// Set whether the text is intense or not.
1818     ///
1819     /// On Unix-like systems, this will output the ANSI escape sequence
1820     /// that will print a high-intensity version of the color
1821     /// specified.
1822     ///
1823     /// On Windows systems, this will output the ANSI escape sequence
1824     /// that will print a brighter version of the color specified.
set_intense(&mut self, yes: bool) -> &mut ColorSpec1825     pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec {
1826         self.intense = yes;
1827         self
1828     }
1829 
1830     /// Returns true if this color specification has no colors or styles.
is_none(&self) -> bool1831     pub fn is_none(&self) -> bool {
1832         self.fg_color.is_none()
1833             && self.bg_color.is_none()
1834             && !self.bold
1835             && !self.underline
1836             && !self.dimmed
1837             && !self.italic
1838             && !self.intense
1839             && !self.strikethrough
1840     }
1841 
1842     /// Clears this color specification so that it has no color/style settings.
clear(&mut self)1843     pub fn clear(&mut self) {
1844         self.fg_color = None;
1845         self.bg_color = None;
1846         self.bold = false;
1847         self.underline = false;
1848         self.intense = false;
1849         self.dimmed = false;
1850         self.italic = false;
1851         self.strikethrough = false;
1852     }
1853 
1854     /// Writes this color spec to the given Windows console.
1855     #[cfg(windows)]
write_console(&self, console: &mut wincon::Console) -> io::Result<()>1856     fn write_console(&self, console: &mut wincon::Console) -> io::Result<()> {
1857         let fg_color = self.fg_color.and_then(|c| c.to_windows(self.intense));
1858         if let Some((intense, color)) = fg_color {
1859             console.fg(intense, color)?;
1860         }
1861         let bg_color = self.bg_color.and_then(|c| c.to_windows(self.intense));
1862         if let Some((intense, color)) = bg_color {
1863             console.bg(intense, color)?;
1864         }
1865         Ok(())
1866     }
1867 }
1868 
1869 /// The set of available colors for the terminal foreground/background.
1870 ///
1871 /// The `Ansi256` and `Rgb` colors will only output the correct codes when
1872 /// paired with the `Ansi` `WriteColor` implementation.
1873 ///
1874 /// The `Ansi256` and `Rgb` color types are not supported when writing colors
1875 /// on Windows using the console. If they are used on Windows, then they are
1876 /// silently ignored and no colors will be emitted.
1877 ///
1878 /// This set may expand over time.
1879 ///
1880 /// This type has a `FromStr` impl that can parse colors from their human
1881 /// readable form. The format is as follows:
1882 ///
1883 /// 1. Any of the explicitly listed colors in English. They are matched
1884 ///    case insensitively.
1885 /// 2. A single 8-bit integer, in either decimal or hexadecimal format.
1886 /// 3. A triple of 8-bit integers separated by a comma, where each integer is
1887 ///    in decimal or hexadecimal format.
1888 ///
1889 /// Hexadecimal numbers are written with a `0x` prefix.
1890 #[allow(missing_docs)]
1891 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1892 pub enum Color {
1893     Black,
1894     Blue,
1895     Green,
1896     Red,
1897     Cyan,
1898     Magenta,
1899     Yellow,
1900     White,
1901     Ansi256(u8),
1902     Rgb(u8, u8, u8),
1903     #[doc(hidden)]
1904     __Nonexhaustive,
1905 }
1906 
1907 impl Color {
1908     /// Translate this color to a wincon::Color.
1909     #[cfg(windows)]
to_windows( self, intense: bool, ) -> Option<(wincon::Intense, wincon::Color)>1910     fn to_windows(
1911         self,
1912         intense: bool,
1913     ) -> Option<(wincon::Intense, wincon::Color)> {
1914         use wincon::Intense::{No, Yes};
1915 
1916         let color = match self {
1917             Color::Black => wincon::Color::Black,
1918             Color::Blue => wincon::Color::Blue,
1919             Color::Green => wincon::Color::Green,
1920             Color::Red => wincon::Color::Red,
1921             Color::Cyan => wincon::Color::Cyan,
1922             Color::Magenta => wincon::Color::Magenta,
1923             Color::Yellow => wincon::Color::Yellow,
1924             Color::White => wincon::Color::White,
1925             Color::Ansi256(0) => return Some((No, wincon::Color::Black)),
1926             Color::Ansi256(1) => return Some((No, wincon::Color::Red)),
1927             Color::Ansi256(2) => return Some((No, wincon::Color::Green)),
1928             Color::Ansi256(3) => return Some((No, wincon::Color::Yellow)),
1929             Color::Ansi256(4) => return Some((No, wincon::Color::Blue)),
1930             Color::Ansi256(5) => return Some((No, wincon::Color::Magenta)),
1931             Color::Ansi256(6) => return Some((No, wincon::Color::Cyan)),
1932             Color::Ansi256(7) => return Some((No, wincon::Color::White)),
1933             Color::Ansi256(8) => return Some((Yes, wincon::Color::Black)),
1934             Color::Ansi256(9) => return Some((Yes, wincon::Color::Red)),
1935             Color::Ansi256(10) => return Some((Yes, wincon::Color::Green)),
1936             Color::Ansi256(11) => return Some((Yes, wincon::Color::Yellow)),
1937             Color::Ansi256(12) => return Some((Yes, wincon::Color::Blue)),
1938             Color::Ansi256(13) => return Some((Yes, wincon::Color::Magenta)),
1939             Color::Ansi256(14) => return Some((Yes, wincon::Color::Cyan)),
1940             Color::Ansi256(15) => return Some((Yes, wincon::Color::White)),
1941             Color::Ansi256(_) => return None,
1942             Color::Rgb(_, _, _) => return None,
1943             Color::__Nonexhaustive => unreachable!(),
1944         };
1945         let intense = if intense { Yes } else { No };
1946         Some((intense, color))
1947     }
1948 
1949     /// Parses a numeric color string, either ANSI or RGB.
from_str_numeric(s: &str) -> Result<Color, ParseColorError>1950     fn from_str_numeric(s: &str) -> Result<Color, ParseColorError> {
1951         // The "ansi256" format is a single number (decimal or hex)
1952         // corresponding to one of 256 colors.
1953         //
1954         // The "rgb" format is a triple of numbers (decimal or hex) delimited
1955         // by a comma corresponding to one of 256^3 colors.
1956 
1957         fn parse_number(s: &str) -> Option<u8> {
1958             use std::u8;
1959 
1960             if s.starts_with("0x") {
1961                 u8::from_str_radix(&s[2..], 16).ok()
1962             } else {
1963                 u8::from_str_radix(s, 10).ok()
1964             }
1965         }
1966 
1967         let codes: Vec<&str> = s.split(',').collect();
1968         if codes.len() == 1 {
1969             if let Some(n) = parse_number(&codes[0]) {
1970                 Ok(Color::Ansi256(n))
1971             } else {
1972                 if s.chars().all(|c| c.is_digit(16)) {
1973                     Err(ParseColorError {
1974                         kind: ParseColorErrorKind::InvalidAnsi256,
1975                         given: s.to_string(),
1976                     })
1977                 } else {
1978                     Err(ParseColorError {
1979                         kind: ParseColorErrorKind::InvalidName,
1980                         given: s.to_string(),
1981                     })
1982                 }
1983             }
1984         } else if codes.len() == 3 {
1985             let mut v = vec![];
1986             for code in codes {
1987                 let n = parse_number(code).ok_or_else(|| ParseColorError {
1988                     kind: ParseColorErrorKind::InvalidRgb,
1989                     given: s.to_string(),
1990                 })?;
1991                 v.push(n);
1992             }
1993             Ok(Color::Rgb(v[0], v[1], v[2]))
1994         } else {
1995             Err(if s.contains(",") {
1996                 ParseColorError {
1997                     kind: ParseColorErrorKind::InvalidRgb,
1998                     given: s.to_string(),
1999                 }
2000             } else {
2001                 ParseColorError {
2002                     kind: ParseColorErrorKind::InvalidName,
2003                     given: s.to_string(),
2004                 }
2005             })
2006         }
2007     }
2008 }
2009 
2010 /// An error from parsing an invalid color specification.
2011 #[derive(Clone, Debug, Eq, PartialEq)]
2012 pub struct ParseColorError {
2013     kind: ParseColorErrorKind,
2014     given: String,
2015 }
2016 
2017 #[derive(Clone, Debug, Eq, PartialEq)]
2018 enum ParseColorErrorKind {
2019     InvalidName,
2020     InvalidAnsi256,
2021     InvalidRgb,
2022 }
2023 
2024 impl ParseColorError {
2025     /// Return the string that couldn't be parsed as a valid color.
invalid(&self) -> &str2026     pub fn invalid(&self) -> &str {
2027         &self.given
2028     }
2029 }
2030 
2031 impl error::Error for ParseColorError {
description(&self) -> &str2032     fn description(&self) -> &str {
2033         use self::ParseColorErrorKind::*;
2034         match self.kind {
2035             InvalidName => "unrecognized color name",
2036             InvalidAnsi256 => "invalid ansi256 color number",
2037             InvalidRgb => "invalid RGB color triple",
2038         }
2039     }
2040 }
2041 
2042 impl fmt::Display for ParseColorError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2043     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2044         use self::ParseColorErrorKind::*;
2045         match self.kind {
2046             InvalidName => write!(
2047                 f,
2048                 "unrecognized color name '{}'. Choose from: \
2049                  black, blue, green, red, cyan, magenta, yellow, \
2050                  white",
2051                 self.given
2052             ),
2053             InvalidAnsi256 => write!(
2054                 f,
2055                 "unrecognized ansi256 color number, \
2056                  should be '[0-255]' (or a hex number), but is '{}'",
2057                 self.given
2058             ),
2059             InvalidRgb => write!(
2060                 f,
2061                 "unrecognized RGB color triple, \
2062                  should be '[0-255],[0-255],[0-255]' (or a hex \
2063                  triple), but is '{}'",
2064                 self.given
2065             ),
2066         }
2067     }
2068 }
2069 
2070 impl FromStr for Color {
2071     type Err = ParseColorError;
2072 
from_str(s: &str) -> Result<Color, ParseColorError>2073     fn from_str(s: &str) -> Result<Color, ParseColorError> {
2074         match &*s.to_lowercase() {
2075             "black" => Ok(Color::Black),
2076             "blue" => Ok(Color::Blue),
2077             "green" => Ok(Color::Green),
2078             "red" => Ok(Color::Red),
2079             "cyan" => Ok(Color::Cyan),
2080             "magenta" => Ok(Color::Magenta),
2081             "yellow" => Ok(Color::Yellow),
2082             "white" => Ok(Color::White),
2083             _ => Color::from_str_numeric(s),
2084         }
2085     }
2086 }
2087 
2088 #[derive(Debug)]
2089 struct LossyStandardStream<W> {
2090     wtr: W,
2091     #[cfg(windows)]
2092     is_console: bool,
2093 }
2094 
2095 impl<W: io::Write> LossyStandardStream<W> {
2096     #[cfg(not(windows))]
new(wtr: W) -> LossyStandardStream<W>2097     fn new(wtr: W) -> LossyStandardStream<W> {
2098         LossyStandardStream { wtr }
2099     }
2100 
2101     #[cfg(windows)]
new(wtr: W) -> LossyStandardStream<W>2102     fn new(wtr: W) -> LossyStandardStream<W> {
2103         let is_console = wincon::Console::stdout().is_ok()
2104             || wincon::Console::stderr().is_ok();
2105         LossyStandardStream { wtr, is_console }
2106     }
2107 
2108     #[cfg(not(windows))]
wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q>2109     fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2110         LossyStandardStream::new(wtr)
2111     }
2112 
2113     #[cfg(windows)]
wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q>2114     fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2115         LossyStandardStream { wtr, is_console: self.is_console }
2116     }
2117 
get_ref(&self) -> &W2118     fn get_ref(&self) -> &W {
2119         &self.wtr
2120     }
2121 }
2122 
2123 impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
supports_color(&self) -> bool2124     fn supports_color(&self) -> bool {
2125         self.wtr.supports_color()
2126     }
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>2127     fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
2128         self.wtr.set_color(spec)
2129     }
reset(&mut self) -> io::Result<()>2130     fn reset(&mut self) -> io::Result<()> {
2131         self.wtr.reset()
2132     }
is_synchronous(&self) -> bool2133     fn is_synchronous(&self) -> bool {
2134         self.wtr.is_synchronous()
2135     }
2136 }
2137 
2138 impl<W: io::Write> io::Write for LossyStandardStream<W> {
2139     #[cfg(not(windows))]
write(&mut self, buf: &[u8]) -> io::Result<usize>2140     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2141         self.wtr.write(buf)
2142     }
2143 
2144     #[cfg(windows)]
write(&mut self, buf: &[u8]) -> io::Result<usize>2145     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2146         if self.is_console {
2147             write_lossy_utf8(&mut self.wtr, buf)
2148         } else {
2149             self.wtr.write(buf)
2150         }
2151     }
2152 
flush(&mut self) -> io::Result<()>2153     fn flush(&mut self) -> io::Result<()> {
2154         self.wtr.flush()
2155     }
2156 }
2157 
2158 #[cfg(windows)]
write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize>2159 fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
2160     match ::std::str::from_utf8(buf) {
2161         Ok(s) => w.write(s.as_bytes()),
2162         Err(ref e) if e.valid_up_to() == 0 => {
2163             w.write(b"\xEF\xBF\xBD")?;
2164             Ok(1)
2165         }
2166         Err(e) => w.write(&buf[..e.valid_up_to()]),
2167     }
2168 }
2169 
2170 #[cfg(test)]
2171 mod tests {
2172     use super::{
2173         Ansi, Color, ColorSpec, ParseColorError, ParseColorErrorKind,
2174         StandardStream, WriteColor,
2175     };
2176 
assert_is_send<T: Send>()2177     fn assert_is_send<T: Send>() {}
2178 
2179     #[test]
standard_stream_is_send()2180     fn standard_stream_is_send() {
2181         assert_is_send::<StandardStream>();
2182     }
2183 
2184     #[test]
test_simple_parse_ok()2185     fn test_simple_parse_ok() {
2186         let color = "green".parse::<Color>();
2187         assert_eq!(color, Ok(Color::Green));
2188     }
2189 
2190     #[test]
test_256_parse_ok()2191     fn test_256_parse_ok() {
2192         let color = "7".parse::<Color>();
2193         assert_eq!(color, Ok(Color::Ansi256(7)));
2194 
2195         let color = "32".parse::<Color>();
2196         assert_eq!(color, Ok(Color::Ansi256(32)));
2197 
2198         let color = "0xFF".parse::<Color>();
2199         assert_eq!(color, Ok(Color::Ansi256(0xFF)));
2200     }
2201 
2202     #[test]
test_256_parse_err_out_of_range()2203     fn test_256_parse_err_out_of_range() {
2204         let color = "256".parse::<Color>();
2205         assert_eq!(
2206             color,
2207             Err(ParseColorError {
2208                 kind: ParseColorErrorKind::InvalidAnsi256,
2209                 given: "256".to_string(),
2210             })
2211         );
2212     }
2213 
2214     #[test]
test_rgb_parse_ok()2215     fn test_rgb_parse_ok() {
2216         let color = "0,0,0".parse::<Color>();
2217         assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2218 
2219         let color = "0,128,255".parse::<Color>();
2220         assert_eq!(color, Ok(Color::Rgb(0, 128, 255)));
2221 
2222         let color = "0x0,0x0,0x0".parse::<Color>();
2223         assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2224 
2225         let color = "0x33,0x66,0xFF".parse::<Color>();
2226         assert_eq!(color, Ok(Color::Rgb(0x33, 0x66, 0xFF)));
2227     }
2228 
2229     #[test]
test_rgb_parse_err_out_of_range()2230     fn test_rgb_parse_err_out_of_range() {
2231         let color = "0,0,256".parse::<Color>();
2232         assert_eq!(
2233             color,
2234             Err(ParseColorError {
2235                 kind: ParseColorErrorKind::InvalidRgb,
2236                 given: "0,0,256".to_string(),
2237             })
2238         );
2239     }
2240 
2241     #[test]
test_rgb_parse_err_bad_format()2242     fn test_rgb_parse_err_bad_format() {
2243         let color = "0,0".parse::<Color>();
2244         assert_eq!(
2245             color,
2246             Err(ParseColorError {
2247                 kind: ParseColorErrorKind::InvalidRgb,
2248                 given: "0,0".to_string(),
2249             })
2250         );
2251 
2252         let color = "not_a_color".parse::<Color>();
2253         assert_eq!(
2254             color,
2255             Err(ParseColorError {
2256                 kind: ParseColorErrorKind::InvalidName,
2257                 given: "not_a_color".to_string(),
2258             })
2259         );
2260     }
2261 
2262     #[test]
test_var_ansi_write_rgb()2263     fn test_var_ansi_write_rgb() {
2264         let mut buf = Ansi::new(vec![]);
2265         let _ = buf.write_color(true, &Color::Rgb(254, 253, 255), false);
2266         assert_eq!(buf.0, b"\x1B[38;2;254;253;255m");
2267     }
2268 
2269     #[test]
test_reset()2270     fn test_reset() {
2271         let spec = ColorSpec::new();
2272         let mut buf = Ansi::new(vec![]);
2273         buf.set_color(&spec).unwrap();
2274         assert_eq!(buf.0, b"\x1B[0m");
2275     }
2276 
2277     #[test]
test_no_reset()2278     fn test_no_reset() {
2279         let mut spec = ColorSpec::new();
2280         spec.set_reset(false);
2281 
2282         let mut buf = Ansi::new(vec![]);
2283         buf.set_color(&spec).unwrap();
2284         assert_eq!(buf.0, b"");
2285     }
2286 
2287     #[test]
test_var_ansi_write_256()2288     fn test_var_ansi_write_256() {
2289         let mut buf = Ansi::new(vec![]);
2290         let _ = buf.write_color(false, &Color::Ansi256(7), false);
2291         assert_eq!(buf.0, b"\x1B[48;5;7m");
2292 
2293         let mut buf = Ansi::new(vec![]);
2294         let _ = buf.write_color(false, &Color::Ansi256(208), false);
2295         assert_eq!(buf.0, b"\x1B[48;5;208m");
2296     }
2297 
all_attributes() -> Vec<ColorSpec>2298     fn all_attributes() -> Vec<ColorSpec> {
2299         let mut result = vec![];
2300         for fg in vec![None, Some(Color::Red)] {
2301             for bg in vec![None, Some(Color::Red)] {
2302                 for bold in vec![false, true] {
2303                     for underline in vec![false, true] {
2304                         for intense in vec![false, true] {
2305                             for italic in vec![false, true] {
2306                                 for strikethrough in vec![false, true] {
2307                                     for dimmed in vec![false, true] {
2308                                         let mut color = ColorSpec::new();
2309                                         color.set_fg(fg);
2310                                         color.set_bg(bg);
2311                                         color.set_bold(bold);
2312                                         color.set_underline(underline);
2313                                         color.set_intense(intense);
2314                                         color.set_italic(italic);
2315                                         color.set_dimmed(dimmed);
2316                                         color.set_strikethrough(strikethrough);
2317                                         result.push(color);
2318                                     }
2319                                 }
2320                             }
2321                         }
2322                     }
2323                 }
2324             }
2325         }
2326         result
2327     }
2328 
2329     #[test]
test_is_none()2330     fn test_is_none() {
2331         for (i, color) in all_attributes().iter().enumerate() {
2332             assert_eq!(
2333                 i == 0,
2334                 color.is_none(),
2335                 "{:?} => {}",
2336                 color,
2337                 color.is_none()
2338             )
2339         }
2340     }
2341 
2342     #[test]
test_clear()2343     fn test_clear() {
2344         for color in all_attributes() {
2345             let mut color1 = color.clone();
2346             color1.clear();
2347             assert!(color1.is_none(), "{:?} => {:?}", color, color1);
2348         }
2349     }
2350 }
2351