env_logger/fmt/writer/buffer/
termcolor.rs

1use std::io::{self, Write};
2use std::sync::Mutex;
3
4use termcolor::{self, ColorSpec, WriteColor};
5
6use crate::fmt::{WritableTarget, WriteStyle};
7
8pub(in crate::fmt::writer) struct BufferWriter {
9    inner: termcolor::BufferWriter,
10    uncolored_target: Option<WritableTarget>,
11    write_style: WriteStyle,
12}
13
14impl BufferWriter {
15    pub(in crate::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self {
16        BufferWriter {
17            inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
18            uncolored_target: if is_test {
19                Some(WritableTarget::PrintStderr)
20            } else {
21                None
22            },
23            write_style,
24        }
25    }
26
27    pub(in crate::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self {
28        BufferWriter {
29            inner: termcolor::BufferWriter::stdout(write_style.into_color_choice()),
30            uncolored_target: if is_test {
31                Some(WritableTarget::PrintStdout)
32            } else {
33                None
34            },
35            write_style,
36        }
37    }
38
39    pub(in crate::fmt::writer) fn pipe(pipe: Box<Mutex<dyn io::Write + Send + 'static>>) -> Self {
40        let write_style = WriteStyle::Never;
41        BufferWriter {
42            // The inner Buffer is never printed from, but it is still needed to handle coloring and other formatting
43            inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
44            uncolored_target: Some(WritableTarget::Pipe(pipe)),
45            write_style,
46        }
47    }
48
49    pub(in crate::fmt::writer) fn write_style(&self) -> WriteStyle {
50        self.write_style
51    }
52
53    pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
54        Buffer {
55            inner: self.inner.buffer(),
56            has_uncolored_target: self.uncolored_target.is_some(),
57        }
58    }
59
60    pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
61        if let Some(target) = &self.uncolored_target {
62            target.print(buf)
63        } else {
64            self.inner.print(&buf.inner)
65        }
66    }
67}
68
69pub(in crate::fmt) struct Buffer {
70    inner: termcolor::Buffer,
71    has_uncolored_target: bool,
72}
73
74impl Buffer {
75    pub(in crate::fmt) fn clear(&mut self) {
76        self.inner.clear()
77    }
78
79    pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
80        self.inner.write(buf)
81    }
82
83    pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
84        self.inner.flush()
85    }
86
87    pub(in crate::fmt) fn as_bytes(&self) -> &[u8] {
88        self.inner.as_slice()
89    }
90
91    pub(in crate::fmt) fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
92        // Ignore styles for test captured logs because they can't be printed
93        if !self.has_uncolored_target {
94            self.inner.set_color(spec)
95        } else {
96            Ok(())
97        }
98    }
99
100    pub(in crate::fmt) fn reset(&mut self) -> io::Result<()> {
101        // Ignore styles for test captured logs because they can't be printed
102        if !self.has_uncolored_target {
103            self.inner.reset()
104        } else {
105            Ok(())
106        }
107    }
108}