4 use self::atty
::{is_stderr, is_stdout}
;
5 use self::termcolor
::BufferWriter
;
6 use std
::{fmt, io, mem, sync::Mutex}
;
9 pub use super::termcolor
::glob
::*;
13 pub(super) use self::termcolor
::Buffer
;
15 /// Log target, either `stdout`, `stderr` or a custom pipe.
18 /// Logs will be sent to standard output.
20 /// Logs will be sent to standard error.
22 /// Logs will be sent to a custom pipe.
23 Pipe(Box
<dyn io
::Write
+ Send
+ '
static>),
26 impl Default
for Target
{
27 fn default() -> Self {
32 impl fmt
::Debug
for Target
{
33 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
38 Self::Stdout
=> "stdout",
39 Self::Stderr
=> "stderr",
40 Self::Pipe(_
) => "pipe",
46 /// Log target, either `stdout`, `stderr` or a custom pipe.
48 /// Same as `Target`, except the pipe is wrapped in a mutex for interior mutability.
49 pub(super) enum WritableTarget
{
50 /// Logs will be sent to standard output.
52 /// Logs will be sent to standard error.
54 /// Logs will be sent to a custom pipe.
55 Pipe(Box
<Mutex
<dyn io
::Write
+ Send
+ '
static>>),
58 impl From
<Target
> for WritableTarget
{
59 fn from(target
: Target
) -> Self {
61 Target
::Stdout
=> Self::Stdout
,
62 Target
::Stderr
=> Self::Stderr
,
63 Target
::Pipe(pipe
) => Self::Pipe(Box
::new(Mutex
::new(pipe
))),
68 impl Default
for WritableTarget
{
69 fn default() -> Self {
70 Self::from(Target
::default())
74 impl fmt
::Debug
for WritableTarget
{
75 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
80 Self::Stdout
=> "stdout",
81 Self::Stderr
=> "stderr",
82 Self::Pipe(_
) => "pipe",
87 /// Whether or not to print styles to the target.
88 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
90 /// Try to print styles, but don't force the issue.
92 /// Try very hard to print styles.
94 /// Never print styles.
98 impl Default
for WriteStyle
{
99 fn default() -> Self {
104 /// A terminal target with color awareness.
105 pub(crate) struct Writer
{
107 write_style
: WriteStyle
,
111 pub fn write_style(&self) -> WriteStyle
{
115 pub(super) fn buffer(&self) -> Buffer
{
119 pub(super) fn print(&self, buf
: &Buffer
) -> io
::Result
<()> {
120 self.inner
.print(buf
)
124 /// A builder for a terminal writer.
126 /// The target and style choice can be configured before building.
128 pub(crate) struct Builder
{
129 target
: WritableTarget
,
130 write_style
: WriteStyle
,
136 /// Initialize the writer builder with defaults.
137 pub(crate) fn new() -> Self {
139 target
: Default
::default(),
140 write_style
: Default
::default(),
146 /// Set the target to write to.
147 pub(crate) fn target(&mut self, target
: Target
) -> &mut Self {
148 self.target
= target
.into();
152 /// Parses a style choice string.
154 /// See the [Disabling colors] section for more details.
156 /// [Disabling colors]: ../index.html#disabling-colors
157 pub(crate) fn parse_write_style(&mut self, write_style
: &str) -> &mut Self {
158 self.write_style(parse_write_style(write_style
))
161 /// Whether or not to print style characters when writing.
162 pub(crate) fn write_style(&mut self, write_style
: WriteStyle
) -> &mut Self {
163 self.write_style
= write_style
;
167 /// Whether or not to capture logs for `cargo test`.
168 pub(crate) fn is_test(&mut self, is_test
: bool
) -> &mut Self {
169 self.is_test
= is_test
;
173 /// Build a terminal writer.
174 pub(crate) fn build(&mut self) -> Writer
{
175 assert
!(!self.built
, "attempt to re-use consumed builder");
178 let color_choice
= match self.write_style
{
179 WriteStyle
::Auto
=> {
180 if match &self.target
{
181 WritableTarget
::Stderr
=> is_stderr(),
182 WritableTarget
::Stdout
=> is_stdout(),
183 WritableTarget
::Pipe(_
) => false,
190 color_choice
=> color_choice
,
193 let writer
= match mem
::take(&mut self.target
) {
194 WritableTarget
::Stderr
=> BufferWriter
::stderr(self.is_test
, color_choice
),
195 WritableTarget
::Stdout
=> BufferWriter
::stdout(self.is_test
, color_choice
),
196 WritableTarget
::Pipe(pipe
) => BufferWriter
::pipe(self.is_test
, color_choice
, pipe
),
201 write_style
: self.write_style
,
206 impl Default
for Builder
{
207 fn default() -> Self {
212 impl fmt
::Debug
for Writer
{
213 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
214 f
.debug_struct("Writer").finish()
218 fn parse_write_style(spec
: &str) -> WriteStyle
{
220 "auto" => WriteStyle
::Auto
,
221 "always" => WriteStyle
::Always
,
222 "never" => WriteStyle
::Never
,
223 _
=> Default
::default(),
232 fn parse_write_style_valid() {
234 ("auto", WriteStyle
::Auto
),
235 ("always", WriteStyle
::Always
),
236 ("never", WriteStyle
::Never
),
239 for (input
, expected
) in inputs
{
240 assert_eq
!(expected
, parse_write_style(input
));
245 fn parse_write_style_invalid() {
246 let inputs
= vec
!["", "true", "false", "NEVER!!"];
248 for input
in inputs
{
249 assert_eq
!(WriteStyle
::Auto
, parse_write_style(input
));