1 use std::io; 2 use std::io::prelude::*; 3 use termcolor::{ColorSpec, WriteColor}; 4 5 // Color tester from: 6 // https://github.com/wycats/language-reporting/blob/b021c87e0d4916b5f32756151bf215c220eee52d/crates/render-tree/src/stylesheet/accumulator.rs 7 8 /// A facility for creating visually inspectable representations of colored output 9 /// so they can be easily tested. 10 /// 11 /// A new color is represented as `{style}` and a reset is represented by `{/}`. 12 /// 13 /// Attributes are printed in this order: 14 /// 15 /// - Foreground color as `fg:Color` 16 /// - Background color as `bg:Color` 17 /// - Bold as `bold` 18 /// - Underline as `underline` 19 /// - Intense as `bright` 20 /// 21 /// For example, the style "intense, bold red foreground" would be printed as: 22 /// 23 /// ```text 24 /// {fg:Red bold intense} 25 /// ``` 26 /// 27 /// Since this implementation attempts to make it possible to faithfully 28 /// understand what real WriteColor implementations would do, it tries 29 /// to approximate the contract in the WriteColor trait: "Subsequent 30 /// writes to this write will use these settings until either reset is 31 /// called or new color settings are set.") 32 /// 33 /// - If set_color is called with a style, `{...}` is emitted containing the 34 /// color attributes. 35 /// - If set_color is called with no style, `{/}` is emitted 36 /// - If reset is called, `{/}` is emitted. 37 pub struct ColorBuffer { 38 buf: Vec<u8>, 39 color: ColorSpec, 40 } 41 42 impl ColorBuffer { new() -> ColorBuffer43 pub fn new() -> ColorBuffer { 44 ColorBuffer { 45 buf: Vec::new(), 46 color: ColorSpec::new(), 47 } 48 } 49 into_string(self) -> String50 pub fn into_string(self) -> String { 51 String::from_utf8(self.buf).unwrap() 52 } 53 } 54 55 impl io::Write for ColorBuffer { write(&mut self, buf: &[u8]) -> io::Result<usize>56 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 57 self.buf.extend(buf); 58 Ok(buf.len()) 59 } 60 flush(&mut self) -> io::Result<()>61 fn flush(&mut self) -> io::Result<()> { 62 Ok(()) 63 } 64 } 65 66 impl WriteColor for ColorBuffer { supports_color(&self) -> bool67 fn supports_color(&self) -> bool { 68 true 69 } 70 set_color(&mut self, spec: &ColorSpec) -> io::Result<()>71 fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { 72 #![allow(unused_assignments)] 73 74 if self.color == *spec { 75 return Ok(()); 76 } else { 77 self.color = spec.clone(); 78 } 79 80 if spec.is_none() { 81 write!(self, "{{/}}")?; 82 return Ok(()); 83 } else { 84 write!(self, "{{")?; 85 } 86 87 let mut first = true; 88 89 fn write_first(first: bool, write: &mut ColorBuffer) -> io::Result<bool> { 90 if !first { 91 write!(write, " ")?; 92 } 93 94 Ok(false) 95 }; 96 97 if let Some(fg) = spec.fg() { 98 first = write_first(first, self)?; 99 write!(self, "fg:{:?}", fg)?; 100 } 101 102 if let Some(bg) = spec.bg() { 103 first = write_first(first, self)?; 104 write!(self, "bg:{:?}", bg)?; 105 } 106 107 if spec.bold() { 108 first = write_first(first, self)?; 109 write!(self, "bold")?; 110 } 111 112 if spec.underline() { 113 first = write_first(first, self)?; 114 write!(self, "underline")?; 115 } 116 117 if spec.intense() { 118 first = write_first(first, self)?; 119 write!(self, "bright")?; 120 } 121 122 write!(self, "}}")?; 123 124 Ok(()) 125 } 126 reset(&mut self) -> io::Result<()>127 fn reset(&mut self) -> io::Result<()> { 128 let color = self.color.clone(); 129 130 if color != ColorSpec::new() { 131 write!(self, "{{/}}")?; 132 self.color = ColorSpec::new(); 133 } 134 135 Ok(()) 136 } 137 } 138