1#![deny(missing_docs)]
121
122use std::env;
128use std::error;
129use std::fmt;
130use std::io::{self, Write};
131use std::str::FromStr;
132use std::sync::atomic::{AtomicBool, Ordering};
133#[cfg(windows)]
134use std::sync::{Mutex, MutexGuard};
135
136#[cfg(windows)]
137use winapi_util::console as wincon;
138
139pub trait WriteColor: io::Write {
141 fn supports_color(&self) -> bool;
143
144 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()>;
152
153 fn reset(&mut self) -> io::Result<()>;
158
159 fn is_synchronous(&self) -> bool {
171 false
172 }
173}
174
175impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T {
176 fn supports_color(&self) -> bool {
177 (&**self).supports_color()
178 }
179 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
180 (&mut **self).set_color(spec)
181 }
182 fn reset(&mut self) -> io::Result<()> {
183 (&mut **self).reset()
184 }
185 fn is_synchronous(&self) -> bool {
186 (&**self).is_synchronous()
187 }
188}
189
190impl<T: ?Sized + WriteColor> WriteColor for Box<T> {
191 fn supports_color(&self) -> bool {
192 (&**self).supports_color()
193 }
194 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
195 (&mut **self).set_color(spec)
196 }
197 fn reset(&mut self) -> io::Result<()> {
198 (&mut **self).reset()
199 }
200 fn is_synchronous(&self) -> bool {
201 (&**self).is_synchronous()
202 }
203}
204
205#[derive(Clone, Copy, Debug, Eq, PartialEq)]
207pub enum ColorChoice {
208 Always,
211 AlwaysAnsi,
214 Auto,
218 Never,
220}
221
222impl ColorChoice {
223 fn should_attempt_color(&self) -> bool {
225 match *self {
226 ColorChoice::Always => true,
227 ColorChoice::AlwaysAnsi => true,
228 ColorChoice::Never => false,
229 ColorChoice::Auto => self.env_allows_color(),
230 }
231 }
232
233 #[cfg(not(windows))]
234 fn env_allows_color(&self) -> bool {
235 match env::var_os("TERM") {
236 None => return false,
239 Some(k) => {
240 if k == "dumb" {
241 return false;
242 }
243 }
244 }
245 if env::var_os("NO_COLOR").is_some() {
248 return false;
249 }
250 true
251 }
252
253 #[cfg(windows)]
254 fn env_allows_color(&self) -> bool {
255 if let Some(k) = env::var_os("TERM") {
259 if k == "dumb" {
260 return false;
261 }
262 }
263 if env::var_os("NO_COLOR").is_some() {
266 return false;
267 }
268 true
269 }
270
271 #[cfg(windows)]
276 fn should_ansi(&self) -> bool {
277 match *self {
278 ColorChoice::Always => false,
279 ColorChoice::AlwaysAnsi => true,
280 ColorChoice::Never => false,
281 ColorChoice::Auto => {
282 match env::var("TERM") {
283 Err(_) => false,
284 Ok(k) => k != "dumb" && k != "cygwin",
288 }
289 }
290 }
291 }
292}
293
294enum StandardStreamType {
299 Stdout,
300 Stderr,
301 StdoutBuffered,
302 StderrBuffered,
303}
304
305enum IoStandardStream {
306 Stdout(io::Stdout),
307 Stderr(io::Stderr),
308 StdoutBuffered(io::BufWriter<io::Stdout>),
309 StderrBuffered(io::BufWriter<io::Stderr>),
310}
311
312impl IoStandardStream {
313 fn new(sty: StandardStreamType) -> IoStandardStream {
314 match sty {
315 StandardStreamType::Stdout => {
316 IoStandardStream::Stdout(io::stdout())
317 }
318 StandardStreamType::Stderr => {
319 IoStandardStream::Stderr(io::stderr())
320 }
321 StandardStreamType::StdoutBuffered => {
322 let wtr = io::BufWriter::new(io::stdout());
323 IoStandardStream::StdoutBuffered(wtr)
324 }
325 StandardStreamType::StderrBuffered => {
326 let wtr = io::BufWriter::new(io::stderr());
327 IoStandardStream::StderrBuffered(wtr)
328 }
329 }
330 }
331
332 fn lock(&self) -> IoStandardStreamLock<'_> {
333 match *self {
334 IoStandardStream::Stdout(ref s) => {
335 IoStandardStreamLock::StdoutLock(s.lock())
336 }
337 IoStandardStream::Stderr(ref s) => {
338 IoStandardStreamLock::StderrLock(s.lock())
339 }
340 IoStandardStream::StdoutBuffered(_)
341 | IoStandardStream::StderrBuffered(_) => {
342 panic!("cannot lock a buffered standard stream")
345 }
346 }
347 }
348}
349
350impl io::Write for IoStandardStream {
351 #[inline(always)]
352 fn write(&mut self, b: &[u8]) -> io::Result<usize> {
353 match *self {
354 IoStandardStream::Stdout(ref mut s) => s.write(b),
355 IoStandardStream::Stderr(ref mut s) => s.write(b),
356 IoStandardStream::StdoutBuffered(ref mut s) => s.write(b),
357 IoStandardStream::StderrBuffered(ref mut s) => s.write(b),
358 }
359 }
360
361 #[inline(always)]
362 fn flush(&mut self) -> io::Result<()> {
363 match *self {
364 IoStandardStream::Stdout(ref mut s) => s.flush(),
365 IoStandardStream::Stderr(ref mut s) => s.flush(),
366 IoStandardStream::StdoutBuffered(ref mut s) => s.flush(),
367 IoStandardStream::StderrBuffered(ref mut s) => s.flush(),
368 }
369 }
370}
371
372enum IoStandardStreamLock<'a> {
375 StdoutLock(io::StdoutLock<'a>),
376 StderrLock(io::StderrLock<'a>),
377}
378
379impl<'a> io::Write for IoStandardStreamLock<'a> {
380 #[inline(always)]
381 fn write(&mut self, b: &[u8]) -> io::Result<usize> {
382 match *self {
383 IoStandardStreamLock::StdoutLock(ref mut s) => s.write(b),
384 IoStandardStreamLock::StderrLock(ref mut s) => s.write(b),
385 }
386 }
387
388 #[inline(always)]
389 fn flush(&mut self) -> io::Result<()> {
390 match *self {
391 IoStandardStreamLock::StdoutLock(ref mut s) => s.flush(),
392 IoStandardStreamLock::StderrLock(ref mut s) => s.flush(),
393 }
394 }
395}
396
397pub struct StandardStream {
400 wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
401}
402
403pub struct StandardStreamLock<'a> {
411 wtr: LossyStandardStream<WriterInnerLock<'a, IoStandardStreamLock<'a>>>,
412}
413
414pub struct BufferedStandardStream {
416 wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
417}
418
419enum WriterInner<W> {
422 NoColor(NoColor<W>),
423 Ansi(Ansi<W>),
424 #[cfg(windows)]
425 Windows {
426 wtr: W,
427 console: Mutex<wincon::Console>,
428 },
429}
430
431enum WriterInnerLock<'a, W> {
434 NoColor(NoColor<W>),
435 Ansi(Ansi<W>),
436 #[allow(dead_code)]
441 Unreachable(::std::marker::PhantomData<&'a ()>),
442 #[cfg(windows)]
443 Windows {
444 wtr: W,
445 console: MutexGuard<'a, wincon::Console>,
446 },
447}
448
449impl StandardStream {
450 pub fn stdout(choice: ColorChoice) -> StandardStream {
459 let wtr = WriterInner::create(StandardStreamType::Stdout, choice);
460 StandardStream { wtr: LossyStandardStream::new(wtr) }
461 }
462
463 pub fn stderr(choice: ColorChoice) -> StandardStream {
472 let wtr = WriterInner::create(StandardStreamType::Stderr, choice);
473 StandardStream { wtr: LossyStandardStream::new(wtr) }
474 }
475
476 pub fn lock(&self) -> StandardStreamLock<'_> {
484 StandardStreamLock::from_stream(self)
485 }
486}
487
488impl<'a> StandardStreamLock<'a> {
489 #[cfg(not(windows))]
490 fn from_stream(stream: &StandardStream) -> StandardStreamLock<'_> {
491 let locked = match *stream.wtr.get_ref() {
492 WriterInner::NoColor(ref w) => {
493 WriterInnerLock::NoColor(NoColor(w.0.lock()))
494 }
495 WriterInner::Ansi(ref w) => {
496 WriterInnerLock::Ansi(Ansi(w.0.lock()))
497 }
498 };
499 StandardStreamLock { wtr: stream.wtr.wrap(locked) }
500 }
501
502 #[cfg(windows)]
503 fn from_stream(stream: &StandardStream) -> StandardStreamLock {
504 let locked = match *stream.wtr.get_ref() {
505 WriterInner::NoColor(ref w) => {
506 WriterInnerLock::NoColor(NoColor(w.0.lock()))
507 }
508 WriterInner::Ansi(ref w) => {
509 WriterInnerLock::Ansi(Ansi(w.0.lock()))
510 }
511 #[cfg(windows)]
512 WriterInner::Windows { ref wtr, ref console } => {
513 WriterInnerLock::Windows {
514 wtr: wtr.lock(),
515 console: console.lock().unwrap(),
516 }
517 }
518 };
519 StandardStreamLock { wtr: stream.wtr.wrap(locked) }
520 }
521}
522
523impl BufferedStandardStream {
524 pub fn stdout(choice: ColorChoice) -> BufferedStandardStream {
533 let wtr =
534 WriterInner::create(StandardStreamType::StdoutBuffered, choice);
535 BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
536 }
537
538 pub fn stderr(choice: ColorChoice) -> BufferedStandardStream {
547 let wtr =
548 WriterInner::create(StandardStreamType::StderrBuffered, choice);
549 BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
550 }
551}
552
553impl WriterInner<IoStandardStream> {
554 #[cfg(not(windows))]
557 fn create(
558 sty: StandardStreamType,
559 choice: ColorChoice,
560 ) -> WriterInner<IoStandardStream> {
561 if choice.should_attempt_color() {
562 WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
563 } else {
564 WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
565 }
566 }
567
568 #[cfg(windows)]
574 fn create(
575 sty: StandardStreamType,
576 choice: ColorChoice,
577 ) -> WriterInner<IoStandardStream> {
578 let mut con = match sty {
579 StandardStreamType::Stdout => wincon::Console::stdout(),
580 StandardStreamType::Stderr => wincon::Console::stderr(),
581 StandardStreamType::StdoutBuffered => wincon::Console::stdout(),
582 StandardStreamType::StderrBuffered => wincon::Console::stderr(),
583 };
584 let is_console_virtual = con
585 .as_mut()
586 .map(|con| con.set_virtual_terminal_processing(true).is_ok())
587 .unwrap_or(false);
588 if choice.should_attempt_color() {
589 if choice.should_ansi() || is_console_virtual {
590 WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
591 } else if let Ok(console) = con {
592 WriterInner::Windows {
593 wtr: IoStandardStream::new(sty),
594 console: Mutex::new(console),
595 }
596 } else {
597 WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
598 }
599 } else {
600 WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
601 }
602 }
603}
604
605impl io::Write for StandardStream {
606 #[inline]
607 fn write(&mut self, b: &[u8]) -> io::Result<usize> {
608 self.wtr.write(b)
609 }
610
611 #[inline]
612 fn flush(&mut self) -> io::Result<()> {
613 self.wtr.flush()
614 }
615}
616
617impl WriteColor for StandardStream {
618 #[inline]
619 fn supports_color(&self) -> bool {
620 self.wtr.supports_color()
621 }
622
623 #[inline]
624 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
625 self.wtr.set_color(spec)
626 }
627
628 #[inline]
629 fn reset(&mut self) -> io::Result<()> {
630 self.wtr.reset()
631 }
632
633 #[inline]
634 fn is_synchronous(&self) -> bool {
635 self.wtr.is_synchronous()
636 }
637}
638
639impl<'a> io::Write for StandardStreamLock<'a> {
640 #[inline]
641 fn write(&mut self, b: &[u8]) -> io::Result<usize> {
642 self.wtr.write(b)
643 }
644
645 #[inline]
646 fn flush(&mut self) -> io::Result<()> {
647 self.wtr.flush()
648 }
649}
650
651impl<'a> WriteColor for StandardStreamLock<'a> {
652 #[inline]
653 fn supports_color(&self) -> bool {
654 self.wtr.supports_color()
655 }
656
657 #[inline]
658 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
659 self.wtr.set_color(spec)
660 }
661
662 #[inline]
663 fn reset(&mut self) -> io::Result<()> {
664 self.wtr.reset()
665 }
666
667 #[inline]
668 fn is_synchronous(&self) -> bool {
669 self.wtr.is_synchronous()
670 }
671}
672
673impl io::Write for BufferedStandardStream {
674 #[inline]
675 fn write(&mut self, b: &[u8]) -> io::Result<usize> {
676 self.wtr.write(b)
677 }
678
679 #[inline]
680 fn flush(&mut self) -> io::Result<()> {
681 self.wtr.flush()
682 }
683}
684
685impl WriteColor for BufferedStandardStream {
686 #[inline]
687 fn supports_color(&self) -> bool {
688 self.wtr.supports_color()
689 }
690
691 #[inline]
692 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
693 if self.is_synchronous() {
694 self.wtr.flush()?;
695 }
696 self.wtr.set_color(spec)
697 }
698
699 #[inline]
700 fn reset(&mut self) -> io::Result<()> {
701 self.wtr.reset()
702 }
703
704 #[inline]
705 fn is_synchronous(&self) -> bool {
706 self.wtr.is_synchronous()
707 }
708}
709
710impl<W: io::Write> io::Write for WriterInner<W> {
711 #[inline(always)]
712 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
713 match *self {
714 WriterInner::NoColor(ref mut wtr) => wtr.write(buf),
715 WriterInner::Ansi(ref mut wtr) => wtr.write(buf),
716 #[cfg(windows)]
717 WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf),
718 }
719 }
720
721 #[inline(always)]
722 fn flush(&mut self) -> io::Result<()> {
723 match *self {
724 WriterInner::NoColor(ref mut wtr) => wtr.flush(),
725 WriterInner::Ansi(ref mut wtr) => wtr.flush(),
726 #[cfg(windows)]
727 WriterInner::Windows { ref mut wtr, .. } => wtr.flush(),
728 }
729 }
730}
731
732impl<W: io::Write> WriteColor for WriterInner<W> {
733 fn supports_color(&self) -> bool {
734 match *self {
735 WriterInner::NoColor(_) => false,
736 WriterInner::Ansi(_) => true,
737 #[cfg(windows)]
738 WriterInner::Windows { .. } => true,
739 }
740 }
741
742 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
743 match *self {
744 WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
745 WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec),
746 #[cfg(windows)]
747 WriterInner::Windows { ref mut wtr, ref console } => {
748 wtr.flush()?;
749 let mut console = console.lock().unwrap();
750 spec.write_console(&mut *console)
751 }
752 }
753 }
754
755 fn reset(&mut self) -> io::Result<()> {
756 match *self {
757 WriterInner::NoColor(ref mut wtr) => wtr.reset(),
758 WriterInner::Ansi(ref mut wtr) => wtr.reset(),
759 #[cfg(windows)]
760 WriterInner::Windows { ref mut wtr, ref mut console } => {
761 wtr.flush()?;
762 console.lock().unwrap().reset()?;
763 Ok(())
764 }
765 }
766 }
767
768 fn is_synchronous(&self) -> bool {
769 match *self {
770 WriterInner::NoColor(_) => false,
771 WriterInner::Ansi(_) => false,
772 #[cfg(windows)]
773 WriterInner::Windows { .. } => true,
774 }
775 }
776}
777
778impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> {
779 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
780 match *self {
781 WriterInnerLock::Unreachable(_) => unreachable!(),
782 WriterInnerLock::NoColor(ref mut wtr) => wtr.write(buf),
783 WriterInnerLock::Ansi(ref mut wtr) => wtr.write(buf),
784 #[cfg(windows)]
785 WriterInnerLock::Windows { ref mut wtr, .. } => wtr.write(buf),
786 }
787 }
788
789 fn flush(&mut self) -> io::Result<()> {
790 match *self {
791 WriterInnerLock::Unreachable(_) => unreachable!(),
792 WriterInnerLock::NoColor(ref mut wtr) => wtr.flush(),
793 WriterInnerLock::Ansi(ref mut wtr) => wtr.flush(),
794 #[cfg(windows)]
795 WriterInnerLock::Windows { ref mut wtr, .. } => wtr.flush(),
796 }
797 }
798}
799
800impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
801 fn supports_color(&self) -> bool {
802 match *self {
803 WriterInnerLock::Unreachable(_) => unreachable!(),
804 WriterInnerLock::NoColor(_) => false,
805 WriterInnerLock::Ansi(_) => true,
806 #[cfg(windows)]
807 WriterInnerLock::Windows { .. } => true,
808 }
809 }
810
811 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
812 match *self {
813 WriterInnerLock::Unreachable(_) => unreachable!(),
814 WriterInnerLock::NoColor(ref mut wtr) => wtr.set_color(spec),
815 WriterInnerLock::Ansi(ref mut wtr) => wtr.set_color(spec),
816 #[cfg(windows)]
817 WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
818 wtr.flush()?;
819 spec.write_console(console)
820 }
821 }
822 }
823
824 fn reset(&mut self) -> io::Result<()> {
825 match *self {
826 WriterInnerLock::Unreachable(_) => unreachable!(),
827 WriterInnerLock::NoColor(ref mut wtr) => wtr.reset(),
828 WriterInnerLock::Ansi(ref mut wtr) => wtr.reset(),
829 #[cfg(windows)]
830 WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
831 wtr.flush()?;
832 console.reset()?;
833 Ok(())
834 }
835 }
836 }
837
838 fn is_synchronous(&self) -> bool {
839 match *self {
840 WriterInnerLock::Unreachable(_) => unreachable!(),
841 WriterInnerLock::NoColor(_) => false,
842 WriterInnerLock::Ansi(_) => false,
843 #[cfg(windows)]
844 WriterInnerLock::Windows { .. } => true,
845 }
846 }
847}
848
849pub struct BufferWriter {
859 stream: LossyStandardStream<IoStandardStream>,
860 printed: AtomicBool,
861 separator: Option<Vec<u8>>,
862 color_choice: ColorChoice,
863 #[cfg(windows)]
864 console: Option<Mutex<wincon::Console>>,
865}
866
867impl BufferWriter {
868 #[cfg(not(windows))]
874 fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
875 BufferWriter {
876 stream: LossyStandardStream::new(IoStandardStream::new(sty)),
877 printed: AtomicBool::new(false),
878 separator: None,
879 color_choice: choice,
880 }
881 }
882
883 #[cfg(windows)]
892 fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
893 let mut con = match sty {
894 StandardStreamType::Stdout => wincon::Console::stdout(),
895 StandardStreamType::Stderr => wincon::Console::stderr(),
896 StandardStreamType::StdoutBuffered => wincon::Console::stdout(),
897 StandardStreamType::StderrBuffered => wincon::Console::stderr(),
898 }
899 .ok();
900 let is_console_virtual = con
901 .as_mut()
902 .map(|con| con.set_virtual_terminal_processing(true).is_ok())
903 .unwrap_or(false);
904 if is_console_virtual {
907 con = None;
908 }
909 let stream = LossyStandardStream::new(IoStandardStream::new(sty));
910 BufferWriter {
911 stream: stream,
912 printed: AtomicBool::new(false),
913 separator: None,
914 color_choice: choice,
915 console: con.map(Mutex::new),
916 }
917 }
918
919 pub fn stdout(choice: ColorChoice) -> BufferWriter {
928 BufferWriter::create(StandardStreamType::Stdout, choice)
929 }
930
931 pub fn stderr(choice: ColorChoice) -> BufferWriter {
940 BufferWriter::create(StandardStreamType::Stderr, choice)
941 }
942
943 pub fn separator(&mut self, sep: Option<Vec<u8>>) {
948 self.separator = sep;
949 }
950
951 #[cfg(not(windows))]
956 pub fn buffer(&self) -> Buffer {
957 Buffer::new(self.color_choice)
958 }
959
960 #[cfg(windows)]
965 pub fn buffer(&self) -> Buffer {
966 Buffer::new(self.color_choice, self.console.is_some())
967 }
968
969 pub fn print(&self, buf: &Buffer) -> io::Result<()> {
975 if buf.is_empty() {
976 return Ok(());
977 }
978 let mut stream = self.stream.wrap(self.stream.get_ref().lock());
979 if let Some(ref sep) = self.separator {
980 if self.printed.load(Ordering::SeqCst) {
981 stream.write_all(sep)?;
982 stream.write_all(b"\n")?;
983 }
984 }
985 match buf.0 {
986 BufferInner::NoColor(ref b) => stream.write_all(&b.0)?,
987 BufferInner::Ansi(ref b) => stream.write_all(&b.0)?,
988 #[cfg(windows)]
989 BufferInner::Windows(ref b) => {
990 let console_mutex = self
993 .console
994 .as_ref()
995 .expect("got Windows buffer but have no Console");
996 let mut console = console_mutex.lock().unwrap();
997 b.print(&mut *console, &mut stream)?;
998 }
999 }
1000 self.printed.store(true, Ordering::SeqCst);
1001 Ok(())
1002 }
1003}
1004
1005pub struct Buffer(BufferInner);
1017
1018enum BufferInner {
1020 NoColor(NoColor<Vec<u8>>),
1023 Ansi(Ansi<Vec<u8>>),
1025 #[cfg(windows)]
1029 Windows(WindowsBuffer),
1030}
1031
1032impl Buffer {
1033 #[cfg(not(windows))]
1035 fn new(choice: ColorChoice) -> Buffer {
1036 if choice.should_attempt_color() {
1037 Buffer::ansi()
1038 } else {
1039 Buffer::no_color()
1040 }
1041 }
1042
1043 #[cfg(windows)]
1051 fn new(choice: ColorChoice, console: bool) -> Buffer {
1052 if choice.should_attempt_color() {
1053 if !console || choice.should_ansi() {
1054 Buffer::ansi()
1055 } else {
1056 Buffer::console()
1057 }
1058 } else {
1059 Buffer::no_color()
1060 }
1061 }
1062
1063 pub fn no_color() -> Buffer {
1065 Buffer(BufferInner::NoColor(NoColor(vec![])))
1066 }
1067
1068 pub fn ansi() -> Buffer {
1070 Buffer(BufferInner::Ansi(Ansi(vec![])))
1071 }
1072
1073 #[cfg(windows)]
1075 pub fn console() -> Buffer {
1076 Buffer(BufferInner::Windows(WindowsBuffer::new()))
1077 }
1078
1079 pub fn is_empty(&self) -> bool {
1081 self.len() == 0
1082 }
1083
1084 pub fn len(&self) -> usize {
1086 match self.0 {
1087 BufferInner::NoColor(ref b) => b.0.len(),
1088 BufferInner::Ansi(ref b) => b.0.len(),
1089 #[cfg(windows)]
1090 BufferInner::Windows(ref b) => b.buf.len(),
1091 }
1092 }
1093
1094 pub fn clear(&mut self) {
1096 match self.0 {
1097 BufferInner::NoColor(ref mut b) => b.0.clear(),
1098 BufferInner::Ansi(ref mut b) => b.0.clear(),
1099 #[cfg(windows)]
1100 BufferInner::Windows(ref mut b) => b.clear(),
1101 }
1102 }
1103
1104 pub fn into_inner(self) -> Vec<u8> {
1109 match self.0 {
1110 BufferInner::NoColor(b) => b.0,
1111 BufferInner::Ansi(b) => b.0,
1112 #[cfg(windows)]
1113 BufferInner::Windows(b) => b.buf,
1114 }
1115 }
1116
1117 pub fn as_slice(&self) -> &[u8] {
1119 match self.0 {
1120 BufferInner::NoColor(ref b) => &b.0,
1121 BufferInner::Ansi(ref b) => &b.0,
1122 #[cfg(windows)]
1123 BufferInner::Windows(ref b) => &b.buf,
1124 }
1125 }
1126
1127 pub fn as_mut_slice(&mut self) -> &mut [u8] {
1129 match self.0 {
1130 BufferInner::NoColor(ref mut b) => &mut b.0,
1131 BufferInner::Ansi(ref mut b) => &mut b.0,
1132 #[cfg(windows)]
1133 BufferInner::Windows(ref mut b) => &mut b.buf,
1134 }
1135 }
1136}
1137
1138impl io::Write for Buffer {
1139 #[inline]
1140 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1141 match self.0 {
1142 BufferInner::NoColor(ref mut w) => w.write(buf),
1143 BufferInner::Ansi(ref mut w) => w.write(buf),
1144 #[cfg(windows)]
1145 BufferInner::Windows(ref mut w) => w.write(buf),
1146 }
1147 }
1148
1149 #[inline]
1150 fn flush(&mut self) -> io::Result<()> {
1151 match self.0 {
1152 BufferInner::NoColor(ref mut w) => w.flush(),
1153 BufferInner::Ansi(ref mut w) => w.flush(),
1154 #[cfg(windows)]
1155 BufferInner::Windows(ref mut w) => w.flush(),
1156 }
1157 }
1158}
1159
1160impl WriteColor for Buffer {
1161 #[inline]
1162 fn supports_color(&self) -> bool {
1163 match self.0 {
1164 BufferInner::NoColor(_) => false,
1165 BufferInner::Ansi(_) => true,
1166 #[cfg(windows)]
1167 BufferInner::Windows(_) => true,
1168 }
1169 }
1170
1171 #[inline]
1172 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1173 match self.0 {
1174 BufferInner::NoColor(ref mut w) => w.set_color(spec),
1175 BufferInner::Ansi(ref mut w) => w.set_color(spec),
1176 #[cfg(windows)]
1177 BufferInner::Windows(ref mut w) => w.set_color(spec),
1178 }
1179 }
1180
1181 #[inline]
1182 fn reset(&mut self) -> io::Result<()> {
1183 match self.0 {
1184 BufferInner::NoColor(ref mut w) => w.reset(),
1185 BufferInner::Ansi(ref mut w) => w.reset(),
1186 #[cfg(windows)]
1187 BufferInner::Windows(ref mut w) => w.reset(),
1188 }
1189 }
1190
1191 #[inline]
1192 fn is_synchronous(&self) -> bool {
1193 false
1194 }
1195}
1196
1197pub struct NoColor<W>(W);
1199
1200impl<W: Write> NoColor<W> {
1201 pub fn new(wtr: W) -> NoColor<W> {
1204 NoColor(wtr)
1205 }
1206
1207 pub fn into_inner(self) -> W {
1209 self.0
1210 }
1211
1212 pub fn get_ref(&self) -> &W {
1214 &self.0
1215 }
1216
1217 pub fn get_mut(&mut self) -> &mut W {
1219 &mut self.0
1220 }
1221}
1222
1223impl<W: io::Write> io::Write for NoColor<W> {
1224 #[inline]
1225 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1226 self.0.write(buf)
1227 }
1228
1229 #[inline]
1230 fn flush(&mut self) -> io::Result<()> {
1231 self.0.flush()
1232 }
1233}
1234
1235impl<W: io::Write> WriteColor for NoColor<W> {
1236 #[inline]
1237 fn supports_color(&self) -> bool {
1238 false
1239 }
1240
1241 #[inline]
1242 fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
1243 Ok(())
1244 }
1245
1246 #[inline]
1247 fn reset(&mut self) -> io::Result<()> {
1248 Ok(())
1249 }
1250
1251 #[inline]
1252 fn is_synchronous(&self) -> bool {
1253 false
1254 }
1255}
1256
1257pub struct Ansi<W>(W);
1259
1260impl<W: Write> Ansi<W> {
1261 pub fn new(wtr: W) -> Ansi<W> {
1264 Ansi(wtr)
1265 }
1266
1267 pub fn into_inner(self) -> W {
1269 self.0
1270 }
1271
1272 pub fn get_ref(&self) -> &W {
1274 &self.0
1275 }
1276
1277 pub fn get_mut(&mut self) -> &mut W {
1279 &mut self.0
1280 }
1281}
1282
1283impl<W: io::Write> io::Write for Ansi<W> {
1284 #[inline]
1285 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1286 self.0.write(buf)
1287 }
1288
1289 #[inline]
1290 fn flush(&mut self) -> io::Result<()> {
1291 self.0.flush()
1292 }
1293}
1294
1295impl<W: io::Write> WriteColor for Ansi<W> {
1296 #[inline]
1297 fn supports_color(&self) -> bool {
1298 true
1299 }
1300
1301 #[inline]
1302 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1303 if spec.reset {
1304 self.reset()?;
1305 }
1306 if spec.bold {
1307 self.write_str("\x1B[1m")?;
1308 }
1309 if spec.dimmed {
1310 self.write_str("\x1B[2m")?;
1311 }
1312 if spec.italic {
1313 self.write_str("\x1B[3m")?;
1314 }
1315 if spec.underline {
1316 self.write_str("\x1B[4m")?;
1317 }
1318 if let Some(ref c) = spec.fg_color {
1319 self.write_color(true, c, spec.intense)?;
1320 }
1321 if let Some(ref c) = spec.bg_color {
1322 self.write_color(false, c, spec.intense)?;
1323 }
1324 Ok(())
1325 }
1326
1327 #[inline]
1328 fn reset(&mut self) -> io::Result<()> {
1329 self.write_str("\x1B[0m")
1330 }
1331
1332 #[inline]
1333 fn is_synchronous(&self) -> bool {
1334 false
1335 }
1336}
1337
1338impl<W: io::Write> Ansi<W> {
1339 fn write_str(&mut self, s: &str) -> io::Result<()> {
1340 self.write_all(s.as_bytes())
1341 }
1342
1343 fn write_color(
1344 &mut self,
1345 fg: bool,
1346 c: &Color,
1347 intense: bool,
1348 ) -> io::Result<()> {
1349 macro_rules! write_intense {
1350 ($clr:expr) => {
1351 if fg {
1352 self.write_str(concat!("\x1B[38;5;", $clr, "m"))
1353 } else {
1354 self.write_str(concat!("\x1B[48;5;", $clr, "m"))
1355 }
1356 };
1357 }
1358 macro_rules! write_normal {
1359 ($clr:expr) => {
1360 if fg {
1361 self.write_str(concat!("\x1B[3", $clr, "m"))
1362 } else {
1363 self.write_str(concat!("\x1B[4", $clr, "m"))
1364 }
1365 };
1366 }
1367 macro_rules! write_var_ansi_code {
1368 ($pre:expr, $($code:expr),+) => {{
1369 let pre_len = $pre.len();
1374 assert!(pre_len <= 7);
1375 let mut fmt = [0u8; 19];
1376 fmt[..pre_len].copy_from_slice($pre);
1377 let mut i = pre_len - 1;
1378 $(
1379 let c1: u8 = ($code / 100) % 10;
1380 let c2: u8 = ($code / 10) % 10;
1381 let c3: u8 = $code % 10;
1382 let mut printed = false;
1383
1384 if c1 != 0 {
1385 printed = true;
1386 i += 1;
1387 fmt[i] = b'0' + c1;
1388 }
1389 if c2 != 0 || printed {
1390 i += 1;
1391 fmt[i] = b'0' + c2;
1392 }
1393 i += 1;
1395 fmt[i] = b'0' + c3;
1396 i += 1;
1397 fmt[i] = b';';
1398 )+
1399
1400 fmt[i] = b'm';
1401 self.write_all(&fmt[0..i+1])
1402 }}
1403 }
1404 macro_rules! write_custom {
1405 ($ansi256:expr) => {
1406 if fg {
1407 write_var_ansi_code!(b"\x1B[38;5;", $ansi256)
1408 } else {
1409 write_var_ansi_code!(b"\x1B[48;5;", $ansi256)
1410 }
1411 };
1412
1413 ($r:expr, $g:expr, $b:expr) => {{
1414 if fg {
1415 write_var_ansi_code!(b"\x1B[38;2;", $r, $g, $b)
1416 } else {
1417 write_var_ansi_code!(b"\x1B[48;2;", $r, $g, $b)
1418 }
1419 }};
1420 }
1421 if intense {
1422 match *c {
1423 Color::Black => write_intense!("8"),
1424 Color::Blue => write_intense!("12"),
1425 Color::Green => write_intense!("10"),
1426 Color::Red => write_intense!("9"),
1427 Color::Cyan => write_intense!("14"),
1428 Color::Magenta => write_intense!("13"),
1429 Color::Yellow => write_intense!("11"),
1430 Color::White => write_intense!("15"),
1431 Color::Ansi256(c) => write_custom!(c),
1432 Color::Rgb(r, g, b) => write_custom!(r, g, b),
1433 Color::__Nonexhaustive => unreachable!(),
1434 }
1435 } else {
1436 match *c {
1437 Color::Black => write_normal!("0"),
1438 Color::Blue => write_normal!("4"),
1439 Color::Green => write_normal!("2"),
1440 Color::Red => write_normal!("1"),
1441 Color::Cyan => write_normal!("6"),
1442 Color::Magenta => write_normal!("5"),
1443 Color::Yellow => write_normal!("3"),
1444 Color::White => write_normal!("7"),
1445 Color::Ansi256(c) => write_custom!(c),
1446 Color::Rgb(r, g, b) => write_custom!(r, g, b),
1447 Color::__Nonexhaustive => unreachable!(),
1448 }
1449 }
1450 }
1451}
1452
1453#[cfg(windows)]
1469#[derive(Clone, Debug)]
1470struct WindowsBuffer {
1471 buf: Vec<u8>,
1473 colors: Vec<(usize, Option<ColorSpec>)>,
1479}
1480
1481#[cfg(windows)]
1482impl WindowsBuffer {
1483 fn new() -> WindowsBuffer {
1485 WindowsBuffer { buf: vec![], colors: vec![] }
1486 }
1487
1488 fn push(&mut self, spec: Option<ColorSpec>) {
1493 let pos = self.buf.len();
1494 self.colors.push((pos, spec));
1495 }
1496
1497 fn print(
1500 &self,
1501 console: &mut wincon::Console,
1502 stream: &mut LossyStandardStream<IoStandardStreamLock>,
1503 ) -> io::Result<()> {
1504 let mut last = 0;
1505 for &(pos, ref spec) in &self.colors {
1506 stream.write_all(&self.buf[last..pos])?;
1507 stream.flush()?;
1508 last = pos;
1509 match *spec {
1510 None => console.reset()?,
1511 Some(ref spec) => spec.write_console(console)?,
1512 }
1513 }
1514 stream.write_all(&self.buf[last..])?;
1515 stream.flush()
1516 }
1517
1518 fn clear(&mut self) {
1520 self.buf.clear();
1521 self.colors.clear();
1522 }
1523}
1524
1525#[cfg(windows)]
1526impl io::Write for WindowsBuffer {
1527 #[inline]
1528 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1529 self.buf.extend_from_slice(buf);
1530 Ok(buf.len())
1531 }
1532
1533 #[inline]
1534 fn flush(&mut self) -> io::Result<()> {
1535 Ok(())
1536 }
1537}
1538
1539#[cfg(windows)]
1540impl WriteColor for WindowsBuffer {
1541 #[inline]
1542 fn supports_color(&self) -> bool {
1543 true
1544 }
1545
1546 #[inline]
1547 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1548 self.push(Some(spec.clone()));
1549 Ok(())
1550 }
1551
1552 #[inline]
1553 fn reset(&mut self) -> io::Result<()> {
1554 self.push(None);
1555 Ok(())
1556 }
1557
1558 #[inline]
1559 fn is_synchronous(&self) -> bool {
1560 false
1561 }
1562}
1563
1564#[derive(Clone, Debug, Eq, PartialEq)]
1566pub struct ColorSpec {
1567 fg_color: Option<Color>,
1568 bg_color: Option<Color>,
1569 bold: bool,
1570 intense: bool,
1571 underline: bool,
1572 dimmed: bool,
1573 italic: bool,
1574 reset: bool,
1575}
1576
1577impl Default for ColorSpec {
1578 fn default() -> ColorSpec {
1579 ColorSpec {
1580 fg_color: None,
1581 bg_color: None,
1582 bold: false,
1583 intense: false,
1584 underline: false,
1585 dimmed: false,
1586 italic: false,
1587 reset: true,
1588 }
1589 }
1590}
1591
1592impl ColorSpec {
1593 pub fn new() -> ColorSpec {
1595 ColorSpec::default()
1596 }
1597
1598 pub fn fg(&self) -> Option<&Color> {
1600 self.fg_color.as_ref()
1601 }
1602
1603 pub fn set_fg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1605 self.fg_color = color;
1606 self
1607 }
1608
1609 pub fn bg(&self) -> Option<&Color> {
1611 self.bg_color.as_ref()
1612 }
1613
1614 pub fn set_bg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1616 self.bg_color = color;
1617 self
1618 }
1619
1620 pub fn bold(&self) -> bool {
1624 self.bold
1625 }
1626
1627 pub fn set_bold(&mut self, yes: bool) -> &mut ColorSpec {
1631 self.bold = yes;
1632 self
1633 }
1634
1635 pub fn dimmed(&self) -> bool {
1639 self.dimmed
1640 }
1641
1642 pub fn set_dimmed(&mut self, yes: bool) -> &mut ColorSpec {
1646 self.dimmed = yes;
1647 self
1648 }
1649
1650 pub fn italic(&self) -> bool {
1654 self.italic
1655 }
1656
1657 pub fn set_italic(&mut self, yes: bool) -> &mut ColorSpec {
1661 self.italic = yes;
1662 self
1663 }
1664
1665 pub fn underline(&self) -> bool {
1669 self.underline
1670 }
1671
1672 pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec {
1676 self.underline = yes;
1677 self
1678 }
1679
1680 pub fn reset(&self) -> bool {
1688 self.reset
1689 }
1690
1691 pub fn set_reset(&mut self, yes: bool) -> &mut ColorSpec {
1703 self.reset = yes;
1704 self
1705 }
1706
1707 pub fn intense(&self) -> bool {
1716 self.intense
1717 }
1718
1719 pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec {
1728 self.intense = yes;
1729 self
1730 }
1731
1732 pub fn is_none(&self) -> bool {
1734 self.fg_color.is_none()
1735 && self.bg_color.is_none()
1736 && !self.bold
1737 && !self.underline
1738 && !self.dimmed
1739 && !self.italic
1740 && !self.intense
1741 }
1742
1743 pub fn clear(&mut self) {
1745 self.fg_color = None;
1746 self.bg_color = None;
1747 self.bold = false;
1748 self.underline = false;
1749 self.intense = false;
1750 self.dimmed = false;
1751 self.italic = false;
1752 }
1753
1754 #[cfg(windows)]
1756 fn write_console(&self, console: &mut wincon::Console) -> io::Result<()> {
1757 let fg_color = self.fg_color.and_then(|c| c.to_windows(self.intense));
1758 if let Some((intense, color)) = fg_color {
1759 console.fg(intense, color)?;
1760 }
1761 let bg_color = self.bg_color.and_then(|c| c.to_windows(self.intense));
1762 if let Some((intense, color)) = bg_color {
1763 console.bg(intense, color)?;
1764 }
1765 Ok(())
1766 }
1767}
1768
1769#[allow(missing_docs)]
1791#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1792pub enum Color {
1793 Black,
1794 Blue,
1795 Green,
1796 Red,
1797 Cyan,
1798 Magenta,
1799 Yellow,
1800 White,
1801 Ansi256(u8),
1802 Rgb(u8, u8, u8),
1803 #[doc(hidden)]
1804 __Nonexhaustive,
1805}
1806
1807impl Color {
1808 #[cfg(windows)]
1810 fn to_windows(
1811 self,
1812 intense: bool,
1813 ) -> Option<(wincon::Intense, wincon::Color)> {
1814 use wincon::Intense::{No, Yes};
1815
1816 let color = match self {
1817 Color::Black => wincon::Color::Black,
1818 Color::Blue => wincon::Color::Blue,
1819 Color::Green => wincon::Color::Green,
1820 Color::Red => wincon::Color::Red,
1821 Color::Cyan => wincon::Color::Cyan,
1822 Color::Magenta => wincon::Color::Magenta,
1823 Color::Yellow => wincon::Color::Yellow,
1824 Color::White => wincon::Color::White,
1825 Color::Ansi256(0) => return Some((No, wincon::Color::Black)),
1826 Color::Ansi256(1) => return Some((No, wincon::Color::Red)),
1827 Color::Ansi256(2) => return Some((No, wincon::Color::Green)),
1828 Color::Ansi256(3) => return Some((No, wincon::Color::Yellow)),
1829 Color::Ansi256(4) => return Some((No, wincon::Color::Blue)),
1830 Color::Ansi256(5) => return Some((No, wincon::Color::Magenta)),
1831 Color::Ansi256(6) => return Some((No, wincon::Color::Cyan)),
1832 Color::Ansi256(7) => return Some((No, wincon::Color::White)),
1833 Color::Ansi256(8) => return Some((Yes, wincon::Color::Black)),
1834 Color::Ansi256(9) => return Some((Yes, wincon::Color::Red)),
1835 Color::Ansi256(10) => return Some((Yes, wincon::Color::Green)),
1836 Color::Ansi256(11) => return Some((Yes, wincon::Color::Yellow)),
1837 Color::Ansi256(12) => return Some((Yes, wincon::Color::Blue)),
1838 Color::Ansi256(13) => return Some((Yes, wincon::Color::Magenta)),
1839 Color::Ansi256(14) => return Some((Yes, wincon::Color::Cyan)),
1840 Color::Ansi256(15) => return Some((Yes, wincon::Color::White)),
1841 Color::Ansi256(_) => return None,
1842 Color::Rgb(_, _, _) => return None,
1843 Color::__Nonexhaustive => unreachable!(),
1844 };
1845 let intense = if intense { Yes } else { No };
1846 Some((intense, color))
1847 }
1848
1849 fn from_str_numeric(s: &str) -> Result<Color, ParseColorError> {
1851 fn parse_number(s: &str) -> Option<u8> {
1858 use std::u8;
1859
1860 if s.starts_with("0x") {
1861 u8::from_str_radix(&s[2..], 16).ok()
1862 } else {
1863 u8::from_str_radix(s, 10).ok()
1864 }
1865 }
1866
1867 let codes: Vec<&str> = s.split(',').collect();
1868 if codes.len() == 1 {
1869 if let Some(n) = parse_number(&codes[0]) {
1870 Ok(Color::Ansi256(n))
1871 } else {
1872 if s.chars().all(|c| c.is_digit(16)) {
1873 Err(ParseColorError {
1874 kind: ParseColorErrorKind::InvalidAnsi256,
1875 given: s.to_string(),
1876 })
1877 } else {
1878 Err(ParseColorError {
1879 kind: ParseColorErrorKind::InvalidName,
1880 given: s.to_string(),
1881 })
1882 }
1883 }
1884 } else if codes.len() == 3 {
1885 let mut v = vec![];
1886 for code in codes {
1887 let n = parse_number(code).ok_or_else(|| ParseColorError {
1888 kind: ParseColorErrorKind::InvalidRgb,
1889 given: s.to_string(),
1890 })?;
1891 v.push(n);
1892 }
1893 Ok(Color::Rgb(v[0], v[1], v[2]))
1894 } else {
1895 Err(if s.contains(",") {
1896 ParseColorError {
1897 kind: ParseColorErrorKind::InvalidRgb,
1898 given: s.to_string(),
1899 }
1900 } else {
1901 ParseColorError {
1902 kind: ParseColorErrorKind::InvalidName,
1903 given: s.to_string(),
1904 }
1905 })
1906 }
1907 }
1908}
1909
1910#[derive(Clone, Debug, Eq, PartialEq)]
1912pub struct ParseColorError {
1913 kind: ParseColorErrorKind,
1914 given: String,
1915}
1916
1917#[derive(Clone, Debug, Eq, PartialEq)]
1918enum ParseColorErrorKind {
1919 InvalidName,
1920 InvalidAnsi256,
1921 InvalidRgb,
1922}
1923
1924impl ParseColorError {
1925 pub fn invalid(&self) -> &str {
1927 &self.given
1928 }
1929}
1930
1931impl error::Error for ParseColorError {
1932 fn description(&self) -> &str {
1933 use self::ParseColorErrorKind::*;
1934 match self.kind {
1935 InvalidName => "unrecognized color name",
1936 InvalidAnsi256 => "invalid ansi256 color number",
1937 InvalidRgb => "invalid RGB color triple",
1938 }
1939 }
1940}
1941
1942impl fmt::Display for ParseColorError {
1943 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1944 use self::ParseColorErrorKind::*;
1945 match self.kind {
1946 InvalidName => write!(
1947 f,
1948 "unrecognized color name '{}'. Choose from: \
1949 black, blue, green, red, cyan, magenta, yellow, \
1950 white",
1951 self.given
1952 ),
1953 InvalidAnsi256 => write!(
1954 f,
1955 "unrecognized ansi256 color number, \
1956 should be '[0-255]' (or a hex number), but is '{}'",
1957 self.given
1958 ),
1959 InvalidRgb => write!(
1960 f,
1961 "unrecognized RGB color triple, \
1962 should be '[0-255],[0-255],[0-255]' (or a hex \
1963 triple), but is '{}'",
1964 self.given
1965 ),
1966 }
1967 }
1968}
1969
1970impl FromStr for Color {
1971 type Err = ParseColorError;
1972
1973 fn from_str(s: &str) -> Result<Color, ParseColorError> {
1974 match &*s.to_lowercase() {
1975 "black" => Ok(Color::Black),
1976 "blue" => Ok(Color::Blue),
1977 "green" => Ok(Color::Green),
1978 "red" => Ok(Color::Red),
1979 "cyan" => Ok(Color::Cyan),
1980 "magenta" => Ok(Color::Magenta),
1981 "yellow" => Ok(Color::Yellow),
1982 "white" => Ok(Color::White),
1983 _ => Color::from_str_numeric(s),
1984 }
1985 }
1986}
1987
1988struct LossyStandardStream<W> {
1989 wtr: W,
1990 #[cfg(windows)]
1991 is_console: bool,
1992}
1993
1994impl<W: io::Write> LossyStandardStream<W> {
1995 #[cfg(not(windows))]
1996 fn new(wtr: W) -> LossyStandardStream<W> {
1997 LossyStandardStream { wtr: wtr }
1998 }
1999
2000 #[cfg(windows)]
2001 fn new(wtr: W) -> LossyStandardStream<W> {
2002 let is_console = wincon::Console::stdout().is_ok()
2003 || wincon::Console::stderr().is_ok();
2004 LossyStandardStream { wtr: wtr, is_console: is_console }
2005 }
2006
2007 #[cfg(not(windows))]
2008 fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2009 LossyStandardStream::new(wtr)
2010 }
2011
2012 #[cfg(windows)]
2013 fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2014 LossyStandardStream { wtr: wtr, is_console: self.is_console }
2015 }
2016
2017 fn get_ref(&self) -> &W {
2018 &self.wtr
2019 }
2020}
2021
2022impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
2023 fn supports_color(&self) -> bool {
2024 self.wtr.supports_color()
2025 }
2026 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
2027 self.wtr.set_color(spec)
2028 }
2029 fn reset(&mut self) -> io::Result<()> {
2030 self.wtr.reset()
2031 }
2032 fn is_synchronous(&self) -> bool {
2033 self.wtr.is_synchronous()
2034 }
2035}
2036
2037impl<W: io::Write> io::Write for LossyStandardStream<W> {
2038 #[cfg(not(windows))]
2039 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2040 self.wtr.write(buf)
2041 }
2042
2043 #[cfg(windows)]
2044 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2045 if self.is_console {
2046 write_lossy_utf8(&mut self.wtr, buf)
2047 } else {
2048 self.wtr.write(buf)
2049 }
2050 }
2051
2052 fn flush(&mut self) -> io::Result<()> {
2053 self.wtr.flush()
2054 }
2055}
2056
2057#[cfg(windows)]
2058fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
2059 match ::std::str::from_utf8(buf) {
2060 Ok(s) => w.write(s.as_bytes()),
2061 Err(ref e) if e.valid_up_to() == 0 => {
2062 w.write(b"\xEF\xBF\xBD")?;
2063 Ok(1)
2064 }
2065 Err(e) => w.write(&buf[..e.valid_up_to()]),
2066 }
2067}
2068
2069#[cfg(test)]
2070mod tests {
2071 use super::{
2072 Ansi, Color, ColorSpec, ParseColorError, ParseColorErrorKind,
2073 StandardStream, WriteColor,
2074 };
2075
2076 fn assert_is_send<T: Send>() {}
2077
2078 #[test]
2079 fn standard_stream_is_send() {
2080 assert_is_send::<StandardStream>();
2081 }
2082
2083 #[test]
2084 fn test_simple_parse_ok() {
2085 let color = "green".parse::<Color>();
2086 assert_eq!(color, Ok(Color::Green));
2087 }
2088
2089 #[test]
2090 fn test_256_parse_ok() {
2091 let color = "7".parse::<Color>();
2092 assert_eq!(color, Ok(Color::Ansi256(7)));
2093
2094 let color = "32".parse::<Color>();
2095 assert_eq!(color, Ok(Color::Ansi256(32)));
2096
2097 let color = "0xFF".parse::<Color>();
2098 assert_eq!(color, Ok(Color::Ansi256(0xFF)));
2099 }
2100
2101 #[test]
2102 fn test_256_parse_err_out_of_range() {
2103 let color = "256".parse::<Color>();
2104 assert_eq!(
2105 color,
2106 Err(ParseColorError {
2107 kind: ParseColorErrorKind::InvalidAnsi256,
2108 given: "256".to_string(),
2109 })
2110 );
2111 }
2112
2113 #[test]
2114 fn test_rgb_parse_ok() {
2115 let color = "0,0,0".parse::<Color>();
2116 assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2117
2118 let color = "0,128,255".parse::<Color>();
2119 assert_eq!(color, Ok(Color::Rgb(0, 128, 255)));
2120
2121 let color = "0x0,0x0,0x0".parse::<Color>();
2122 assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2123
2124 let color = "0x33,0x66,0xFF".parse::<Color>();
2125 assert_eq!(color, Ok(Color::Rgb(0x33, 0x66, 0xFF)));
2126 }
2127
2128 #[test]
2129 fn test_rgb_parse_err_out_of_range() {
2130 let color = "0,0,256".parse::<Color>();
2131 assert_eq!(
2132 color,
2133 Err(ParseColorError {
2134 kind: ParseColorErrorKind::InvalidRgb,
2135 given: "0,0,256".to_string(),
2136 })
2137 );
2138 }
2139
2140 #[test]
2141 fn test_rgb_parse_err_bad_format() {
2142 let color = "0,0".parse::<Color>();
2143 assert_eq!(
2144 color,
2145 Err(ParseColorError {
2146 kind: ParseColorErrorKind::InvalidRgb,
2147 given: "0,0".to_string(),
2148 })
2149 );
2150
2151 let color = "not_a_color".parse::<Color>();
2152 assert_eq!(
2153 color,
2154 Err(ParseColorError {
2155 kind: ParseColorErrorKind::InvalidName,
2156 given: "not_a_color".to_string(),
2157 })
2158 );
2159 }
2160
2161 #[test]
2162 fn test_var_ansi_write_rgb() {
2163 let mut buf = Ansi::new(vec![]);
2164 let _ = buf.write_color(true, &Color::Rgb(254, 253, 255), false);
2165 assert_eq!(buf.0, b"\x1B[38;2;254;253;255m");
2166 }
2167
2168 #[test]
2169 fn test_reset() {
2170 let spec = ColorSpec::new();
2171 let mut buf = Ansi::new(vec![]);
2172 buf.set_color(&spec).unwrap();
2173 assert_eq!(buf.0, b"\x1B[0m");
2174 }
2175
2176 #[test]
2177 fn test_no_reset() {
2178 let mut spec = ColorSpec::new();
2179 spec.set_reset(false);
2180
2181 let mut buf = Ansi::new(vec![]);
2182 buf.set_color(&spec).unwrap();
2183 assert_eq!(buf.0, b"");
2184 }
2185
2186 #[test]
2187 fn test_var_ansi_write_256() {
2188 let mut buf = Ansi::new(vec![]);
2189 let _ = buf.write_color(false, &Color::Ansi256(7), false);
2190 assert_eq!(buf.0, b"\x1B[48;5;7m");
2191
2192 let mut buf = Ansi::new(vec![]);
2193 let _ = buf.write_color(false, &Color::Ansi256(208), false);
2194 assert_eq!(buf.0, b"\x1B[48;5;208m");
2195 }
2196
2197 fn all_attributes() -> Vec<ColorSpec> {
2198 let mut result = vec![];
2199 for fg in vec![None, Some(Color::Red)] {
2200 for bg in vec![None, Some(Color::Red)] {
2201 for bold in vec![false, true] {
2202 for underline in vec![false, true] {
2203 for intense in vec![false, true] {
2204 for italic in vec![false, true] {
2205 for dimmed in vec![false, true] {
2206 let mut color = ColorSpec::new();
2207 color.set_fg(fg);
2208 color.set_bg(bg);
2209 color.set_bold(bold);
2210 color.set_underline(underline);
2211 color.set_intense(intense);
2212 color.set_dimmed(dimmed);
2213 color.set_italic(italic);
2214 result.push(color);
2215 }
2216 }
2217 }
2218 }
2219 }
2220 }
2221 }
2222 result
2223 }
2224
2225 #[test]
2226 fn test_is_none() {
2227 for (i, color) in all_attributes().iter().enumerate() {
2228 assert_eq!(
2229 i == 0,
2230 color.is_none(),
2231 "{:?} => {}",
2232 color,
2233 color.is_none()
2234 )
2235 }
2236 }
2237
2238 #[test]
2239 fn test_clear() {
2240 for color in all_attributes() {
2241 let mut color1 = color.clone();
2242 color1.clear();
2243 assert!(color1.is_none(), "{:?} => {:?}", color, color1);
2244 }
2245 }
2246}