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