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 { stderr(is_test: bool, write_style: WriteStyle) -> Self15 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 stdout(is_test: bool, write_style: WriteStyle) -> Self27 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 pipe(pipe: Box<Mutex<dyn io::Write + Send + 'static>>) -> Self39 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 write_style(&self) -> WriteStyle49 pub(in crate::fmt::writer) fn write_style(&self) -> WriteStyle { 50 self.write_style 51 } 52 buffer(&self) -> Buffer53 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 print(&self, buf: &Buffer) -> io::Result<()>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 { clear(&mut self)75 pub(in crate::fmt) fn clear(&mut self) { 76 self.inner.clear() 77 } 78 write(&mut self, buf: &[u8]) -> io::Result<usize>79 pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 80 self.inner.write(buf) 81 } 82 flush(&mut self) -> io::Result<()>83 pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> { 84 self.inner.flush() 85 } 86 as_bytes(&self) -> &[u8]87 pub(in crate::fmt) fn as_bytes(&self) -> &[u8] { 88 self.inner.as_slice() 89 } 90 set_color(&mut self, spec: &ColorSpec) -> io::Result<()>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 reset(&mut self) -> io::Result<()>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