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`](http://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
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)]
1470struct 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)]
1482impl WindowsBuffer {
1483    /// Create a new empty buffer for Windows console coloring.
1484    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.
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.
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.
1519    fn clear(&mut self) {
1520        self.buf.clear();
1521        self.colors.clear();
1522    }
1523}
1524
1525#[cfg(windows)]
1526impl io::Write for WindowsBuffer {
1527    #[inline]
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]
1534    fn flush(&mut self) -> io::Result<()> {
1535        Ok(())
1536    }
1537}
1538
1539#[cfg(windows)]
1540impl WriteColor for WindowsBuffer {
1541    #[inline]
1542    fn supports_color(&self) -> bool {
1543        true
1544    }
1545
1546    #[inline]
1547    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1548        self.push(Some(spec.clone()));
1549        Ok(())
1550    }
1551
1552    #[inline]
1553    fn reset(&mut self) -> io::Result<()> {
1554        self.push(None);
1555        Ok(())
1556    }
1557
1558    #[inline]
1559    fn is_synchronous(&self) -> bool {
1560        false
1561    }
1562}
1563
1564/// A color specification.
1565#[derive(Clone, Debug, Eq, PartialEq)]
1566pub 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
1577impl Default for ColorSpec {
1578    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
1592impl ColorSpec {
1593    /// Create a new color specification that has no colors or styles.
1594    pub fn new() -> ColorSpec {
1595        ColorSpec::default()
1596    }
1597
1598    /// Get the foreground color.
1599    pub fn fg(&self) -> Option<&Color> {
1600        self.fg_color.as_ref()
1601    }
1602
1603    /// Set the foreground color.
1604    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.
1610    pub fn bg(&self) -> Option<&Color> {
1611        self.bg_color.as_ref()
1612    }
1613
1614    /// Set the background color.
1615    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.
1623    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.
1630    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.
1638    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.
1645    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.
1653    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.
1660    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.
1668    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.
1675    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.
1687    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.
1702    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.
1715    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.
1727    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.
1733    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.
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)]
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)]
1792pub 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
1807impl Color {
1808    /// Translate this color to a wincon::Color.
1809    #[cfg(windows)]
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.
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)]
1912pub struct ParseColorError {
1913    kind: ParseColorErrorKind,
1914    given: String,
1915}
1916
1917#[derive(Clone, Debug, Eq, PartialEq)]
1918enum ParseColorErrorKind {
1919    InvalidName,
1920    InvalidAnsi256,
1921    InvalidRgb,
1922}
1923
1924impl ParseColorError {
1925    /// Return the string that couldn't be parsed as a valid color.
1926    pub fn invalid(&self) -> &str {
1927        &self.given
1928    }
1929}
1930
1931impl error::Error for ParseColorError {
1932    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
1942impl fmt::Display for ParseColorError {
1943    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
1970impl FromStr for Color {
1971    type Err = ParseColorError;
1972
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
1988struct LossyStandardStream<W> {
1989    wtr: W,
1990    #[cfg(windows)]
1991    is_console: bool,
1992}
1993
1994impl<W: io::Write> LossyStandardStream<W> {
1995    #[cfg(not(windows))]
1996    fn new(wtr: W) -> LossyStandardStream<W> {
1997        LossyStandardStream { wtr: wtr }
1998    }
1999
2000    #[cfg(windows)]
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))]
2008    fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2009        LossyStandardStream::new(wtr)
2010    }
2011
2012    #[cfg(windows)]
2013    fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2014        LossyStandardStream { wtr: wtr, is_console: self.is_console }
2015    }
2016
2017    fn get_ref(&self) -> &W {
2018        &self.wtr
2019    }
2020}
2021
2022impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
2023    fn supports_color(&self) -> bool {
2024        self.wtr.supports_color()
2025    }
2026    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
2027        self.wtr.set_color(spec)
2028    }
2029    fn reset(&mut self) -> io::Result<()> {
2030        self.wtr.reset()
2031    }
2032    fn is_synchronous(&self) -> bool {
2033        self.wtr.is_synchronous()
2034    }
2035}
2036
2037impl<W: io::Write> io::Write for LossyStandardStream<W> {
2038    #[cfg(not(windows))]
2039    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2040        self.wtr.write(buf)
2041    }
2042
2043    #[cfg(windows)]
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
2052    fn flush(&mut self) -> io::Result<()> {
2053        self.wtr.flush()
2054    }
2055}
2056
2057#[cfg(windows)]
2058fn 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)]
2070mod tests {
2071    use super::{
2072        Ansi, Color, ColorSpec, ParseColorError, ParseColorErrorKind,
2073        StandardStream, WriteColor,
2074    };
2075
2076    fn assert_is_send<T: Send>() {}
2077
2078    #[test]
2079    fn standard_stream_is_send() {
2080        assert_is_send::<StandardStream>();
2081    }
2082
2083    #[test]
2084    fn test_simple_parse_ok() {
2085        let color = "green".parse::<Color>();
2086        assert_eq!(color, Ok(Color::Green));
2087    }
2088
2089    #[test]
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]
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]
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]
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]
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]
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]
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]
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]
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
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]
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]
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}