termcolor/
lib.rs

1/*!
2This crate provides a cross platform abstraction for writing colored text to
3a terminal. Colors are written using either ANSI escape sequences or by
4communicating with a Windows console. Much of this API was motivated by use
5inside command line applications, where colors or styles can be configured
6by the end user and/or the environment.
7
8This crate also provides platform independent support for writing colored text
9to 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
11Windows console API, which requires synchronous communication.
12
13# Organization
14
15The `WriteColor` trait extends the `io::Write` trait with methods for setting
16colors or resetting them.
17
18`StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are
19analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr`
20and `std::io::StderrLock`.
21
22`Buffer` is an in memory buffer that supports colored text. In a parallel
23program, each thread might write to its own buffer. A buffer can be printed to
24using a `BufferWriter`. The advantage of this design is that each thread can
25work in parallel on a buffer without having to synchronize access to global
26resources such as the Windows console. Moreover, this design also prevents
27interleaving 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
31analogous type for the Windows console is not provided since it cannot exist.
32
33# Example: using `StandardStream`
34
35The `StandardStream` type in this crate works similarly to `std::io::Stdout`,
36except it is augmented with methods for coloring by the `WriteColor` trait.
37For example, to write some green text:
38
39```rust,no_run
40# fn test() -> Result<(), Box<::std::error::Error>> {
41use std::io::Write;
42use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
43
44let mut stdout = StandardStream::stdout(ColorChoice::Always);
45stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
46writeln!(&mut stdout, "green text!")?;
47# Ok(()) }
48```
49
50Note that any text written to the terminal now will be colored
51green when using ANSI escape sequences, even if it is written via
52stderr, and even if stderr had previously been set to `Color::Red`.
53Users will need to manage any color changes themselves by calling
54[`WriteColor::set_color`](trait.WriteColor.html#tymethod.set_color), and this
55may include calling [`WriteColor::reset`](trait.WriteColor.html#tymethod.reset)
56before the program exits to a shell.
57
58# Example: using `BufferWriter`
59
60A `BufferWriter` can create buffers and write buffers to stdout or stderr. It
61does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer`
62implements `io::Write` and `io::WriteColor`.
63
64This example shows how to print some green text to stderr.
65
66```rust,no_run
67# fn test() -> Result<(), Box<::std::error::Error>> {
68use std::io::Write;
69use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
70
71let mut bufwtr = BufferWriter::stderr(ColorChoice::Always);
72let mut buffer = bufwtr.buffer();
73buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
74writeln!(&mut buffer, "green text!")?;
75bufwtr.print(&buffer)?;
76# Ok(()) }
77```
78
79# Detecting presence of a terminal
80
81In many scenarios when using color, one often wants to enable colors
82automatically when writing to a terminal and disable colors automatically when
83writing to anything else. The typical way to achieve this in Unix environments
84is via libc's
85[`isatty`](https://man7.org/linux/man-pages/man3/isatty.3.html)
86function.
87Unfortunately, this notoriously does not work well in Windows environments. To
88work around that, the currently recommended solution is to use the
89[`atty`](https://crates.io/crates/atty)
90crate, which goes out of its way to get this as right as possible in Windows
91environments.
92
93For example, in a command line application that exposes a `--color` flag,
94your logic for how to enable colors might look like this:
95
96```rust,ignore
97use atty;
98use termcolor::{ColorChoice, StandardStream};
99
100let preference = argv.get_flag("color").unwrap_or("auto");
101let 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};
113let stdout = StandardStream::stdout(choice);
114// ... write to stdout
115```
116
117Currently, `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
127use std::env;
128use std::error;
129use std::fmt;
130use std::io::{self, Write};
131use std::str::FromStr;
132use std::sync::atomic::{AtomicBool, Ordering};
133#[cfg(windows)]
134use std::sync::{Mutex, MutexGuard};
135
136#[cfg(windows)]
137use winapi_util::console as wincon;
138
139/// This trait describes the behavior of writers that support colored output.
140pub trait WriteColor: io::Write {
141    /// Returns true if and only if the underlying writer supports colors.
142    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.
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.
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.
170    fn is_synchronous(&self) -> bool {
171        false
172    }
173}
174
175impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T {
176    fn supports_color(&self) -> bool {
177        (&**self).supports_color()
178    }
179    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
180        (&mut **self).set_color(spec)
181    }
182    fn reset(&mut self) -> io::Result<()> {
183        (&mut **self).reset()
184    }
185    fn is_synchronous(&self) -> bool {
186        (&**self).is_synchronous()
187    }
188}
189
190impl<T: ?Sized + WriteColor> WriteColor for Box<T> {
191    fn supports_color(&self) -> bool {
192        (&**self).supports_color()
193    }
194    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
195        (&mut **self).set_color(spec)
196    }
197    fn reset(&mut self) -> io::Result<()> {
198        (&mut **self).reset()
199    }
200    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)]
207pub 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
222impl ColorChoice {
223    /// Returns true if we should attempt to write colored output.
224    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))]
234    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)]
254    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)]
276    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
298enum StandardStreamType {
299    Stdout,
300    Stderr,
301    StdoutBuffered,
302    StderrBuffered,
303}
304
305enum IoStandardStream {
306    Stdout(io::Stdout),
307    Stderr(io::Stderr),
308    StdoutBuffered(io::BufWriter<io::Stdout>),
309    StderrBuffered(io::BufWriter<io::Stderr>),
310}
311
312impl IoStandardStream {
313    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
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
350impl io::Write for IoStandardStream {
351    #[inline(always)]
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)]
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
374enum IoStandardStreamLock<'a> {
375    StdoutLock(io::StdoutLock<'a>),
376    StderrLock(io::StderrLock<'a>),
377}
378
379impl<'a> io::Write for IoStandardStreamLock<'a> {
380    #[inline(always)]
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)]
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.
399pub 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`.
410pub struct StandardStreamLock<'a> {
411    wtr: LossyStandardStream<WriterInnerLock<'a, IoStandardStreamLock<'a>>>,
412}
413
414/// Like `StandardStream`, but does buffered writing.
415pub 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.
421enum 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.
433enum 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
449impl 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.
458    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.
471    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.
483    pub fn lock(&self) -> StandardStreamLock<'_> {
484        StandardStreamLock::from_stream(self)
485    }
486}
487
488impl<'a> StandardStreamLock<'a> {
489    #[cfg(not(windows))]
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)]
503    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
523impl 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.
532    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.
546    pub fn stderr(choice: ColorChoice) -> BufferedStandardStream {
547        let wtr =
548            WriterInner::create(StandardStreamType::StderrBuffered, choice);
549        BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
550    }
551}
552
553impl WriterInner<IoStandardStream> {
554    /// Create a new inner writer for a standard stream with the given color
555    /// preferences.
556    #[cfg(not(windows))]
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)]
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
605impl io::Write for StandardStream {
606    #[inline]
607    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
608        self.wtr.write(b)
609    }
610
611    #[inline]
612    fn flush(&mut self) -> io::Result<()> {
613        self.wtr.flush()
614    }
615}
616
617impl WriteColor for StandardStream {
618    #[inline]
619    fn supports_color(&self) -> bool {
620        self.wtr.supports_color()
621    }
622
623    #[inline]
624    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
625        self.wtr.set_color(spec)
626    }
627
628    #[inline]
629    fn reset(&mut self) -> io::Result<()> {
630        self.wtr.reset()
631    }
632
633    #[inline]
634    fn is_synchronous(&self) -> bool {
635        self.wtr.is_synchronous()
636    }
637}
638
639impl<'a> io::Write for StandardStreamLock<'a> {
640    #[inline]
641    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
642        self.wtr.write(b)
643    }
644
645    #[inline]
646    fn flush(&mut self) -> io::Result<()> {
647        self.wtr.flush()
648    }
649}
650
651impl<'a> WriteColor for StandardStreamLock<'a> {
652    #[inline]
653    fn supports_color(&self) -> bool {
654        self.wtr.supports_color()
655    }
656
657    #[inline]
658    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
659        self.wtr.set_color(spec)
660    }
661
662    #[inline]
663    fn reset(&mut self) -> io::Result<()> {
664        self.wtr.reset()
665    }
666
667    #[inline]
668    fn is_synchronous(&self) -> bool {
669        self.wtr.is_synchronous()
670    }
671}
672
673impl io::Write for BufferedStandardStream {
674    #[inline]
675    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
676        self.wtr.write(b)
677    }
678
679    #[inline]
680    fn flush(&mut self) -> io::Result<()> {
681        self.wtr.flush()
682    }
683}
684
685impl WriteColor for BufferedStandardStream {
686    #[inline]
687    fn supports_color(&self) -> bool {
688        self.wtr.supports_color()
689    }
690
691    #[inline]
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]
700    fn reset(&mut self) -> io::Result<()> {
701        self.wtr.reset()
702    }
703
704    #[inline]
705    fn is_synchronous(&self) -> bool {
706        self.wtr.is_synchronous()
707    }
708}
709
710impl<W: io::Write> io::Write for WriterInner<W> {
711    #[inline(always)]
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)]
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
732impl<W: io::Write> WriteColor for WriterInner<W> {
733    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
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
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
768    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
778impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> {
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
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
800impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
801    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
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
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
838    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.
858pub 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
867impl 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))]
874    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)]
892    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.
927    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.
939    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`.
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))]
956    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)]
965    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.
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).
1016pub struct Buffer(BufferInner);
1017
1018/// BufferInner is an enumeration of different buffer types.
1019enum 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
1032impl Buffer {
1033    /// Create a new buffer with the given color settings.
1034    #[cfg(not(windows))]
1035    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)]
1051    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.
1064    pub fn no_color() -> Buffer {
1065        Buffer(BufferInner::NoColor(NoColor(vec![])))
1066    }
1067
1068    /// Create a buffer that uses ANSI escape sequences.
1069    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)]
1075    pub fn console() -> Buffer {
1076        Buffer(BufferInner::Windows(WindowsBuffer::new()))
1077    }
1078
1079    /// Returns true if and only if this buffer is empty.
1080    pub fn is_empty(&self) -> bool {
1081        self.len() == 0
1082    }
1083
1084    /// Returns the length of this buffer in bytes.
1085    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.
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.
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.
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.
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
1138impl io::Write for Buffer {
1139    #[inline]
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]
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
1160impl WriteColor for Buffer {
1161    #[inline]
1162    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]
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]
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]
1192    fn is_synchronous(&self) -> bool {
1193        false
1194    }
1195}
1196
1197/// Satisfies `WriteColor` but ignores all color options.
1198pub struct NoColor<W>(W);
1199
1200impl<W: Write> NoColor<W> {
1201    /// Create a new writer that satisfies `WriteColor` but drops all color
1202    /// information.
1203    pub fn new(wtr: W) -> NoColor<W> {
1204        NoColor(wtr)
1205    }
1206
1207    /// Consume this `NoColor` value and return the inner writer.
1208    pub fn into_inner(self) -> W {
1209        self.0
1210    }
1211
1212    /// Return a reference to the inner writer.
1213    pub fn get_ref(&self) -> &W {
1214        &self.0
1215    }
1216
1217    /// Return a mutable reference to the inner writer.
1218    pub fn get_mut(&mut self) -> &mut W {
1219        &mut self.0
1220    }
1221}
1222
1223impl<W: io::Write> io::Write for NoColor<W> {
1224    #[inline]
1225    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1226        self.0.write(buf)
1227    }
1228
1229    #[inline]
1230    fn flush(&mut self) -> io::Result<()> {
1231        self.0.flush()
1232    }
1233}
1234
1235impl<W: io::Write> WriteColor for NoColor<W> {
1236    #[inline]
1237    fn supports_color(&self) -> bool {
1238        false
1239    }
1240
1241    #[inline]
1242    fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
1243        Ok(())
1244    }
1245
1246    #[inline]
1247    fn reset(&mut self) -> io::Result<()> {
1248        Ok(())
1249    }
1250
1251    #[inline]
1252    fn is_synchronous(&self) -> bool {
1253        false
1254    }
1255}
1256
1257/// Satisfies `WriteColor` using standard ANSI escape sequences.
1258pub struct Ansi<W>(W);
1259
1260impl<W: Write> Ansi<W> {
1261    /// Create a new writer that satisfies `WriteColor` using standard ANSI
1262    /// escape sequences.
1263    pub fn new(wtr: W) -> Ansi<W> {
1264        Ansi(wtr)
1265    }
1266
1267    /// Consume this `Ansi` value and return the inner writer.
1268    pub fn into_inner(self) -> W {
1269        self.0
1270    }
1271
1272    /// Return a reference to the inner writer.
1273    pub fn get_ref(&self) -> &W {
1274        &self.0
1275    }
1276
1277    /// Return a mutable reference to the inner writer.
1278    pub fn get_mut(&mut self) -> &mut W {
1279        &mut self.0
1280    }
1281}
1282
1283impl<W: io::Write> io::Write for Ansi<W> {
1284    #[inline]
1285    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1286        self.0.write(buf)
1287    }
1288
1289    #[inline]
1290    fn flush(&mut self) -> io::Result<()> {
1291        self.0.flush()
1292    }
1293}
1294
1295impl<W: io::Write> WriteColor for Ansi<W> {
1296    #[inline]
1297    fn supports_color(&self) -> bool {
1298        true
1299    }
1300
1301    #[inline]
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]
1328    fn reset(&mut self) -> io::Result<()> {
1329        self.write_str("\x1B[0m")
1330    }
1331
1332    #[inline]
1333    fn is_synchronous(&self) -> bool {
1334        false
1335    }
1336}
1337
1338impl<W: io::Write> Ansi<W> {
1339    fn write_str(&mut self, s: &str) -> io::Result<()> {
1340        self.write_all(s.as_bytes())
1341    }
1342
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
1453impl WriteColor for io::Sink {
1454    fn supports_color(&self) -> bool {
1455        false
1456    }
1457
1458    fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
1459        Ok(())
1460    }
1461
1462    fn reset(&mut self) -> io::Result<()> {
1463        Ok(())
1464    }
1465}
1466
1467/// An in-memory buffer that provides Windows console coloring.
1468///
1469/// This doesn't actually communicate with the Windows console. Instead, it
1470/// acts like a normal buffer but also saves the color information associated
1471/// with positions in the buffer. It is only when the buffer is written to the
1472/// console that coloring is actually applied.
1473///
1474/// This is roughly isomorphic to the ANSI based approach (i.e.,
1475/// `Ansi<Vec<u8>>`), except with ANSI, the color information is embedded
1476/// directly into the buffer.
1477///
1478/// Note that there is no way to write something generic like
1479/// `WindowsConsole<W: io::Write>` since coloring on Windows is tied
1480/// specifically to the console APIs, and therefore can't work on arbitrary
1481/// writers.
1482#[cfg(windows)]
1483#[derive(Clone, Debug)]
1484struct WindowsBuffer {
1485    /// The actual content that should be printed.
1486    buf: Vec<u8>,
1487    /// A sequence of position oriented color specifications. Namely, each
1488    /// element is a position and a color spec, where the color spec should
1489    /// be applied at the position inside of `buf`.
1490    ///
1491    /// A missing color spec implies the underlying console should be reset.
1492    colors: Vec<(usize, Option<ColorSpec>)>,
1493}
1494
1495#[cfg(windows)]
1496impl WindowsBuffer {
1497    /// Create a new empty buffer for Windows console coloring.
1498    fn new() -> WindowsBuffer {
1499        WindowsBuffer { buf: vec![], colors: vec![] }
1500    }
1501
1502    /// Push the given color specification into this buffer.
1503    ///
1504    /// This has the effect of setting the given color information at the
1505    /// current position in the buffer.
1506    fn push(&mut self, spec: Option<ColorSpec>) {
1507        let pos = self.buf.len();
1508        self.colors.push((pos, spec));
1509    }
1510
1511    /// Print the contents to the given stream handle, and use the console
1512    /// for coloring.
1513    fn print(
1514        &self,
1515        console: &mut wincon::Console,
1516        stream: &mut LossyStandardStream<IoStandardStreamLock>,
1517    ) -> io::Result<()> {
1518        let mut last = 0;
1519        for &(pos, ref spec) in &self.colors {
1520            stream.write_all(&self.buf[last..pos])?;
1521            stream.flush()?;
1522            last = pos;
1523            match *spec {
1524                None => console.reset()?,
1525                Some(ref spec) => spec.write_console(console)?,
1526            }
1527        }
1528        stream.write_all(&self.buf[last..])?;
1529        stream.flush()
1530    }
1531
1532    /// Clear the buffer.
1533    fn clear(&mut self) {
1534        self.buf.clear();
1535        self.colors.clear();
1536    }
1537}
1538
1539#[cfg(windows)]
1540impl io::Write for WindowsBuffer {
1541    #[inline]
1542    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1543        self.buf.extend_from_slice(buf);
1544        Ok(buf.len())
1545    }
1546
1547    #[inline]
1548    fn flush(&mut self) -> io::Result<()> {
1549        Ok(())
1550    }
1551}
1552
1553#[cfg(windows)]
1554impl WriteColor for WindowsBuffer {
1555    #[inline]
1556    fn supports_color(&self) -> bool {
1557        true
1558    }
1559
1560    #[inline]
1561    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1562        self.push(Some(spec.clone()));
1563        Ok(())
1564    }
1565
1566    #[inline]
1567    fn reset(&mut self) -> io::Result<()> {
1568        self.push(None);
1569        Ok(())
1570    }
1571
1572    #[inline]
1573    fn is_synchronous(&self) -> bool {
1574        false
1575    }
1576}
1577
1578/// A color specification.
1579#[derive(Clone, Debug, Eq, PartialEq)]
1580pub struct ColorSpec {
1581    fg_color: Option<Color>,
1582    bg_color: Option<Color>,
1583    bold: bool,
1584    intense: bool,
1585    underline: bool,
1586    dimmed: bool,
1587    italic: bool,
1588    reset: bool,
1589}
1590
1591impl Default for ColorSpec {
1592    fn default() -> ColorSpec {
1593        ColorSpec {
1594            fg_color: None,
1595            bg_color: None,
1596            bold: false,
1597            intense: false,
1598            underline: false,
1599            dimmed: false,
1600            italic: false,
1601            reset: true,
1602        }
1603    }
1604}
1605
1606impl ColorSpec {
1607    /// Create a new color specification that has no colors or styles.
1608    pub fn new() -> ColorSpec {
1609        ColorSpec::default()
1610    }
1611
1612    /// Get the foreground color.
1613    pub fn fg(&self) -> Option<&Color> {
1614        self.fg_color.as_ref()
1615    }
1616
1617    /// Set the foreground color.
1618    pub fn set_fg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1619        self.fg_color = color;
1620        self
1621    }
1622
1623    /// Get the background color.
1624    pub fn bg(&self) -> Option<&Color> {
1625        self.bg_color.as_ref()
1626    }
1627
1628    /// Set the background color.
1629    pub fn set_bg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1630        self.bg_color = color;
1631        self
1632    }
1633
1634    /// Get whether this is bold or not.
1635    ///
1636    /// Note that the bold setting has no effect in a Windows console.
1637    pub fn bold(&self) -> bool {
1638        self.bold
1639    }
1640
1641    /// Set whether the text is bolded or not.
1642    ///
1643    /// Note that the bold setting has no effect in a Windows console.
1644    pub fn set_bold(&mut self, yes: bool) -> &mut ColorSpec {
1645        self.bold = yes;
1646        self
1647    }
1648
1649    /// Get whether this is dimmed or not.
1650    ///
1651    /// Note that the dimmed setting has no effect in a Windows console.
1652    pub fn dimmed(&self) -> bool {
1653        self.dimmed
1654    }
1655
1656    /// Set whether the text is dimmed or not.
1657    ///
1658    /// Note that the dimmed setting has no effect in a Windows console.
1659    pub fn set_dimmed(&mut self, yes: bool) -> &mut ColorSpec {
1660        self.dimmed = yes;
1661        self
1662    }
1663
1664    /// Get whether this is italic or not.
1665    ///
1666    /// Note that the italic setting has no effect in a Windows console.
1667    pub fn italic(&self) -> bool {
1668        self.italic
1669    }
1670
1671    /// Set whether the text is italicized or not.
1672    ///
1673    /// Note that the italic setting has no effect in a Windows console.
1674    pub fn set_italic(&mut self, yes: bool) -> &mut ColorSpec {
1675        self.italic = yes;
1676        self
1677    }
1678
1679    /// Get whether this is underline or not.
1680    ///
1681    /// Note that the underline setting has no effect in a Windows console.
1682    pub fn underline(&self) -> bool {
1683        self.underline
1684    }
1685
1686    /// Set whether the text is underlined or not.
1687    ///
1688    /// Note that the underline setting has no effect in a Windows console.
1689    pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec {
1690        self.underline = yes;
1691        self
1692    }
1693
1694    /// Get whether reset is enabled or not.
1695    ///
1696    /// reset is enabled by default. When disabled and using ANSI escape
1697    /// sequences, a "reset" code will be emitted every time a `ColorSpec`'s
1698    /// settings are applied.
1699    ///
1700    /// Note that the reset setting has no effect in a Windows console.
1701    pub fn reset(&self) -> bool {
1702        self.reset
1703    }
1704
1705    /// Set whether to reset the terminal whenever color settings are applied.
1706    ///
1707    /// reset is enabled by default. When disabled and using ANSI escape
1708    /// sequences, a "reset" code will be emitted every time a `ColorSpec`'s
1709    /// settings are applied.
1710    ///
1711    /// Typically this is useful if callers have a requirement to more
1712    /// scrupulously manage the exact sequence of escape codes that are emitted
1713    /// when using ANSI for colors.
1714    ///
1715    /// Note that the reset setting has no effect in a Windows console.
1716    pub fn set_reset(&mut self, yes: bool) -> &mut ColorSpec {
1717        self.reset = yes;
1718        self
1719    }
1720
1721    /// Get whether this is intense or not.
1722    ///
1723    /// On Unix-like systems, this will output the ANSI escape sequence
1724    /// that will print a high-intensity version of the color
1725    /// specified.
1726    ///
1727    /// On Windows systems, this will output the ANSI escape sequence
1728    /// that will print a brighter version of the color specified.
1729    pub fn intense(&self) -> bool {
1730        self.intense
1731    }
1732
1733    /// Set whether the text is intense or not.
1734    ///
1735    /// On Unix-like systems, this will output the ANSI escape sequence
1736    /// that will print a high-intensity version of the color
1737    /// specified.
1738    ///
1739    /// On Windows systems, this will output the ANSI escape sequence
1740    /// that will print a brighter version of the color specified.
1741    pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec {
1742        self.intense = yes;
1743        self
1744    }
1745
1746    /// Returns true if this color specification has no colors or styles.
1747    pub fn is_none(&self) -> bool {
1748        self.fg_color.is_none()
1749            && self.bg_color.is_none()
1750            && !self.bold
1751            && !self.underline
1752            && !self.dimmed
1753            && !self.italic
1754            && !self.intense
1755    }
1756
1757    /// Clears this color specification so that it has no color/style settings.
1758    pub fn clear(&mut self) {
1759        self.fg_color = None;
1760        self.bg_color = None;
1761        self.bold = false;
1762        self.underline = false;
1763        self.intense = false;
1764        self.dimmed = false;
1765        self.italic = false;
1766    }
1767
1768    /// Writes this color spec to the given Windows console.
1769    #[cfg(windows)]
1770    fn write_console(&self, console: &mut wincon::Console) -> io::Result<()> {
1771        let fg_color = self.fg_color.and_then(|c| c.to_windows(self.intense));
1772        if let Some((intense, color)) = fg_color {
1773            console.fg(intense, color)?;
1774        }
1775        let bg_color = self.bg_color.and_then(|c| c.to_windows(self.intense));
1776        if let Some((intense, color)) = bg_color {
1777            console.bg(intense, color)?;
1778        }
1779        Ok(())
1780    }
1781}
1782
1783/// The set of available colors for the terminal foreground/background.
1784///
1785/// The `Ansi256` and `Rgb` colors will only output the correct codes when
1786/// paired with the `Ansi` `WriteColor` implementation.
1787///
1788/// The `Ansi256` and `Rgb` color types are not supported when writing colors
1789/// on Windows using the console. If they are used on Windows, then they are
1790/// silently ignored and no colors will be emitted.
1791///
1792/// This set may expand over time.
1793///
1794/// This type has a `FromStr` impl that can parse colors from their human
1795/// readable form. The format is as follows:
1796///
1797/// 1. Any of the explicitly listed colors in English. They are matched
1798///    case insensitively.
1799/// 2. A single 8-bit integer, in either decimal or hexadecimal format.
1800/// 3. A triple of 8-bit integers separated by a comma, where each integer is
1801///    in decimal or hexadecimal format.
1802///
1803/// Hexadecimal numbers are written with a `0x` prefix.
1804#[allow(missing_docs)]
1805#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1806pub enum Color {
1807    Black,
1808    Blue,
1809    Green,
1810    Red,
1811    Cyan,
1812    Magenta,
1813    Yellow,
1814    White,
1815    Ansi256(u8),
1816    Rgb(u8, u8, u8),
1817    #[doc(hidden)]
1818    __Nonexhaustive,
1819}
1820
1821impl Color {
1822    /// Translate this color to a wincon::Color.
1823    #[cfg(windows)]
1824    fn to_windows(
1825        self,
1826        intense: bool,
1827    ) -> Option<(wincon::Intense, wincon::Color)> {
1828        use wincon::Intense::{No, Yes};
1829
1830        let color = match self {
1831            Color::Black => wincon::Color::Black,
1832            Color::Blue => wincon::Color::Blue,
1833            Color::Green => wincon::Color::Green,
1834            Color::Red => wincon::Color::Red,
1835            Color::Cyan => wincon::Color::Cyan,
1836            Color::Magenta => wincon::Color::Magenta,
1837            Color::Yellow => wincon::Color::Yellow,
1838            Color::White => wincon::Color::White,
1839            Color::Ansi256(0) => return Some((No, wincon::Color::Black)),
1840            Color::Ansi256(1) => return Some((No, wincon::Color::Red)),
1841            Color::Ansi256(2) => return Some((No, wincon::Color::Green)),
1842            Color::Ansi256(3) => return Some((No, wincon::Color::Yellow)),
1843            Color::Ansi256(4) => return Some((No, wincon::Color::Blue)),
1844            Color::Ansi256(5) => return Some((No, wincon::Color::Magenta)),
1845            Color::Ansi256(6) => return Some((No, wincon::Color::Cyan)),
1846            Color::Ansi256(7) => return Some((No, wincon::Color::White)),
1847            Color::Ansi256(8) => return Some((Yes, wincon::Color::Black)),
1848            Color::Ansi256(9) => return Some((Yes, wincon::Color::Red)),
1849            Color::Ansi256(10) => return Some((Yes, wincon::Color::Green)),
1850            Color::Ansi256(11) => return Some((Yes, wincon::Color::Yellow)),
1851            Color::Ansi256(12) => return Some((Yes, wincon::Color::Blue)),
1852            Color::Ansi256(13) => return Some((Yes, wincon::Color::Magenta)),
1853            Color::Ansi256(14) => return Some((Yes, wincon::Color::Cyan)),
1854            Color::Ansi256(15) => return Some((Yes, wincon::Color::White)),
1855            Color::Ansi256(_) => return None,
1856            Color::Rgb(_, _, _) => return None,
1857            Color::__Nonexhaustive => unreachable!(),
1858        };
1859        let intense = if intense { Yes } else { No };
1860        Some((intense, color))
1861    }
1862
1863    /// Parses a numeric color string, either ANSI or RGB.
1864    fn from_str_numeric(s: &str) -> Result<Color, ParseColorError> {
1865        // The "ansi256" format is a single number (decimal or hex)
1866        // corresponding to one of 256 colors.
1867        //
1868        // The "rgb" format is a triple of numbers (decimal or hex) delimited
1869        // by a comma corresponding to one of 256^3 colors.
1870
1871        fn parse_number(s: &str) -> Option<u8> {
1872            use std::u8;
1873
1874            if s.starts_with("0x") {
1875                u8::from_str_radix(&s[2..], 16).ok()
1876            } else {
1877                u8::from_str_radix(s, 10).ok()
1878            }
1879        }
1880
1881        let codes: Vec<&str> = s.split(',').collect();
1882        if codes.len() == 1 {
1883            if let Some(n) = parse_number(&codes[0]) {
1884                Ok(Color::Ansi256(n))
1885            } else {
1886                if s.chars().all(|c| c.is_digit(16)) {
1887                    Err(ParseColorError {
1888                        kind: ParseColorErrorKind::InvalidAnsi256,
1889                        given: s.to_string(),
1890                    })
1891                } else {
1892                    Err(ParseColorError {
1893                        kind: ParseColorErrorKind::InvalidName,
1894                        given: s.to_string(),
1895                    })
1896                }
1897            }
1898        } else if codes.len() == 3 {
1899            let mut v = vec![];
1900            for code in codes {
1901                let n = parse_number(code).ok_or_else(|| ParseColorError {
1902                    kind: ParseColorErrorKind::InvalidRgb,
1903                    given: s.to_string(),
1904                })?;
1905                v.push(n);
1906            }
1907            Ok(Color::Rgb(v[0], v[1], v[2]))
1908        } else {
1909            Err(if s.contains(",") {
1910                ParseColorError {
1911                    kind: ParseColorErrorKind::InvalidRgb,
1912                    given: s.to_string(),
1913                }
1914            } else {
1915                ParseColorError {
1916                    kind: ParseColorErrorKind::InvalidName,
1917                    given: s.to_string(),
1918                }
1919            })
1920        }
1921    }
1922}
1923
1924/// An error from parsing an invalid color specification.
1925#[derive(Clone, Debug, Eq, PartialEq)]
1926pub struct ParseColorError {
1927    kind: ParseColorErrorKind,
1928    given: String,
1929}
1930
1931#[derive(Clone, Debug, Eq, PartialEq)]
1932enum ParseColorErrorKind {
1933    InvalidName,
1934    InvalidAnsi256,
1935    InvalidRgb,
1936}
1937
1938impl ParseColorError {
1939    /// Return the string that couldn't be parsed as a valid color.
1940    pub fn invalid(&self) -> &str {
1941        &self.given
1942    }
1943}
1944
1945impl error::Error for ParseColorError {
1946    fn description(&self) -> &str {
1947        use self::ParseColorErrorKind::*;
1948        match self.kind {
1949            InvalidName => "unrecognized color name",
1950            InvalidAnsi256 => "invalid ansi256 color number",
1951            InvalidRgb => "invalid RGB color triple",
1952        }
1953    }
1954}
1955
1956impl fmt::Display for ParseColorError {
1957    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1958        use self::ParseColorErrorKind::*;
1959        match self.kind {
1960            InvalidName => write!(
1961                f,
1962                "unrecognized color name '{}'. Choose from: \
1963                 black, blue, green, red, cyan, magenta, yellow, \
1964                 white",
1965                self.given
1966            ),
1967            InvalidAnsi256 => write!(
1968                f,
1969                "unrecognized ansi256 color number, \
1970                 should be '[0-255]' (or a hex number), but is '{}'",
1971                self.given
1972            ),
1973            InvalidRgb => write!(
1974                f,
1975                "unrecognized RGB color triple, \
1976                 should be '[0-255],[0-255],[0-255]' (or a hex \
1977                 triple), but is '{}'",
1978                self.given
1979            ),
1980        }
1981    }
1982}
1983
1984impl FromStr for Color {
1985    type Err = ParseColorError;
1986
1987    fn from_str(s: &str) -> Result<Color, ParseColorError> {
1988        match &*s.to_lowercase() {
1989            "black" => Ok(Color::Black),
1990            "blue" => Ok(Color::Blue),
1991            "green" => Ok(Color::Green),
1992            "red" => Ok(Color::Red),
1993            "cyan" => Ok(Color::Cyan),
1994            "magenta" => Ok(Color::Magenta),
1995            "yellow" => Ok(Color::Yellow),
1996            "white" => Ok(Color::White),
1997            _ => Color::from_str_numeric(s),
1998        }
1999    }
2000}
2001
2002struct LossyStandardStream<W> {
2003    wtr: W,
2004    #[cfg(windows)]
2005    is_console: bool,
2006}
2007
2008impl<W: io::Write> LossyStandardStream<W> {
2009    #[cfg(not(windows))]
2010    fn new(wtr: W) -> LossyStandardStream<W> {
2011        LossyStandardStream { wtr: wtr }
2012    }
2013
2014    #[cfg(windows)]
2015    fn new(wtr: W) -> LossyStandardStream<W> {
2016        let is_console = wincon::Console::stdout().is_ok()
2017            || wincon::Console::stderr().is_ok();
2018        LossyStandardStream { wtr: wtr, is_console: is_console }
2019    }
2020
2021    #[cfg(not(windows))]
2022    fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2023        LossyStandardStream::new(wtr)
2024    }
2025
2026    #[cfg(windows)]
2027    fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2028        LossyStandardStream { wtr: wtr, is_console: self.is_console }
2029    }
2030
2031    fn get_ref(&self) -> &W {
2032        &self.wtr
2033    }
2034}
2035
2036impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
2037    fn supports_color(&self) -> bool {
2038        self.wtr.supports_color()
2039    }
2040    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
2041        self.wtr.set_color(spec)
2042    }
2043    fn reset(&mut self) -> io::Result<()> {
2044        self.wtr.reset()
2045    }
2046    fn is_synchronous(&self) -> bool {
2047        self.wtr.is_synchronous()
2048    }
2049}
2050
2051impl<W: io::Write> io::Write for LossyStandardStream<W> {
2052    #[cfg(not(windows))]
2053    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2054        self.wtr.write(buf)
2055    }
2056
2057    #[cfg(windows)]
2058    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2059        if self.is_console {
2060            write_lossy_utf8(&mut self.wtr, buf)
2061        } else {
2062            self.wtr.write(buf)
2063        }
2064    }
2065
2066    fn flush(&mut self) -> io::Result<()> {
2067        self.wtr.flush()
2068    }
2069}
2070
2071#[cfg(windows)]
2072fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
2073    match ::std::str::from_utf8(buf) {
2074        Ok(s) => w.write(s.as_bytes()),
2075        Err(ref e) if e.valid_up_to() == 0 => {
2076            w.write(b"\xEF\xBF\xBD")?;
2077            Ok(1)
2078        }
2079        Err(e) => w.write(&buf[..e.valid_up_to()]),
2080    }
2081}
2082
2083#[cfg(test)]
2084mod tests {
2085    use super::{
2086        Ansi, Color, ColorSpec, ParseColorError, ParseColorErrorKind,
2087        StandardStream, WriteColor,
2088    };
2089
2090    fn assert_is_send<T: Send>() {}
2091
2092    #[test]
2093    fn standard_stream_is_send() {
2094        assert_is_send::<StandardStream>();
2095    }
2096
2097    #[test]
2098    fn test_simple_parse_ok() {
2099        let color = "green".parse::<Color>();
2100        assert_eq!(color, Ok(Color::Green));
2101    }
2102
2103    #[test]
2104    fn test_256_parse_ok() {
2105        let color = "7".parse::<Color>();
2106        assert_eq!(color, Ok(Color::Ansi256(7)));
2107
2108        let color = "32".parse::<Color>();
2109        assert_eq!(color, Ok(Color::Ansi256(32)));
2110
2111        let color = "0xFF".parse::<Color>();
2112        assert_eq!(color, Ok(Color::Ansi256(0xFF)));
2113    }
2114
2115    #[test]
2116    fn test_256_parse_err_out_of_range() {
2117        let color = "256".parse::<Color>();
2118        assert_eq!(
2119            color,
2120            Err(ParseColorError {
2121                kind: ParseColorErrorKind::InvalidAnsi256,
2122                given: "256".to_string(),
2123            })
2124        );
2125    }
2126
2127    #[test]
2128    fn test_rgb_parse_ok() {
2129        let color = "0,0,0".parse::<Color>();
2130        assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2131
2132        let color = "0,128,255".parse::<Color>();
2133        assert_eq!(color, Ok(Color::Rgb(0, 128, 255)));
2134
2135        let color = "0x0,0x0,0x0".parse::<Color>();
2136        assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2137
2138        let color = "0x33,0x66,0xFF".parse::<Color>();
2139        assert_eq!(color, Ok(Color::Rgb(0x33, 0x66, 0xFF)));
2140    }
2141
2142    #[test]
2143    fn test_rgb_parse_err_out_of_range() {
2144        let color = "0,0,256".parse::<Color>();
2145        assert_eq!(
2146            color,
2147            Err(ParseColorError {
2148                kind: ParseColorErrorKind::InvalidRgb,
2149                given: "0,0,256".to_string(),
2150            })
2151        );
2152    }
2153
2154    #[test]
2155    fn test_rgb_parse_err_bad_format() {
2156        let color = "0,0".parse::<Color>();
2157        assert_eq!(
2158            color,
2159            Err(ParseColorError {
2160                kind: ParseColorErrorKind::InvalidRgb,
2161                given: "0,0".to_string(),
2162            })
2163        );
2164
2165        let color = "not_a_color".parse::<Color>();
2166        assert_eq!(
2167            color,
2168            Err(ParseColorError {
2169                kind: ParseColorErrorKind::InvalidName,
2170                given: "not_a_color".to_string(),
2171            })
2172        );
2173    }
2174
2175    #[test]
2176    fn test_var_ansi_write_rgb() {
2177        let mut buf = Ansi::new(vec![]);
2178        let _ = buf.write_color(true, &Color::Rgb(254, 253, 255), false);
2179        assert_eq!(buf.0, b"\x1B[38;2;254;253;255m");
2180    }
2181
2182    #[test]
2183    fn test_reset() {
2184        let spec = ColorSpec::new();
2185        let mut buf = Ansi::new(vec![]);
2186        buf.set_color(&spec).unwrap();
2187        assert_eq!(buf.0, b"\x1B[0m");
2188    }
2189
2190    #[test]
2191    fn test_no_reset() {
2192        let mut spec = ColorSpec::new();
2193        spec.set_reset(false);
2194
2195        let mut buf = Ansi::new(vec![]);
2196        buf.set_color(&spec).unwrap();
2197        assert_eq!(buf.0, b"");
2198    }
2199
2200    #[test]
2201    fn test_var_ansi_write_256() {
2202        let mut buf = Ansi::new(vec![]);
2203        let _ = buf.write_color(false, &Color::Ansi256(7), false);
2204        assert_eq!(buf.0, b"\x1B[48;5;7m");
2205
2206        let mut buf = Ansi::new(vec![]);
2207        let _ = buf.write_color(false, &Color::Ansi256(208), false);
2208        assert_eq!(buf.0, b"\x1B[48;5;208m");
2209    }
2210
2211    fn all_attributes() -> Vec<ColorSpec> {
2212        let mut result = vec![];
2213        for fg in vec![None, Some(Color::Red)] {
2214            for bg in vec![None, Some(Color::Red)] {
2215                for bold in vec![false, true] {
2216                    for underline in vec![false, true] {
2217                        for intense in vec![false, true] {
2218                            for italic in vec![false, true] {
2219                                for dimmed in vec![false, true] {
2220                                    let mut color = ColorSpec::new();
2221                                    color.set_fg(fg);
2222                                    color.set_bg(bg);
2223                                    color.set_bold(bold);
2224                                    color.set_underline(underline);
2225                                    color.set_intense(intense);
2226                                    color.set_dimmed(dimmed);
2227                                    color.set_italic(italic);
2228                                    result.push(color);
2229                                }
2230                            }
2231                        }
2232                    }
2233                }
2234            }
2235        }
2236        result
2237    }
2238
2239    #[test]
2240    fn test_is_none() {
2241        for (i, color) in all_attributes().iter().enumerate() {
2242            assert_eq!(
2243                i == 0,
2244                color.is_none(),
2245                "{:?} => {}",
2246                color,
2247                color.is_none()
2248            )
2249        }
2250    }
2251
2252    #[test]
2253    fn test_clear() {
2254        for color in all_attributes() {
2255            let mut color1 = color.clone();
2256            color1.clear();
2257            assert!(color1.is_none(), "{:?} => {:?}", color, color1);
2258        }
2259    }
2260}