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
50# Example: using `BufferWriter`
51
52A `BufferWriter` can create buffers and write buffers to stdout or stderr. It
53does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer`
54implements `io::Write` and `io::WriteColor`.
55
56This example shows how to print some green text to stderr.
57
58```rust,no_run
59# fn test() -> Result<(), Box<::std::error::Error>> {
60use std::io::Write;
61use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
62
63let mut bufwtr = BufferWriter::stderr(ColorChoice::Always);
64let mut buffer = bufwtr.buffer();
65buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
66writeln!(&mut buffer, "green text!")?;
67bufwtr.print(&buffer)?;
68# Ok(()) }
69```
70*/
71
72#![deny(missing_docs)]
73
74#[cfg(windows)]
75extern crate wincolor;
76
77use std::env;
78use std::error;
79use std::fmt;
80use std::io::{self, Write};
81use std::str::FromStr;
82#[cfg(windows)]
83use std::sync::{Mutex, MutexGuard};
84use std::sync::atomic::{AtomicBool, Ordering};
85
86/// This trait describes the behavior of writers that support colored output.
87pub trait WriteColor: io::Write {
88    /// Returns true if and only if the underlying writer supports colors.
89    fn supports_color(&self) -> bool;
90
91    /// Set the color settings of the writer.
92    ///
93    /// Subsequent writes to this writer will use these settings until either
94    /// `reset` is called or new color settings are set.
95    ///
96    /// If there was a problem setting the color settings, then an error is
97    /// returned.
98    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()>;
99
100    /// Reset the current color settings to their original settings.
101    ///
102    /// If there was a problem resetting the color settings, then an error is
103    /// returned.
104    fn reset(&mut self) -> io::Result<()>;
105
106    /// Returns true if and only if the underlying writer must synchronously
107    /// interact with an end user's device in order to control colors. By
108    /// default, this always returns `false`.
109    ///
110    /// In practice, this should return `true` if the underlying writer is
111    /// manipulating colors using the Windows console APIs.
112    ///
113    /// This is useful for writing generic code (such as a buffered writer)
114    /// that can perform certain optimizations when the underlying writer
115    /// doesn't rely on synchronous APIs. For example, ANSI escape sequences
116    /// can be passed through to the end user's device as is.
117    fn is_synchronous(&self) -> bool {
118        false
119    }
120}
121
122impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T {
123    fn supports_color(&self) -> bool { (&**self).supports_color() }
124    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
125        (&mut **self).set_color(spec)
126    }
127    fn reset(&mut self) -> io::Result<()> { (&mut **self).reset() }
128    fn is_synchronous(&self) -> bool { (&**self).is_synchronous() }
129}
130
131impl<T: ?Sized + WriteColor> WriteColor for Box<T> {
132    fn supports_color(&self) -> bool { (&**self).supports_color() }
133    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
134        (&mut **self).set_color(spec)
135    }
136    fn reset(&mut self) -> io::Result<()> { (&mut **self).reset() }
137    fn is_synchronous(&self) -> bool { (&**self).is_synchronous() }
138}
139
140/// ColorChoice represents the color preferences of an end user.
141#[derive(Clone, Copy, Debug, Eq, PartialEq)]
142pub enum ColorChoice {
143    /// Try very hard to emit colors. This includes emitting ANSI colors
144    /// on Windows if the console API is unavailable.
145    Always,
146    /// AlwaysAnsi is like Always, except it never tries to use anything other
147    /// than emitting ANSI color codes.
148    AlwaysAnsi,
149    /// Try to use colors, but don't force the issue. If the console isn't
150    /// available on Windows, or if TERM=dumb, for example, then don't use
151    /// colors.
152    Auto,
153    /// Never emit colors.
154    Never,
155}
156
157impl ColorChoice {
158    /// Returns true if we should attempt to write colored output.
159    #[cfg(not(windows))]
160    fn should_attempt_color(&self) -> bool {
161        match *self {
162            ColorChoice::Always => true,
163            ColorChoice::AlwaysAnsi => true,
164            ColorChoice::Never => false,
165            ColorChoice::Auto => {
166                match env::var("TERM") {
167                    Err(_) => false,
168                    Ok(k) => k != "dumb",
169                }
170            }
171        }
172    }
173
174    /// Returns true if we should attempt to write colored output.
175    #[cfg(windows)]
176    fn should_attempt_color(&self) -> bool {
177        match *self {
178            ColorChoice::Always => true,
179            ColorChoice::AlwaysAnsi => true,
180            ColorChoice::Never => false,
181            ColorChoice::Auto => {
182                match env::var("TERM") {
183                    Err(_) => true,
184                    Ok(k) => k != "dumb",
185                }
186            }
187        }
188    }
189
190    /// Returns true if this choice should forcefully use ANSI color codes.
191    ///
192    /// It's possible that ANSI is still the correct choice even if this
193    /// returns false.
194    #[cfg(windows)]
195    fn should_ansi(&self) -> bool {
196        match *self {
197            ColorChoice::Always => false,
198            ColorChoice::AlwaysAnsi => true,
199            ColorChoice::Never => false,
200            ColorChoice::Auto => {
201                match env::var("TERM") {
202                    Err(_) => false,
203                    // cygwin doesn't seem to support ANSI escape sequences
204                    // and instead has its own variety. However, the Windows
205                    // console API may be available.
206                    Ok(k) => k != "dumb" && k != "cygwin",
207                }
208            }
209        }
210    }
211}
212
213/// `std::io` implements `Stdout` and `Stderr` (and their `Lock` variants) as
214/// separate types, which makes it difficult to abstract over them. We use
215/// some simple internal enum types to work around this.
216
217enum StandardStreamType {
218    Stdout,
219    Stderr,
220    StdoutBuffered,
221    StderrBuffered,
222}
223
224enum IoStandardStream {
225    Stdout(io::Stdout),
226    Stderr(io::Stderr),
227    StdoutBuffered(io::BufWriter<io::Stdout>),
228    StderrBuffered(io::BufWriter<io::Stderr>),
229}
230
231impl IoStandardStream {
232    fn new(sty: StandardStreamType) -> IoStandardStream {
233        match sty {
234            StandardStreamType::Stdout => {
235                IoStandardStream::Stdout(io::stdout())
236            }
237            StandardStreamType::Stderr => {
238                IoStandardStream::Stderr(io::stderr())
239            }
240            StandardStreamType::StdoutBuffered => {
241                let wtr = io::BufWriter::new(io::stdout());
242                IoStandardStream::StdoutBuffered(wtr)
243            }
244            StandardStreamType::StderrBuffered => {
245                let wtr = io::BufWriter::new(io::stderr());
246                IoStandardStream::StderrBuffered(wtr)
247            }
248        }
249    }
250
251    fn lock(&self) -> IoStandardStreamLock {
252        match *self {
253            IoStandardStream::Stdout(ref s) => {
254                IoStandardStreamLock::StdoutLock(s.lock())
255            }
256            IoStandardStream::Stderr(ref s) => {
257                IoStandardStreamLock::StderrLock(s.lock())
258            }
259            IoStandardStream::StdoutBuffered(_)
260            | IoStandardStream::StderrBuffered(_) => {
261                // We don't permit this case to ever occur in the public API,
262                // so it's OK to panic.
263                panic!("cannot lock a buffered standard stream")
264            }
265        }
266    }
267}
268
269impl io::Write for IoStandardStream {
270    #[inline(always)]
271    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
272        match *self {
273            IoStandardStream::Stdout(ref mut s) => s.write(b),
274            IoStandardStream::Stderr(ref mut s) => s.write(b),
275            IoStandardStream::StdoutBuffered(ref mut s) => s.write(b),
276            IoStandardStream::StderrBuffered(ref mut s) => s.write(b),
277        }
278    }
279
280    #[inline(always)]
281    fn flush(&mut self) -> io::Result<()> {
282        match *self {
283            IoStandardStream::Stdout(ref mut s) => s.flush(),
284            IoStandardStream::Stderr(ref mut s) => s.flush(),
285            IoStandardStream::StdoutBuffered(ref mut s) => s.flush(),
286            IoStandardStream::StderrBuffered(ref mut s) => s.flush(),
287        }
288    }
289}
290
291// Same rigmarole for the locked variants of the standard streams.
292
293enum IoStandardStreamLock<'a> {
294    StdoutLock(io::StdoutLock<'a>),
295    StderrLock(io::StderrLock<'a>),
296}
297
298impl<'a> io::Write for IoStandardStreamLock<'a> {
299    #[inline(always)]
300    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
301        match *self {
302            IoStandardStreamLock::StdoutLock(ref mut s) => s.write(b),
303            IoStandardStreamLock::StderrLock(ref mut s) => s.write(b),
304        }
305    }
306
307    #[inline(always)]
308    fn flush(&mut self) -> io::Result<()> {
309        match *self {
310            IoStandardStreamLock::StdoutLock(ref mut s) => s.flush(),
311            IoStandardStreamLock::StderrLock(ref mut s) => s.flush(),
312        }
313    }
314}
315
316/// Satisfies `io::Write` and `WriteColor`, and supports optional coloring
317/// to either of the standard output streams, stdout and stderr.
318pub struct StandardStream {
319    wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
320}
321
322/// `StandardStreamLock` is a locked reference to a `StandardStream`.
323///
324/// This implements the `io::Write` and `WriteColor` traits, and is constructed
325/// via the `Write::lock` method.
326///
327/// The lifetime `'a` refers to the lifetime of the corresponding
328/// `StandardStream`.
329pub struct StandardStreamLock<'a> {
330    wtr: LossyStandardStream<WriterInnerLock<'a, IoStandardStreamLock<'a>>>,
331}
332
333/// Like `StandardStream`, but does buffered writing.
334pub struct BufferedStandardStream {
335    wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
336}
337
338/// WriterInner is a (limited) generic representation of a writer. It is
339/// limited because W should only ever be stdout/stderr on Windows.
340enum WriterInner<W> {
341    NoColor(NoColor<W>),
342    Ansi(Ansi<W>),
343    #[cfg(windows)]
344    Windows { wtr: W, console: Mutex<wincolor::Console> },
345}
346
347/// WriterInnerLock is a (limited) generic representation of a writer. It is
348/// limited because W should only ever be stdout/stderr on Windows.
349enum WriterInnerLock<'a, W> {
350    NoColor(NoColor<W>),
351    Ansi(Ansi<W>),
352    /// What a gross hack. On Windows, we need to specify a lifetime for the
353    /// console when in a locked state, but obviously don't need to do that
354    /// on Unix, which makes the `'a` unused. To satisfy the compiler, we need
355    /// a PhantomData.
356    #[allow(dead_code)]
357    Unreachable(::std::marker::PhantomData<&'a ()>),
358    #[cfg(windows)]
359    Windows { wtr: W, console: MutexGuard<'a, wincolor::Console> },
360}
361
362impl StandardStream {
363    /// Create a new `StandardStream` with the given color preferences that
364    /// writes to standard output.
365    ///
366    /// On Windows, if coloring is desired and a Windows console could not be
367    /// found, then ANSI escape sequences are used instead.
368    ///
369    /// The specific color/style settings can be configured when writing via
370    /// the `WriteColor` trait.
371    pub fn stdout(choice: ColorChoice) -> StandardStream {
372        let wtr = WriterInner::create(StandardStreamType::Stdout, choice);
373        StandardStream { wtr: LossyStandardStream::new(wtr) }
374    }
375
376    /// Create a new `StandardStream` with the given color preferences that
377    /// writes to standard error.
378    ///
379    /// On Windows, if coloring is desired and a Windows console could not be
380    /// found, then ANSI escape sequences are used instead.
381    ///
382    /// The specific color/style settings can be configured when writing via
383    /// the `WriteColor` trait.
384    pub fn stderr(choice: ColorChoice) -> StandardStream {
385        let wtr = WriterInner::create(StandardStreamType::Stderr, choice);
386        StandardStream { wtr: LossyStandardStream::new(wtr) }
387    }
388
389    /// Lock the underlying writer.
390    ///
391    /// The lock guard returned also satisfies `io::Write` and
392    /// `WriteColor`.
393    ///
394    /// This method is **not reentrant**. It may panic if `lock` is called
395    /// while a `StandardStreamLock` is still alive.
396    pub fn lock(&self) -> StandardStreamLock {
397        StandardStreamLock::from_stream(self)
398    }
399}
400
401impl<'a> StandardStreamLock<'a> {
402    #[cfg(not(windows))]
403    fn from_stream(stream: &StandardStream) -> StandardStreamLock {
404        let locked = match *stream.wtr.get_ref() {
405            WriterInner::NoColor(ref w) => {
406                WriterInnerLock::NoColor(NoColor(w.0.lock()))
407            }
408            WriterInner::Ansi(ref w) => {
409                WriterInnerLock::Ansi(Ansi(w.0.lock()))
410            }
411        };
412        StandardStreamLock { wtr: stream.wtr.wrap(locked) }
413    }
414
415    #[cfg(windows)]
416    fn from_stream(stream: &StandardStream) -> StandardStreamLock {
417        let locked = match *stream.wtr.get_ref() {
418            WriterInner::NoColor(ref w) => {
419                WriterInnerLock::NoColor(NoColor(w.0.lock()))
420            }
421            WriterInner::Ansi(ref w) => {
422                WriterInnerLock::Ansi(Ansi(w.0.lock()))
423            }
424            #[cfg(windows)]
425            WriterInner::Windows { ref wtr, ref console } => {
426                WriterInnerLock::Windows {
427                    wtr: wtr.lock(),
428                    console: console.lock().unwrap(),
429                }
430            }
431        };
432        StandardStreamLock { wtr: stream.wtr.wrap(locked) }
433    }
434}
435
436impl BufferedStandardStream {
437    /// Create a new `BufferedStandardStream` with the given color preferences
438    /// that writes to standard output via a buffered writer.
439    ///
440    /// On Windows, if coloring is desired and a Windows console could not be
441    /// found, then ANSI escape sequences are used instead.
442    ///
443    /// The specific color/style settings can be configured when writing via
444    /// the `WriteColor` trait.
445    pub fn stdout(choice: ColorChoice) -> BufferedStandardStream {
446        let wtr = WriterInner::create(
447            StandardStreamType::StdoutBuffered,
448            choice,
449        );
450        BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
451    }
452
453    /// Create a new `BufferedStandardStream` with the given color preferences
454    /// that writes to standard error via a buffered writer.
455    ///
456    /// On Windows, if coloring is desired and a Windows console could not be
457    /// found, then ANSI escape sequences are used instead.
458    ///
459    /// The specific color/style settings can be configured when writing via
460    /// the `WriteColor` trait.
461    pub fn stderr(choice: ColorChoice) -> BufferedStandardStream {
462        let wtr = WriterInner::create(
463            StandardStreamType::StderrBuffered,
464            choice,
465        );
466        BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
467    }
468}
469
470impl WriterInner<IoStandardStream> {
471    /// Create a new inner writer for a standard stream with the given color
472    /// preferences.
473    #[cfg(not(windows))]
474    fn create(
475        sty: StandardStreamType,
476        choice: ColorChoice,
477    ) -> WriterInner<IoStandardStream> {
478        if choice.should_attempt_color() {
479            WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
480        } else {
481            WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
482        }
483    }
484
485    /// Create a new inner writer for a standard stream with the given color
486    /// preferences.
487    ///
488    /// If coloring is desired and a Windows console could not be found, then
489    /// ANSI escape sequences are used instead.
490    #[cfg(windows)]
491    fn create(
492        sty: StandardStreamType,
493        choice: ColorChoice,
494    ) -> WriterInner<IoStandardStream> {
495        let mut con = match sty {
496            StandardStreamType::Stdout => wincolor::Console::stdout(),
497            StandardStreamType::Stderr => wincolor::Console::stderr(),
498            StandardStreamType::StdoutBuffered => wincolor::Console::stdout(),
499            StandardStreamType::StderrBuffered => wincolor::Console::stderr(),
500        };
501        let is_console_virtual = con.as_mut().map(|con| {
502            con.set_virtual_terminal_processing(true).is_ok()
503        }).unwrap_or(false);
504        if choice.should_attempt_color() {
505            if choice.should_ansi() || is_console_virtual {
506                WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
507            } else if let Ok(console) = con {
508                WriterInner::Windows {
509                    wtr: IoStandardStream::new(sty),
510                    console: Mutex::new(console),
511                }
512            } else {
513                WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
514            }
515        } else {
516            WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
517        }
518    }
519}
520
521impl io::Write for StandardStream {
522    #[inline]
523    fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
524
525    #[inline]
526    fn flush(&mut self) -> io::Result<()> { self.wtr.flush() }
527}
528
529impl WriteColor for StandardStream {
530    #[inline]
531    fn supports_color(&self) -> bool { self.wtr.supports_color() }
532
533    #[inline]
534    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
535        self.wtr.set_color(spec)
536    }
537
538    #[inline]
539    fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
540
541    #[inline]
542    fn is_synchronous(&self) -> bool { self.wtr.is_synchronous() }
543}
544
545impl<'a> io::Write for StandardStreamLock<'a> {
546    #[inline]
547    fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
548
549    #[inline]
550    fn flush(&mut self) -> io::Result<()> { self.wtr.flush() }
551}
552
553impl<'a> WriteColor for StandardStreamLock<'a> {
554    #[inline]
555    fn supports_color(&self) -> bool { self.wtr.supports_color() }
556
557    #[inline]
558    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
559        self.wtr.set_color(spec)
560    }
561
562    #[inline]
563    fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
564
565    #[inline]
566    fn is_synchronous(&self) -> bool { self.wtr.is_synchronous() }
567}
568
569impl io::Write for BufferedStandardStream {
570    #[inline]
571    fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) }
572
573    #[inline]
574    fn flush(&mut self) -> io::Result<()> { self.wtr.flush() }
575}
576
577impl WriteColor for BufferedStandardStream {
578    #[inline]
579    fn supports_color(&self) -> bool { self.wtr.supports_color() }
580
581    #[inline]
582    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
583        if self.is_synchronous() {
584            self.wtr.flush()?;
585        }
586        self.wtr.set_color(spec)
587    }
588
589    #[inline]
590    fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
591
592    #[inline]
593    fn is_synchronous(&self) -> bool { self.wtr.is_synchronous() }
594}
595
596impl<W: io::Write> io::Write for WriterInner<W> {
597    #[inline(always)]
598    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
599        match *self {
600            WriterInner::NoColor(ref mut wtr) => wtr.write(buf),
601            WriterInner::Ansi(ref mut wtr) => wtr.write(buf),
602            #[cfg(windows)]
603            WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf),
604        }
605    }
606
607    #[inline(always)]
608    fn flush(&mut self) -> io::Result<()> {
609        match *self {
610            WriterInner::NoColor(ref mut wtr) => wtr.flush(),
611            WriterInner::Ansi(ref mut wtr) => wtr.flush(),
612            #[cfg(windows)]
613            WriterInner::Windows { ref mut wtr, .. } => wtr.flush(),
614        }
615    }
616}
617
618impl<W: io::Write> WriteColor for WriterInner<W> {
619    fn supports_color(&self) -> bool {
620        match *self {
621            WriterInner::NoColor(_) => false,
622            WriterInner::Ansi(_) => true,
623            #[cfg(windows)]
624            WriterInner::Windows { .. } => true,
625        }
626    }
627
628    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
629        match *self {
630            WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
631            WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec),
632            #[cfg(windows)]
633            WriterInner::Windows { ref mut wtr, ref console } => {
634                wtr.flush()?;
635                let mut console = console.lock().unwrap();
636                spec.write_console(&mut *console)
637            }
638        }
639    }
640
641    fn reset(&mut self) -> io::Result<()> {
642        match *self {
643            WriterInner::NoColor(ref mut wtr) => wtr.reset(),
644            WriterInner::Ansi(ref mut wtr) => wtr.reset(),
645            #[cfg(windows)]
646            WriterInner::Windows { ref mut wtr, ref mut console } => {
647                wtr.flush()?;
648                console.lock().unwrap().reset()?;
649                Ok(())
650            }
651        }
652    }
653
654    fn is_synchronous(&self) -> bool {
655        match *self {
656            WriterInner::NoColor(_) => false,
657            WriterInner::Ansi(_) => false,
658            #[cfg(windows)]
659            WriterInner::Windows {..} => true,
660        }
661    }
662}
663
664impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> {
665    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
666        match *self {
667            WriterInnerLock::Unreachable(_) => unreachable!(),
668            WriterInnerLock::NoColor(ref mut wtr) => wtr.write(buf),
669            WriterInnerLock::Ansi(ref mut wtr) => wtr.write(buf),
670            #[cfg(windows)]
671            WriterInnerLock::Windows { ref mut wtr, .. } => wtr.write(buf),
672        }
673    }
674
675    fn flush(&mut self) -> io::Result<()> {
676        match *self {
677            WriterInnerLock::Unreachable(_) => unreachable!(),
678            WriterInnerLock::NoColor(ref mut wtr) => wtr.flush(),
679            WriterInnerLock::Ansi(ref mut wtr) => wtr.flush(),
680            #[cfg(windows)]
681            WriterInnerLock::Windows { ref mut wtr, .. } => wtr.flush(),
682        }
683    }
684}
685
686impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
687    fn supports_color(&self) -> bool {
688        match *self {
689            WriterInnerLock::Unreachable(_) => unreachable!(),
690            WriterInnerLock::NoColor(_) => false,
691            WriterInnerLock::Ansi(_) => true,
692            #[cfg(windows)]
693            WriterInnerLock::Windows { .. } => true,
694        }
695    }
696
697    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
698        match *self {
699            WriterInnerLock::Unreachable(_) => unreachable!(),
700            WriterInnerLock::NoColor(ref mut wtr) => wtr.set_color(spec),
701            WriterInnerLock::Ansi(ref mut wtr) => wtr.set_color(spec),
702            #[cfg(windows)]
703            WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
704                wtr.flush()?;
705                spec.write_console(console)
706            }
707        }
708    }
709
710    fn reset(&mut self) -> io::Result<()> {
711        match *self {
712            WriterInnerLock::Unreachable(_) => unreachable!(),
713            WriterInnerLock::NoColor(ref mut wtr) => wtr.reset(),
714            WriterInnerLock::Ansi(ref mut wtr) => wtr.reset(),
715            #[cfg(windows)]
716            WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
717                wtr.flush()?;
718                console.reset()?;
719                Ok(())
720            }
721        }
722    }
723
724    fn is_synchronous(&self) -> bool {
725        match *self {
726            WriterInnerLock::Unreachable(_) => unreachable!(),
727            WriterInnerLock::NoColor(_) => false,
728            WriterInnerLock::Ansi(_) => false,
729            #[cfg(windows)]
730            WriterInnerLock::Windows {..} => true,
731        }
732    }
733}
734
735/// Writes colored buffers to stdout or stderr.
736///
737/// Writable buffers can be obtained by calling `buffer` on a `BufferWriter`.
738///
739/// This writer works with terminals that support ANSI escape sequences or
740/// with a Windows console.
741///
742/// It is intended for a `BufferWriter` to be put in an `Arc` and written to
743/// from multiple threads simultaneously.
744pub struct BufferWriter {
745    stream: LossyStandardStream<IoStandardStream>,
746    printed: AtomicBool,
747    separator: Option<Vec<u8>>,
748    color_choice: ColorChoice,
749    #[cfg(windows)]
750    console: Option<Mutex<wincolor::Console>>,
751}
752
753impl BufferWriter {
754    /// Create a new `BufferWriter` that writes to a standard stream with the
755    /// given color preferences.
756    ///
757    /// The specific color/style settings can be configured when writing to
758    /// the buffers themselves.
759    #[cfg(not(windows))]
760    fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
761        BufferWriter {
762            stream: LossyStandardStream::new(IoStandardStream::new(sty)),
763            printed: AtomicBool::new(false),
764            separator: None,
765            color_choice: choice,
766        }
767    }
768
769    /// Create a new `BufferWriter` that writes to a standard stream with the
770    /// given color preferences.
771    ///
772    /// If coloring is desired and a Windows console could not be found, then
773    /// ANSI escape sequences are used instead.
774    ///
775    /// The specific color/style settings can be configured when writing to
776    /// the buffers themselves.
777    #[cfg(windows)]
778    fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
779        let mut con = match sty {
780            StandardStreamType::Stdout => wincolor::Console::stdout(),
781            StandardStreamType::Stderr => wincolor::Console::stderr(),
782            StandardStreamType::StdoutBuffered => wincolor::Console::stdout(),
783            StandardStreamType::StderrBuffered => wincolor::Console::stderr(),
784        }.ok();
785        let is_console_virtual = con.as_mut().map(|con| {
786            con.set_virtual_terminal_processing(true).is_ok()
787        }).unwrap_or(false);
788        // If we can enable ANSI on Windows, then we don't need the console
789        // anymore.
790        if is_console_virtual {
791            con = None;
792        }
793        let stream = LossyStandardStream::new(IoStandardStream::new(sty));
794        BufferWriter {
795            stream: stream,
796            printed: AtomicBool::new(false),
797            separator: None,
798            color_choice: choice,
799            console: con.map(Mutex::new),
800        }
801    }
802
803    /// Create a new `BufferWriter` that writes to stdout with the given
804    /// color preferences.
805    ///
806    /// On Windows, if coloring is desired and a Windows console could not be
807    /// found, then ANSI escape sequences are used instead.
808    ///
809    /// The specific color/style settings can be configured when writing to
810    /// the buffers themselves.
811    pub fn stdout(choice: ColorChoice) -> BufferWriter {
812        BufferWriter::create(StandardStreamType::Stdout, choice)
813    }
814
815    /// Create a new `BufferWriter` that writes to stderr with the given
816    /// color preferences.
817    ///
818    /// On Windows, if coloring is desired and a Windows console could not be
819    /// found, then ANSI escape sequences are used instead.
820    ///
821    /// The specific color/style settings can be configured when writing to
822    /// the buffers themselves.
823    pub fn stderr(choice: ColorChoice) -> BufferWriter {
824        BufferWriter::create(StandardStreamType::Stderr, choice)
825    }
826
827    /// If set, the separator given is printed between buffers. By default, no
828    /// separator is printed.
829    ///
830    /// The default value is `None`.
831    pub fn separator(&mut self, sep: Option<Vec<u8>>) {
832        self.separator = sep;
833    }
834
835    /// Creates a new `Buffer` with the current color preferences.
836    ///
837    /// A `Buffer` satisfies both `io::Write` and `WriteColor`. A `Buffer` can
838    /// be printed using the `print` method.
839    #[cfg(not(windows))]
840    pub fn buffer(&self) -> Buffer {
841        Buffer::new(self.color_choice)
842    }
843
844    /// Creates a new `Buffer` with the current color preferences.
845    ///
846    /// A `Buffer` satisfies both `io::Write` and `WriteColor`. A `Buffer` can
847    /// be printed using the `print` method.
848    #[cfg(windows)]
849    pub fn buffer(&self) -> Buffer {
850        Buffer::new(self.color_choice, self.console.is_some())
851    }
852
853    /// Prints the contents of the given buffer.
854    ///
855    /// It is safe to call this from multiple threads simultaneously. In
856    /// particular, all buffers are written atomically. No interleaving will
857    /// occur.
858    pub fn print(&self, buf: &Buffer) -> io::Result<()> {
859        if buf.is_empty() {
860            return Ok(());
861        }
862        let mut stream = self.stream.wrap(self.stream.get_ref().lock());
863        if let Some(ref sep) = self.separator {
864            if self.printed.load(Ordering::SeqCst) {
865                stream.write_all(sep)?;
866                stream.write_all(b"\n")?;
867            }
868        }
869        match buf.0 {
870            BufferInner::NoColor(ref b) => stream.write_all(&b.0)?,
871            BufferInner::Ansi(ref b) => stream.write_all(&b.0)?,
872            #[cfg(windows)]
873            BufferInner::Windows(ref b) => {
874                // We guarantee by construction that we have a console here.
875                // Namely, a BufferWriter is the only way to produce a Buffer.
876                let console_mutex = self.console.as_ref()
877                    .expect("got Windows buffer but have no Console");
878                let mut console = console_mutex.lock().unwrap();
879                b.print(&mut *console, &mut stream)?;
880            }
881        }
882        self.printed.store(true, Ordering::SeqCst);
883        Ok(())
884    }
885}
886
887/// Write colored text to memory.
888///
889/// `Buffer` is a platform independent abstraction for printing colored text to
890/// an in memory buffer. When the buffer is printed using a `BufferWriter`, the
891/// color information will be applied to the output device (a tty on Unix and a
892/// console on Windows).
893///
894/// A `Buffer` is typically created by calling the `BufferWriter.buffer`
895/// method, which will take color preferences and the environment into
896/// account. However, buffers can also be manually created using `no_color`,
897/// `ansi` or `console` (on Windows).
898pub struct Buffer(BufferInner);
899
900/// BufferInner is an enumeration of different buffer types.
901enum BufferInner {
902    /// No coloring information should be applied. This ignores all coloring
903    /// directives.
904    NoColor(NoColor<Vec<u8>>),
905    /// Apply coloring using ANSI escape sequences embedded into the buffer.
906    Ansi(Ansi<Vec<u8>>),
907    /// Apply coloring using the Windows console APIs. This buffer saves
908    /// color information in memory and only interacts with the console when
909    /// the buffer is printed.
910    #[cfg(windows)]
911    Windows(WindowsBuffer),
912}
913
914impl Buffer {
915    /// Create a new buffer with the given color settings.
916    #[cfg(not(windows))]
917    fn new(choice: ColorChoice) -> Buffer {
918        if choice.should_attempt_color() {
919            Buffer::ansi()
920        } else {
921            Buffer::no_color()
922        }
923    }
924
925    /// Create a new buffer with the given color settings.
926    ///
927    /// On Windows, one can elect to create a buffer capable of being written
928    /// to a console. Only enable it if a console is available.
929    ///
930    /// If coloring is desired and `console` is false, then ANSI escape
931    /// sequences are used instead.
932    #[cfg(windows)]
933    fn new(choice: ColorChoice, console: bool) -> Buffer {
934        if choice.should_attempt_color() {
935            if !console || choice.should_ansi() {
936                Buffer::ansi()
937            } else {
938                Buffer::console()
939            }
940        } else {
941            Buffer::no_color()
942        }
943    }
944
945    /// Create a buffer that drops all color information.
946    pub fn no_color() -> Buffer {
947        Buffer(BufferInner::NoColor(NoColor(vec![])))
948    }
949
950    /// Create a buffer that uses ANSI escape sequences.
951    pub fn ansi() -> Buffer {
952        Buffer(BufferInner::Ansi(Ansi(vec![])))
953    }
954
955    /// Create a buffer that can be written to a Windows console.
956    #[cfg(windows)]
957    pub fn console() -> Buffer {
958        Buffer(BufferInner::Windows(WindowsBuffer::new()))
959    }
960
961    /// Returns true if and only if this buffer is empty.
962    pub fn is_empty(&self) -> bool {
963        self.len() == 0
964    }
965
966    /// Returns the length of this buffer in bytes.
967    pub fn len(&self) -> usize {
968        match self.0 {
969            BufferInner::NoColor(ref b) => b.0.len(),
970            BufferInner::Ansi(ref b) => b.0.len(),
971            #[cfg(windows)]
972            BufferInner::Windows(ref b) => b.buf.len(),
973        }
974    }
975
976    /// Clears this buffer.
977    pub fn clear(&mut self) {
978        match self.0 {
979            BufferInner::NoColor(ref mut b) => b.0.clear(),
980            BufferInner::Ansi(ref mut b) => b.0.clear(),
981            #[cfg(windows)]
982            BufferInner::Windows(ref mut b) => b.clear(),
983        }
984    }
985
986    /// Consume this buffer and return the underlying raw data.
987    ///
988    /// On Windows, this unrecoverably drops all color information associated
989    /// with the buffer.
990    pub fn into_inner(self) -> Vec<u8> {
991        match self.0 {
992            BufferInner::NoColor(b) => b.0,
993            BufferInner::Ansi(b) => b.0,
994            #[cfg(windows)]
995            BufferInner::Windows(b) => b.buf,
996        }
997    }
998
999    /// Return the underlying data of the buffer.
1000    pub fn as_slice(&self) -> &[u8] {
1001        match self.0 {
1002            BufferInner::NoColor(ref b) => &b.0,
1003            BufferInner::Ansi(ref b) => &b.0,
1004            #[cfg(windows)]
1005            BufferInner::Windows(ref b) => &b.buf,
1006        }
1007    }
1008
1009    /// Return the underlying data of the buffer as a mutable slice.
1010    pub fn as_mut_slice(&mut self) -> &mut [u8] {
1011        match self.0 {
1012            BufferInner::NoColor(ref mut b) => &mut b.0,
1013            BufferInner::Ansi(ref mut b) => &mut b.0,
1014            #[cfg(windows)]
1015            BufferInner::Windows(ref mut b) => &mut b.buf,
1016        }
1017    }
1018}
1019
1020impl io::Write for Buffer {
1021    #[inline]
1022    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1023        match self.0 {
1024            BufferInner::NoColor(ref mut w) => w.write(buf),
1025            BufferInner::Ansi(ref mut w) => w.write(buf),
1026            #[cfg(windows)]
1027            BufferInner::Windows(ref mut w) => w.write(buf),
1028        }
1029    }
1030
1031    #[inline]
1032    fn flush(&mut self) -> io::Result<()> {
1033        match self.0 {
1034            BufferInner::NoColor(ref mut w) => w.flush(),
1035            BufferInner::Ansi(ref mut w) => w.flush(),
1036            #[cfg(windows)]
1037            BufferInner::Windows(ref mut w) => w.flush(),
1038        }
1039    }
1040}
1041
1042impl WriteColor for Buffer {
1043    #[inline]
1044    fn supports_color(&self) -> bool {
1045        match self.0 {
1046            BufferInner::NoColor(_) => false,
1047            BufferInner::Ansi(_) => true,
1048            #[cfg(windows)]
1049            BufferInner::Windows(_) => true,
1050        }
1051    }
1052
1053    #[inline]
1054    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1055        match self.0 {
1056            BufferInner::NoColor(ref mut w) => w.set_color(spec),
1057            BufferInner::Ansi(ref mut w) => w.set_color(spec),
1058            #[cfg(windows)]
1059            BufferInner::Windows(ref mut w) => w.set_color(spec),
1060        }
1061    }
1062
1063    #[inline]
1064    fn reset(&mut self) -> io::Result<()> {
1065        match self.0 {
1066            BufferInner::NoColor(ref mut w) => w.reset(),
1067            BufferInner::Ansi(ref mut w) => w.reset(),
1068            #[cfg(windows)]
1069            BufferInner::Windows(ref mut w) => w.reset(),
1070        }
1071    }
1072
1073    #[inline]
1074    fn is_synchronous(&self) -> bool {
1075        false
1076    }
1077}
1078
1079/// Satisfies `WriteColor` but ignores all color options.
1080pub struct NoColor<W>(W);
1081
1082impl<W: Write> NoColor<W> {
1083    /// Create a new writer that satisfies `WriteColor` but drops all color
1084    /// information.
1085    pub fn new(wtr: W) -> NoColor<W> { NoColor(wtr) }
1086
1087    /// Consume this `NoColor` value and return the inner writer.
1088    pub fn into_inner(self) -> W { self.0 }
1089
1090    /// Return a reference to the inner writer.
1091    pub fn get_ref(&self) -> &W { &self.0 }
1092
1093    /// Return a mutable reference to the inner writer.
1094    pub fn get_mut(&mut self) -> &mut W { &mut self.0 }
1095}
1096
1097impl<W: io::Write> io::Write for NoColor<W> {
1098    #[inline]
1099    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1100        self.0.write(buf)
1101    }
1102
1103    #[inline]
1104    fn flush(&mut self) -> io::Result<()> {
1105        self.0.flush()
1106    }
1107}
1108
1109impl<W: io::Write> WriteColor for NoColor<W> {
1110    #[inline]
1111    fn supports_color(&self) -> bool { false }
1112
1113    #[inline]
1114    fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> { Ok(()) }
1115
1116    #[inline]
1117    fn reset(&mut self) -> io::Result<()> { Ok(()) }
1118
1119    #[inline]
1120    fn is_synchronous(&self) -> bool { false }
1121}
1122
1123/// Satisfies `WriteColor` using standard ANSI escape sequences.
1124pub struct Ansi<W>(W);
1125
1126impl<W: Write> Ansi<W> {
1127    /// Create a new writer that satisfies `WriteColor` using standard ANSI
1128    /// escape sequences.
1129    pub fn new(wtr: W) -> Ansi<W> { Ansi(wtr) }
1130
1131    /// Consume this `Ansi` value and return the inner writer.
1132    pub fn into_inner(self) -> W { self.0 }
1133
1134    /// Return a reference to the inner writer.
1135    pub fn get_ref(&self) -> &W { &self.0 }
1136
1137    /// Return a mutable reference to the inner writer.
1138    pub fn get_mut(&mut self) -> &mut W { &mut self.0 }
1139}
1140
1141impl<W: io::Write> io::Write for Ansi<W> {
1142    #[inline]
1143    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1144        self.0.write(buf)
1145    }
1146
1147    #[inline]
1148    fn flush(&mut self) -> io::Result<()> {
1149        self.0.flush()
1150    }
1151}
1152
1153impl<W: io::Write> WriteColor for Ansi<W> {
1154    #[inline]
1155    fn supports_color(&self) -> bool { true }
1156
1157    #[inline]
1158    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1159        self.reset()?;
1160        if spec.bold {
1161            self.write_str("\x1B[1m")?;
1162        }
1163        if spec.underline {
1164            self.write_str("\x1B[4m")?;
1165        }
1166        if let Some(ref c) = spec.fg_color {
1167            self.write_color(true, c, spec.intense)?;
1168        }
1169        if let Some(ref c) = spec.bg_color {
1170            self.write_color(false, c, spec.intense)?;
1171        }
1172        Ok(())
1173    }
1174
1175    #[inline]
1176    fn reset(&mut self) -> io::Result<()> {
1177        self.write_str("\x1B[0m")
1178    }
1179
1180    #[inline]
1181    fn is_synchronous(&self) -> bool { false }
1182}
1183
1184impl<W: io::Write> Ansi<W> {
1185    fn write_str(&mut self, s: &str) -> io::Result<()> {
1186        self.write_all(s.as_bytes())
1187    }
1188
1189    fn write_color(
1190        &mut self,
1191        fg: bool,
1192        c: &Color,
1193        intense: bool,
1194    ) -> io::Result<()> {
1195        macro_rules! write_intense {
1196            ($clr:expr) => {
1197                if fg {
1198                    self.write_str(concat!("\x1B[38;5;", $clr, "m"))
1199                } else {
1200                    self.write_str(concat!("\x1B[48;5;", $clr, "m"))
1201                }
1202            }
1203        }
1204        macro_rules! write_normal {
1205            ($clr:expr) => {
1206                if fg {
1207                    self.write_str(concat!("\x1B[3", $clr, "m"))
1208                } else {
1209                    self.write_str(concat!("\x1B[4", $clr, "m"))
1210                }
1211            }
1212        }
1213        macro_rules! write_var_ansi_code {
1214            ($pre:expr, $($code:expr),+) => {{
1215                // The loop generates at worst a literal of the form
1216                // '255,255,255m' which is 12-bytes.
1217                // The largest `pre` expression we currently use is 7 bytes.
1218                // This gives us the maximum of 19-bytes for our work buffer.
1219                let pre_len = $pre.len();
1220                assert!(pre_len <= 7);
1221                let mut fmt = [0u8; 19];
1222                fmt[..pre_len].copy_from_slice($pre);
1223                let mut i = pre_len - 1;
1224                $(
1225                    let c1: u8 = ($code / 100) % 10;
1226                    let c2: u8 = ($code / 10) % 10;
1227                    let c3: u8 = $code % 10;
1228                    let mut printed = false;
1229
1230                    if c1 != 0 {
1231                        printed = true;
1232                        i += 1;
1233                        fmt[i] = b'0' + c1;
1234                    }
1235                    if c2 != 0 || printed {
1236                        i += 1;
1237                        fmt[i] = b'0' + c2;
1238                    }
1239                    // If we received a zero value we must still print a value.
1240                    i += 1;
1241                    fmt[i] = b'0' + c3;
1242                    i += 1;
1243                    fmt[i] = b';';
1244                )+
1245
1246                fmt[i] = b'm';
1247                self.write_all(&fmt[0..i+1])
1248            }}
1249        }
1250        macro_rules! write_custom {
1251            ($ansi256:expr) => {
1252                if fg {
1253                    write_var_ansi_code!(b"\x1B[38;5;", $ansi256)
1254                } else {
1255                    write_var_ansi_code!(b"\x1B[48;5;", $ansi256)
1256                }
1257            };
1258
1259            ($r:expr, $g:expr, $b:expr) => {{
1260                if fg {
1261                    write_var_ansi_code!(b"\x1B[38;2;", $r, $g, $b)
1262                } else {
1263                    write_var_ansi_code!(b"\x1B[48;2;", $r, $g, $b)
1264                }
1265            }};
1266        }
1267        if intense {
1268            match *c {
1269                Color::Black => write_intense!("8"),
1270                Color::Blue => write_intense!("12"),
1271                Color::Green => write_intense!("10"),
1272                Color::Red => write_intense!("9"),
1273                Color::Cyan => write_intense!("14"),
1274                Color::Magenta => write_intense!("13"),
1275                Color::Yellow => write_intense!("11"),
1276                Color::White => write_intense!("15"),
1277                Color::Ansi256(c) => write_custom!(c),
1278                Color::Rgb(r, g, b) => write_custom!(r, g, b),
1279                Color::__Nonexhaustive => unreachable!(),
1280            }
1281        } else {
1282            match *c {
1283                Color::Black => write_normal!("0"),
1284                Color::Blue => write_normal!("4"),
1285                Color::Green => write_normal!("2"),
1286                Color::Red => write_normal!("1"),
1287                Color::Cyan => write_normal!("6"),
1288                Color::Magenta => write_normal!("5"),
1289                Color::Yellow => write_normal!("3"),
1290                Color::White => write_normal!("7"),
1291                Color::Ansi256(c) => write_custom!(c),
1292                Color::Rgb(r, g, b) => write_custom!(r, g, b),
1293                Color::__Nonexhaustive => unreachable!(),
1294            }
1295        }
1296    }
1297}
1298
1299/// An in-memory buffer that provides Windows console coloring.
1300///
1301/// This doesn't actually communicate with the Windows console. Instead, it
1302/// acts like a normal buffer but also saves the color information associated
1303/// with positions in the buffer. It is only when the buffer is written to the
1304/// console that coloring is actually applied.
1305///
1306/// This is roughly isomorphic to the ANSI based approach (i.e.,
1307/// `Ansi<Vec<u8>>`), except with ANSI, the color information is embedded
1308/// directly into the buffer.
1309///
1310/// Note that there is no way to write something generic like
1311/// `WindowsConsole<W: io::Write>` since coloring on Windows is tied
1312/// specifically to the console APIs, and therefore can't work on arbitrary
1313/// writers.
1314#[cfg(windows)]
1315#[derive(Clone, Debug)]
1316struct WindowsBuffer {
1317    /// The actual content that should be printed.
1318    buf: Vec<u8>,
1319    /// A sequence of position oriented color specifications. Namely, each
1320    /// element is a position and a color spec, where the color spec should
1321    /// be applied at the position inside of `buf`.
1322    ///
1323    /// A missing color spec implies the underlying console should be reset.
1324    colors: Vec<(usize, Option<ColorSpec>)>,
1325}
1326
1327#[cfg(windows)]
1328impl WindowsBuffer {
1329    /// Create a new empty buffer for Windows console coloring.
1330    fn new() -> WindowsBuffer {
1331        WindowsBuffer {
1332            buf: vec![],
1333            colors: vec![],
1334        }
1335    }
1336
1337    /// Push the given color specification into this buffer.
1338    ///
1339    /// This has the effect of setting the given color information at the
1340    /// current position in the buffer.
1341    fn push(&mut self, spec: Option<ColorSpec>) {
1342        let pos = self.buf.len();
1343        self.colors.push((pos, spec));
1344    }
1345
1346    /// Print the contents to the given stream handle, and use the console
1347    /// for coloring.
1348    fn print(
1349        &self,
1350        console: &mut wincolor::Console,
1351        stream: &mut LossyStandardStream<IoStandardStreamLock>,
1352    ) -> io::Result<()> {
1353        let mut last = 0;
1354        for &(pos, ref spec) in &self.colors {
1355            stream.write_all(&self.buf[last..pos])?;
1356            stream.flush()?;
1357            last = pos;
1358            match *spec {
1359                None => console.reset()?,
1360                Some(ref spec) => spec.write_console(console)?,
1361            }
1362        }
1363        stream.write_all(&self.buf[last..])?;
1364        stream.flush()
1365    }
1366
1367    /// Clear the buffer.
1368    fn clear(&mut self) {
1369        self.buf.clear();
1370        self.colors.clear();
1371    }
1372}
1373
1374#[cfg(windows)]
1375impl io::Write for WindowsBuffer {
1376    #[inline]
1377    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1378        self.buf.extend_from_slice(buf);
1379        Ok(buf.len())
1380    }
1381
1382    #[inline]
1383    fn flush(&mut self) -> io::Result<()> {
1384        Ok(())
1385    }
1386}
1387
1388#[cfg(windows)]
1389impl WriteColor for WindowsBuffer {
1390    #[inline]
1391    fn supports_color(&self) -> bool { true }
1392
1393    #[inline]
1394    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1395        self.push(Some(spec.clone()));
1396        Ok(())
1397    }
1398
1399    #[inline]
1400    fn reset(&mut self) -> io::Result<()> {
1401        self.push(None);
1402        Ok(())
1403    }
1404
1405    #[inline]
1406    fn is_synchronous(&self) -> bool {
1407        false
1408    }
1409}
1410
1411/// A color specification.
1412#[derive(Clone, Debug, Default, Eq, PartialEq)]
1413pub struct ColorSpec {
1414    fg_color: Option<Color>,
1415    bg_color: Option<Color>,
1416    bold: bool,
1417    intense: bool,
1418    underline: bool,
1419}
1420
1421impl ColorSpec {
1422    /// Create a new color specification that has no colors or styles.
1423    pub fn new() -> ColorSpec {
1424        ColorSpec::default()
1425    }
1426
1427    /// Get the foreground color.
1428    pub fn fg(&self) -> Option<&Color> { self.fg_color.as_ref() }
1429
1430    /// Set the foreground color.
1431    pub fn set_fg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1432        self.fg_color = color;
1433        self
1434    }
1435
1436    /// Get the background color.
1437    pub fn bg(&self) -> Option<&Color> { self.bg_color.as_ref() }
1438
1439    /// Set the background color.
1440    pub fn set_bg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1441        self.bg_color = color;
1442        self
1443    }
1444
1445    /// Get whether this is bold or not.
1446    ///
1447    /// Note that the bold setting has no effect in a Windows console.
1448    pub fn bold(&self) -> bool { self.bold }
1449
1450    /// Set whether the text is bolded or not.
1451    ///
1452    /// Note that the bold setting has no effect in a Windows console.
1453    pub fn set_bold(&mut self, yes: bool) -> &mut ColorSpec {
1454        self.bold = yes;
1455        self
1456    }
1457
1458    /// Get whether this is underline or not.
1459    ///
1460    /// Note that the underline setting has no effect in a Windows console.
1461    pub fn underline(&self) -> bool { self.underline }
1462
1463    /// Set whether the text is underlined or not.
1464    ///
1465    /// Note that the underline setting has no effect in a Windows console.
1466    pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec {
1467        self.underline = yes;
1468        self
1469    }
1470
1471    /// Get whether this is intense or not.
1472    ///
1473    /// On Unix-like systems, this will output the ANSI escape sequence
1474    /// that will print a high-intensity version of the color
1475    /// specified.
1476    ///
1477    /// On Windows systems, this will output the ANSI escape sequence
1478    /// that will print a brighter version of the color specified.
1479    pub fn intense(&self) -> bool { self.intense }
1480
1481    /// Set whether the text is intense or not.
1482    ///
1483    /// On Unix-like systems, this will output the ANSI escape sequence
1484    /// that will print a high-intensity version of the color
1485    /// specified.
1486    ///
1487    /// On Windows systems, this will output the ANSI escape sequence
1488    /// that will print a brighter version of the color specified.
1489    pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec {
1490        self.intense = yes;
1491        self
1492    }
1493
1494    /// Returns true if this color specification has no colors or styles.
1495    pub fn is_none(&self) -> bool {
1496        self.fg_color.is_none() && self.bg_color.is_none()
1497            && !self.bold && !self.underline
1498    }
1499
1500    /// Clears this color specification so that it has no color/style settings.
1501    pub fn clear(&mut self) {
1502        self.fg_color = None;
1503        self.bg_color = None;
1504        self.bold = false;
1505        self.underline = false;
1506    }
1507
1508    /// Writes this color spec to the given Windows console.
1509    #[cfg(windows)]
1510    fn write_console(
1511        &self,
1512        console: &mut wincolor::Console,
1513    ) -> io::Result<()> {
1514        let fg_color = self.fg_color.and_then(|c| c.to_windows(self.intense));
1515        if let Some((intense, color)) = fg_color {
1516            console.fg(intense, color)?;
1517        }
1518        let bg_color = self.bg_color.and_then(|c| c.to_windows(self.intense));
1519        if let Some((intense, color)) = bg_color {
1520            console.bg(intense, color)?;
1521        }
1522        Ok(())
1523    }
1524}
1525
1526/// The set of available colors for the terminal foreground/background.
1527///
1528/// The `Ansi256` and `Rgb` colors will only output the correct codes when
1529/// paired with the `Ansi` `WriteColor` implementation.
1530///
1531/// The `Ansi256` and `Rgb` color types are not supported when writing colors
1532/// on Windows using the console. If they are used on Windows, then they are
1533/// silently ignored and no colors will be emitted.
1534///
1535/// This set may expand over time.
1536///
1537/// This type has a `FromStr` impl that can parse colors from their human
1538/// readable form. The format is as follows:
1539///
1540/// 1. Any of the explicitly listed colors in English. They are matched
1541///    case insensitively.
1542/// 2. A single 8-bit integer, in either decimal or hexadecimal format.
1543/// 3. A triple of 8-bit integers separated by a comma, where each integer is
1544///    in decimal or hexadecimal format.
1545///
1546/// Hexadecimal numbers are written with a `0x` prefix.
1547#[allow(missing_docs)]
1548#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1549pub enum Color {
1550    Black,
1551    Blue,
1552    Green,
1553    Red,
1554    Cyan,
1555    Magenta,
1556    Yellow,
1557    White,
1558    Ansi256(u8),
1559    Rgb(u8, u8, u8),
1560    #[doc(hidden)]
1561    __Nonexhaustive,
1562}
1563
1564impl Color {
1565    /// Translate this color to a wincolor::Color.
1566    #[cfg(windows)]
1567    fn to_windows(
1568        self,
1569        intense: bool,
1570    ) -> Option<(wincolor::Intense, wincolor::Color)> {
1571        use wincolor::Intense::{Yes, No};
1572
1573        let color = match self {
1574            Color::Black => wincolor::Color::Black,
1575            Color::Blue => wincolor::Color::Blue,
1576            Color::Green => wincolor::Color::Green,
1577            Color::Red => wincolor::Color::Red,
1578            Color::Cyan => wincolor::Color::Cyan,
1579            Color::Magenta => wincolor::Color::Magenta,
1580            Color::Yellow => wincolor::Color::Yellow,
1581            Color::White => wincolor::Color::White,
1582            Color::Ansi256(0) => return Some((No, wincolor::Color::Black)),
1583            Color::Ansi256(1) => return Some((No, wincolor::Color::Red)),
1584            Color::Ansi256(2) => return Some((No, wincolor::Color::Green)),
1585            Color::Ansi256(3) => return Some((No, wincolor::Color::Yellow)),
1586            Color::Ansi256(4) => return Some((No, wincolor::Color::Blue)),
1587            Color::Ansi256(5) => return Some((No, wincolor::Color::Magenta)),
1588            Color::Ansi256(6) => return Some((No, wincolor::Color::Cyan)),
1589            Color::Ansi256(7) => return Some((No, wincolor::Color::White)),
1590            Color::Ansi256(8) => return Some((Yes, wincolor::Color::Black)),
1591            Color::Ansi256(9) => return Some((Yes, wincolor::Color::Red)),
1592            Color::Ansi256(10) => return Some((Yes, wincolor::Color::Green)),
1593            Color::Ansi256(11) => return Some((Yes, wincolor::Color::Yellow)),
1594            Color::Ansi256(12) => return Some((Yes, wincolor::Color::Blue)),
1595            Color::Ansi256(13) => return Some((Yes, wincolor::Color::Magenta)),
1596            Color::Ansi256(14) => return Some((Yes, wincolor::Color::Cyan)),
1597            Color::Ansi256(15) => return Some((Yes, wincolor::Color::White)),
1598            Color::Ansi256(_) => return None,
1599            Color::Rgb(_, _, _) => return None,
1600            Color::__Nonexhaustive => unreachable!(),
1601        };
1602        let intense = if intense { Yes } else { No };
1603        Some((intense, color))
1604    }
1605
1606    /// Parses a numeric color string, either ANSI or RGB.
1607    fn from_str_numeric(s: &str) -> Result<Color, ParseColorError> {
1608        // The "ansi256" format is a single number (decimal or hex)
1609        // corresponding to one of 256 colors.
1610        //
1611        // The "rgb" format is a triple of numbers (decimal or hex) delimited
1612        // by a comma corresponding to one of 256^3 colors.
1613
1614        fn parse_number(s: &str) -> Option<u8> {
1615            use std::u8;
1616
1617            if s.starts_with("0x") {
1618                u8::from_str_radix(&s[2..], 16).ok()
1619            } else {
1620                u8::from_str_radix(s, 10).ok()
1621            }
1622        }
1623
1624        let codes: Vec<&str> = s.split(',').collect();
1625        if codes.len() == 1 {
1626            if let Some(n) = parse_number(&codes[0]) {
1627                Ok(Color::Ansi256(n))
1628            } else {
1629                if s.chars().all(|c| c.is_digit(16)) {
1630                    Err(ParseColorError {
1631                        kind: ParseColorErrorKind::InvalidAnsi256,
1632                        given: s.to_string(),
1633                    })
1634                } else {
1635                    Err(ParseColorError {
1636                        kind: ParseColorErrorKind::InvalidName,
1637                        given: s.to_string(),
1638                    })
1639                }
1640            }
1641        } else if codes.len() == 3 {
1642            let mut v = vec![];
1643            for code in codes {
1644                let n = parse_number(code).ok_or_else(|| {
1645                    ParseColorError {
1646                        kind: ParseColorErrorKind::InvalidRgb,
1647                        given: s.to_string(),
1648                    }
1649                })?;
1650                v.push(n);
1651            }
1652            Ok(Color::Rgb(v[0], v[1], v[2]))
1653        } else {
1654            Err(if s.contains(",") {
1655                ParseColorError {
1656                    kind: ParseColorErrorKind::InvalidRgb,
1657                    given: s.to_string(),
1658                }
1659            } else {
1660                ParseColorError {
1661                    kind: ParseColorErrorKind::InvalidName,
1662                    given: s.to_string(),
1663                }
1664            })
1665        }
1666    }
1667}
1668
1669/// An error from parsing an invalid color specification.
1670#[derive(Clone, Debug, Eq, PartialEq)]
1671pub struct ParseColorError {
1672    kind: ParseColorErrorKind,
1673    given: String,
1674}
1675
1676#[derive(Clone, Debug, Eq, PartialEq)]
1677enum ParseColorErrorKind {
1678    InvalidName,
1679    InvalidAnsi256,
1680    InvalidRgb,
1681}
1682
1683impl ParseColorError {
1684    /// Return the string that couldn't be parsed as a valid color.
1685    pub fn invalid(&self) -> &str { &self.given }
1686}
1687
1688impl error::Error for ParseColorError {
1689    fn description(&self) -> &str {
1690        use self::ParseColorErrorKind::*;
1691        match self.kind {
1692            InvalidName => "unrecognized color name",
1693            InvalidAnsi256 => "invalid ansi256 color number",
1694            InvalidRgb => "invalid RGB color triple",
1695        }
1696    }
1697}
1698
1699impl fmt::Display for ParseColorError {
1700    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1701        use self::ParseColorErrorKind::*;
1702        match self.kind {
1703            InvalidName => {
1704                write!(f, "unrecognized color name '{}'. Choose from: \
1705                        black, blue, green, red, cyan, magenta, yellow, \
1706                        white",
1707                        self.given)
1708            }
1709            InvalidAnsi256 => {
1710                write!(f, "unrecognized ansi256 color number, \
1711                           should be '[0-255]' (or a hex number), but is '{}'",
1712                           self.given)
1713            }
1714            InvalidRgb => {
1715                write!(f, "unrecognized RGB color triple, \
1716                           should be '[0-255],[0-255],[0-255]' (or a hex \
1717                           triple), but is '{}'", self.given)
1718            }
1719        }
1720    }
1721}
1722
1723impl FromStr for Color {
1724    type Err = ParseColorError;
1725
1726    fn from_str(s: &str) -> Result<Color, ParseColorError> {
1727        match &*s.to_lowercase() {
1728            "black" => Ok(Color::Black),
1729            "blue" => Ok(Color::Blue),
1730            "green" => Ok(Color::Green),
1731            "red" => Ok(Color::Red),
1732            "cyan" => Ok(Color::Cyan),
1733            "magenta" => Ok(Color::Magenta),
1734            "yellow" => Ok(Color::Yellow),
1735            "white" => Ok(Color::White),
1736            _ => Color::from_str_numeric(s),
1737        }
1738    }
1739}
1740
1741struct LossyStandardStream<W> {
1742    wtr: W,
1743    #[cfg(windows)]
1744    is_console: bool,
1745}
1746
1747impl<W: io::Write> LossyStandardStream<W> {
1748    #[cfg(not(windows))]
1749    fn new(wtr: W) -> LossyStandardStream<W> {
1750        LossyStandardStream { wtr: wtr }
1751    }
1752
1753    #[cfg(windows)]
1754    fn new(wtr: W) -> LossyStandardStream<W> {
1755        let is_console =
1756            wincolor::Console::stdout().is_ok()
1757            || wincolor::Console::stderr().is_ok();
1758        LossyStandardStream { wtr: wtr, is_console: is_console }
1759    }
1760
1761    #[cfg(not(windows))]
1762    fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
1763        LossyStandardStream::new(wtr)
1764    }
1765
1766    #[cfg(windows)]
1767    fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
1768        LossyStandardStream { wtr: wtr, is_console: self.is_console }
1769    }
1770
1771    fn get_ref(&self) -> &W {
1772        &self.wtr
1773    }
1774}
1775
1776impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
1777    fn supports_color(&self) -> bool { self.wtr.supports_color() }
1778    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1779        self.wtr.set_color(spec)
1780    }
1781    fn reset(&mut self) -> io::Result<()> { self.wtr.reset() }
1782    fn is_synchronous(&self) -> bool { self.wtr.is_synchronous() }
1783}
1784
1785impl<W: io::Write> io::Write for LossyStandardStream<W> {
1786    #[cfg(not(windows))]
1787    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1788        self.wtr.write(buf)
1789    }
1790
1791    #[cfg(windows)]
1792    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1793        if self.is_console {
1794            write_lossy_utf8(&mut self.wtr, buf)
1795        } else {
1796            self.wtr.write(buf)
1797        }
1798    }
1799
1800    fn flush(&mut self) -> io::Result<()> {
1801        self.wtr.flush()
1802    }
1803}
1804
1805#[cfg(windows)]
1806fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
1807    match ::std::str::from_utf8(buf) {
1808        Ok(s) => w.write(s.as_bytes()),
1809        Err(ref e) if e.valid_up_to() == 0 => {
1810            w.write(b"\xEF\xBF\xBD")?;
1811            Ok(1)
1812        }
1813        Err(e) => w.write(&buf[..e.valid_up_to()]),
1814    }
1815}
1816
1817#[cfg(test)]
1818mod tests {
1819    use super::{
1820        Ansi, Color, ParseColorError, ParseColorErrorKind, StandardStream,
1821    };
1822
1823    fn assert_is_send<T: Send>() {}
1824
1825    #[test]
1826    fn standard_stream_is_send() {
1827        assert_is_send::<StandardStream>();
1828    }
1829
1830    #[test]
1831    fn test_simple_parse_ok() {
1832        let color = "green".parse::<Color>();
1833        assert_eq!(color, Ok(Color::Green));
1834    }
1835
1836    #[test]
1837    fn test_256_parse_ok() {
1838        let color = "7".parse::<Color>();
1839        assert_eq!(color, Ok(Color::Ansi256(7)));
1840
1841        let color = "32".parse::<Color>();
1842        assert_eq!(color, Ok(Color::Ansi256(32)));
1843
1844        let color = "0xFF".parse::<Color>();
1845        assert_eq!(color, Ok(Color::Ansi256(0xFF)));
1846    }
1847
1848    #[test]
1849    fn test_256_parse_err_out_of_range() {
1850        let color = "256".parse::<Color>();
1851        assert_eq!(color, Err(ParseColorError {
1852            kind: ParseColorErrorKind::InvalidAnsi256,
1853            given: "256".to_string(),
1854        }));
1855    }
1856
1857    #[test]
1858    fn test_rgb_parse_ok() {
1859        let color = "0,0,0".parse::<Color>();
1860        assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
1861
1862        let color = "0,128,255".parse::<Color>();
1863        assert_eq!(color, Ok(Color::Rgb(0, 128, 255)));
1864
1865        let color = "0x0,0x0,0x0".parse::<Color>();
1866        assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
1867
1868        let color = "0x33,0x66,0xFF".parse::<Color>();
1869        assert_eq!(color, Ok(Color::Rgb(0x33, 0x66, 0xFF)));
1870    }
1871
1872    #[test]
1873    fn test_rgb_parse_err_out_of_range() {
1874        let color = "0,0,256".parse::<Color>();
1875        assert_eq!(color, Err(ParseColorError {
1876            kind: ParseColorErrorKind::InvalidRgb,
1877            given: "0,0,256".to_string(),
1878        }));
1879    }
1880
1881    #[test]
1882    fn test_rgb_parse_err_bad_format() {
1883        let color = "0,0".parse::<Color>();
1884        assert_eq!(color, Err(ParseColorError {
1885            kind: ParseColorErrorKind::InvalidRgb,
1886            given: "0,0".to_string(),
1887        }));
1888
1889        let color = "not_a_color".parse::<Color>();
1890        assert_eq!(color, Err(ParseColorError {
1891            kind: ParseColorErrorKind::InvalidName,
1892            given: "not_a_color".to_string(),
1893        }));
1894    }
1895
1896    #[test]
1897    fn test_var_ansi_write_rgb() {
1898        let mut buf = Ansi::new(vec![]);
1899        let _ = buf.write_color(true, &Color::Rgb(254, 253, 255), false);
1900        assert_eq!(buf.0, b"\x1B[38;2;254;253;255m");
1901    }
1902
1903    #[test]
1904    fn test_var_ansi_write_256() {
1905        let mut buf = Ansi::new(vec![]);
1906        let _ = buf.write_color(false, &Color::Ansi256(7), false);
1907        assert_eq!(buf.0, b"\x1B[48;5;7m");
1908
1909        let mut buf = Ansi::new(vec![]);
1910        let _ = buf.write_color(false, &Color::Ansi256(208), false);
1911        assert_eq!(buf.0, b"\x1B[48;5;208m");
1912    }
1913}