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