]> git.proxmox.com Git - rustc.git/blob - vendor/clap/src/output/fmt.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / vendor / clap / src / output / fmt.rs
1 use crate::util::color::ColorChoice;
2
3 use std::{
4 fmt::{self, Display, Formatter},
5 io::{self, Write},
6 };
7
8 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
9 pub(crate) enum Stream {
10 Stdout,
11 Stderr,
12 }
13
14 #[derive(Clone, Debug)]
15 pub(crate) struct Colorizer {
16 stream: Stream,
17 #[allow(unused)]
18 color_when: ColorChoice,
19 pieces: Vec<(String, Style)>,
20 }
21
22 impl Colorizer {
23 #[inline(never)]
24 pub(crate) fn new(stream: Stream, color_when: ColorChoice) -> Self {
25 Colorizer {
26 stream,
27 color_when,
28 pieces: vec![],
29 }
30 }
31
32 #[inline(never)]
33 pub(crate) fn good(&mut self, msg: impl Into<String>) {
34 self.pieces.push((msg.into(), Style::Good));
35 }
36
37 #[inline(never)]
38 pub(crate) fn warning(&mut self, msg: impl Into<String>) {
39 self.pieces.push((msg.into(), Style::Warning));
40 }
41
42 #[inline(never)]
43 pub(crate) fn error(&mut self, msg: impl Into<String>) {
44 self.pieces.push((msg.into(), Style::Error));
45 }
46
47 #[inline(never)]
48 #[allow(dead_code)]
49 pub(crate) fn hint(&mut self, msg: impl Into<String>) {
50 self.pieces.push((msg.into(), Style::Hint));
51 }
52
53 #[inline(never)]
54 pub(crate) fn none(&mut self, msg: impl Into<String>) {
55 self.pieces.push((msg.into(), Style::Default));
56 }
57 }
58
59 /// Printing methods.
60 impl Colorizer {
61 #[cfg(feature = "color")]
62 pub(crate) fn print(&self) -> io::Result<()> {
63 use termcolor::{BufferWriter, ColorChoice as DepColorChoice, ColorSpec, WriteColor};
64
65 let color_when = match self.color_when {
66 ColorChoice::Always => DepColorChoice::Always,
67 ColorChoice::Auto if is_a_tty(self.stream) => DepColorChoice::Auto,
68 _ => DepColorChoice::Never,
69 };
70
71 let writer = match self.stream {
72 Stream::Stderr => BufferWriter::stderr(color_when),
73 Stream::Stdout => BufferWriter::stdout(color_when),
74 };
75
76 let mut buffer = writer.buffer();
77
78 for piece in &self.pieces {
79 let mut color = ColorSpec::new();
80 match piece.1 {
81 Style::Good => {
82 color.set_fg(Some(termcolor::Color::Green));
83 }
84 Style::Warning => {
85 color.set_fg(Some(termcolor::Color::Yellow));
86 }
87 Style::Error => {
88 color.set_fg(Some(termcolor::Color::Red));
89 color.set_bold(true);
90 }
91 Style::Hint => {
92 color.set_dimmed(true);
93 }
94 Style::Default => {}
95 }
96
97 buffer.set_color(&color)?;
98 buffer.write_all(piece.0.as_bytes())?;
99 buffer.reset()?;
100 }
101
102 writer.print(&buffer)
103 }
104
105 #[cfg(not(feature = "color"))]
106 pub(crate) fn print(&self) -> io::Result<()> {
107 // [e]println can't be used here because it panics
108 // if something went wrong. We don't want that.
109 match self.stream {
110 Stream::Stdout => {
111 let stdout = std::io::stdout();
112 let mut stdout = stdout.lock();
113 write!(stdout, "{}", self)
114 }
115 Stream::Stderr => {
116 let stderr = std::io::stderr();
117 let mut stderr = stderr.lock();
118 write!(stderr, "{}", self)
119 }
120 }
121 }
122 }
123
124 /// Color-unaware printing. Never uses coloring.
125 impl Display for Colorizer {
126 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
127 for piece in &self.pieces {
128 Display::fmt(&piece.0, f)?;
129 }
130
131 Ok(())
132 }
133 }
134
135 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
136 pub enum Style {
137 Good,
138 Warning,
139 Error,
140 Hint,
141 Default,
142 }
143
144 impl Default for Style {
145 fn default() -> Self {
146 Self::Default
147 }
148 }
149
150 #[cfg(feature = "color")]
151 fn is_a_tty(stream: Stream) -> bool {
152 let stream = match stream {
153 Stream::Stdout => atty::Stream::Stdout,
154 Stream::Stderr => atty::Stream::Stderr,
155 };
156
157 atty::is(stream)
158 }