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
1453impl WriteColor for io::Sink {
1454 fn supports_color(&self) -> bool {
1455 false
1456 }
1457
1458 fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
1459 Ok(())
1460 }
1461
1462 fn reset(&mut self) -> io::Result<()> {
1463 Ok(())
1464 }
1465}
1466
1467#[cfg(windows)]
1483#[derive(Clone, Debug)]
1484struct WindowsBuffer {
1485 buf: Vec<u8>,
1487 colors: Vec<(usize, Option<ColorSpec>)>,
1493}
1494
1495#[cfg(windows)]
1496impl WindowsBuffer {
1497 fn new() -> WindowsBuffer {
1499 WindowsBuffer { buf: vec![], colors: vec![] }
1500 }
1501
1502 fn push(&mut self, spec: Option<ColorSpec>) {
1507 let pos = self.buf.len();
1508 self.colors.push((pos, spec));
1509 }
1510
1511 fn print(
1514 &self,
1515 console: &mut wincon::Console,
1516 stream: &mut LossyStandardStream<IoStandardStreamLock>,
1517 ) -> io::Result<()> {
1518 let mut last = 0;
1519 for &(pos, ref spec) in &self.colors {
1520 stream.write_all(&self.buf[last..pos])?;
1521 stream.flush()?;
1522 last = pos;
1523 match *spec {
1524 None => console.reset()?,
1525 Some(ref spec) => spec.write_console(console)?,
1526 }
1527 }
1528 stream.write_all(&self.buf[last..])?;
1529 stream.flush()
1530 }
1531
1532 fn clear(&mut self) {
1534 self.buf.clear();
1535 self.colors.clear();
1536 }
1537}
1538
1539#[cfg(windows)]
1540impl io::Write for WindowsBuffer {
1541 #[inline]
1542 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1543 self.buf.extend_from_slice(buf);
1544 Ok(buf.len())
1545 }
1546
1547 #[inline]
1548 fn flush(&mut self) -> io::Result<()> {
1549 Ok(())
1550 }
1551}
1552
1553#[cfg(windows)]
1554impl WriteColor for WindowsBuffer {
1555 #[inline]
1556 fn supports_color(&self) -> bool {
1557 true
1558 }
1559
1560 #[inline]
1561 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1562 self.push(Some(spec.clone()));
1563 Ok(())
1564 }
1565
1566 #[inline]
1567 fn reset(&mut self) -> io::Result<()> {
1568 self.push(None);
1569 Ok(())
1570 }
1571
1572 #[inline]
1573 fn is_synchronous(&self) -> bool {
1574 false
1575 }
1576}
1577
1578#[derive(Clone, Debug, Eq, PartialEq)]
1580pub struct ColorSpec {
1581 fg_color: Option<Color>,
1582 bg_color: Option<Color>,
1583 bold: bool,
1584 intense: bool,
1585 underline: bool,
1586 dimmed: bool,
1587 italic: bool,
1588 reset: bool,
1589}
1590
1591impl Default for ColorSpec {
1592 fn default() -> ColorSpec {
1593 ColorSpec {
1594 fg_color: None,
1595 bg_color: None,
1596 bold: false,
1597 intense: false,
1598 underline: false,
1599 dimmed: false,
1600 italic: false,
1601 reset: true,
1602 }
1603 }
1604}
1605
1606impl ColorSpec {
1607 pub fn new() -> ColorSpec {
1609 ColorSpec::default()
1610 }
1611
1612 pub fn fg(&self) -> Option<&Color> {
1614 self.fg_color.as_ref()
1615 }
1616
1617 pub fn set_fg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1619 self.fg_color = color;
1620 self
1621 }
1622
1623 pub fn bg(&self) -> Option<&Color> {
1625 self.bg_color.as_ref()
1626 }
1627
1628 pub fn set_bg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1630 self.bg_color = color;
1631 self
1632 }
1633
1634 pub fn bold(&self) -> bool {
1638 self.bold
1639 }
1640
1641 pub fn set_bold(&mut self, yes: bool) -> &mut ColorSpec {
1645 self.bold = yes;
1646 self
1647 }
1648
1649 pub fn dimmed(&self) -> bool {
1653 self.dimmed
1654 }
1655
1656 pub fn set_dimmed(&mut self, yes: bool) -> &mut ColorSpec {
1660 self.dimmed = yes;
1661 self
1662 }
1663
1664 pub fn italic(&self) -> bool {
1668 self.italic
1669 }
1670
1671 pub fn set_italic(&mut self, yes: bool) -> &mut ColorSpec {
1675 self.italic = yes;
1676 self
1677 }
1678
1679 pub fn underline(&self) -> bool {
1683 self.underline
1684 }
1685
1686 pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec {
1690 self.underline = yes;
1691 self
1692 }
1693
1694 pub fn reset(&self) -> bool {
1702 self.reset
1703 }
1704
1705 pub fn set_reset(&mut self, yes: bool) -> &mut ColorSpec {
1717 self.reset = yes;
1718 self
1719 }
1720
1721 pub fn intense(&self) -> bool {
1730 self.intense
1731 }
1732
1733 pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec {
1742 self.intense = yes;
1743 self
1744 }
1745
1746 pub fn is_none(&self) -> bool {
1748 self.fg_color.is_none()
1749 && self.bg_color.is_none()
1750 && !self.bold
1751 && !self.underline
1752 && !self.dimmed
1753 && !self.italic
1754 && !self.intense
1755 }
1756
1757 pub fn clear(&mut self) {
1759 self.fg_color = None;
1760 self.bg_color = None;
1761 self.bold = false;
1762 self.underline = false;
1763 self.intense = false;
1764 self.dimmed = false;
1765 self.italic = false;
1766 }
1767
1768 #[cfg(windows)]
1770 fn write_console(&self, console: &mut wincon::Console) -> io::Result<()> {
1771 let fg_color = self.fg_color.and_then(|c| c.to_windows(self.intense));
1772 if let Some((intense, color)) = fg_color {
1773 console.fg(intense, color)?;
1774 }
1775 let bg_color = self.bg_color.and_then(|c| c.to_windows(self.intense));
1776 if let Some((intense, color)) = bg_color {
1777 console.bg(intense, color)?;
1778 }
1779 Ok(())
1780 }
1781}
1782
1783#[allow(missing_docs)]
1805#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1806pub enum Color {
1807 Black,
1808 Blue,
1809 Green,
1810 Red,
1811 Cyan,
1812 Magenta,
1813 Yellow,
1814 White,
1815 Ansi256(u8),
1816 Rgb(u8, u8, u8),
1817 #[doc(hidden)]
1818 __Nonexhaustive,
1819}
1820
1821impl Color {
1822 #[cfg(windows)]
1824 fn to_windows(
1825 self,
1826 intense: bool,
1827 ) -> Option<(wincon::Intense, wincon::Color)> {
1828 use wincon::Intense::{No, Yes};
1829
1830 let color = match self {
1831 Color::Black => wincon::Color::Black,
1832 Color::Blue => wincon::Color::Blue,
1833 Color::Green => wincon::Color::Green,
1834 Color::Red => wincon::Color::Red,
1835 Color::Cyan => wincon::Color::Cyan,
1836 Color::Magenta => wincon::Color::Magenta,
1837 Color::Yellow => wincon::Color::Yellow,
1838 Color::White => wincon::Color::White,
1839 Color::Ansi256(0) => return Some((No, wincon::Color::Black)),
1840 Color::Ansi256(1) => return Some((No, wincon::Color::Red)),
1841 Color::Ansi256(2) => return Some((No, wincon::Color::Green)),
1842 Color::Ansi256(3) => return Some((No, wincon::Color::Yellow)),
1843 Color::Ansi256(4) => return Some((No, wincon::Color::Blue)),
1844 Color::Ansi256(5) => return Some((No, wincon::Color::Magenta)),
1845 Color::Ansi256(6) => return Some((No, wincon::Color::Cyan)),
1846 Color::Ansi256(7) => return Some((No, wincon::Color::White)),
1847 Color::Ansi256(8) => return Some((Yes, wincon::Color::Black)),
1848 Color::Ansi256(9) => return Some((Yes, wincon::Color::Red)),
1849 Color::Ansi256(10) => return Some((Yes, wincon::Color::Green)),
1850 Color::Ansi256(11) => return Some((Yes, wincon::Color::Yellow)),
1851 Color::Ansi256(12) => return Some((Yes, wincon::Color::Blue)),
1852 Color::Ansi256(13) => return Some((Yes, wincon::Color::Magenta)),
1853 Color::Ansi256(14) => return Some((Yes, wincon::Color::Cyan)),
1854 Color::Ansi256(15) => return Some((Yes, wincon::Color::White)),
1855 Color::Ansi256(_) => return None,
1856 Color::Rgb(_, _, _) => return None,
1857 Color::__Nonexhaustive => unreachable!(),
1858 };
1859 let intense = if intense { Yes } else { No };
1860 Some((intense, color))
1861 }
1862
1863 fn from_str_numeric(s: &str) -> Result<Color, ParseColorError> {
1865 fn parse_number(s: &str) -> Option<u8> {
1872 use std::u8;
1873
1874 if s.starts_with("0x") {
1875 u8::from_str_radix(&s[2..], 16).ok()
1876 } else {
1877 u8::from_str_radix(s, 10).ok()
1878 }
1879 }
1880
1881 let codes: Vec<&str> = s.split(',').collect();
1882 if codes.len() == 1 {
1883 if let Some(n) = parse_number(&codes[0]) {
1884 Ok(Color::Ansi256(n))
1885 } else {
1886 if s.chars().all(|c| c.is_digit(16)) {
1887 Err(ParseColorError {
1888 kind: ParseColorErrorKind::InvalidAnsi256,
1889 given: s.to_string(),
1890 })
1891 } else {
1892 Err(ParseColorError {
1893 kind: ParseColorErrorKind::InvalidName,
1894 given: s.to_string(),
1895 })
1896 }
1897 }
1898 } else if codes.len() == 3 {
1899 let mut v = vec![];
1900 for code in codes {
1901 let n = parse_number(code).ok_or_else(|| ParseColorError {
1902 kind: ParseColorErrorKind::InvalidRgb,
1903 given: s.to_string(),
1904 })?;
1905 v.push(n);
1906 }
1907 Ok(Color::Rgb(v[0], v[1], v[2]))
1908 } else {
1909 Err(if s.contains(",") {
1910 ParseColorError {
1911 kind: ParseColorErrorKind::InvalidRgb,
1912 given: s.to_string(),
1913 }
1914 } else {
1915 ParseColorError {
1916 kind: ParseColorErrorKind::InvalidName,
1917 given: s.to_string(),
1918 }
1919 })
1920 }
1921 }
1922}
1923
1924#[derive(Clone, Debug, Eq, PartialEq)]
1926pub struct ParseColorError {
1927 kind: ParseColorErrorKind,
1928 given: String,
1929}
1930
1931#[derive(Clone, Debug, Eq, PartialEq)]
1932enum ParseColorErrorKind {
1933 InvalidName,
1934 InvalidAnsi256,
1935 InvalidRgb,
1936}
1937
1938impl ParseColorError {
1939 pub fn invalid(&self) -> &str {
1941 &self.given
1942 }
1943}
1944
1945impl error::Error for ParseColorError {
1946 fn description(&self) -> &str {
1947 use self::ParseColorErrorKind::*;
1948 match self.kind {
1949 InvalidName => "unrecognized color name",
1950 InvalidAnsi256 => "invalid ansi256 color number",
1951 InvalidRgb => "invalid RGB color triple",
1952 }
1953 }
1954}
1955
1956impl fmt::Display for ParseColorError {
1957 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1958 use self::ParseColorErrorKind::*;
1959 match self.kind {
1960 InvalidName => write!(
1961 f,
1962 "unrecognized color name '{}'. Choose from: \
1963 black, blue, green, red, cyan, magenta, yellow, \
1964 white",
1965 self.given
1966 ),
1967 InvalidAnsi256 => write!(
1968 f,
1969 "unrecognized ansi256 color number, \
1970 should be '[0-255]' (or a hex number), but is '{}'",
1971 self.given
1972 ),
1973 InvalidRgb => write!(
1974 f,
1975 "unrecognized RGB color triple, \
1976 should be '[0-255],[0-255],[0-255]' (or a hex \
1977 triple), but is '{}'",
1978 self.given
1979 ),
1980 }
1981 }
1982}
1983
1984impl FromStr for Color {
1985 type Err = ParseColorError;
1986
1987 fn from_str(s: &str) -> Result<Color, ParseColorError> {
1988 match &*s.to_lowercase() {
1989 "black" => Ok(Color::Black),
1990 "blue" => Ok(Color::Blue),
1991 "green" => Ok(Color::Green),
1992 "red" => Ok(Color::Red),
1993 "cyan" => Ok(Color::Cyan),
1994 "magenta" => Ok(Color::Magenta),
1995 "yellow" => Ok(Color::Yellow),
1996 "white" => Ok(Color::White),
1997 _ => Color::from_str_numeric(s),
1998 }
1999 }
2000}
2001
2002struct LossyStandardStream<W> {
2003 wtr: W,
2004 #[cfg(windows)]
2005 is_console: bool,
2006}
2007
2008impl<W: io::Write> LossyStandardStream<W> {
2009 #[cfg(not(windows))]
2010 fn new(wtr: W) -> LossyStandardStream<W> {
2011 LossyStandardStream { wtr: wtr }
2012 }
2013
2014 #[cfg(windows)]
2015 fn new(wtr: W) -> LossyStandardStream<W> {
2016 let is_console = wincon::Console::stdout().is_ok()
2017 || wincon::Console::stderr().is_ok();
2018 LossyStandardStream { wtr: wtr, is_console: is_console }
2019 }
2020
2021 #[cfg(not(windows))]
2022 fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2023 LossyStandardStream::new(wtr)
2024 }
2025
2026 #[cfg(windows)]
2027 fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2028 LossyStandardStream { wtr: wtr, is_console: self.is_console }
2029 }
2030
2031 fn get_ref(&self) -> &W {
2032 &self.wtr
2033 }
2034}
2035
2036impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
2037 fn supports_color(&self) -> bool {
2038 self.wtr.supports_color()
2039 }
2040 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
2041 self.wtr.set_color(spec)
2042 }
2043 fn reset(&mut self) -> io::Result<()> {
2044 self.wtr.reset()
2045 }
2046 fn is_synchronous(&self) -> bool {
2047 self.wtr.is_synchronous()
2048 }
2049}
2050
2051impl<W: io::Write> io::Write for LossyStandardStream<W> {
2052 #[cfg(not(windows))]
2053 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2054 self.wtr.write(buf)
2055 }
2056
2057 #[cfg(windows)]
2058 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2059 if self.is_console {
2060 write_lossy_utf8(&mut self.wtr, buf)
2061 } else {
2062 self.wtr.write(buf)
2063 }
2064 }
2065
2066 fn flush(&mut self) -> io::Result<()> {
2067 self.wtr.flush()
2068 }
2069}
2070
2071#[cfg(windows)]
2072fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
2073 match ::std::str::from_utf8(buf) {
2074 Ok(s) => w.write(s.as_bytes()),
2075 Err(ref e) if e.valid_up_to() == 0 => {
2076 w.write(b"\xEF\xBF\xBD")?;
2077 Ok(1)
2078 }
2079 Err(e) => w.write(&buf[..e.valid_up_to()]),
2080 }
2081}
2082
2083#[cfg(test)]
2084mod tests {
2085 use super::{
2086 Ansi, Color, ColorSpec, ParseColorError, ParseColorErrorKind,
2087 StandardStream, WriteColor,
2088 };
2089
2090 fn assert_is_send<T: Send>() {}
2091
2092 #[test]
2093 fn standard_stream_is_send() {
2094 assert_is_send::<StandardStream>();
2095 }
2096
2097 #[test]
2098 fn test_simple_parse_ok() {
2099 let color = "green".parse::<Color>();
2100 assert_eq!(color, Ok(Color::Green));
2101 }
2102
2103 #[test]
2104 fn test_256_parse_ok() {
2105 let color = "7".parse::<Color>();
2106 assert_eq!(color, Ok(Color::Ansi256(7)));
2107
2108 let color = "32".parse::<Color>();
2109 assert_eq!(color, Ok(Color::Ansi256(32)));
2110
2111 let color = "0xFF".parse::<Color>();
2112 assert_eq!(color, Ok(Color::Ansi256(0xFF)));
2113 }
2114
2115 #[test]
2116 fn test_256_parse_err_out_of_range() {
2117 let color = "256".parse::<Color>();
2118 assert_eq!(
2119 color,
2120 Err(ParseColorError {
2121 kind: ParseColorErrorKind::InvalidAnsi256,
2122 given: "256".to_string(),
2123 })
2124 );
2125 }
2126
2127 #[test]
2128 fn test_rgb_parse_ok() {
2129 let color = "0,0,0".parse::<Color>();
2130 assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2131
2132 let color = "0,128,255".parse::<Color>();
2133 assert_eq!(color, Ok(Color::Rgb(0, 128, 255)));
2134
2135 let color = "0x0,0x0,0x0".parse::<Color>();
2136 assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2137
2138 let color = "0x33,0x66,0xFF".parse::<Color>();
2139 assert_eq!(color, Ok(Color::Rgb(0x33, 0x66, 0xFF)));
2140 }
2141
2142 #[test]
2143 fn test_rgb_parse_err_out_of_range() {
2144 let color = "0,0,256".parse::<Color>();
2145 assert_eq!(
2146 color,
2147 Err(ParseColorError {
2148 kind: ParseColorErrorKind::InvalidRgb,
2149 given: "0,0,256".to_string(),
2150 })
2151 );
2152 }
2153
2154 #[test]
2155 fn test_rgb_parse_err_bad_format() {
2156 let color = "0,0".parse::<Color>();
2157 assert_eq!(
2158 color,
2159 Err(ParseColorError {
2160 kind: ParseColorErrorKind::InvalidRgb,
2161 given: "0,0".to_string(),
2162 })
2163 );
2164
2165 let color = "not_a_color".parse::<Color>();
2166 assert_eq!(
2167 color,
2168 Err(ParseColorError {
2169 kind: ParseColorErrorKind::InvalidName,
2170 given: "not_a_color".to_string(),
2171 })
2172 );
2173 }
2174
2175 #[test]
2176 fn test_var_ansi_write_rgb() {
2177 let mut buf = Ansi::new(vec![]);
2178 let _ = buf.write_color(true, &Color::Rgb(254, 253, 255), false);
2179 assert_eq!(buf.0, b"\x1B[38;2;254;253;255m");
2180 }
2181
2182 #[test]
2183 fn test_reset() {
2184 let spec = ColorSpec::new();
2185 let mut buf = Ansi::new(vec![]);
2186 buf.set_color(&spec).unwrap();
2187 assert_eq!(buf.0, b"\x1B[0m");
2188 }
2189
2190 #[test]
2191 fn test_no_reset() {
2192 let mut spec = ColorSpec::new();
2193 spec.set_reset(false);
2194
2195 let mut buf = Ansi::new(vec![]);
2196 buf.set_color(&spec).unwrap();
2197 assert_eq!(buf.0, b"");
2198 }
2199
2200 #[test]
2201 fn test_var_ansi_write_256() {
2202 let mut buf = Ansi::new(vec![]);
2203 let _ = buf.write_color(false, &Color::Ansi256(7), false);
2204 assert_eq!(buf.0, b"\x1B[48;5;7m");
2205
2206 let mut buf = Ansi::new(vec![]);
2207 let _ = buf.write_color(false, &Color::Ansi256(208), false);
2208 assert_eq!(buf.0, b"\x1B[48;5;208m");
2209 }
2210
2211 fn all_attributes() -> Vec<ColorSpec> {
2212 let mut result = vec![];
2213 for fg in vec![None, Some(Color::Red)] {
2214 for bg in vec![None, Some(Color::Red)] {
2215 for bold in vec![false, true] {
2216 for underline in vec![false, true] {
2217 for intense in vec![false, true] {
2218 for italic in vec![false, true] {
2219 for dimmed in vec![false, true] {
2220 let mut color = ColorSpec::new();
2221 color.set_fg(fg);
2222 color.set_bg(bg);
2223 color.set_bold(bold);
2224 color.set_underline(underline);
2225 color.set_intense(intense);
2226 color.set_dimmed(dimmed);
2227 color.set_italic(italic);
2228 result.push(color);
2229 }
2230 }
2231 }
2232 }
2233 }
2234 }
2235 }
2236 result
2237 }
2238
2239 #[test]
2240 fn test_is_none() {
2241 for (i, color) in all_attributes().iter().enumerate() {
2242 assert_eq!(
2243 i == 0,
2244 color.is_none(),
2245 "{:?} => {}",
2246 color,
2247 color.is_none()
2248 )
2249 }
2250 }
2251
2252 #[test]
2253 fn test_clear() {
2254 for color in all_attributes() {
2255 let mut color1 = color.clone();
2256 color1.clear();
2257 assert!(color1.is_none(), "{:?} => {:?}", color, color1);
2258 }
2259 }
2260}