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}
109