use std::io; use std::io::prelude::*; use termcolor::{ColorSpec, WriteColor}; // Color tester from: // https://github.com/wycats/language-reporting/blob/b021c87e0d4916b5f32756151bf215c220eee52d/crates/render-tree/src/stylesheet/accumulator.rs /// A facility for creating visually inspectable representations of colored output /// so they can be easily tested. /// /// A new color is represented as `{style}` and a reset is represented by `{/}`. /// /// Attributes are printed in this order: /// /// - Foreground color as `fg:Color` /// - Background color as `bg:Color` /// - Bold as `bold` /// - Underline as `underline` /// - Intense as `bright` /// /// For example, the style "intense, bold red foreground" would be printed as: /// /// ```text /// {fg:Red bold intense} /// ``` /// /// Since this implementation attempts to make it possible to faithfully /// understand what real WriteColor implementations would do, it tries /// to approximate the contract in the WriteColor trait: "Subsequent /// writes to this write will use these settings until either reset is /// called or new color settings are set.") /// /// - If set_color is called with a style, `{...}` is emitted containing the /// color attributes. /// - If set_color is called with no style, `{/}` is emitted /// - If reset is called, `{/}` is emitted. pub struct ColorBuffer { buf: Vec, color: ColorSpec, } impl ColorBuffer { pub fn new() -> ColorBuffer { ColorBuffer { buf: Vec::new(), color: ColorSpec::new(), } } pub fn into_string(self) -> String { String::from_utf8(self.buf).unwrap() } } impl io::Write for ColorBuffer { fn write(&mut self, buf: &[u8]) -> io::Result { self.buf.extend(buf); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } impl WriteColor for ColorBuffer { fn supports_color(&self) -> bool { true } fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { #![allow(unused_assignments)] if self.color == *spec { return Ok(()); } else { self.color = spec.clone(); } if spec.is_none() { write!(self, "{{/}}")?; return Ok(()); } else { write!(self, "{{")?; } let mut first = true; fn write_first(first: bool, write: &mut ColorBuffer) -> io::Result { if !first { write!(write, " ")?; } Ok(false) }; if let Some(fg) = spec.fg() { first = write_first(first, self)?; write!(self, "fg:{:?}", fg)?; } if let Some(bg) = spec.bg() { first = write_first(first, self)?; write!(self, "bg:{:?}", bg)?; } if spec.bold() { first = write_first(first, self)?; write!(self, "bold")?; } if spec.underline() { first = write_first(first, self)?; write!(self, "underline")?; } if spec.intense() { first = write_first(first, self)?; write!(self, "bright")?; } write!(self, "}}")?; Ok(()) } fn reset(&mut self) -> io::Result<()> { let color = self.color.clone(); if color != ColorSpec::new() { write!(self, "{{/}}")?; self.color = ColorSpec::new(); } Ok(()) } }