1 | use std::io::{self, Write}; |
2 | use std::sync::Mutex; |
3 | |
4 | use termcolor::{self, ColorSpec, WriteColor}; |
5 | |
6 | use crate::fmt::{WritableTarget, WriteStyle}; |
7 | |
8 | pub(in crate::fmt::writer) struct BufferWriter { |
9 | inner: termcolor::BufferWriter, |
10 | uncolored_target: Option<WritableTarget>, |
11 | write_style: WriteStyle, |
12 | } |
13 | |
14 | impl 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 | |
69 | pub(in crate::fmt) struct Buffer { |
70 | inner: termcolor::Buffer, |
71 | has_uncolored_target: bool, |
72 | } |
73 | |
74 | impl 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 | } |
109 | |