1#![deny(missing_debug_implementations, missing_docs)]
115
116use std::env;
122use std::error;
123use std::fmt;
124use std::io::{self, Write};
125use std::str::FromStr;
126use std::sync::atomic::{AtomicBool, Ordering};
127#[cfg(windows)]
128use std::sync::{Mutex, MutexGuard};
129
130#[cfg(windows)]
131use winapi_util::console as wincon;
132
133pub trait WriteColor: io::Write {
135    fn supports_color(&self) -> bool;
137
138    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()>;
146
147    fn reset(&mut self) -> io::Result<()>;
156
157    fn is_synchronous(&self) -> bool {
169        false
170    }
171
172    fn set_hyperlink(&mut self, _link: &HyperlinkSpec) -> io::Result<()> {
188        Ok(())
189    }
190
191    fn supports_hyperlinks(&self) -> bool {
197        false
198    }
199}
200
201impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T {
202    fn supports_color(&self) -> bool {
203        (&**self).supports_color()
204    }
205    fn supports_hyperlinks(&self) -> bool {
206        (&**self).supports_hyperlinks()
207    }
208    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
209        (&mut **self).set_color(spec)
210    }
211    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
212        (&mut **self).set_hyperlink(link)
213    }
214    fn reset(&mut self) -> io::Result<()> {
215        (&mut **self).reset()
216    }
217    fn is_synchronous(&self) -> bool {
218        (&**self).is_synchronous()
219    }
220}
221
222impl<T: ?Sized + WriteColor> WriteColor for Box<T> {
223    fn supports_color(&self) -> bool {
224        (&**self).supports_color()
225    }
226    fn supports_hyperlinks(&self) -> bool {
227        (&**self).supports_hyperlinks()
228    }
229    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
230        (&mut **self).set_color(spec)
231    }
232    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
233        (&mut **self).set_hyperlink(link)
234    }
235    fn reset(&mut self) -> io::Result<()> {
236        (&mut **self).reset()
237    }
238    fn is_synchronous(&self) -> bool {
239        (&**self).is_synchronous()
240    }
241}
242
243#[derive(Clone, Copy, Debug, Eq, PartialEq)]
252pub enum ColorChoice {
253    Always,
256    AlwaysAnsi,
259    Auto,
263    Never,
265}
266
267impl Default for ColorChoice {
269    fn default() -> ColorChoice {
270        ColorChoice::Auto
271    }
272}
273
274impl FromStr for ColorChoice {
275    type Err = ColorChoiceParseError;
276
277    fn from_str(s: &str) -> Result<ColorChoice, ColorChoiceParseError> {
278        match s.to_lowercase().as_str() {
279            "always" => Ok(ColorChoice::Always),
280            "always-ansi" => Ok(ColorChoice::AlwaysAnsi),
281            "never" => Ok(ColorChoice::Never),
282            "auto" => Ok(ColorChoice::Auto),
283            unknown => Err(ColorChoiceParseError {
284                unknown_choice: unknown.to_string(),
285            }),
286        }
287    }
288}
289
290impl ColorChoice {
291    fn should_attempt_color(&self) -> bool {
293        match *self {
294            ColorChoice::Always => true,
295            ColorChoice::AlwaysAnsi => true,
296            ColorChoice::Never => false,
297            ColorChoice::Auto => self.env_allows_color(),
298        }
299    }
300
301    #[cfg(not(windows))]
302    fn env_allows_color(&self) -> bool {
303        match env::var_os("TERM") {
304            None => return false,
307            Some(k) => {
308                if k == "dumb" {
309                    return false;
310                }
311            }
312        }
313        if env::var_os("NO_COLOR").is_some() {
316            return false;
317        }
318        true
319    }
320
321    #[cfg(windows)]
322    fn env_allows_color(&self) -> bool {
323        if let Some(k) = env::var_os("TERM") {
327            if k == "dumb" {
328                return false;
329            }
330        }
331        if env::var_os("NO_COLOR").is_some() {
334            return false;
335        }
336        true
337    }
338
339    #[cfg(windows)]
344    fn should_ansi(&self) -> bool {
345        match *self {
346            ColorChoice::Always => false,
347            ColorChoice::AlwaysAnsi => true,
348            ColorChoice::Never => false,
349            ColorChoice::Auto => {
350                match env::var("TERM") {
351                    Err(_) => false,
352                    Ok(k) => k != "dumb" && k != "cygwin",
356                }
357            }
358        }
359    }
360}
361
362#[derive(Clone, Debug)]
364pub struct ColorChoiceParseError {
365    unknown_choice: String,
366}
367
368impl std::error::Error for ColorChoiceParseError {}
369
370impl fmt::Display for ColorChoiceParseError {
371    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372        write!(
373            f,
374            "unrecognized color choice '{}': valid choices are: \
375             always, always-ansi, never, auto",
376            self.unknown_choice,
377        )
378    }
379}
380
381enum StandardStreamType {
386    Stdout,
387    Stderr,
388    StdoutBuffered,
389    StderrBuffered,
390}
391
392#[derive(Debug)]
393enum IoStandardStream {
394    Stdout(io::Stdout),
395    Stderr(io::Stderr),
396    StdoutBuffered(io::BufWriter<io::Stdout>),
397    StderrBuffered(io::BufWriter<io::Stderr>),
398}
399
400impl IoStandardStream {
401    fn new(sty: StandardStreamType) -> IoStandardStream {
402        match sty {
403            StandardStreamType::Stdout => {
404                IoStandardStream::Stdout(io::stdout())
405            }
406            StandardStreamType::Stderr => {
407                IoStandardStream::Stderr(io::stderr())
408            }
409            StandardStreamType::StdoutBuffered => {
410                let wtr = io::BufWriter::new(io::stdout());
411                IoStandardStream::StdoutBuffered(wtr)
412            }
413            StandardStreamType::StderrBuffered => {
414                let wtr = io::BufWriter::new(io::stderr());
415                IoStandardStream::StderrBuffered(wtr)
416            }
417        }
418    }
419
420    fn lock(&self) -> IoStandardStreamLock<'_> {
421        match *self {
422            IoStandardStream::Stdout(ref s) => {
423                IoStandardStreamLock::StdoutLock(s.lock())
424            }
425            IoStandardStream::Stderr(ref s) => {
426                IoStandardStreamLock::StderrLock(s.lock())
427            }
428            IoStandardStream::StdoutBuffered(_)
429            | IoStandardStream::StderrBuffered(_) => {
430                panic!("cannot lock a buffered standard stream")
433            }
434        }
435    }
436}
437
438impl io::Write for IoStandardStream {
439    #[inline(always)]
440    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
441        match *self {
442            IoStandardStream::Stdout(ref mut s) => s.write(b),
443            IoStandardStream::Stderr(ref mut s) => s.write(b),
444            IoStandardStream::StdoutBuffered(ref mut s) => s.write(b),
445            IoStandardStream::StderrBuffered(ref mut s) => s.write(b),
446        }
447    }
448
449    #[inline(always)]
450    fn flush(&mut self) -> io::Result<()> {
451        match *self {
452            IoStandardStream::Stdout(ref mut s) => s.flush(),
453            IoStandardStream::Stderr(ref mut s) => s.flush(),
454            IoStandardStream::StdoutBuffered(ref mut s) => s.flush(),
455            IoStandardStream::StderrBuffered(ref mut s) => s.flush(),
456        }
457    }
458}
459
460#[derive(Debug)]
463enum IoStandardStreamLock<'a> {
464    StdoutLock(io::StdoutLock<'a>),
465    StderrLock(io::StderrLock<'a>),
466}
467
468impl<'a> io::Write for IoStandardStreamLock<'a> {
469    #[inline(always)]
470    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
471        match *self {
472            IoStandardStreamLock::StdoutLock(ref mut s) => s.write(b),
473            IoStandardStreamLock::StderrLock(ref mut s) => s.write(b),
474        }
475    }
476
477    #[inline(always)]
478    fn flush(&mut self) -> io::Result<()> {
479        match *self {
480            IoStandardStreamLock::StdoutLock(ref mut s) => s.flush(),
481            IoStandardStreamLock::StderrLock(ref mut s) => s.flush(),
482        }
483    }
484}
485
486#[derive(Debug)]
489pub struct StandardStream {
490    wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
491}
492
493#[derive(Debug)]
501pub struct StandardStreamLock<'a> {
502    wtr: LossyStandardStream<WriterInnerLock<'a, IoStandardStreamLock<'a>>>,
503}
504
505#[derive(Debug)]
507pub struct BufferedStandardStream {
508    wtr: LossyStandardStream<WriterInner<IoStandardStream>>,
509}
510
511#[derive(Debug)]
514enum WriterInner<W> {
515    NoColor(NoColor<W>),
516    Ansi(Ansi<W>),
517    #[cfg(windows)]
518    Windows {
519        wtr: W,
520        console: Mutex<wincon::Console>,
521    },
522}
523
524#[derive(Debug)]
527enum WriterInnerLock<'a, W> {
528    NoColor(NoColor<W>),
529    Ansi(Ansi<W>),
530    #[allow(dead_code)]
535    Unreachable(::std::marker::PhantomData<&'a ()>),
536    #[cfg(windows)]
537    Windows {
538        wtr: W,
539        console: MutexGuard<'a, wincon::Console>,
540    },
541}
542
543impl StandardStream {
544    pub fn stdout(choice: ColorChoice) -> StandardStream {
553        let wtr = WriterInner::create(StandardStreamType::Stdout, choice);
554        StandardStream { wtr: LossyStandardStream::new(wtr) }
555    }
556
557    pub fn stderr(choice: ColorChoice) -> StandardStream {
566        let wtr = WriterInner::create(StandardStreamType::Stderr, choice);
567        StandardStream { wtr: LossyStandardStream::new(wtr) }
568    }
569
570    pub fn lock(&self) -> StandardStreamLock<'_> {
578        StandardStreamLock::from_stream(self)
579    }
580}
581
582impl<'a> StandardStreamLock<'a> {
583    #[cfg(not(windows))]
584    fn from_stream(stream: &StandardStream) -> StandardStreamLock<'_> {
585        let locked = match *stream.wtr.get_ref() {
586            WriterInner::NoColor(ref w) => {
587                WriterInnerLock::NoColor(NoColor(w.0.lock()))
588            }
589            WriterInner::Ansi(ref w) => {
590                WriterInnerLock::Ansi(Ansi(w.0.lock()))
591            }
592        };
593        StandardStreamLock { wtr: stream.wtr.wrap(locked) }
594    }
595
596    #[cfg(windows)]
597    fn from_stream(stream: &StandardStream) -> StandardStreamLock {
598        let locked = match *stream.wtr.get_ref() {
599            WriterInner::NoColor(ref w) => {
600                WriterInnerLock::NoColor(NoColor(w.0.lock()))
601            }
602            WriterInner::Ansi(ref w) => {
603                WriterInnerLock::Ansi(Ansi(w.0.lock()))
604            }
605            #[cfg(windows)]
606            WriterInner::Windows { ref wtr, ref console } => {
607                WriterInnerLock::Windows {
608                    wtr: wtr.lock(),
609                    console: console.lock().unwrap(),
610                }
611            }
612        };
613        StandardStreamLock { wtr: stream.wtr.wrap(locked) }
614    }
615}
616
617impl BufferedStandardStream {
618    pub fn stdout(choice: ColorChoice) -> BufferedStandardStream {
627        let wtr =
628            WriterInner::create(StandardStreamType::StdoutBuffered, choice);
629        BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
630    }
631
632    pub fn stderr(choice: ColorChoice) -> BufferedStandardStream {
641        let wtr =
642            WriterInner::create(StandardStreamType::StderrBuffered, choice);
643        BufferedStandardStream { wtr: LossyStandardStream::new(wtr) }
644    }
645}
646
647impl WriterInner<IoStandardStream> {
648    #[cfg(not(windows))]
651    fn create(
652        sty: StandardStreamType,
653        choice: ColorChoice,
654    ) -> WriterInner<IoStandardStream> {
655        if choice.should_attempt_color() {
656            WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
657        } else {
658            WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
659        }
660    }
661
662    #[cfg(windows)]
668    fn create(
669        sty: StandardStreamType,
670        choice: ColorChoice,
671    ) -> WriterInner<IoStandardStream> {
672        let mut con = match sty {
673            StandardStreamType::Stdout => wincon::Console::stdout(),
674            StandardStreamType::Stderr => wincon::Console::stderr(),
675            StandardStreamType::StdoutBuffered => wincon::Console::stdout(),
676            StandardStreamType::StderrBuffered => wincon::Console::stderr(),
677        };
678        let is_console_virtual = con
679            .as_mut()
680            .map(|con| con.set_virtual_terminal_processing(true).is_ok())
681            .unwrap_or(false);
682        if choice.should_attempt_color() {
683            if choice.should_ansi() || is_console_virtual {
684                WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
685            } else if let Ok(console) = con {
686                WriterInner::Windows {
687                    wtr: IoStandardStream::new(sty),
688                    console: Mutex::new(console),
689                }
690            } else {
691                WriterInner::Ansi(Ansi(IoStandardStream::new(sty)))
692            }
693        } else {
694            WriterInner::NoColor(NoColor(IoStandardStream::new(sty)))
695        }
696    }
697}
698
699impl io::Write for StandardStream {
700    #[inline]
701    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
702        self.wtr.write(b)
703    }
704
705    #[inline]
706    fn flush(&mut self) -> io::Result<()> {
707        self.wtr.flush()
708    }
709}
710
711impl WriteColor for StandardStream {
712    #[inline]
713    fn supports_color(&self) -> bool {
714        self.wtr.supports_color()
715    }
716
717    #[inline]
718    fn supports_hyperlinks(&self) -> bool {
719        self.wtr.supports_hyperlinks()
720    }
721
722    #[inline]
723    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
724        self.wtr.set_color(spec)
725    }
726
727    #[inline]
728    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
729        self.wtr.set_hyperlink(link)
730    }
731
732    #[inline]
733    fn reset(&mut self) -> io::Result<()> {
734        self.wtr.reset()
735    }
736
737    #[inline]
738    fn is_synchronous(&self) -> bool {
739        self.wtr.is_synchronous()
740    }
741}
742
743impl<'a> io::Write for StandardStreamLock<'a> {
744    #[inline]
745    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
746        self.wtr.write(b)
747    }
748
749    #[inline]
750    fn flush(&mut self) -> io::Result<()> {
751        self.wtr.flush()
752    }
753}
754
755impl<'a> WriteColor for StandardStreamLock<'a> {
756    #[inline]
757    fn supports_color(&self) -> bool {
758        self.wtr.supports_color()
759    }
760
761    #[inline]
762    fn supports_hyperlinks(&self) -> bool {
763        self.wtr.supports_hyperlinks()
764    }
765
766    #[inline]
767    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
768        self.wtr.set_color(spec)
769    }
770
771    #[inline]
772    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
773        self.wtr.set_hyperlink(link)
774    }
775
776    #[inline]
777    fn reset(&mut self) -> io::Result<()> {
778        self.wtr.reset()
779    }
780
781    #[inline]
782    fn is_synchronous(&self) -> bool {
783        self.wtr.is_synchronous()
784    }
785}
786
787impl io::Write for BufferedStandardStream {
788    #[inline]
789    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
790        self.wtr.write(b)
791    }
792
793    #[inline]
794    fn flush(&mut self) -> io::Result<()> {
795        self.wtr.flush()
796    }
797}
798
799impl WriteColor for BufferedStandardStream {
800    #[inline]
801    fn supports_color(&self) -> bool {
802        self.wtr.supports_color()
803    }
804
805    #[inline]
806    fn supports_hyperlinks(&self) -> bool {
807        self.wtr.supports_hyperlinks()
808    }
809
810    #[inline]
811    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
812        if self.is_synchronous() {
813            self.wtr.flush()?;
814        }
815        self.wtr.set_color(spec)
816    }
817
818    #[inline]
819    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
820        if self.is_synchronous() {
821            self.wtr.flush()?;
822        }
823        self.wtr.set_hyperlink(link)
824    }
825
826    #[inline]
827    fn reset(&mut self) -> io::Result<()> {
828        self.wtr.reset()
829    }
830
831    #[inline]
832    fn is_synchronous(&self) -> bool {
833        self.wtr.is_synchronous()
834    }
835}
836
837impl<W: io::Write> io::Write for WriterInner<W> {
838    #[inline(always)]
839    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
840        match *self {
841            WriterInner::NoColor(ref mut wtr) => wtr.write(buf),
842            WriterInner::Ansi(ref mut wtr) => wtr.write(buf),
843            #[cfg(windows)]
844            WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf),
845        }
846    }
847
848    #[inline(always)]
849    fn flush(&mut self) -> io::Result<()> {
850        match *self {
851            WriterInner::NoColor(ref mut wtr) => wtr.flush(),
852            WriterInner::Ansi(ref mut wtr) => wtr.flush(),
853            #[cfg(windows)]
854            WriterInner::Windows { ref mut wtr, .. } => wtr.flush(),
855        }
856    }
857}
858
859impl<W: io::Write> WriteColor for WriterInner<W> {
860    fn supports_color(&self) -> bool {
861        match *self {
862            WriterInner::NoColor(_) => false,
863            WriterInner::Ansi(_) => true,
864            #[cfg(windows)]
865            WriterInner::Windows { .. } => true,
866        }
867    }
868
869    fn supports_hyperlinks(&self) -> bool {
870        match *self {
871            WriterInner::NoColor(_) => false,
872            WriterInner::Ansi(_) => true,
873            #[cfg(windows)]
874            WriterInner::Windows { .. } => false,
875        }
876    }
877
878    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
879        match *self {
880            WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
881            WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec),
882            #[cfg(windows)]
883            WriterInner::Windows { ref mut wtr, ref console } => {
884                wtr.flush()?;
885                let mut console = console.lock().unwrap();
886                spec.write_console(&mut *console)
887            }
888        }
889    }
890
891    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
892        match *self {
893            WriterInner::NoColor(ref mut wtr) => wtr.set_hyperlink(link),
894            WriterInner::Ansi(ref mut wtr) => wtr.set_hyperlink(link),
895            #[cfg(windows)]
896            WriterInner::Windows { .. } => Ok(()),
897        }
898    }
899
900    fn reset(&mut self) -> io::Result<()> {
901        match *self {
902            WriterInner::NoColor(ref mut wtr) => wtr.reset(),
903            WriterInner::Ansi(ref mut wtr) => wtr.reset(),
904            #[cfg(windows)]
905            WriterInner::Windows { ref mut wtr, ref mut console } => {
906                wtr.flush()?;
907                console.lock().unwrap().reset()?;
908                Ok(())
909            }
910        }
911    }
912
913    fn is_synchronous(&self) -> bool {
914        match *self {
915            WriterInner::NoColor(_) => false,
916            WriterInner::Ansi(_) => false,
917            #[cfg(windows)]
918            WriterInner::Windows { .. } => true,
919        }
920    }
921}
922
923impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> {
924    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
925        match *self {
926            WriterInnerLock::Unreachable(_) => unreachable!(),
927            WriterInnerLock::NoColor(ref mut wtr) => wtr.write(buf),
928            WriterInnerLock::Ansi(ref mut wtr) => wtr.write(buf),
929            #[cfg(windows)]
930            WriterInnerLock::Windows { ref mut wtr, .. } => wtr.write(buf),
931        }
932    }
933
934    fn flush(&mut self) -> io::Result<()> {
935        match *self {
936            WriterInnerLock::Unreachable(_) => unreachable!(),
937            WriterInnerLock::NoColor(ref mut wtr) => wtr.flush(),
938            WriterInnerLock::Ansi(ref mut wtr) => wtr.flush(),
939            #[cfg(windows)]
940            WriterInnerLock::Windows { ref mut wtr, .. } => wtr.flush(),
941        }
942    }
943}
944
945impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
946    fn supports_color(&self) -> bool {
947        match *self {
948            WriterInnerLock::Unreachable(_) => unreachable!(),
949            WriterInnerLock::NoColor(_) => false,
950            WriterInnerLock::Ansi(_) => true,
951            #[cfg(windows)]
952            WriterInnerLock::Windows { .. } => true,
953        }
954    }
955
956    fn supports_hyperlinks(&self) -> bool {
957        match *self {
958            WriterInnerLock::Unreachable(_) => unreachable!(),
959            WriterInnerLock::NoColor(_) => false,
960            WriterInnerLock::Ansi(_) => true,
961            #[cfg(windows)]
962            WriterInnerLock::Windows { .. } => false,
963        }
964    }
965
966    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
967        match *self {
968            WriterInnerLock::Unreachable(_) => unreachable!(),
969            WriterInnerLock::NoColor(ref mut wtr) => wtr.set_color(spec),
970            WriterInnerLock::Ansi(ref mut wtr) => wtr.set_color(spec),
971            #[cfg(windows)]
972            WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
973                wtr.flush()?;
974                spec.write_console(console)
975            }
976        }
977    }
978
979    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
980        match *self {
981            WriterInnerLock::Unreachable(_) => unreachable!(),
982            WriterInnerLock::NoColor(ref mut wtr) => wtr.set_hyperlink(link),
983            WriterInnerLock::Ansi(ref mut wtr) => wtr.set_hyperlink(link),
984            #[cfg(windows)]
985            WriterInnerLock::Windows { .. } => Ok(()),
986        }
987    }
988
989    fn reset(&mut self) -> io::Result<()> {
990        match *self {
991            WriterInnerLock::Unreachable(_) => unreachable!(),
992            WriterInnerLock::NoColor(ref mut wtr) => wtr.reset(),
993            WriterInnerLock::Ansi(ref mut wtr) => wtr.reset(),
994            #[cfg(windows)]
995            WriterInnerLock::Windows { ref mut wtr, ref mut console } => {
996                wtr.flush()?;
997                console.reset()?;
998                Ok(())
999            }
1000        }
1001    }
1002
1003    fn is_synchronous(&self) -> bool {
1004        match *self {
1005            WriterInnerLock::Unreachable(_) => unreachable!(),
1006            WriterInnerLock::NoColor(_) => false,
1007            WriterInnerLock::Ansi(_) => false,
1008            #[cfg(windows)]
1009            WriterInnerLock::Windows { .. } => true,
1010        }
1011    }
1012}
1013
1014#[derive(Debug)]
1024pub struct BufferWriter {
1025    stream: LossyStandardStream<IoStandardStream>,
1026    printed: AtomicBool,
1027    separator: Option<Vec<u8>>,
1028    color_choice: ColorChoice,
1029    #[cfg(windows)]
1030    console: Option<Mutex<wincon::Console>>,
1031}
1032
1033impl BufferWriter {
1034    #[cfg(not(windows))]
1040    fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
1041        BufferWriter {
1042            stream: LossyStandardStream::new(IoStandardStream::new(sty)),
1043            printed: AtomicBool::new(false),
1044            separator: None,
1045            color_choice: choice,
1046        }
1047    }
1048
1049    #[cfg(windows)]
1058    fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter {
1059        let mut con = match sty {
1060            StandardStreamType::Stdout => wincon::Console::stdout(),
1061            StandardStreamType::Stderr => wincon::Console::stderr(),
1062            StandardStreamType::StdoutBuffered => wincon::Console::stdout(),
1063            StandardStreamType::StderrBuffered => wincon::Console::stderr(),
1064        }
1065        .ok();
1066        let is_console_virtual = con
1067            .as_mut()
1068            .map(|con| con.set_virtual_terminal_processing(true).is_ok())
1069            .unwrap_or(false);
1070        if is_console_virtual {
1073            con = None;
1074        }
1075        let stream = LossyStandardStream::new(IoStandardStream::new(sty));
1076        BufferWriter {
1077            stream,
1078            printed: AtomicBool::new(false),
1079            separator: None,
1080            color_choice: choice,
1081            console: con.map(Mutex::new),
1082        }
1083    }
1084
1085    pub fn stdout(choice: ColorChoice) -> BufferWriter {
1094        BufferWriter::create(StandardStreamType::Stdout, choice)
1095    }
1096
1097    pub fn stderr(choice: ColorChoice) -> BufferWriter {
1106        BufferWriter::create(StandardStreamType::Stderr, choice)
1107    }
1108
1109    pub fn separator(&mut self, sep: Option<Vec<u8>>) {
1114        self.separator = sep;
1115    }
1116
1117    #[cfg(not(windows))]
1122    pub fn buffer(&self) -> Buffer {
1123        Buffer::new(self.color_choice)
1124    }
1125
1126    #[cfg(windows)]
1131    pub fn buffer(&self) -> Buffer {
1132        Buffer::new(self.color_choice, self.console.is_some())
1133    }
1134
1135    pub fn print(&self, buf: &Buffer) -> io::Result<()> {
1141        if buf.is_empty() {
1142            return Ok(());
1143        }
1144        let mut stream = self.stream.wrap(self.stream.get_ref().lock());
1145        if let Some(ref sep) = self.separator {
1146            if self.printed.load(Ordering::Relaxed) {
1147                stream.write_all(sep)?;
1148                stream.write_all(b"\n")?;
1149            }
1150        }
1151        match buf.0 {
1152            BufferInner::NoColor(ref b) => stream.write_all(&b.0)?,
1153            BufferInner::Ansi(ref b) => stream.write_all(&b.0)?,
1154            #[cfg(windows)]
1155            BufferInner::Windows(ref b) => {
1156                let console_mutex = self
1159                    .console
1160                    .as_ref()
1161                    .expect("got Windows buffer but have no Console");
1162                let mut console = console_mutex.lock().unwrap();
1163                b.print(&mut *console, &mut stream)?;
1164            }
1165        }
1166        self.printed.store(true, Ordering::Relaxed);
1167        Ok(())
1168    }
1169}
1170
1171#[derive(Clone, Debug)]
1183pub struct Buffer(BufferInner);
1184
1185#[derive(Clone, Debug)]
1187enum BufferInner {
1188    NoColor(NoColor<Vec<u8>>),
1191    Ansi(Ansi<Vec<u8>>),
1193    #[cfg(windows)]
1197    Windows(WindowsBuffer),
1198}
1199
1200impl Buffer {
1201    #[cfg(not(windows))]
1203    fn new(choice: ColorChoice) -> Buffer {
1204        if choice.should_attempt_color() {
1205            Buffer::ansi()
1206        } else {
1207            Buffer::no_color()
1208        }
1209    }
1210
1211    #[cfg(windows)]
1219    fn new(choice: ColorChoice, console: bool) -> Buffer {
1220        if choice.should_attempt_color() {
1221            if !console || choice.should_ansi() {
1222                Buffer::ansi()
1223            } else {
1224                Buffer::console()
1225            }
1226        } else {
1227            Buffer::no_color()
1228        }
1229    }
1230
1231    pub fn no_color() -> Buffer {
1233        Buffer(BufferInner::NoColor(NoColor(vec![])))
1234    }
1235
1236    pub fn ansi() -> Buffer {
1238        Buffer(BufferInner::Ansi(Ansi(vec![])))
1239    }
1240
1241    #[cfg(windows)]
1243    pub fn console() -> Buffer {
1244        Buffer(BufferInner::Windows(WindowsBuffer::new()))
1245    }
1246
1247    pub fn is_empty(&self) -> bool {
1249        self.len() == 0
1250    }
1251
1252    pub fn len(&self) -> usize {
1254        match self.0 {
1255            BufferInner::NoColor(ref b) => b.0.len(),
1256            BufferInner::Ansi(ref b) => b.0.len(),
1257            #[cfg(windows)]
1258            BufferInner::Windows(ref b) => b.buf.len(),
1259        }
1260    }
1261
1262    pub fn clear(&mut self) {
1264        match self.0 {
1265            BufferInner::NoColor(ref mut b) => b.0.clear(),
1266            BufferInner::Ansi(ref mut b) => b.0.clear(),
1267            #[cfg(windows)]
1268            BufferInner::Windows(ref mut b) => b.clear(),
1269        }
1270    }
1271
1272    pub fn into_inner(self) -> Vec<u8> {
1277        match self.0 {
1278            BufferInner::NoColor(b) => b.0,
1279            BufferInner::Ansi(b) => b.0,
1280            #[cfg(windows)]
1281            BufferInner::Windows(b) => b.buf,
1282        }
1283    }
1284
1285    pub fn as_slice(&self) -> &[u8] {
1287        match self.0 {
1288            BufferInner::NoColor(ref b) => &b.0,
1289            BufferInner::Ansi(ref b) => &b.0,
1290            #[cfg(windows)]
1291            BufferInner::Windows(ref b) => &b.buf,
1292        }
1293    }
1294
1295    pub fn as_mut_slice(&mut self) -> &mut [u8] {
1297        match self.0 {
1298            BufferInner::NoColor(ref mut b) => &mut b.0,
1299            BufferInner::Ansi(ref mut b) => &mut b.0,
1300            #[cfg(windows)]
1301            BufferInner::Windows(ref mut b) => &mut b.buf,
1302        }
1303    }
1304}
1305
1306impl io::Write for Buffer {
1307    #[inline]
1308    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1309        match self.0 {
1310            BufferInner::NoColor(ref mut w) => w.write(buf),
1311            BufferInner::Ansi(ref mut w) => w.write(buf),
1312            #[cfg(windows)]
1313            BufferInner::Windows(ref mut w) => w.write(buf),
1314        }
1315    }
1316
1317    #[inline]
1318    fn flush(&mut self) -> io::Result<()> {
1319        match self.0 {
1320            BufferInner::NoColor(ref mut w) => w.flush(),
1321            BufferInner::Ansi(ref mut w) => w.flush(),
1322            #[cfg(windows)]
1323            BufferInner::Windows(ref mut w) => w.flush(),
1324        }
1325    }
1326}
1327
1328impl WriteColor for Buffer {
1329    #[inline]
1330    fn supports_color(&self) -> bool {
1331        match self.0 {
1332            BufferInner::NoColor(_) => false,
1333            BufferInner::Ansi(_) => true,
1334            #[cfg(windows)]
1335            BufferInner::Windows(_) => true,
1336        }
1337    }
1338
1339    #[inline]
1340    fn supports_hyperlinks(&self) -> bool {
1341        match self.0 {
1342            BufferInner::NoColor(_) => false,
1343            BufferInner::Ansi(_) => true,
1344            #[cfg(windows)]
1345            BufferInner::Windows(_) => false,
1346        }
1347    }
1348
1349    #[inline]
1350    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1351        match self.0 {
1352            BufferInner::NoColor(ref mut w) => w.set_color(spec),
1353            BufferInner::Ansi(ref mut w) => w.set_color(spec),
1354            #[cfg(windows)]
1355            BufferInner::Windows(ref mut w) => w.set_color(spec),
1356        }
1357    }
1358
1359    #[inline]
1360    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
1361        match self.0 {
1362            BufferInner::NoColor(ref mut w) => w.set_hyperlink(link),
1363            BufferInner::Ansi(ref mut w) => w.set_hyperlink(link),
1364            #[cfg(windows)]
1365            BufferInner::Windows(ref mut w) => w.set_hyperlink(link),
1366        }
1367    }
1368
1369    #[inline]
1370    fn reset(&mut self) -> io::Result<()> {
1371        match self.0 {
1372            BufferInner::NoColor(ref mut w) => w.reset(),
1373            BufferInner::Ansi(ref mut w) => w.reset(),
1374            #[cfg(windows)]
1375            BufferInner::Windows(ref mut w) => w.reset(),
1376        }
1377    }
1378
1379    #[inline]
1380    fn is_synchronous(&self) -> bool {
1381        false
1382    }
1383}
1384
1385#[derive(Clone, Debug)]
1387pub struct NoColor<W>(W);
1388
1389impl<W: Write> NoColor<W> {
1390    pub fn new(wtr: W) -> NoColor<W> {
1393        NoColor(wtr)
1394    }
1395
1396    pub fn into_inner(self) -> W {
1398        self.0
1399    }
1400
1401    pub fn get_ref(&self) -> &W {
1403        &self.0
1404    }
1405
1406    pub fn get_mut(&mut self) -> &mut W {
1408        &mut self.0
1409    }
1410}
1411
1412impl<W: io::Write> io::Write for NoColor<W> {
1413    #[inline]
1414    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1415        self.0.write(buf)
1416    }
1417
1418    #[inline]
1419    fn flush(&mut self) -> io::Result<()> {
1420        self.0.flush()
1421    }
1422}
1423
1424impl<W: io::Write> WriteColor for NoColor<W> {
1425    #[inline]
1426    fn supports_color(&self) -> bool {
1427        false
1428    }
1429
1430    #[inline]
1431    fn supports_hyperlinks(&self) -> bool {
1432        false
1433    }
1434
1435    #[inline]
1436    fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
1437        Ok(())
1438    }
1439
1440    #[inline]
1441    fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
1442        Ok(())
1443    }
1444
1445    #[inline]
1446    fn reset(&mut self) -> io::Result<()> {
1447        Ok(())
1448    }
1449
1450    #[inline]
1451    fn is_synchronous(&self) -> bool {
1452        false
1453    }
1454}
1455
1456#[derive(Clone, Debug)]
1458pub struct Ansi<W>(W);
1459
1460impl<W: Write> Ansi<W> {
1461    pub fn new(wtr: W) -> Ansi<W> {
1464        Ansi(wtr)
1465    }
1466
1467    pub fn into_inner(self) -> W {
1469        self.0
1470    }
1471
1472    pub fn get_ref(&self) -> &W {
1474        &self.0
1475    }
1476
1477    pub fn get_mut(&mut self) -> &mut W {
1479        &mut self.0
1480    }
1481}
1482
1483impl<W: io::Write> io::Write for Ansi<W> {
1484    #[inline]
1485    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1486        self.0.write(buf)
1487    }
1488
1489    #[inline]
1496    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1497        self.0.write_all(buf)
1498    }
1499
1500    #[inline]
1501    fn flush(&mut self) -> io::Result<()> {
1502        self.0.flush()
1503    }
1504}
1505
1506impl<W: io::Write> WriteColor for Ansi<W> {
1507    #[inline]
1508    fn supports_color(&self) -> bool {
1509        true
1510    }
1511
1512    #[inline]
1513    fn supports_hyperlinks(&self) -> bool {
1514        true
1515    }
1516
1517    #[inline]
1518    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1519        if spec.reset {
1520            self.reset()?;
1521        }
1522        if spec.bold {
1523            self.write_str("\x1B[1m")?;
1524        }
1525        if spec.dimmed {
1526            self.write_str("\x1B[2m")?;
1527        }
1528        if spec.italic {
1529            self.write_str("\x1B[3m")?;
1530        }
1531        if spec.underline {
1532            self.write_str("\x1B[4m")?;
1533        }
1534        if spec.strikethrough {
1535            self.write_str("\x1B[9m")?;
1536        }
1537        if let Some(ref c) = spec.fg_color {
1538            self.write_color(true, c, spec.intense)?;
1539        }
1540        if let Some(ref c) = spec.bg_color {
1541            self.write_color(false, c, spec.intense)?;
1542        }
1543        Ok(())
1544    }
1545
1546    #[inline]
1547    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
1548        self.write_str("\x1B]8;;")?;
1549        if let Some(uri) = link.uri() {
1550            self.write_all(uri)?;
1551        }
1552        self.write_str("\x1B\\")
1553    }
1554
1555    #[inline]
1556    fn reset(&mut self) -> io::Result<()> {
1557        self.write_str("\x1B[0m")
1558    }
1559
1560    #[inline]
1561    fn is_synchronous(&self) -> bool {
1562        false
1563    }
1564}
1565
1566impl<W: io::Write> Ansi<W> {
1567    fn write_str(&mut self, s: &str) -> io::Result<()> {
1568        self.write_all(s.as_bytes())
1569    }
1570
1571    fn write_color(
1572        &mut self,
1573        fg: bool,
1574        c: &Color,
1575        intense: bool,
1576    ) -> io::Result<()> {
1577        macro_rules! write_intense {
1578            ($clr:expr) => {
1579                if fg {
1580                    self.write_str(concat!("\x1B[38;5;", $clr, "m"))
1581                } else {
1582                    self.write_str(concat!("\x1B[48;5;", $clr, "m"))
1583                }
1584            };
1585        }
1586        macro_rules! write_normal {
1587            ($clr:expr) => {
1588                if fg {
1589                    self.write_str(concat!("\x1B[3", $clr, "m"))
1590                } else {
1591                    self.write_str(concat!("\x1B[4", $clr, "m"))
1592                }
1593            };
1594        }
1595        macro_rules! write_var_ansi_code {
1596            ($pre:expr, $($code:expr),+) => {{
1597                let pre_len = $pre.len();
1602                assert!(pre_len <= 7);
1603                let mut fmt = [0u8; 19];
1604                fmt[..pre_len].copy_from_slice($pre);
1605                let mut i = pre_len - 1;
1606                $(
1607                    let c1: u8 = ($code / 100) % 10;
1608                    let c2: u8 = ($code / 10) % 10;
1609                    let c3: u8 = $code % 10;
1610                    let mut printed = false;
1611
1612                    if c1 != 0 {
1613                        printed = true;
1614                        i += 1;
1615                        fmt[i] = b'0' + c1;
1616                    }
1617                    if c2 != 0 || printed {
1618                        i += 1;
1619                        fmt[i] = b'0' + c2;
1620                    }
1621                    i += 1;
1623                    fmt[i] = b'0' + c3;
1624                    i += 1;
1625                    fmt[i] = b';';
1626                )+
1627
1628                fmt[i] = b'm';
1629                self.write_all(&fmt[0..i+1])
1630            }}
1631        }
1632        macro_rules! write_custom {
1633            ($ansi256:expr) => {
1634                if fg {
1635                    write_var_ansi_code!(b"\x1B[38;5;", $ansi256)
1636                } else {
1637                    write_var_ansi_code!(b"\x1B[48;5;", $ansi256)
1638                }
1639            };
1640
1641            ($r:expr, $g:expr, $b:expr) => {{
1642                if fg {
1643                    write_var_ansi_code!(b"\x1B[38;2;", $r, $g, $b)
1644                } else {
1645                    write_var_ansi_code!(b"\x1B[48;2;", $r, $g, $b)
1646                }
1647            }};
1648        }
1649        if intense {
1650            match *c {
1651                Color::Black => write_intense!("8"),
1652                Color::Blue => write_intense!("12"),
1653                Color::Green => write_intense!("10"),
1654                Color::Red => write_intense!("9"),
1655                Color::Cyan => write_intense!("14"),
1656                Color::Magenta => write_intense!("13"),
1657                Color::Yellow => write_intense!("11"),
1658                Color::White => write_intense!("15"),
1659                Color::Ansi256(c) => write_custom!(c),
1660                Color::Rgb(r, g, b) => write_custom!(r, g, b),
1661                Color::__Nonexhaustive => unreachable!(),
1662            }
1663        } else {
1664            match *c {
1665                Color::Black => write_normal!("0"),
1666                Color::Blue => write_normal!("4"),
1667                Color::Green => write_normal!("2"),
1668                Color::Red => write_normal!("1"),
1669                Color::Cyan => write_normal!("6"),
1670                Color::Magenta => write_normal!("5"),
1671                Color::Yellow => write_normal!("3"),
1672                Color::White => write_normal!("7"),
1673                Color::Ansi256(c) => write_custom!(c),
1674                Color::Rgb(r, g, b) => write_custom!(r, g, b),
1675                Color::__Nonexhaustive => unreachable!(),
1676            }
1677        }
1678    }
1679}
1680
1681impl WriteColor for io::Sink {
1682    fn supports_color(&self) -> bool {
1683        false
1684    }
1685
1686    fn supports_hyperlinks(&self) -> bool {
1687        false
1688    }
1689
1690    fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
1691        Ok(())
1692    }
1693
1694    fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
1695        Ok(())
1696    }
1697
1698    fn reset(&mut self) -> io::Result<()> {
1699        Ok(())
1700    }
1701}
1702
1703#[cfg(windows)]
1719#[derive(Clone, Debug)]
1720struct WindowsBuffer {
1721    buf: Vec<u8>,
1723    colors: Vec<(usize, Option<ColorSpec>)>,
1729}
1730
1731#[cfg(windows)]
1732impl WindowsBuffer {
1733    fn new() -> WindowsBuffer {
1735        WindowsBuffer { buf: vec![], colors: vec![] }
1736    }
1737
1738    fn push(&mut self, spec: Option<ColorSpec>) {
1743        let pos = self.buf.len();
1744        self.colors.push((pos, spec));
1745    }
1746
1747    fn print(
1750        &self,
1751        console: &mut wincon::Console,
1752        stream: &mut LossyStandardStream<IoStandardStreamLock>,
1753    ) -> io::Result<()> {
1754        let mut last = 0;
1755        for &(pos, ref spec) in &self.colors {
1756            stream.write_all(&self.buf[last..pos])?;
1757            stream.flush()?;
1758            last = pos;
1759            match *spec {
1760                None => console.reset()?,
1761                Some(ref spec) => spec.write_console(console)?,
1762            }
1763        }
1764        stream.write_all(&self.buf[last..])?;
1765        stream.flush()
1766    }
1767
1768    fn clear(&mut self) {
1770        self.buf.clear();
1771        self.colors.clear();
1772    }
1773}
1774
1775#[cfg(windows)]
1776impl io::Write for WindowsBuffer {
1777    #[inline]
1778    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1779        self.buf.extend_from_slice(buf);
1780        Ok(buf.len())
1781    }
1782
1783    #[inline]
1784    fn flush(&mut self) -> io::Result<()> {
1785        Ok(())
1786    }
1787}
1788
1789#[cfg(windows)]
1790impl WriteColor for WindowsBuffer {
1791    #[inline]
1792    fn supports_color(&self) -> bool {
1793        true
1794    }
1795
1796    #[inline]
1797    fn supports_hyperlinks(&self) -> bool {
1798        false
1799    }
1800
1801    #[inline]
1802    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
1803        self.push(Some(spec.clone()));
1804        Ok(())
1805    }
1806
1807    #[inline]
1808    fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
1809        Ok(())
1810    }
1811
1812    #[inline]
1813    fn reset(&mut self) -> io::Result<()> {
1814        self.push(None);
1815        Ok(())
1816    }
1817
1818    #[inline]
1819    fn is_synchronous(&self) -> bool {
1820        false
1821    }
1822}
1823
1824#[derive(Clone, Debug, Eq, PartialEq)]
1826pub struct ColorSpec {
1827    fg_color: Option<Color>,
1828    bg_color: Option<Color>,
1829    bold: bool,
1830    intense: bool,
1831    underline: bool,
1832    dimmed: bool,
1833    italic: bool,
1834    reset: bool,
1835    strikethrough: bool,
1836}
1837
1838impl Default for ColorSpec {
1839    fn default() -> ColorSpec {
1840        ColorSpec {
1841            fg_color: None,
1842            bg_color: None,
1843            bold: false,
1844            intense: false,
1845            underline: false,
1846            dimmed: false,
1847            italic: false,
1848            reset: true,
1849            strikethrough: false,
1850        }
1851    }
1852}
1853
1854impl ColorSpec {
1855    pub fn new() -> ColorSpec {
1857        ColorSpec::default()
1858    }
1859
1860    pub fn fg(&self) -> Option<&Color> {
1862        self.fg_color.as_ref()
1863    }
1864
1865    pub fn set_fg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1867        self.fg_color = color;
1868        self
1869    }
1870
1871    pub fn bg(&self) -> Option<&Color> {
1873        self.bg_color.as_ref()
1874    }
1875
1876    pub fn set_bg(&mut self, color: Option<Color>) -> &mut ColorSpec {
1878        self.bg_color = color;
1879        self
1880    }
1881
1882    pub fn bold(&self) -> bool {
1886        self.bold
1887    }
1888
1889    pub fn set_bold(&mut self, yes: bool) -> &mut ColorSpec {
1893        self.bold = yes;
1894        self
1895    }
1896
1897    pub fn dimmed(&self) -> bool {
1901        self.dimmed
1902    }
1903
1904    pub fn set_dimmed(&mut self, yes: bool) -> &mut ColorSpec {
1908        self.dimmed = yes;
1909        self
1910    }
1911
1912    pub fn italic(&self) -> bool {
1916        self.italic
1917    }
1918
1919    pub fn set_italic(&mut self, yes: bool) -> &mut ColorSpec {
1923        self.italic = yes;
1924        self
1925    }
1926
1927    pub fn underline(&self) -> bool {
1931        self.underline
1932    }
1933
1934    pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec {
1938        self.underline = yes;
1939        self
1940    }
1941
1942    pub fn strikethrough(&self) -> bool {
1946        self.strikethrough
1947    }
1948
1949    pub fn set_strikethrough(&mut self, yes: bool) -> &mut ColorSpec {
1953        self.strikethrough = yes;
1954        self
1955    }
1956
1957    pub fn reset(&self) -> bool {
1965        self.reset
1966    }
1967
1968    pub fn set_reset(&mut self, yes: bool) -> &mut ColorSpec {
1980        self.reset = yes;
1981        self
1982    }
1983
1984    pub fn intense(&self) -> bool {
1993        self.intense
1994    }
1995
1996    pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec {
2005        self.intense = yes;
2006        self
2007    }
2008
2009    pub fn is_none(&self) -> bool {
2011        self.fg_color.is_none()
2012            && self.bg_color.is_none()
2013            && !self.bold
2014            && !self.underline
2015            && !self.dimmed
2016            && !self.italic
2017            && !self.intense
2018            && !self.strikethrough
2019    }
2020
2021    pub fn clear(&mut self) {
2023        self.fg_color = None;
2024        self.bg_color = None;
2025        self.bold = false;
2026        self.underline = false;
2027        self.intense = false;
2028        self.dimmed = false;
2029        self.italic = false;
2030        self.strikethrough = false;
2031    }
2032
2033    #[cfg(windows)]
2035    fn write_console(&self, console: &mut wincon::Console) -> io::Result<()> {
2036        let fg_color = self.fg_color.and_then(|c| c.to_windows(self.intense));
2037        if let Some((intense, color)) = fg_color {
2038            console.fg(intense, color)?;
2039        }
2040        let bg_color = self.bg_color.and_then(|c| c.to_windows(self.intense));
2041        if let Some((intense, color)) = bg_color {
2042            console.bg(intense, color)?;
2043        }
2044        Ok(())
2045    }
2046}
2047
2048#[allow(missing_docs)]
2070#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2071pub enum Color {
2072    Black,
2073    Blue,
2074    Green,
2075    Red,
2076    Cyan,
2077    Magenta,
2078    Yellow,
2079    White,
2080    Ansi256(u8),
2081    Rgb(u8, u8, u8),
2082    #[doc(hidden)]
2083    __Nonexhaustive,
2084}
2085
2086impl Color {
2087    #[cfg(windows)]
2089    fn to_windows(
2090        self,
2091        intense: bool,
2092    ) -> Option<(wincon::Intense, wincon::Color)> {
2093        use wincon::Intense::{No, Yes};
2094
2095        let color = match self {
2096            Color::Black => wincon::Color::Black,
2097            Color::Blue => wincon::Color::Blue,
2098            Color::Green => wincon::Color::Green,
2099            Color::Red => wincon::Color::Red,
2100            Color::Cyan => wincon::Color::Cyan,
2101            Color::Magenta => wincon::Color::Magenta,
2102            Color::Yellow => wincon::Color::Yellow,
2103            Color::White => wincon::Color::White,
2104            Color::Ansi256(0) => return Some((No, wincon::Color::Black)),
2105            Color::Ansi256(1) => return Some((No, wincon::Color::Red)),
2106            Color::Ansi256(2) => return Some((No, wincon::Color::Green)),
2107            Color::Ansi256(3) => return Some((No, wincon::Color::Yellow)),
2108            Color::Ansi256(4) => return Some((No, wincon::Color::Blue)),
2109            Color::Ansi256(5) => return Some((No, wincon::Color::Magenta)),
2110            Color::Ansi256(6) => return Some((No, wincon::Color::Cyan)),
2111            Color::Ansi256(7) => return Some((No, wincon::Color::White)),
2112            Color::Ansi256(8) => return Some((Yes, wincon::Color::Black)),
2113            Color::Ansi256(9) => return Some((Yes, wincon::Color::Red)),
2114            Color::Ansi256(10) => return Some((Yes, wincon::Color::Green)),
2115            Color::Ansi256(11) => return Some((Yes, wincon::Color::Yellow)),
2116            Color::Ansi256(12) => return Some((Yes, wincon::Color::Blue)),
2117            Color::Ansi256(13) => return Some((Yes, wincon::Color::Magenta)),
2118            Color::Ansi256(14) => return Some((Yes, wincon::Color::Cyan)),
2119            Color::Ansi256(15) => return Some((Yes, wincon::Color::White)),
2120            Color::Ansi256(_) => return None,
2121            Color::Rgb(_, _, _) => return None,
2122            Color::__Nonexhaustive => unreachable!(),
2123        };
2124        let intense = if intense { Yes } else { No };
2125        Some((intense, color))
2126    }
2127
2128    fn from_str_numeric(s: &str) -> Result<Color, ParseColorError> {
2130        fn parse_number(s: &str) -> Option<u8> {
2137            use std::u8;
2138
2139            if s.starts_with("0x") {
2140                u8::from_str_radix(&s[2..], 16).ok()
2141            } else {
2142                u8::from_str_radix(s, 10).ok()
2143            }
2144        }
2145
2146        let codes: Vec<&str> = s.split(',').collect();
2147        if codes.len() == 1 {
2148            if let Some(n) = parse_number(&codes[0]) {
2149                Ok(Color::Ansi256(n))
2150            } else {
2151                if s.chars().all(|c| c.is_digit(16)) {
2152                    Err(ParseColorError {
2153                        kind: ParseColorErrorKind::InvalidAnsi256,
2154                        given: s.to_string(),
2155                    })
2156                } else {
2157                    Err(ParseColorError {
2158                        kind: ParseColorErrorKind::InvalidName,
2159                        given: s.to_string(),
2160                    })
2161                }
2162            }
2163        } else if codes.len() == 3 {
2164            let mut v = vec![];
2165            for code in codes {
2166                let n = parse_number(code).ok_or_else(|| ParseColorError {
2167                    kind: ParseColorErrorKind::InvalidRgb,
2168                    given: s.to_string(),
2169                })?;
2170                v.push(n);
2171            }
2172            Ok(Color::Rgb(v[0], v[1], v[2]))
2173        } else {
2174            Err(if s.contains(",") {
2175                ParseColorError {
2176                    kind: ParseColorErrorKind::InvalidRgb,
2177                    given: s.to_string(),
2178                }
2179            } else {
2180                ParseColorError {
2181                    kind: ParseColorErrorKind::InvalidName,
2182                    given: s.to_string(),
2183                }
2184            })
2185        }
2186    }
2187}
2188
2189#[derive(Clone, Debug, Eq, PartialEq)]
2191pub struct ParseColorError {
2192    kind: ParseColorErrorKind,
2193    given: String,
2194}
2195
2196#[derive(Clone, Debug, Eq, PartialEq)]
2197enum ParseColorErrorKind {
2198    InvalidName,
2199    InvalidAnsi256,
2200    InvalidRgb,
2201}
2202
2203impl ParseColorError {
2204    pub fn invalid(&self) -> &str {
2206        &self.given
2207    }
2208}
2209
2210impl error::Error for ParseColorError {
2211    fn description(&self) -> &str {
2212        use self::ParseColorErrorKind::*;
2213        match self.kind {
2214            InvalidName => "unrecognized color name",
2215            InvalidAnsi256 => "invalid ansi256 color number",
2216            InvalidRgb => "invalid RGB color triple",
2217        }
2218    }
2219}
2220
2221impl fmt::Display for ParseColorError {
2222    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2223        use self::ParseColorErrorKind::*;
2224        match self.kind {
2225            InvalidName => write!(
2226                f,
2227                "unrecognized color name '{}'. Choose from: \
2228                 black, blue, green, red, cyan, magenta, yellow, \
2229                 white",
2230                self.given
2231            ),
2232            InvalidAnsi256 => write!(
2233                f,
2234                "unrecognized ansi256 color number, \
2235                 should be '[0-255]' (or a hex number), but is '{}'",
2236                self.given
2237            ),
2238            InvalidRgb => write!(
2239                f,
2240                "unrecognized RGB color triple, \
2241                 should be '[0-255],[0-255],[0-255]' (or a hex \
2242                 triple), but is '{}'",
2243                self.given
2244            ),
2245        }
2246    }
2247}
2248
2249impl FromStr for Color {
2250    type Err = ParseColorError;
2251
2252    fn from_str(s: &str) -> Result<Color, ParseColorError> {
2253        match &*s.to_lowercase() {
2254            "black" => Ok(Color::Black),
2255            "blue" => Ok(Color::Blue),
2256            "green" => Ok(Color::Green),
2257            "red" => Ok(Color::Red),
2258            "cyan" => Ok(Color::Cyan),
2259            "magenta" => Ok(Color::Magenta),
2260            "yellow" => Ok(Color::Yellow),
2261            "white" => Ok(Color::White),
2262            _ => Color::from_str_numeric(s),
2263        }
2264    }
2265}
2266
2267#[derive(Clone, Debug)]
2269pub struct HyperlinkSpec<'a> {
2270    uri: Option<&'a [u8]>,
2271}
2272
2273impl<'a> HyperlinkSpec<'a> {
2274    pub fn open(uri: &'a [u8]) -> HyperlinkSpec<'a> {
2276        HyperlinkSpec { uri: Some(uri) }
2277    }
2278
2279    pub fn close() -> HyperlinkSpec<'a> {
2281        HyperlinkSpec { uri: None }
2282    }
2283
2284    pub fn uri(&self) -> Option<&'a [u8]> {
2286        self.uri
2287    }
2288}
2289
2290#[derive(Debug)]
2291struct LossyStandardStream<W> {
2292    wtr: W,
2293    #[cfg(windows)]
2294    is_console: bool,
2295}
2296
2297impl<W: io::Write> LossyStandardStream<W> {
2298    #[cfg(not(windows))]
2299    fn new(wtr: W) -> LossyStandardStream<W> {
2300        LossyStandardStream { wtr }
2301    }
2302
2303    #[cfg(windows)]
2304    fn new(wtr: W) -> LossyStandardStream<W> {
2305        let is_console = wincon::Console::stdout().is_ok()
2306            || wincon::Console::stderr().is_ok();
2307        LossyStandardStream { wtr, is_console }
2308    }
2309
2310    #[cfg(not(windows))]
2311    fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2312        LossyStandardStream::new(wtr)
2313    }
2314
2315    #[cfg(windows)]
2316    fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> {
2317        LossyStandardStream { wtr, is_console: self.is_console }
2318    }
2319
2320    fn get_ref(&self) -> &W {
2321        &self.wtr
2322    }
2323}
2324
2325impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
2326    fn supports_color(&self) -> bool {
2327        self.wtr.supports_color()
2328    }
2329    fn supports_hyperlinks(&self) -> bool {
2330        self.wtr.supports_hyperlinks()
2331    }
2332    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
2333        self.wtr.set_color(spec)
2334    }
2335    fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
2336        self.wtr.set_hyperlink(link)
2337    }
2338    fn reset(&mut self) -> io::Result<()> {
2339        self.wtr.reset()
2340    }
2341    fn is_synchronous(&self) -> bool {
2342        self.wtr.is_synchronous()
2343    }
2344}
2345
2346impl<W: io::Write> io::Write for LossyStandardStream<W> {
2347    #[cfg(not(windows))]
2348    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2349        self.wtr.write(buf)
2350    }
2351
2352    #[cfg(windows)]
2353    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2354        if self.is_console {
2355            write_lossy_utf8(&mut self.wtr, buf)
2356        } else {
2357            self.wtr.write(buf)
2358        }
2359    }
2360
2361    fn flush(&mut self) -> io::Result<()> {
2362        self.wtr.flush()
2363    }
2364}
2365
2366#[cfg(windows)]
2367fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
2368    match ::std::str::from_utf8(buf) {
2369        Ok(s) => w.write(s.as_bytes()),
2370        Err(ref e) if e.valid_up_to() == 0 => {
2371            w.write(b"\xEF\xBF\xBD")?;
2372            Ok(1)
2373        }
2374        Err(e) => w.write(&buf[..e.valid_up_to()]),
2375    }
2376}
2377
2378#[cfg(test)]
2379mod tests {
2380    use super::{
2381        Ansi, Color, ColorSpec, HyperlinkSpec, ParseColorError,
2382        ParseColorErrorKind, StandardStream, WriteColor,
2383    };
2384
2385    fn assert_is_send<T: Send>() {}
2386
2387    #[test]
2388    fn standard_stream_is_send() {
2389        assert_is_send::<StandardStream>();
2390    }
2391
2392    #[test]
2393    fn test_simple_parse_ok() {
2394        let color = "green".parse::<Color>();
2395        assert_eq!(color, Ok(Color::Green));
2396    }
2397
2398    #[test]
2399    fn test_256_parse_ok() {
2400        let color = "7".parse::<Color>();
2401        assert_eq!(color, Ok(Color::Ansi256(7)));
2402
2403        let color = "32".parse::<Color>();
2404        assert_eq!(color, Ok(Color::Ansi256(32)));
2405
2406        let color = "0xFF".parse::<Color>();
2407        assert_eq!(color, Ok(Color::Ansi256(0xFF)));
2408    }
2409
2410    #[test]
2411    fn test_256_parse_err_out_of_range() {
2412        let color = "256".parse::<Color>();
2413        assert_eq!(
2414            color,
2415            Err(ParseColorError {
2416                kind: ParseColorErrorKind::InvalidAnsi256,
2417                given: "256".to_string(),
2418            })
2419        );
2420    }
2421
2422    #[test]
2423    fn test_rgb_parse_ok() {
2424        let color = "0,0,0".parse::<Color>();
2425        assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2426
2427        let color = "0,128,255".parse::<Color>();
2428        assert_eq!(color, Ok(Color::Rgb(0, 128, 255)));
2429
2430        let color = "0x0,0x0,0x0".parse::<Color>();
2431        assert_eq!(color, Ok(Color::Rgb(0, 0, 0)));
2432
2433        let color = "0x33,0x66,0xFF".parse::<Color>();
2434        assert_eq!(color, Ok(Color::Rgb(0x33, 0x66, 0xFF)));
2435    }
2436
2437    #[test]
2438    fn test_rgb_parse_err_out_of_range() {
2439        let color = "0,0,256".parse::<Color>();
2440        assert_eq!(
2441            color,
2442            Err(ParseColorError {
2443                kind: ParseColorErrorKind::InvalidRgb,
2444                given: "0,0,256".to_string(),
2445            })
2446        );
2447    }
2448
2449    #[test]
2450    fn test_rgb_parse_err_bad_format() {
2451        let color = "0,0".parse::<Color>();
2452        assert_eq!(
2453            color,
2454            Err(ParseColorError {
2455                kind: ParseColorErrorKind::InvalidRgb,
2456                given: "0,0".to_string(),
2457            })
2458        );
2459
2460        let color = "not_a_color".parse::<Color>();
2461        assert_eq!(
2462            color,
2463            Err(ParseColorError {
2464                kind: ParseColorErrorKind::InvalidName,
2465                given: "not_a_color".to_string(),
2466            })
2467        );
2468    }
2469
2470    #[test]
2471    fn test_var_ansi_write_rgb() {
2472        let mut buf = Ansi::new(vec![]);
2473        let _ = buf.write_color(true, &Color::Rgb(254, 253, 255), false);
2474        assert_eq!(buf.0, b"\x1B[38;2;254;253;255m");
2475    }
2476
2477    #[test]
2478    fn test_reset() {
2479        let spec = ColorSpec::new();
2480        let mut buf = Ansi::new(vec![]);
2481        buf.set_color(&spec).unwrap();
2482        assert_eq!(buf.0, b"\x1B[0m");
2483    }
2484
2485    #[test]
2486    fn test_no_reset() {
2487        let mut spec = ColorSpec::new();
2488        spec.set_reset(false);
2489
2490        let mut buf = Ansi::new(vec![]);
2491        buf.set_color(&spec).unwrap();
2492        assert_eq!(buf.0, b"");
2493    }
2494
2495    #[test]
2496    fn test_var_ansi_write_256() {
2497        let mut buf = Ansi::new(vec![]);
2498        let _ = buf.write_color(false, &Color::Ansi256(7), false);
2499        assert_eq!(buf.0, b"\x1B[48;5;7m");
2500
2501        let mut buf = Ansi::new(vec![]);
2502        let _ = buf.write_color(false, &Color::Ansi256(208), false);
2503        assert_eq!(buf.0, b"\x1B[48;5;208m");
2504    }
2505
2506    fn all_attributes() -> Vec<ColorSpec> {
2507        let mut result = vec![];
2508        for fg in vec![None, Some(Color::Red)] {
2509            for bg in vec![None, Some(Color::Red)] {
2510                for bold in vec![false, true] {
2511                    for underline in vec![false, true] {
2512                        for intense in vec![false, true] {
2513                            for italic in vec![false, true] {
2514                                for strikethrough in vec![false, true] {
2515                                    for dimmed in vec![false, true] {
2516                                        let mut color = ColorSpec::new();
2517                                        color.set_fg(fg);
2518                                        color.set_bg(bg);
2519                                        color.set_bold(bold);
2520                                        color.set_underline(underline);
2521                                        color.set_intense(intense);
2522                                        color.set_italic(italic);
2523                                        color.set_dimmed(dimmed);
2524                                        color.set_strikethrough(strikethrough);
2525                                        result.push(color);
2526                                    }
2527                                }
2528                            }
2529                        }
2530                    }
2531                }
2532            }
2533        }
2534        result
2535    }
2536
2537    #[test]
2538    fn test_is_none() {
2539        for (i, color) in all_attributes().iter().enumerate() {
2540            assert_eq!(
2541                i == 0,
2542                color.is_none(),
2543                "{:?} => {}",
2544                color,
2545                color.is_none()
2546            )
2547        }
2548    }
2549
2550    #[test]
2551    fn test_clear() {
2552        for color in all_attributes() {
2553            let mut color1 = color.clone();
2554            color1.clear();
2555            assert!(color1.is_none(), "{:?} => {:?}", color, color1);
2556        }
2557    }
2558
2559    #[test]
2560    fn test_ansi_hyperlink() {
2561        let mut buf = Ansi::new(vec![]);
2562        buf.set_hyperlink(&HyperlinkSpec::open(b"https://example.com"))
2563            .unwrap();
2564        buf.write_str("label").unwrap();
2565        buf.set_hyperlink(&HyperlinkSpec::close()).unwrap();
2566
2567        assert_eq!(
2568            buf.0,
2569            b"\x1B]8;;https://example.com\x1B\\label\x1B]8;;\x1B\\".to_vec()
2570        );
2571    }
2572}