2 This crate provides a cross platform abstraction for writing colored text to
3 a terminal. Colors are written using either ANSI escape sequences or by
4 communicating with a Windows console. Much of this API was motivated by use
5 inside command line applications, where colors or styles can be configured
6 by the end user and/or the environment.
8 This crate also provides platform independent support for writing colored text
9 to an in memory buffer. While this is easy to do with ANSI escape sequences
10 (because they are in the buffer themselves), it is trickier to do with the
11 Windows console API, which requires synchronous communication.
15 The `WriteColor` trait extends the `io::Write` trait with methods for setting
16 colors or resetting them.
18 `StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are
19 analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr`
20 and `std::io::StderrLock`.
22 `Buffer` is an in memory buffer that supports colored text. In a parallel
23 program, each thread might write to its own buffer. A buffer can be printed to
24 using a `BufferWriter`. The advantage of this design is that each thread can
25 work in parallel on a buffer without having to synchronize access to global
26 resources such as the Windows console. Moreover, this design also prevents
27 interleaving of buffer output.
29 `Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of
30 `io::Write`. These types are useful when you know exactly what you need. An
31 analogous type for the Windows console is not provided since it cannot exist.
33 # Example: using `StandardStream`
35 The `StandardStream` type in this crate works similarly to `std::io::Stdout`,
36 except it is augmented with methods for coloring by the `WriteColor` trait.
37 For example, to write some green text:
40 # fn test() -> Result<(), Box<::std::error::Error>> {
42 use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
44 let mut stdout = StandardStream::stdout(ColorChoice::Always);
45 stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
46 writeln!(&mut stdout, "green text!")?;
50 Note that any text written to the terminal now will be colored
51 green when using ANSI escape sequences, even if it is written via
52 stderr, and even if stderr had previously been set to `Color::Red`.
53 Users will need to manage any color changes themselves by calling
54 [`WriteColor::set_color`](trait.WriteColor.html#tymethod.set_color), and this
55 may include calling [`WriteColor::reset`](trait.WriteColor.html#tymethod.reset)
56 before the program exits to a shell.
58 # Example: using `BufferWriter`
60 A `BufferWriter` can create buffers and write buffers to stdout or stderr. It
61 does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer`
62 implements `io::Write` and `io::WriteColor`.
64 This example shows how to print some green text to stderr.
67 # fn test() -> Result<(), Box<::std::error::Error>> {
69 use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
71 let mut bufwtr = BufferWriter::stderr(ColorChoice::Always);
72 let mut buffer = bufwtr.buffer();
73 buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
74 writeln!(&mut buffer, "green text!")?;
75 bufwtr.print(&buffer)?;
79 # Detecting presence of a terminal
81 In many scenarios when using color, one often wants to enable colors
82 automatically when writing to a terminal and disable colors automatically when
83 writing to anything else. The typical way to achieve this in Unix environments
85 [`isatty`](http://man7.org/linux/man-pages/man3/isatty.3.html)
87 Unfortunately, this notoriously does not work well in Windows environments. To
88 work around that, the currently recommended solution is to use the
89 [`atty`](https://crates.io/crates/atty)
90 crate, which goes out of its way to get this as right as possible in Windows
93 For example, in a command line application that exposes a `--color` flag,
94 your logic for how to enable colors might look like this:
98 use termcolor::{ColorChoice, StandardStream};
100 let preference = argv.get_flag("color").unwrap_or("auto");
101 let choice = match preference {
102 "always" => ColorChoice::Always,
103 "ansi" => ColorChoice::AlwaysAnsi,
105 if atty::is(atty::Stream::Stdout) {
111 _ => ColorChoice::Never,
113 let stdout = StandardStream::stdout(choice);
114 // ... write to stdout
117 Currently, `termcolor` does not provide anything to do this for you.
120 #![deny(missing_docs)]
123 use doc_comment
::doctest
;
125 doctest
!("../README.md");
130 use std
::io
::{self, Write}
;
131 use std
::str::FromStr
;
132 use std
::sync
::atomic
::{AtomicBool, Ordering}
;
134 use std
::sync
::{Mutex, MutexGuard}
;
137 use winapi_util
::console
as wincon
;
139 /// This trait describes the behavior of writers that support colored output.
140 pub trait WriteColor
: io
::Write
{
141 /// Returns true if and only if the underlying writer supports colors.
142 fn supports_color(&self) -> bool
;
144 /// Set the color settings of the writer.
146 /// Subsequent writes to this writer will use these settings until either
147 /// `reset` is called or new color settings are set.
149 /// If there was a problem setting the color settings, then an error is
151 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()>;
153 /// Reset the current color settings to their original settings.
155 /// If there was a problem resetting the color settings, then an error is
157 fn reset(&mut self) -> io
::Result
<()>;
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`.
163 /// In practice, this should return `true` if the underlying writer is
164 /// manipulating colors using the Windows console APIs.
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
{
175 impl<'a
, T
: ?Sized
+ WriteColor
> WriteColor
for &'a
mut T
{
176 fn supports_color(&self) -> bool
{
177 (&**self).supports_color()
179 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
180 (&mut **self).set_color(spec
)
182 fn reset(&mut self) -> io
::Result
<()> {
183 (&mut **self).reset()
185 fn is_synchronous(&self) -> bool
{
186 (&**self).is_synchronous()
190 impl<T
: ?Sized
+ WriteColor
> WriteColor
for Box
<T
> {
191 fn supports_color(&self) -> bool
{
192 (&**self).supports_color()
194 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
195 (&mut **self).set_color(spec
)
197 fn reset(&mut self) -> io
::Result
<()> {
198 (&mut **self).reset()
200 fn is_synchronous(&self) -> bool
{
201 (&**self).is_synchronous()
205 /// ColorChoice represents the color preferences of an end user.
206 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
207 pub enum ColorChoice
{
208 /// Try very hard to emit colors. This includes emitting ANSI colors
209 /// on Windows if the console API is unavailable.
211 /// AlwaysAnsi is like Always, except it never tries to use anything other
212 /// than emitting ANSI color codes.
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.
218 /// Never emit colors.
223 /// Returns true if we should attempt to write colored output.
224 fn should_attempt_color(&self) -> bool
{
226 ColorChoice
::Always
=> true,
227 ColorChoice
::AlwaysAnsi
=> true,
228 ColorChoice
::Never
=> false,
229 ColorChoice
::Auto
=> self.env_allows_color(),
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,
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() {
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") {
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() {
271 /// Returns true if this choice should forcefully use ANSI color codes.
273 /// It's possible that ANSI is still the correct choice even if this
276 fn should_ansi(&self) -> bool
{
278 ColorChoice
::Always
=> false,
279 ColorChoice
::AlwaysAnsi
=> true,
280 ColorChoice
::Never
=> false,
281 ColorChoice
::Auto
=> {
282 match env
::var("TERM") {
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",
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.
298 enum StandardStreamType
{
305 enum IoStandardStream
{
308 StdoutBuffered(io
::BufWriter
<io
::Stdout
>),
309 StderrBuffered(io
::BufWriter
<io
::Stderr
>),
312 impl IoStandardStream
{
313 fn new(sty
: StandardStreamType
) -> IoStandardStream
{
315 StandardStreamType
::Stdout
=> {
316 IoStandardStream
::Stdout(io
::stdout())
318 StandardStreamType
::Stderr
=> {
319 IoStandardStream
::Stderr(io
::stderr())
321 StandardStreamType
::StdoutBuffered
=> {
322 let wtr
= io
::BufWriter
::new(io
::stdout());
323 IoStandardStream
::StdoutBuffered(wtr
)
325 StandardStreamType
::StderrBuffered
=> {
326 let wtr
= io
::BufWriter
::new(io
::stderr());
327 IoStandardStream
::StderrBuffered(wtr
)
332 fn lock(&self) -> IoStandardStreamLock
<'_
> {
334 IoStandardStream
::Stdout(ref s
) => {
335 IoStandardStreamLock
::StdoutLock(s
.lock())
337 IoStandardStream
::Stderr(ref s
) => {
338 IoStandardStreamLock
::StderrLock(s
.lock())
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")
350 impl io
::Write
for IoStandardStream
{
352 fn write(&mut self, b
: &[u8]) -> io
::Result
<usize> {
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
),
362 fn flush(&mut self) -> io
::Result
<()> {
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(),
372 // Same rigmarole for the locked variants of the standard streams.
374 enum IoStandardStreamLock
<'a
> {
375 StdoutLock(io
::StdoutLock
<'a
>),
376 StderrLock(io
::StderrLock
<'a
>),
379 impl<'a
> io
::Write
for IoStandardStreamLock
<'a
> {
381 fn write(&mut self, b
: &[u8]) -> io
::Result
<usize> {
383 IoStandardStreamLock
::StdoutLock(ref mut s
) => s
.write(b
),
384 IoStandardStreamLock
::StderrLock(ref mut s
) => s
.write(b
),
389 fn flush(&mut self) -> io
::Result
<()> {
391 IoStandardStreamLock
::StdoutLock(ref mut s
) => s
.flush(),
392 IoStandardStreamLock
::StderrLock(ref mut s
) => s
.flush(),
397 /// Satisfies `io::Write` and `WriteColor`, and supports optional coloring
398 /// to either of the standard output streams, stdout and stderr.
399 pub struct StandardStream
{
400 wtr
: LossyStandardStream
<WriterInner
<IoStandardStream
>>,
403 /// `StandardStreamLock` is a locked reference to a `StandardStream`.
405 /// This implements the `io::Write` and `WriteColor` traits, and is constructed
406 /// via the `Write::lock` method.
408 /// The lifetime `'a` refers to the lifetime of the corresponding
409 /// `StandardStream`.
410 pub struct StandardStreamLock
<'a
> {
411 wtr
: LossyStandardStream
<WriterInnerLock
<'a
, IoStandardStreamLock
<'a
>>>,
414 /// Like `StandardStream`, but does buffered writing.
415 pub struct BufferedStandardStream
{
416 wtr
: LossyStandardStream
<WriterInner
<IoStandardStream
>>,
419 /// WriterInner is a (limited) generic representation of a writer. It is
420 /// limited because W should only ever be stdout/stderr on Windows.
421 enum WriterInner
<W
> {
427 console
: Mutex
<wincon
::Console
>,
431 /// WriterInnerLock is a (limited) generic representation of a writer. It is
432 /// limited because W should only ever be stdout/stderr on Windows.
433 enum WriterInnerLock
<'a
, W
> {
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
441 Unreachable(::std
::marker
::PhantomData
<&'
a ()>),
445 console
: MutexGuard
<'a
, wincon
::Console
>,
449 impl StandardStream
{
450 /// Create a new `StandardStream` with the given color preferences that
451 /// writes to standard output.
453 /// On Windows, if coloring is desired and a Windows console could not be
454 /// found, then ANSI escape sequences are used instead.
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) }
463 /// Create a new `StandardStream` with the given color preferences that
464 /// writes to standard error.
466 /// On Windows, if coloring is desired and a Windows console could not be
467 /// found, then ANSI escape sequences are used instead.
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) }
476 /// Lock the underlying writer.
478 /// The lock guard returned also satisfies `io::Write` and
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)
488 impl<'a
> StandardStreamLock
<'a
> {
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()))
495 WriterInner
::Ansi(ref w
) => {
496 WriterInnerLock
::Ansi(Ansi(w
.0.lock()))
499 StandardStreamLock { wtr: stream.wtr.wrap(locked) }
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()))
508 WriterInner
::Ansi(ref w
) => {
509 WriterInnerLock
::Ansi(Ansi(w
.0.lock()))
512 WriterInner
::Windows { ref wtr, ref console }
=> {
513 WriterInnerLock
::Windows
{
515 console
: console
.lock().unwrap(),
519 StandardStreamLock { wtr: stream.wtr.wrap(locked) }
523 impl BufferedStandardStream
{
524 /// Create a new `BufferedStandardStream` with the given color preferences
525 /// that writes to standard output via a buffered writer.
527 /// On Windows, if coloring is desired and a Windows console could not be
528 /// found, then ANSI escape sequences are used instead.
530 /// The specific color/style settings can be configured when writing via
531 /// the `WriteColor` trait.
532 pub fn stdout(choice
: ColorChoice
) -> BufferedStandardStream
{
534 WriterInner
::create(StandardStreamType
::StdoutBuffered
, choice
);
535 BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
538 /// Create a new `BufferedStandardStream` with the given color preferences
539 /// that writes to standard error via a buffered writer.
541 /// On Windows, if coloring is desired and a Windows console could not be
542 /// found, then ANSI escape sequences are used instead.
544 /// The specific color/style settings can be configured when writing via
545 /// the `WriteColor` trait.
546 pub fn stderr(choice
: ColorChoice
) -> BufferedStandardStream
{
548 WriterInner
::create(StandardStreamType
::StderrBuffered
, choice
);
549 BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
553 impl WriterInner
<IoStandardStream
> {
554 /// Create a new inner writer for a standard stream with the given color
558 sty
: StandardStreamType
,
560 ) -> WriterInner
<IoStandardStream
> {
561 if choice
.should_attempt_color() {
562 WriterInner
::Ansi(Ansi(IoStandardStream
::new(sty
)))
564 WriterInner
::NoColor(NoColor(IoStandardStream
::new(sty
)))
568 /// Create a new inner writer for a standard stream with the given color
571 /// If coloring is desired and a Windows console could not be found, then
572 /// ANSI escape sequences are used instead.
575 sty
: StandardStreamType
,
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(),
584 let is_console_virtual
= con
586 .map(|con
| con
.set_virtual_terminal_processing(true).is_ok())
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
),
597 WriterInner
::Ansi(Ansi(IoStandardStream
::new(sty
)))
600 WriterInner
::NoColor(NoColor(IoStandardStream
::new(sty
)))
605 impl io
::Write
for StandardStream
{
607 fn write(&mut self, b
: &[u8]) -> io
::Result
<usize> {
612 fn flush(&mut self) -> io
::Result
<()> {
617 impl WriteColor
for StandardStream
{
619 fn supports_color(&self) -> bool
{
620 self.wtr
.supports_color()
624 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
625 self.wtr
.set_color(spec
)
629 fn reset(&mut self) -> io
::Result
<()> {
634 fn is_synchronous(&self) -> bool
{
635 self.wtr
.is_synchronous()
639 impl<'a
> io
::Write
for StandardStreamLock
<'a
> {
641 fn write(&mut self, b
: &[u8]) -> io
::Result
<usize> {
646 fn flush(&mut self) -> io
::Result
<()> {
651 impl<'a
> WriteColor
for StandardStreamLock
<'a
> {
653 fn supports_color(&self) -> bool
{
654 self.wtr
.supports_color()
658 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
659 self.wtr
.set_color(spec
)
663 fn reset(&mut self) -> io
::Result
<()> {
668 fn is_synchronous(&self) -> bool
{
669 self.wtr
.is_synchronous()
673 impl io
::Write
for BufferedStandardStream
{
675 fn write(&mut self, b
: &[u8]) -> io
::Result
<usize> {
680 fn flush(&mut self) -> io
::Result
<()> {
685 impl WriteColor
for BufferedStandardStream
{
687 fn supports_color(&self) -> bool
{
688 self.wtr
.supports_color()
692 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
693 if self.is_synchronous() {
696 self.wtr
.set_color(spec
)
700 fn reset(&mut self) -> io
::Result
<()> {
705 fn is_synchronous(&self) -> bool
{
706 self.wtr
.is_synchronous()
710 impl<W
: io
::Write
> io
::Write
for WriterInner
<W
> {
712 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
714 WriterInner
::NoColor(ref mut wtr
) => wtr
.write(buf
),
715 WriterInner
::Ansi(ref mut wtr
) => wtr
.write(buf
),
717 WriterInner
::Windows { ref mut wtr, .. }
=> wtr
.write(buf
),
722 fn flush(&mut self) -> io
::Result
<()> {
724 WriterInner
::NoColor(ref mut wtr
) => wtr
.flush(),
725 WriterInner
::Ansi(ref mut wtr
) => wtr
.flush(),
727 WriterInner
::Windows { ref mut wtr, .. }
=> wtr
.flush(),
732 impl<W
: io
::Write
> WriteColor
for WriterInner
<W
> {
733 fn supports_color(&self) -> bool
{
735 WriterInner
::NoColor(_
) => false,
736 WriterInner
::Ansi(_
) => true,
738 WriterInner
::Windows { .. }
=> true,
742 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
744 WriterInner
::NoColor(ref mut wtr
) => wtr
.set_color(spec
),
745 WriterInner
::Ansi(ref mut wtr
) => wtr
.set_color(spec
),
747 WriterInner
::Windows { ref mut wtr, ref console }
=> {
749 let mut console
= console
.lock().unwrap();
750 spec
.write_console(&mut *console
)
755 fn reset(&mut self) -> io
::Result
<()> {
757 WriterInner
::NoColor(ref mut wtr
) => wtr
.reset(),
758 WriterInner
::Ansi(ref mut wtr
) => wtr
.reset(),
760 WriterInner
::Windows { ref mut wtr, ref mut console }
=> {
762 console
.lock().unwrap().reset()?
;
768 fn is_synchronous(&self) -> bool
{
770 WriterInner
::NoColor(_
) => false,
771 WriterInner
::Ansi(_
) => false,
773 WriterInner
::Windows { .. }
=> true,
778 impl<'a
, W
: io
::Write
> io
::Write
for WriterInnerLock
<'a
, W
> {
779 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
781 WriterInnerLock
::Unreachable(_
) => unreachable
!(),
782 WriterInnerLock
::NoColor(ref mut wtr
) => wtr
.write(buf
),
783 WriterInnerLock
::Ansi(ref mut wtr
) => wtr
.write(buf
),
785 WriterInnerLock
::Windows { ref mut wtr, .. }
=> wtr
.write(buf
),
789 fn flush(&mut self) -> io
::Result
<()> {
791 WriterInnerLock
::Unreachable(_
) => unreachable
!(),
792 WriterInnerLock
::NoColor(ref mut wtr
) => wtr
.flush(),
793 WriterInnerLock
::Ansi(ref mut wtr
) => wtr
.flush(),
795 WriterInnerLock
::Windows { ref mut wtr, .. }
=> wtr
.flush(),
800 impl<'a
, W
: io
::Write
> WriteColor
for WriterInnerLock
<'a
, W
> {
801 fn supports_color(&self) -> bool
{
803 WriterInnerLock
::Unreachable(_
) => unreachable
!(),
804 WriterInnerLock
::NoColor(_
) => false,
805 WriterInnerLock
::Ansi(_
) => true,
807 WriterInnerLock
::Windows { .. }
=> true,
811 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
813 WriterInnerLock
::Unreachable(_
) => unreachable
!(),
814 WriterInnerLock
::NoColor(ref mut wtr
) => wtr
.set_color(spec
),
815 WriterInnerLock
::Ansi(ref mut wtr
) => wtr
.set_color(spec
),
817 WriterInnerLock
::Windows { ref mut wtr, ref mut console }
=> {
819 spec
.write_console(console
)
824 fn reset(&mut self) -> io
::Result
<()> {
826 WriterInnerLock
::Unreachable(_
) => unreachable
!(),
827 WriterInnerLock
::NoColor(ref mut wtr
) => wtr
.reset(),
828 WriterInnerLock
::Ansi(ref mut wtr
) => wtr
.reset(),
830 WriterInnerLock
::Windows { ref mut wtr, ref mut console }
=> {
838 fn is_synchronous(&self) -> bool
{
840 WriterInnerLock
::Unreachable(_
) => unreachable
!(),
841 WriterInnerLock
::NoColor(_
) => false,
842 WriterInnerLock
::Ansi(_
) => false,
844 WriterInnerLock
::Windows { .. }
=> true,
849 /// Writes colored buffers to stdout or stderr.
851 /// Writable buffers can be obtained by calling `buffer` on a `BufferWriter`.
853 /// This writer works with terminals that support ANSI escape sequences or
854 /// with a Windows console.
856 /// It is intended for a `BufferWriter` to be put in an `Arc` and written to
857 /// from multiple threads simultaneously.
858 pub struct BufferWriter
{
859 stream
: LossyStandardStream
<IoStandardStream
>,
861 separator
: Option
<Vec
<u8>>,
862 color_choice
: ColorChoice
,
864 console
: Option
<Mutex
<wincon
::Console
>>,
868 /// Create a new `BufferWriter` that writes to a standard stream with the
869 /// given color preferences.
871 /// The specific color/style settings can be configured when writing to
872 /// the buffers themselves.
874 fn create(sty
: StandardStreamType
, choice
: ColorChoice
) -> BufferWriter
{
876 stream
: LossyStandardStream
::new(IoStandardStream
::new(sty
)),
877 printed
: AtomicBool
::new(false),
879 color_choice
: choice
,
883 /// Create a new `BufferWriter` that writes to a standard stream with the
884 /// given color preferences.
886 /// If coloring is desired and a Windows console could not be found, then
887 /// ANSI escape sequences are used instead.
889 /// The specific color/style settings can be configured when writing to
890 /// the buffers themselves.
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(),
900 let is_console_virtual
= con
902 .map(|con
| con
.set_virtual_terminal_processing(true).is_ok())
904 // If we can enable ANSI on Windows, then we don't need the console
906 if is_console_virtual
{
909 let stream
= LossyStandardStream
::new(IoStandardStream
::new(sty
));
912 printed
: AtomicBool
::new(false),
914 color_choice
: choice
,
915 console
: con
.map(Mutex
::new
),
919 /// Create a new `BufferWriter` that writes to stdout with the given
920 /// color preferences.
922 /// On Windows, if coloring is desired and a Windows console could not be
923 /// found, then ANSI escape sequences are used instead.
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
)
931 /// Create a new `BufferWriter` that writes to stderr with the given
932 /// color preferences.
934 /// On Windows, if coloring is desired and a Windows console could not be
935 /// found, then ANSI escape sequences are used instead.
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
)
943 /// If set, the separator given is printed between buffers. By default, no
944 /// separator is printed.
946 /// The default value is `None`.
947 pub fn separator(&mut self, sep
: Option
<Vec
<u8>>) {
948 self.separator
= sep
;
951 /// Creates a new `Buffer` with the current color preferences.
953 /// A `Buffer` satisfies both `io::Write` and `WriteColor`. A `Buffer` can
954 /// be printed using the `print` method.
956 pub fn buffer(&self) -> Buffer
{
957 Buffer
::new(self.color_choice
)
960 /// Creates a new `Buffer` with the current color preferences.
962 /// A `Buffer` satisfies both `io::Write` and `WriteColor`. A `Buffer` can
963 /// be printed using the `print` method.
965 pub fn buffer(&self) -> Buffer
{
966 Buffer
::new(self.color_choice
, self.console
.is_some())
969 /// Prints the contents of the given buffer.
971 /// It is safe to call this from multiple threads simultaneously. In
972 /// particular, all buffers are written atomically. No interleaving will
974 pub fn print(&self, buf
: &Buffer
) -> io
::Result
<()> {
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")?
;
986 BufferInner
::NoColor(ref b
) => stream
.write_all(&b
.0)?
,
987 BufferInner
::Ansi(ref b
) => stream
.write_all(&b
.0)?
,
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
995 .expect("got Windows buffer but have no Console");
996 let mut console
= console_mutex
.lock().unwrap();
997 b
.print(&mut *console
, &mut stream
)?
;
1000 self.printed
.store(true, Ordering
::SeqCst
);
1005 /// Write colored text to memory.
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).
1012 /// A `Buffer` is typically created by calling the `BufferWriter.buffer`
1013 /// method, which will take color preferences and the environment into
1014 /// account. However, buffers can also be manually created using `no_color`,
1015 /// `ansi` or `console` (on Windows).
1016 pub struct Buffer(BufferInner
);
1018 /// BufferInner is an enumeration of different buffer types.
1020 /// No coloring information should be applied. This ignores all coloring
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.
1029 Windows(WindowsBuffer
),
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() {
1043 /// Create a new buffer with the given color settings.
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.
1048 /// If coloring is desired and `console` is false, then ANSI escape
1049 /// sequences are used instead.
1051 fn new(choice
: ColorChoice
, console
: bool
) -> Buffer
{
1052 if choice
.should_attempt_color() {
1053 if !console
|| choice
.should_ansi() {
1063 /// Create a buffer that drops all color information.
1064 pub fn no_color() -> Buffer
{
1065 Buffer(BufferInner
::NoColor(NoColor(vec
![])))
1068 /// Create a buffer that uses ANSI escape sequences.
1069 pub fn ansi() -> Buffer
{
1070 Buffer(BufferInner
::Ansi(Ansi(vec
![])))
1073 /// Create a buffer that can be written to a Windows console.
1075 pub fn console() -> Buffer
{
1076 Buffer(BufferInner
::Windows(WindowsBuffer
::new()))
1079 /// Returns true if and only if this buffer is empty.
1080 pub fn is_empty(&self) -> bool
{
1084 /// Returns the length of this buffer in bytes.
1085 pub fn len(&self) -> usize {
1087 BufferInner
::NoColor(ref b
) => b
.0.len(),
1088 BufferInner
::Ansi(ref b
) => b
.0.len(),
1090 BufferInner
::Windows(ref b
) => b
.buf
.len(),
1094 /// Clears this buffer.
1095 pub fn clear(&mut self) {
1097 BufferInner
::NoColor(ref mut b
) => b
.0.clear(),
1098 BufferInner
::Ansi(ref mut b
) => b
.0.clear(),
1100 BufferInner
::Windows(ref mut b
) => b
.clear(),
1104 /// Consume this buffer and return the underlying raw data.
1106 /// On Windows, this unrecoverably drops all color information associated
1107 /// with the buffer.
1108 pub fn into_inner(self) -> Vec
<u8> {
1110 BufferInner
::NoColor(b
) => b
.0,
1111 BufferInner
::Ansi(b
) => b
.0,
1113 BufferInner
::Windows(b
) => b
.buf
,
1117 /// Return the underlying data of the buffer.
1118 pub fn as_slice(&self) -> &[u8] {
1120 BufferInner
::NoColor(ref b
) => &b
.0,
1121 BufferInner
::Ansi(ref b
) => &b
.0,
1123 BufferInner
::Windows(ref b
) => &b
.buf
,
1127 /// Return the underlying data of the buffer as a mutable slice.
1128 pub fn as_mut_slice(&mut self) -> &mut [u8] {
1130 BufferInner
::NoColor(ref mut b
) => &mut b
.0,
1131 BufferInner
::Ansi(ref mut b
) => &mut b
.0,
1133 BufferInner
::Windows(ref mut b
) => &mut b
.buf
,
1138 impl io
::Write
for Buffer
{
1140 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
1142 BufferInner
::NoColor(ref mut w
) => w
.write(buf
),
1143 BufferInner
::Ansi(ref mut w
) => w
.write(buf
),
1145 BufferInner
::Windows(ref mut w
) => w
.write(buf
),
1150 fn flush(&mut self) -> io
::Result
<()> {
1152 BufferInner
::NoColor(ref mut w
) => w
.flush(),
1153 BufferInner
::Ansi(ref mut w
) => w
.flush(),
1155 BufferInner
::Windows(ref mut w
) => w
.flush(),
1160 impl WriteColor
for Buffer
{
1162 fn supports_color(&self) -> bool
{
1164 BufferInner
::NoColor(_
) => false,
1165 BufferInner
::Ansi(_
) => true,
1167 BufferInner
::Windows(_
) => true,
1172 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
1174 BufferInner
::NoColor(ref mut w
) => w
.set_color(spec
),
1175 BufferInner
::Ansi(ref mut w
) => w
.set_color(spec
),
1177 BufferInner
::Windows(ref mut w
) => w
.set_color(spec
),
1182 fn reset(&mut self) -> io
::Result
<()> {
1184 BufferInner
::NoColor(ref mut w
) => w
.reset(),
1185 BufferInner
::Ansi(ref mut w
) => w
.reset(),
1187 BufferInner
::Windows(ref mut w
) => w
.reset(),
1192 fn is_synchronous(&self) -> bool
{
1197 /// Satisfies `WriteColor` but ignores all color options.
1198 pub struct NoColor
<W
>(W
);
1200 impl<W
: Write
> NoColor
<W
> {
1201 /// Create a new writer that satisfies `WriteColor` but drops all color
1203 pub fn new(wtr
: W
) -> NoColor
<W
> {
1207 /// Consume this `NoColor` value and return the inner writer.
1208 pub fn into_inner(self) -> W
{
1212 /// Return a reference to the inner writer.
1213 pub fn get_ref(&self) -> &W
{
1217 /// Return a mutable reference to the inner writer.
1218 pub fn get_mut(&mut self) -> &mut W
{
1223 impl<W
: io
::Write
> io
::Write
for NoColor
<W
> {
1225 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
1230 fn flush(&mut self) -> io
::Result
<()> {
1235 impl<W
: io
::Write
> WriteColor
for NoColor
<W
> {
1237 fn supports_color(&self) -> bool
{
1242 fn set_color(&mut self, _
: &ColorSpec
) -> io
::Result
<()> {
1247 fn reset(&mut self) -> io
::Result
<()> {
1252 fn is_synchronous(&self) -> bool
{
1257 /// Satisfies `WriteColor` using standard ANSI escape sequences.
1258 pub struct Ansi
<W
>(W
);
1260 impl<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
> {
1267 /// Consume this `Ansi` value and return the inner writer.
1268 pub fn into_inner(self) -> W
{
1272 /// Return a reference to the inner writer.
1273 pub fn get_ref(&self) -> &W
{
1277 /// Return a mutable reference to the inner writer.
1278 pub fn get_mut(&mut self) -> &mut W
{
1283 impl<W
: io
::Write
> io
::Write
for Ansi
<W
> {
1285 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
1290 fn flush(&mut self) -> io
::Result
<()> {
1295 impl<W
: io
::Write
> WriteColor
for Ansi
<W
> {
1297 fn supports_color(&self) -> bool
{
1302 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
1307 self.write_str("\x1B[1m")?
;
1310 self.write_str("\x1B[3m")?
;
1313 self.write_str("\x1B[4m")?
;
1315 if let Some(ref c
) = spec
.fg_color
{
1316 self.write_color(true, c
, spec
.intense
)?
;
1318 if let Some(ref c
) = spec
.bg_color
{
1319 self.write_color(false, c
, spec
.intense
)?
;
1325 fn reset(&mut self) -> io
::Result
<()> {
1326 self.write_str("\x1B[0m")
1330 fn is_synchronous(&self) -> bool
{
1335 impl<W
: io
::Write
> Ansi
<W
> {
1336 fn write_str(&mut self, s
: &str) -> io
::Result
<()> {
1337 self.write_all(s
.as_bytes())
1345 ) -> io
::Result
<()> {
1346 macro_rules
! write_intense
{
1349 self.write_str(concat
!("\x1B[38;5;", $clr
, "m"))
1351 self.write_str(concat
!("\x1B[48;5;", $clr
, "m"))
1355 macro_rules
! write_normal
{
1358 self.write_str(concat
!("\x1B[3", $clr
, "m"))
1360 self.write_str(concat
!("\x1B[4", $clr
, "m"))
1364 macro_rules
! write_var_ansi_code
{
1365 ($pre
:expr
, $
($code
:expr
),+) => {{
1366 // The loop generates at worst a literal of the form
1367 // '255,255,255m' which is 12-bytes.
1368 // The largest `pre` expression we currently use is 7 bytes.
1369 // This gives us the maximum of 19-bytes for our work buffer.
1370 let pre_len
= $pre
.len();
1371 assert
!(pre_len
<= 7);
1372 let mut fmt
= [0u8; 19];
1373 fmt
[..pre_len
].copy_from_slice($pre
);
1374 let mut i
= pre_len
- 1;
1376 let c1
: u8 = ($code
/ 100) % 10;
1377 let c2
: u8 = ($code
/ 10) % 10;
1378 let c3
: u8 = $code
% 10;
1379 let mut printed
= false;
1386 if c2
!= 0 || printed
{
1390 // If we received a zero value we must still print a value.
1398 self.write_all(&fmt
[0..i
+1])
1401 macro_rules
! write_custom
{
1402 ($ansi256
:expr
) => {
1404 write_var_ansi_code
!(b
"\x1B[38;5;", $ansi256
)
1406 write_var_ansi_code
!(b
"\x1B[48;5;", $ansi256
)
1410 ($r
:expr
, $g
:expr
, $b
:expr
) => {{
1412 write_var_ansi_code
!(b
"\x1B[38;2;", $r
, $g
, $b
)
1414 write_var_ansi_code
!(b
"\x1B[48;2;", $r
, $g
, $b
)
1420 Color
::Black
=> write_intense
!("8"),
1421 Color
::Blue
=> write_intense
!("12"),
1422 Color
::Green
=> write_intense
!("10"),
1423 Color
::Red
=> write_intense
!("9"),
1424 Color
::Cyan
=> write_intense
!("14"),
1425 Color
::Magenta
=> write_intense
!("13"),
1426 Color
::Yellow
=> write_intense
!("11"),
1427 Color
::White
=> write_intense
!("15"),
1428 Color
::Ansi256(c
) => write_custom
!(c
),
1429 Color
::Rgb(r
, g
, b
) => write_custom
!(r
, g
, b
),
1430 Color
::__Nonexhaustive
=> unreachable
!(),
1434 Color
::Black
=> write_normal
!("0"),
1435 Color
::Blue
=> write_normal
!("4"),
1436 Color
::Green
=> write_normal
!("2"),
1437 Color
::Red
=> write_normal
!("1"),
1438 Color
::Cyan
=> write_normal
!("6"),
1439 Color
::Magenta
=> write_normal
!("5"),
1440 Color
::Yellow
=> write_normal
!("3"),
1441 Color
::White
=> write_normal
!("7"),
1442 Color
::Ansi256(c
) => write_custom
!(c
),
1443 Color
::Rgb(r
, g
, b
) => write_custom
!(r
, g
, b
),
1444 Color
::__Nonexhaustive
=> unreachable
!(),
1450 /// An in-memory buffer that provides Windows console coloring.
1452 /// This doesn't actually communicate with the Windows console. Instead, it
1453 /// acts like a normal buffer but also saves the color information associated
1454 /// with positions in the buffer. It is only when the buffer is written to the
1455 /// console that coloring is actually applied.
1457 /// This is roughly isomorphic to the ANSI based approach (i.e.,
1458 /// `Ansi<Vec<u8>>`), except with ANSI, the color information is embedded
1459 /// directly into the buffer.
1461 /// Note that there is no way to write something generic like
1462 /// `WindowsConsole<W: io::Write>` since coloring on Windows is tied
1463 /// specifically to the console APIs, and therefore can't work on arbitrary
1466 #[derive(Clone, Debug)]
1467 struct WindowsBuffer
{
1468 /// The actual content that should be printed.
1470 /// A sequence of position oriented color specifications. Namely, each
1471 /// element is a position and a color spec, where the color spec should
1472 /// be applied at the position inside of `buf`.
1474 /// A missing color spec implies the underlying console should be reset.
1475 colors
: Vec
<(usize, Option
<ColorSpec
>)>,
1479 impl WindowsBuffer
{
1480 /// Create a new empty buffer for Windows console coloring.
1481 fn new() -> WindowsBuffer
{
1482 WindowsBuffer { buf: vec![], colors: vec![] }
1485 /// Push the given color specification into this buffer.
1487 /// This has the effect of setting the given color information at the
1488 /// current position in the buffer.
1489 fn push(&mut self, spec
: Option
<ColorSpec
>) {
1490 let pos
= self.buf
.len();
1491 self.colors
.push((pos
, spec
));
1494 /// Print the contents to the given stream handle, and use the console
1498 console
: &mut wincon
::Console
,
1499 stream
: &mut LossyStandardStream
<IoStandardStreamLock
>,
1500 ) -> io
::Result
<()> {
1502 for &(pos
, ref spec
) in &self.colors
{
1503 stream
.write_all(&self.buf
[last
..pos
])?
;
1507 None
=> console
.reset()?
,
1508 Some(ref spec
) => spec
.write_console(console
)?
,
1511 stream
.write_all(&self.buf
[last
..])?
;
1515 /// Clear the buffer.
1516 fn clear(&mut self) {
1518 self.colors
.clear();
1523 impl io
::Write
for WindowsBuffer
{
1525 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
1526 self.buf
.extend_from_slice(buf
);
1531 fn flush(&mut self) -> io
::Result
<()> {
1537 impl WriteColor
for WindowsBuffer
{
1539 fn supports_color(&self) -> bool
{
1544 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
1545 self.push(Some(spec
.clone()));
1550 fn reset(&mut self) -> io
::Result
<()> {
1556 fn is_synchronous(&self) -> bool
{
1561 /// A color specification.
1562 #[derive(Clone, Debug, Eq, PartialEq)]
1563 pub struct ColorSpec
{
1564 fg_color
: Option
<Color
>,
1565 bg_color
: Option
<Color
>,
1573 impl Default
for ColorSpec
{
1574 fn default() -> ColorSpec
{
1588 /// Create a new color specification that has no colors or styles.
1589 pub fn new() -> ColorSpec
{
1590 ColorSpec
::default()
1593 /// Get the foreground color.
1594 pub fn fg(&self) -> Option
<&Color
> {
1595 self.fg_color
.as_ref()
1598 /// Set the foreground color.
1599 pub fn set_fg(&mut self, color
: Option
<Color
>) -> &mut ColorSpec
{
1600 self.fg_color
= color
;
1604 /// Get the background color.
1605 pub fn bg(&self) -> Option
<&Color
> {
1606 self.bg_color
.as_ref()
1609 /// Set the background color.
1610 pub fn set_bg(&mut self, color
: Option
<Color
>) -> &mut ColorSpec
{
1611 self.bg_color
= color
;
1615 /// Get whether this is bold or not.
1617 /// Note that the bold setting has no effect in a Windows console.
1618 pub fn bold(&self) -> bool
{
1622 /// Set whether the text is bolded or not.
1624 /// Note that the bold setting has no effect in a Windows console.
1625 pub fn set_bold(&mut self, yes
: bool
) -> &mut ColorSpec
{
1630 /// Get whether this is italic or not.
1632 /// Note that the italic setting has no effect in a Windows console.
1633 pub fn italic(&self) -> bool
{
1637 /// Set whether the text is italicized or not.
1639 /// Note that the italic setting has no effect in a Windows console.
1640 pub fn set_italic(&mut self, yes
: bool
) -> &mut ColorSpec
{
1645 /// Get whether this is underline or not.
1647 /// Note that the underline setting has no effect in a Windows console.
1648 pub fn underline(&self) -> bool
{
1652 /// Set whether the text is underlined or not.
1654 /// Note that the underline setting has no effect in a Windows console.
1655 pub fn set_underline(&mut self, yes
: bool
) -> &mut ColorSpec
{
1656 self.underline
= yes
;
1660 /// Get whether reset is enabled or not.
1662 /// reset is enabled by default. When disabled and using ANSI escape
1663 /// sequences, a "reset" code will be emitted every time a `ColorSpec`'s
1664 /// settings are applied.
1666 /// Note that the reset setting has no effect in a Windows console.
1667 pub fn reset(&self) -> bool
{
1671 /// Set whether to reset the terminal whenever color settings are applied.
1673 /// reset is enabled by default. When disabled and using ANSI escape
1674 /// sequences, a "reset" code will be emitted every time a `ColorSpec`'s
1675 /// settings are applied.
1677 /// Typically this is useful if callers have a requirement to more
1678 /// scrupulously manage the exact sequence of escape codes that are emitted
1679 /// when using ANSI for colors.
1681 /// Note that the reset setting has no effect in a Windows console.
1682 pub fn set_reset(&mut self, yes
: bool
) -> &mut ColorSpec
{
1687 /// Get whether this is intense or not.
1689 /// On Unix-like systems, this will output the ANSI escape sequence
1690 /// that will print a high-intensity version of the color
1693 /// On Windows systems, this will output the ANSI escape sequence
1694 /// that will print a brighter version of the color specified.
1695 pub fn intense(&self) -> bool
{
1699 /// Set whether the text is intense or not.
1701 /// On Unix-like systems, this will output the ANSI escape sequence
1702 /// that will print a high-intensity version of the color
1705 /// On Windows systems, this will output the ANSI escape sequence
1706 /// that will print a brighter version of the color specified.
1707 pub fn set_intense(&mut self, yes
: bool
) -> &mut ColorSpec
{
1712 /// Returns true if this color specification has no colors or styles.
1713 pub fn is_none(&self) -> bool
{
1714 self.fg_color
.is_none()
1715 && self.bg_color
.is_none()
1722 /// Clears this color specification so that it has no color/style settings.
1723 pub fn clear(&mut self) {
1724 self.fg_color
= None
;
1725 self.bg_color
= None
;
1727 self.underline
= false;
1728 self.intense
= false;
1729 self.italic
= false;
1732 /// Writes this color spec to the given Windows console.
1734 fn write_console(&self, console
: &mut wincon
::Console
) -> io
::Result
<()> {
1735 let fg_color
= self.fg_color
.and_then(|c
| c
.to_windows(self.intense
));
1736 if let Some((intense
, color
)) = fg_color
{
1737 console
.fg(intense
, color
)?
;
1739 let bg_color
= self.bg_color
.and_then(|c
| c
.to_windows(self.intense
));
1740 if let Some((intense
, color
)) = bg_color
{
1741 console
.bg(intense
, color
)?
;
1747 /// The set of available colors for the terminal foreground/background.
1749 /// The `Ansi256` and `Rgb` colors will only output the correct codes when
1750 /// paired with the `Ansi` `WriteColor` implementation.
1752 /// The `Ansi256` and `Rgb` color types are not supported when writing colors
1753 /// on Windows using the console. If they are used on Windows, then they are
1754 /// silently ignored and no colors will be emitted.
1756 /// This set may expand over time.
1758 /// This type has a `FromStr` impl that can parse colors from their human
1759 /// readable form. The format is as follows:
1761 /// 1. Any of the explicitly listed colors in English. They are matched
1762 /// case insensitively.
1763 /// 2. A single 8-bit integer, in either decimal or hexadecimal format.
1764 /// 3. A triple of 8-bit integers separated by a comma, where each integer is
1765 /// in decimal or hexadecimal format.
1767 /// Hexadecimal numbers are written with a `0x` prefix.
1768 #[allow(missing_docs)]
1769 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1786 /// Translate this color to a wincon::Color.
1791 ) -> Option
<(wincon
::Intense
, wincon
::Color
)> {
1792 use wincon
::Intense
::{No, Yes}
;
1794 let color
= match self {
1795 Color
::Black
=> wincon
::Color
::Black
,
1796 Color
::Blue
=> wincon
::Color
::Blue
,
1797 Color
::Green
=> wincon
::Color
::Green
,
1798 Color
::Red
=> wincon
::Color
::Red
,
1799 Color
::Cyan
=> wincon
::Color
::Cyan
,
1800 Color
::Magenta
=> wincon
::Color
::Magenta
,
1801 Color
::Yellow
=> wincon
::Color
::Yellow
,
1802 Color
::White
=> wincon
::Color
::White
,
1803 Color
::Ansi256(0) => return Some((No
, wincon
::Color
::Black
)),
1804 Color
::Ansi256(1) => return Some((No
, wincon
::Color
::Red
)),
1805 Color
::Ansi256(2) => return Some((No
, wincon
::Color
::Green
)),
1806 Color
::Ansi256(3) => return Some((No
, wincon
::Color
::Yellow
)),
1807 Color
::Ansi256(4) => return Some((No
, wincon
::Color
::Blue
)),
1808 Color
::Ansi256(5) => return Some((No
, wincon
::Color
::Magenta
)),
1809 Color
::Ansi256(6) => return Some((No
, wincon
::Color
::Cyan
)),
1810 Color
::Ansi256(7) => return Some((No
, wincon
::Color
::White
)),
1811 Color
::Ansi256(8) => return Some((Yes
, wincon
::Color
::Black
)),
1812 Color
::Ansi256(9) => return Some((Yes
, wincon
::Color
::Red
)),
1813 Color
::Ansi256(10) => return Some((Yes
, wincon
::Color
::Green
)),
1814 Color
::Ansi256(11) => return Some((Yes
, wincon
::Color
::Yellow
)),
1815 Color
::Ansi256(12) => return Some((Yes
, wincon
::Color
::Blue
)),
1816 Color
::Ansi256(13) => return Some((Yes
, wincon
::Color
::Magenta
)),
1817 Color
::Ansi256(14) => return Some((Yes
, wincon
::Color
::Cyan
)),
1818 Color
::Ansi256(15) => return Some((Yes
, wincon
::Color
::White
)),
1819 Color
::Ansi256(_
) => return None
,
1820 Color
::Rgb(_
, _
, _
) => return None
,
1821 Color
::__Nonexhaustive
=> unreachable
!(),
1823 let intense
= if intense { Yes }
else { No }
;
1824 Some((intense
, color
))
1827 /// Parses a numeric color string, either ANSI or RGB.
1828 fn from_str_numeric(s
: &str) -> Result
<Color
, ParseColorError
> {
1829 // The "ansi256" format is a single number (decimal or hex)
1830 // corresponding to one of 256 colors.
1832 // The "rgb" format is a triple of numbers (decimal or hex) delimited
1833 // by a comma corresponding to one of 256^3 colors.
1835 fn parse_number(s
: &str) -> Option
<u8> {
1838 if s
.starts_with("0x") {
1839 u8::from_str_radix(&s
[2..], 16).ok()
1841 u8::from_str_radix(s
, 10).ok()
1845 let codes
: Vec
<&str> = s
.split('
,'
).collect();
1846 if codes
.len() == 1 {
1847 if let Some(n
) = parse_number(&codes
[0]) {
1848 Ok(Color
::Ansi256(n
))
1850 if s
.chars().all(|c
| c
.is_digit(16)) {
1851 Err(ParseColorError
{
1852 kind
: ParseColorErrorKind
::InvalidAnsi256
,
1853 given
: s
.to_string(),
1856 Err(ParseColorError
{
1857 kind
: ParseColorErrorKind
::InvalidName
,
1858 given
: s
.to_string(),
1862 } else if codes
.len() == 3 {
1865 let n
= parse_number(code
).ok_or_else(|| ParseColorError
{
1866 kind
: ParseColorErrorKind
::InvalidRgb
,
1867 given
: s
.to_string(),
1871 Ok(Color
::Rgb(v
[0], v
[1], v
[2]))
1873 Err(if s
.contains(",") {
1875 kind
: ParseColorErrorKind
::InvalidRgb
,
1876 given
: s
.to_string(),
1880 kind
: ParseColorErrorKind
::InvalidName
,
1881 given
: s
.to_string(),
1888 /// An error from parsing an invalid color specification.
1889 #[derive(Clone, Debug, Eq, PartialEq)]
1890 pub struct ParseColorError
{
1891 kind
: ParseColorErrorKind
,
1895 #[derive(Clone, Debug, Eq, PartialEq)]
1896 enum ParseColorErrorKind
{
1902 impl ParseColorError
{
1903 /// Return the string that couldn't be parsed as a valid color.
1904 pub fn invalid(&self) -> &str {
1909 impl error
::Error
for ParseColorError
{
1910 fn description(&self) -> &str {
1911 use self::ParseColorErrorKind
::*;
1913 InvalidName
=> "unrecognized color name",
1914 InvalidAnsi256
=> "invalid ansi256 color number",
1915 InvalidRgb
=> "invalid RGB color triple",
1920 impl fmt
::Display
for ParseColorError
{
1921 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1922 use self::ParseColorErrorKind
::*;
1924 InvalidName
=> write
!(
1926 "unrecognized color name '{}'. Choose from: \
1927 black, blue, green, red, cyan, magenta, yellow, \
1931 InvalidAnsi256
=> write
!(
1933 "unrecognized ansi256 color number, \
1934 should be '[0-255]' (or a hex number), but is '{}'",
1937 InvalidRgb
=> write
!(
1939 "unrecognized RGB color triple, \
1940 should be '[0-255],[0-255],[0-255]' (or a hex \
1941 triple), but is '{}'",
1948 impl FromStr
for Color
{
1949 type Err
= ParseColorError
;
1951 fn from_str(s
: &str) -> Result
<Color
, ParseColorError
> {
1952 match &*s
.to_lowercase() {
1953 "black" => Ok(Color
::Black
),
1954 "blue" => Ok(Color
::Blue
),
1955 "green" => Ok(Color
::Green
),
1956 "red" => Ok(Color
::Red
),
1957 "cyan" => Ok(Color
::Cyan
),
1958 "magenta" => Ok(Color
::Magenta
),
1959 "yellow" => Ok(Color
::Yellow
),
1960 "white" => Ok(Color
::White
),
1961 _
=> Color
::from_str_numeric(s
),
1966 struct LossyStandardStream
<W
> {
1972 impl<W
: io
::Write
> LossyStandardStream
<W
> {
1973 #[cfg(not(windows))]
1974 fn new(wtr
: W
) -> LossyStandardStream
<W
> {
1975 LossyStandardStream { wtr: wtr }
1979 fn new(wtr
: W
) -> LossyStandardStream
<W
> {
1980 let is_console
= wincon
::Console
::stdout().is_ok()
1981 || wincon
::Console
::stderr().is_ok();
1982 LossyStandardStream { wtr: wtr, is_console: is_console }
1985 #[cfg(not(windows))]
1986 fn wrap
<Q
: io
::Write
>(&self, wtr
: Q
) -> LossyStandardStream
<Q
> {
1987 LossyStandardStream
::new(wtr
)
1991 fn wrap
<Q
: io
::Write
>(&self, wtr
: Q
) -> LossyStandardStream
<Q
> {
1992 LossyStandardStream { wtr: wtr, is_console: self.is_console }
1995 fn get_ref(&self) -> &W
{
2000 impl<W
: WriteColor
> WriteColor
for LossyStandardStream
<W
> {
2001 fn supports_color(&self) -> bool
{
2002 self.wtr
.supports_color()
2004 fn set_color(&mut self, spec
: &ColorSpec
) -> io
::Result
<()> {
2005 self.wtr
.set_color(spec
)
2007 fn reset(&mut self) -> io
::Result
<()> {
2010 fn is_synchronous(&self) -> bool
{
2011 self.wtr
.is_synchronous()
2015 impl<W
: io
::Write
> io
::Write
for LossyStandardStream
<W
> {
2016 #[cfg(not(windows))]
2017 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
2022 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
2023 if self.is_console
{
2024 write_lossy_utf8(&mut self.wtr
, buf
)
2030 fn flush(&mut self) -> io
::Result
<()> {
2036 fn write_lossy_utf8
<W
: io
::Write
>(mut w
: W
, buf
: &[u8]) -> io
::Result
<usize> {
2037 match ::std
::str::from_utf8(buf
) {
2038 Ok(s
) => w
.write(s
.as_bytes()),
2039 Err(ref e
) if e
.valid_up_to() == 0 => {
2040 w
.write(b
"\xEF\xBF\xBD")?
;
2043 Err(e
) => w
.write(&buf
[..e
.valid_up_to()]),
2050 Ansi
, Color
, ColorSpec
, ParseColorError
, ParseColorErrorKind
,
2051 StandardStream
, WriteColor
,
2054 fn assert_is_send
<T
: Send
>() {}
2057 fn standard_stream_is_send() {
2058 assert_is_send
::<StandardStream
>();
2062 fn test_simple_parse_ok() {
2063 let color
= "green".parse
::<Color
>();
2064 assert_eq
!(color
, Ok(Color
::Green
));
2068 fn test_256_parse_ok() {
2069 let color
= "7".parse
::<Color
>();
2070 assert_eq
!(color
, Ok(Color
::Ansi256(7)));
2072 let color
= "32".parse
::<Color
>();
2073 assert_eq
!(color
, Ok(Color
::Ansi256(32)));
2075 let color
= "0xFF".parse
::<Color
>();
2076 assert_eq
!(color
, Ok(Color
::Ansi256(0xFF)));
2080 fn test_256_parse_err_out_of_range() {
2081 let color
= "256".parse
::<Color
>();
2084 Err(ParseColorError
{
2085 kind
: ParseColorErrorKind
::InvalidAnsi256
,
2086 given
: "256".to_string(),
2092 fn test_rgb_parse_ok() {
2093 let color
= "0,0,0".parse
::<Color
>();
2094 assert_eq
!(color
, Ok(Color
::Rgb(0, 0, 0)));
2096 let color
= "0,128,255".parse
::<Color
>();
2097 assert_eq
!(color
, Ok(Color
::Rgb(0, 128, 255)));
2099 let color
= "0x0,0x0,0x0".parse
::<Color
>();
2100 assert_eq
!(color
, Ok(Color
::Rgb(0, 0, 0)));
2102 let color
= "0x33,0x66,0xFF".parse
::<Color
>();
2103 assert_eq
!(color
, Ok(Color
::Rgb(0x33, 0x66, 0xFF)));
2107 fn test_rgb_parse_err_out_of_range() {
2108 let color
= "0,0,256".parse
::<Color
>();
2111 Err(ParseColorError
{
2112 kind
: ParseColorErrorKind
::InvalidRgb
,
2113 given
: "0,0,256".to_string(),
2119 fn test_rgb_parse_err_bad_format() {
2120 let color
= "0,0".parse
::<Color
>();
2123 Err(ParseColorError
{
2124 kind
: ParseColorErrorKind
::InvalidRgb
,
2125 given
: "0,0".to_string(),
2129 let color
= "not_a_color".parse
::<Color
>();
2132 Err(ParseColorError
{
2133 kind
: ParseColorErrorKind
::InvalidName
,
2134 given
: "not_a_color".to_string(),
2140 fn test_var_ansi_write_rgb() {
2141 let mut buf
= Ansi
::new(vec
![]);
2142 let _
= buf
.write_color(true, &Color
::Rgb(254, 253, 255), false);
2143 assert_eq
!(buf
.0, b
"\x1B[38;2;254;253;255m");
2148 let spec
= ColorSpec
::new();
2149 let mut buf
= Ansi
::new(vec
![]);
2150 buf
.set_color(&spec
).unwrap();
2151 assert_eq
!(buf
.0, b
"\x1B[0m");
2155 fn test_no_reset() {
2156 let mut spec
= ColorSpec
::new();
2157 spec
.set_reset(false);
2159 let mut buf
= Ansi
::new(vec
![]);
2160 buf
.set_color(&spec
).unwrap();
2161 assert_eq
!(buf
.0, b
"");
2165 fn test_var_ansi_write_256() {
2166 let mut buf
= Ansi
::new(vec
![]);
2167 let _
= buf
.write_color(false, &Color
::Ansi256(7), false);
2168 assert_eq
!(buf
.0, b
"\x1B[48;5;7m");
2170 let mut buf
= Ansi
::new(vec
![]);
2171 let _
= buf
.write_color(false, &Color
::Ansi256(208), false);
2172 assert_eq
!(buf
.0, b
"\x1B[48;5;208m");
2175 fn all_attributes() -> Vec
<ColorSpec
> {
2176 let mut result
= vec
![];
2177 for fg
in vec
![None
, Some(Color
::Red
)] {
2178 for bg
in vec
![None
, Some(Color
::Red
)] {
2179 for bold
in vec
![false, true] {
2180 for underline
in vec
![false, true] {
2181 for intense
in vec
![false, true] {
2182 for italic
in vec
![false, true] {
2183 let mut color
= ColorSpec
::new();
2186 color
.set_bold(bold
);
2187 color
.set_underline(underline
);
2188 color
.set_intense(intense
);
2189 color
.set_italic(italic
);
2202 for (i
, color
) in all_attributes().iter().enumerate() {
2215 for color
in all_attributes() {
2216 let mut color1
= color
.clone();
2218 assert
!(color1
.is_none(), "{:?} => {:?}", color
, color1
);