]> git.proxmox.com Git - rustc.git/blob - vendor/nu-ansi-term/src/display.rs
New upstream version 1.75.0+dfsg1
[rustc.git] / vendor / nu-ansi-term / src / display.rs
1 use crate::ansi::RESET;
2 use crate::difference::Difference;
3 use crate::style::{Color, Style};
4 use crate::write::AnyWrite;
5 use std::borrow::Cow;
6 use std::fmt;
7 use std::io;
8
9 /// An `AnsiGenericString` includes a generic string type and a `Style` to
10 /// display that string. `AnsiString` and `AnsiByteString` are aliases for
11 /// this type on `str` and `\[u8]`, respectively.
12 #[derive(PartialEq, Debug)]
13 pub struct AnsiGenericString<'a, S: 'a + ToOwned + ?Sized>
14 where
15 <S as ToOwned>::Owned: fmt::Debug,
16 {
17 pub(crate) style: Style,
18 pub(crate) string: Cow<'a, S>,
19 }
20
21 /// Cloning an `AnsiGenericString` will clone its underlying string.
22 ///
23 /// # Examples
24 ///
25 /// ```
26 /// use nu_ansi_term::AnsiString;
27 ///
28 /// let plain_string = AnsiString::from("a plain string");
29 /// let clone_string = plain_string.clone();
30 /// assert_eq!(clone_string, plain_string);
31 /// ```
32 impl<'a, S: 'a + ToOwned + ?Sized> Clone for AnsiGenericString<'a, S>
33 where
34 <S as ToOwned>::Owned: fmt::Debug,
35 {
36 fn clone(&self) -> AnsiGenericString<'a, S> {
37 AnsiGenericString {
38 style: self.style,
39 string: self.string.clone(),
40 }
41 }
42 }
43
44 // You might think that the hand-written Clone impl above is the same as the
45 // one that gets generated with #[derive]. But it’s not *quite* the same!
46 //
47 // `str` is not Clone, and the derived Clone implementation puts a Clone
48 // constraint on the S type parameter (generated using --pretty=expanded):
49 //
50 // ↓_________________↓
51 // impl <'a, S: ::std::clone::Clone + 'a + ToOwned + ?Sized> ::std::clone::Clone
52 // for ANSIGenericString<'a, S> where
53 // <S as ToOwned>::Owned: fmt::Debug { ... }
54 //
55 // This resulted in compile errors when you tried to derive Clone on a type
56 // that used it:
57 //
58 // #[derive(PartialEq, Debug, Clone, Default)]
59 // pub struct TextCellContents(Vec<AnsiString<'static>>);
60 // ^^^^^^^^^^^^^^^^^^^^^^^^^
61 // error[E0277]: the trait `std::clone::Clone` is not implemented for `str`
62 //
63 // The hand-written impl above can ignore that constraint and still compile.
64
65 /// An ANSI String is a string coupled with the `Style` to display it
66 /// in a terminal.
67 ///
68 /// Although not technically a string itself, it can be turned into
69 /// one with the `to_string` method.
70 ///
71 /// # Examples
72 ///
73 /// ```
74 /// use nu_ansi_term::AnsiString;
75 /// use nu_ansi_term::Color::Red;
76 ///
77 /// let red_string = Red.paint("a red string");
78 /// println!("{}", red_string);
79 /// ```
80 ///
81 /// ```
82 /// use nu_ansi_term::AnsiString;
83 ///
84 /// let plain_string = AnsiString::from("a plain string");
85 /// ```
86 pub type AnsiString<'a> = AnsiGenericString<'a, str>;
87
88 /// An `AnsiByteString` represents a formatted series of bytes. Use
89 /// `AnsiByteString` when styling text with an unknown encoding.
90 pub type AnsiByteString<'a> = AnsiGenericString<'a, [u8]>;
91
92 impl<'a, I, S: 'a + ToOwned + ?Sized> From<I> for AnsiGenericString<'a, S>
93 where
94 I: Into<Cow<'a, S>>,
95 <S as ToOwned>::Owned: fmt::Debug,
96 {
97 fn from(input: I) -> AnsiGenericString<'a, S> {
98 AnsiGenericString {
99 string: input.into(),
100 style: Style::default(),
101 }
102 }
103 }
104
105 impl<'a, S: 'a + ToOwned + ?Sized> AnsiGenericString<'a, S>
106 where
107 <S as ToOwned>::Owned: fmt::Debug,
108 {
109 /// Directly access the style
110 pub fn style_ref(&self) -> &Style {
111 &self.style
112 }
113
114 /// Directly access the style mutably
115 pub fn style_ref_mut(&mut self) -> &mut Style {
116 &mut self.style
117 }
118 }
119
120 /// A set of `AnsiGenericStrings`s collected together, in order to be
121 /// written with a minimum of control characters.
122 #[derive(Debug, PartialEq)]
123 pub struct AnsiGenericStrings<'a, S: 'a + ToOwned + ?Sized>(pub &'a [AnsiGenericString<'a, S>])
124 where
125 <S as ToOwned>::Owned: fmt::Debug,
126 S: PartialEq;
127
128 /// A set of `AnsiString`s collected together, in order to be written with a
129 /// minimum of control characters.
130 pub type AnsiStrings<'a> = AnsiGenericStrings<'a, str>;
131
132 /// A function to construct an `AnsiStrings` instance.
133 #[allow(non_snake_case)]
134 pub fn AnsiStrings<'a>(arg: &'a [AnsiString<'a>]) -> AnsiStrings<'a> {
135 AnsiGenericStrings(arg)
136 }
137
138 /// A set of `AnsiByteString`s collected together, in order to be
139 /// written with a minimum of control characters.
140 pub type AnsiByteStrings<'a> = AnsiGenericStrings<'a, [u8]>;
141
142 /// A function to construct an `AnsiByteStrings` instance.
143 #[allow(non_snake_case)]
144 pub fn AnsiByteStrings<'a>(arg: &'a [AnsiByteString<'a>]) -> AnsiByteStrings<'a> {
145 AnsiGenericStrings(arg)
146 }
147
148 // ---- paint functions ----
149
150 impl Style {
151 /// Paints the given text with this color, returning an ANSI string.
152 #[must_use]
153 pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> AnsiGenericString<'a, S>
154 where
155 I: Into<Cow<'a, S>>,
156 <S as ToOwned>::Owned: fmt::Debug,
157 {
158 AnsiGenericString {
159 string: input.into(),
160 style: self,
161 }
162 }
163 }
164
165 impl Color {
166 /// Paints the given text with this color, returning an ANSI string.
167 /// This is a short-cut so you don’t have to use `Blue.normal()` just
168 /// to get blue text.
169 ///
170 /// ```
171 /// use nu_ansi_term::Color::Blue;
172 /// println!("{}", Blue.paint("da ba dee"));
173 /// ```
174 #[must_use]
175 pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> AnsiGenericString<'a, S>
176 where
177 I: Into<Cow<'a, S>>,
178 <S as ToOwned>::Owned: fmt::Debug,
179 {
180 AnsiGenericString {
181 string: input.into(),
182 style: self.normal(),
183 }
184 }
185 }
186
187 // ---- writers for individual ANSI strings ----
188
189 impl<'a> fmt::Display for AnsiString<'a> {
190 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191 let w: &mut dyn fmt::Write = f;
192 self.write_to_any(w)
193 }
194 }
195
196 impl<'a> AnsiByteString<'a> {
197 /// Write an `AnsiByteString` to an `io::Write`. This writes the escape
198 /// sequences for the associated `Style` around the bytes.
199 pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
200 let w: &mut dyn io::Write = w;
201 self.write_to_any(w)
202 }
203 }
204
205 impl<'a, S: 'a + ToOwned + ?Sized> AnsiGenericString<'a, S>
206 where
207 <S as ToOwned>::Owned: fmt::Debug,
208 &'a S: AsRef<[u8]>,
209 {
210 fn write_to_any<W: AnyWrite<Wstr = S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
211 write!(w, "{}", self.style.prefix())?;
212 w.write_str(self.string.as_ref())?;
213 write!(w, "{}", self.style.suffix())
214 }
215 }
216
217 // ---- writers for combined ANSI strings ----
218
219 impl<'a> fmt::Display for AnsiStrings<'a> {
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 let f: &mut dyn fmt::Write = f;
222 self.write_to_any(f)
223 }
224 }
225
226 impl<'a> AnsiByteStrings<'a> {
227 /// Write `AnsiByteStrings` to an `io::Write`. This writes the minimal
228 /// escape sequences for the associated `Style`s around each set of
229 /// bytes.
230 pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
231 let w: &mut dyn io::Write = w;
232 self.write_to_any(w)
233 }
234 }
235
236 impl<'a, S: 'a + ToOwned + ?Sized + PartialEq> AnsiGenericStrings<'a, S>
237 where
238 <S as ToOwned>::Owned: fmt::Debug,
239 &'a S: AsRef<[u8]>,
240 {
241 fn write_to_any<W: AnyWrite<Wstr = S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
242 use self::Difference::*;
243
244 let first = match self.0.first() {
245 None => return Ok(()),
246 Some(f) => f,
247 };
248
249 write!(w, "{}", first.style.prefix())?;
250 w.write_str(first.string.as_ref())?;
251
252 for window in self.0.windows(2) {
253 match Difference::between(&window[0].style, &window[1].style) {
254 ExtraStyles(style) => write!(w, "{}", style.prefix())?,
255 Reset => write!(w, "{}{}", RESET, window[1].style.prefix())?,
256 Empty => { /* Do nothing! */ }
257 }
258
259 w.write_str(&window[1].string)?;
260 }
261
262 // Write the final reset string after all of the AnsiStrings have been
263 // written, *except* if the last one has no styles, because it would
264 // have already been written by this point.
265 if let Some(last) = self.0.last() {
266 if !last.style.is_plain() {
267 write!(w, "{}", RESET)?;
268 }
269 }
270
271 Ok(())
272 }
273 }
274
275 // ---- tests ----
276
277 #[cfg(test)]
278 mod tests {
279 pub use super::super::AnsiStrings;
280 pub use crate::style::Color::*;
281 pub use crate::style::Style;
282
283 #[test]
284 fn no_control_codes_for_plain() {
285 let one = Style::default().paint("one");
286 let two = Style::default().paint("two");
287 let output = AnsiStrings(&[one, two]).to_string();
288 assert_eq!(output, "onetwo");
289 }
290 }