1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
use std::{ fmt, io::{self, Write}, }; use termcolor::{Color, ColorSpec, StandardStream, WriteColor as _}; pub struct Shell { output: ShellOut, } impl Shell { pub fn new() -> Self { Self { output: ShellOut::stream(), } } pub(crate) fn out(&mut self) -> &mut dyn Write { let ShellOut::Stream { stdout, .. } = &mut self.output; stdout } pub fn err(&mut self) -> &mut dyn Write { let ShellOut::Stream { stderr, .. } = &mut self.output; stderr } pub(crate) fn status( &mut self, status: impl fmt::Display, message: impl fmt::Display, ) -> io::Result<()> { self.print(status, message, Color::Green, true) } pub(crate) fn warn(&mut self, message: impl fmt::Display) -> io::Result<()> { self.print("warning", message, Color::Yellow, false) } pub fn error(&mut self, message: impl fmt::Display) -> io::Result<()> { self.print("error", message, Color::Red, false) } fn print( &mut self, status: impl fmt::Display, message: impl fmt::Display, color: Color, justified: bool, ) -> io::Result<()> { let ShellOut::Stream { stderr, .. } = &mut self.output; stderr.set_color(ColorSpec::new().set_bold(true).set_fg(Some(color)))?; if justified { write!(stderr, "{:>12}", status)?; } else { write!(stderr, "{}", status)?; stderr.set_color(ColorSpec::new().set_bold(true))?; write!(stderr, ":")?; } stderr.reset()?; writeln!(stderr, " {}", message) } } impl Default for Shell { fn default() -> Self { Self::new() } } enum ShellOut { Stream { stdout: StandardStream, stderr: StandardStream, }, } impl ShellOut { fn stream() -> Self { Self::Stream { stdout: StandardStream::stdout(if atty::is(atty::Stream::Stdout) { termcolor::ColorChoice::Auto } else { termcolor::ColorChoice::Never }), stderr: StandardStream::stderr(if atty::is(atty::Stream::Stderr) { termcolor::ColorChoice::Auto } else { termcolor::ColorChoice::Never }), } } }