1 | /// A style is a collection of properties that can format a string |
2 | /// using ANSI escape codes. |
3 | /// |
4 | /// # Examples |
5 | /// |
6 | /// ``` |
7 | /// use ansi_term::{Style, Colour}; |
8 | /// |
9 | /// let style = Style::new().bold().on(Colour::Black); |
10 | /// println!("{}" , style.paint("Bold on black" )); |
11 | /// ``` |
12 | #[derive (PartialEq, Clone, Copy)] |
13 | #[cfg_attr (feature = "derive_serde_style" , derive(serde::Deserialize, serde::Serialize))] |
14 | pub struct Style { |
15 | |
16 | /// The style's foreground colour, if it has one. |
17 | pub foreground: Option<Colour>, |
18 | |
19 | /// The style's background colour, if it has one. |
20 | pub background: Option<Colour>, |
21 | |
22 | /// Whether this style is bold. |
23 | pub is_bold: bool, |
24 | |
25 | /// Whether this style is dimmed. |
26 | pub is_dimmed: bool, |
27 | |
28 | /// Whether this style is italic. |
29 | pub is_italic: bool, |
30 | |
31 | /// Whether this style is underlined. |
32 | pub is_underline: bool, |
33 | |
34 | /// Whether this style is blinking. |
35 | pub is_blink: bool, |
36 | |
37 | /// Whether this style has reverse colours. |
38 | pub is_reverse: bool, |
39 | |
40 | /// Whether this style is hidden. |
41 | pub is_hidden: bool, |
42 | |
43 | /// Whether this style is struckthrough. |
44 | pub is_strikethrough: bool |
45 | } |
46 | |
47 | impl Style { |
48 | |
49 | /// Creates a new Style with no properties set. |
50 | /// |
51 | /// # Examples |
52 | /// |
53 | /// ``` |
54 | /// use ansi_term::Style; |
55 | /// |
56 | /// let style = Style::new(); |
57 | /// println!("{}" , style.paint("hi" )); |
58 | /// ``` |
59 | pub fn new() -> Style { |
60 | Style::default() |
61 | } |
62 | |
63 | /// Returns a `Style` with the bold property set. |
64 | /// |
65 | /// # Examples |
66 | /// |
67 | /// ``` |
68 | /// use ansi_term::Style; |
69 | /// |
70 | /// let style = Style::new().bold(); |
71 | /// println!("{}" , style.paint("hey" )); |
72 | /// ``` |
73 | pub fn bold(&self) -> Style { |
74 | Style { is_bold: true, .. *self } |
75 | } |
76 | |
77 | /// Returns a `Style` with the dimmed property set. |
78 | /// |
79 | /// # Examples |
80 | /// |
81 | /// ``` |
82 | /// use ansi_term::Style; |
83 | /// |
84 | /// let style = Style::new().dimmed(); |
85 | /// println!("{}" , style.paint("sup" )); |
86 | /// ``` |
87 | pub fn dimmed(&self) -> Style { |
88 | Style { is_dimmed: true, .. *self } |
89 | } |
90 | |
91 | /// Returns a `Style` with the italic property set. |
92 | /// |
93 | /// # Examples |
94 | /// |
95 | /// ``` |
96 | /// use ansi_term::Style; |
97 | /// |
98 | /// let style = Style::new().italic(); |
99 | /// println!("{}" , style.paint("greetings" )); |
100 | /// ``` |
101 | pub fn italic(&self) -> Style { |
102 | Style { is_italic: true, .. *self } |
103 | } |
104 | |
105 | /// Returns a `Style` with the underline property set. |
106 | /// |
107 | /// # Examples |
108 | /// |
109 | /// ``` |
110 | /// use ansi_term::Style; |
111 | /// |
112 | /// let style = Style::new().underline(); |
113 | /// println!("{}" , style.paint("salutations" )); |
114 | /// ``` |
115 | pub fn underline(&self) -> Style { |
116 | Style { is_underline: true, .. *self } |
117 | } |
118 | |
119 | /// Returns a `Style` with the blink property set. |
120 | /// # Examples |
121 | /// |
122 | /// ``` |
123 | /// use ansi_term::Style; |
124 | /// |
125 | /// let style = Style::new().blink(); |
126 | /// println!("{}" , style.paint("wazzup" )); |
127 | /// ``` |
128 | pub fn blink(&self) -> Style { |
129 | Style { is_blink: true, .. *self } |
130 | } |
131 | |
132 | /// Returns a `Style` with the reverse property set. |
133 | /// |
134 | /// # Examples |
135 | /// |
136 | /// ``` |
137 | /// use ansi_term::Style; |
138 | /// |
139 | /// let style = Style::new().reverse(); |
140 | /// println!("{}" , style.paint("aloha" )); |
141 | /// ``` |
142 | pub fn reverse(&self) -> Style { |
143 | Style { is_reverse: true, .. *self } |
144 | } |
145 | |
146 | /// Returns a `Style` with the hidden property set. |
147 | /// |
148 | /// # Examples |
149 | /// |
150 | /// ``` |
151 | /// use ansi_term::Style; |
152 | /// |
153 | /// let style = Style::new().hidden(); |
154 | /// println!("{}" , style.paint("ahoy" )); |
155 | /// ``` |
156 | pub fn hidden(&self) -> Style { |
157 | Style { is_hidden: true, .. *self } |
158 | } |
159 | |
160 | /// Returns a `Style` with the strikethrough property set. |
161 | /// |
162 | /// # Examples |
163 | /// |
164 | /// ``` |
165 | /// use ansi_term::Style; |
166 | /// |
167 | /// let style = Style::new().strikethrough(); |
168 | /// println!("{}" , style.paint("yo" )); |
169 | /// ``` |
170 | pub fn strikethrough(&self) -> Style { |
171 | Style { is_strikethrough: true, .. *self } |
172 | } |
173 | |
174 | /// Returns a `Style` with the foreground colour property set. |
175 | /// |
176 | /// # Examples |
177 | /// |
178 | /// ``` |
179 | /// use ansi_term::{Style, Colour}; |
180 | /// |
181 | /// let style = Style::new().fg(Colour::Yellow); |
182 | /// println!("{}" , style.paint("hi" )); |
183 | /// ``` |
184 | pub fn fg(&self, foreground: Colour) -> Style { |
185 | Style { foreground: Some(foreground), .. *self } |
186 | } |
187 | |
188 | /// Returns a `Style` with the background colour property set. |
189 | /// |
190 | /// # Examples |
191 | /// |
192 | /// ``` |
193 | /// use ansi_term::{Style, Colour}; |
194 | /// |
195 | /// let style = Style::new().on(Colour::Blue); |
196 | /// println!("{}" , style.paint("eyyyy" )); |
197 | /// ``` |
198 | pub fn on(&self, background: Colour) -> Style { |
199 | Style { background: Some(background), .. *self } |
200 | } |
201 | |
202 | /// Return true if this `Style` has no actual styles, and can be written |
203 | /// without any control characters. |
204 | /// |
205 | /// # Examples |
206 | /// |
207 | /// ``` |
208 | /// use ansi_term::Style; |
209 | /// |
210 | /// assert_eq!(true, Style::default().is_plain()); |
211 | /// assert_eq!(false, Style::default().bold().is_plain()); |
212 | /// ``` |
213 | pub fn is_plain(self) -> bool { |
214 | self == Style::default() |
215 | } |
216 | } |
217 | |
218 | impl Default for Style { |
219 | |
220 | /// Returns a style with *no* properties set. Formatting text using this |
221 | /// style returns the exact same text. |
222 | /// |
223 | /// ``` |
224 | /// use ansi_term::Style; |
225 | /// assert_eq!(None, Style::default().foreground); |
226 | /// assert_eq!(None, Style::default().background); |
227 | /// assert_eq!(false, Style::default().is_bold); |
228 | /// assert_eq!("txt" , Style::default().paint("txt" ).to_string()); |
229 | /// ``` |
230 | fn default() -> Style { |
231 | Style { |
232 | foreground: None, |
233 | background: None, |
234 | is_bold: false, |
235 | is_dimmed: false, |
236 | is_italic: false, |
237 | is_underline: false, |
238 | is_blink: false, |
239 | is_reverse: false, |
240 | is_hidden: false, |
241 | is_strikethrough: false, |
242 | } |
243 | } |
244 | } |
245 | |
246 | |
247 | // ---- colours ---- |
248 | |
249 | /// A colour is one specific type of ANSI escape code, and can refer |
250 | /// to either the foreground or background colour. |
251 | /// |
252 | /// These use the standard numeric sequences. |
253 | /// See <http://invisible-island.net/xterm/ctlseqs/ctlseqs.html> |
254 | #[derive (PartialEq, Clone, Copy, Debug)] |
255 | #[cfg_attr (feature = "derive_serde_style" , derive(serde::Deserialize, serde::Serialize))] |
256 | pub enum Colour { |
257 | |
258 | /// Colour #0 (foreground code `30`, background code `40`). |
259 | /// |
260 | /// This is not necessarily the background colour, and using it as one may |
261 | /// render the text hard to read on terminals with dark backgrounds. |
262 | Black, |
263 | |
264 | /// Colour #1 (foreground code `31`, background code `41`). |
265 | Red, |
266 | |
267 | /// Colour #2 (foreground code `32`, background code `42`). |
268 | Green, |
269 | |
270 | /// Colour #3 (foreground code `33`, background code `43`). |
271 | Yellow, |
272 | |
273 | /// Colour #4 (foreground code `34`, background code `44`). |
274 | Blue, |
275 | |
276 | /// Colour #5 (foreground code `35`, background code `45`). |
277 | Purple, |
278 | |
279 | /// Colour #6 (foreground code `36`, background code `46`). |
280 | Cyan, |
281 | |
282 | /// Colour #7 (foreground code `37`, background code `47`). |
283 | /// |
284 | /// As above, this is not necessarily the foreground colour, and may be |
285 | /// hard to read on terminals with light backgrounds. |
286 | White, |
287 | |
288 | /// A colour number from 0 to 255, for use in 256-colour terminal |
289 | /// environments. |
290 | /// |
291 | /// - Colours 0 to 7 are the `Black` to `White` variants respectively. |
292 | /// These colours can usually be changed in the terminal emulator. |
293 | /// - Colours 8 to 15 are brighter versions of the eight colours above. |
294 | /// These can also usually be changed in the terminal emulator, or it |
295 | /// could be configured to use the original colours and show the text in |
296 | /// bold instead. It varies depending on the program. |
297 | /// - Colours 16 to 231 contain several palettes of bright colours, |
298 | /// arranged in six squares measuring six by six each. |
299 | /// - Colours 232 to 255 are shades of grey from black to white. |
300 | /// |
301 | /// It might make more sense to look at a [colour chart][cc]. |
302 | /// |
303 | /// [cc]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg |
304 | Fixed(u8), |
305 | |
306 | /// A 24-bit RGB color, as specified by ISO-8613-3. |
307 | RGB(u8, u8, u8), |
308 | } |
309 | |
310 | |
311 | impl Colour { |
312 | |
313 | /// Returns a `Style` with the foreground colour set to this colour. |
314 | /// |
315 | /// # Examples |
316 | /// |
317 | /// ``` |
318 | /// use ansi_term::Colour; |
319 | /// |
320 | /// let style = Colour::Red.normal(); |
321 | /// println!("{}" , style.paint("hi" )); |
322 | /// ``` |
323 | pub fn normal(self) -> Style { |
324 | Style { foreground: Some(self), .. Style::default() } |
325 | } |
326 | |
327 | /// Returns a `Style` with the foreground colour set to this colour and the |
328 | /// bold property set. |
329 | /// |
330 | /// # Examples |
331 | /// |
332 | /// ``` |
333 | /// use ansi_term::Colour; |
334 | /// |
335 | /// let style = Colour::Green.bold(); |
336 | /// println!("{}" , style.paint("hey" )); |
337 | /// ``` |
338 | pub fn bold(self) -> Style { |
339 | Style { foreground: Some(self), is_bold: true, .. Style::default() } |
340 | } |
341 | |
342 | /// Returns a `Style` with the foreground colour set to this colour and the |
343 | /// dimmed property set. |
344 | /// |
345 | /// # Examples |
346 | /// |
347 | /// ``` |
348 | /// use ansi_term::Colour; |
349 | /// |
350 | /// let style = Colour::Yellow.dimmed(); |
351 | /// println!("{}" , style.paint("sup" )); |
352 | /// ``` |
353 | pub fn dimmed(self) -> Style { |
354 | Style { foreground: Some(self), is_dimmed: true, .. Style::default() } |
355 | } |
356 | |
357 | /// Returns a `Style` with the foreground colour set to this colour and the |
358 | /// italic property set. |
359 | /// |
360 | /// # Examples |
361 | /// |
362 | /// ``` |
363 | /// use ansi_term::Colour; |
364 | /// |
365 | /// let style = Colour::Blue.italic(); |
366 | /// println!("{}" , style.paint("greetings" )); |
367 | /// ``` |
368 | pub fn italic(self) -> Style { |
369 | Style { foreground: Some(self), is_italic: true, .. Style::default() } |
370 | } |
371 | |
372 | /// Returns a `Style` with the foreground colour set to this colour and the |
373 | /// underline property set. |
374 | /// |
375 | /// # Examples |
376 | /// |
377 | /// ``` |
378 | /// use ansi_term::Colour; |
379 | /// |
380 | /// let style = Colour::Purple.underline(); |
381 | /// println!("{}" , style.paint("salutations" )); |
382 | /// ``` |
383 | pub fn underline(self) -> Style { |
384 | Style { foreground: Some(self), is_underline: true, .. Style::default() } |
385 | } |
386 | |
387 | /// Returns a `Style` with the foreground colour set to this colour and the |
388 | /// blink property set. |
389 | /// |
390 | /// # Examples |
391 | /// |
392 | /// ``` |
393 | /// use ansi_term::Colour; |
394 | /// |
395 | /// let style = Colour::Cyan.blink(); |
396 | /// println!("{}" , style.paint("wazzup" )); |
397 | /// ``` |
398 | pub fn blink(self) -> Style { |
399 | Style { foreground: Some(self), is_blink: true, .. Style::default() } |
400 | } |
401 | |
402 | /// Returns a `Style` with the foreground colour set to this colour and the |
403 | /// reverse property set. |
404 | /// |
405 | /// # Examples |
406 | /// |
407 | /// ``` |
408 | /// use ansi_term::Colour; |
409 | /// |
410 | /// let style = Colour::Black.reverse(); |
411 | /// println!("{}" , style.paint("aloha" )); |
412 | /// ``` |
413 | pub fn reverse(self) -> Style { |
414 | Style { foreground: Some(self), is_reverse: true, .. Style::default() } |
415 | } |
416 | |
417 | /// Returns a `Style` with the foreground colour set to this colour and the |
418 | /// hidden property set. |
419 | /// |
420 | /// # Examples |
421 | /// |
422 | /// ``` |
423 | /// use ansi_term::Colour; |
424 | /// |
425 | /// let style = Colour::White.hidden(); |
426 | /// println!("{}" , style.paint("ahoy" )); |
427 | /// ``` |
428 | pub fn hidden(self) -> Style { |
429 | Style { foreground: Some(self), is_hidden: true, .. Style::default() } |
430 | } |
431 | |
432 | /// Returns a `Style` with the foreground colour set to this colour and the |
433 | /// strikethrough property set. |
434 | /// |
435 | /// # Examples |
436 | /// |
437 | /// ``` |
438 | /// use ansi_term::Colour; |
439 | /// |
440 | /// let style = Colour::Fixed(244).strikethrough(); |
441 | /// println!("{}" , style.paint("yo" )); |
442 | /// ``` |
443 | pub fn strikethrough(self) -> Style { |
444 | Style { foreground: Some(self), is_strikethrough: true, .. Style::default() } |
445 | } |
446 | |
447 | /// Returns a `Style` with the foreground colour set to this colour and the |
448 | /// background colour property set to the given colour. |
449 | /// |
450 | /// # Examples |
451 | /// |
452 | /// ``` |
453 | /// use ansi_term::Colour; |
454 | /// |
455 | /// let style = Colour::RGB(31, 31, 31).on(Colour::White); |
456 | /// println!("{}" , style.paint("eyyyy" )); |
457 | /// ``` |
458 | pub fn on(self, background: Colour) -> Style { |
459 | Style { foreground: Some(self), background: Some(background), .. Style::default() } |
460 | } |
461 | } |
462 | |
463 | impl From<Colour> for Style { |
464 | |
465 | /// You can turn a `Colour` into a `Style` with the foreground colour set |
466 | /// with the `From` trait. |
467 | /// |
468 | /// ``` |
469 | /// use ansi_term::{Style, Colour}; |
470 | /// let green_foreground = Style::default().fg(Colour::Green); |
471 | /// assert_eq!(green_foreground, Colour::Green.normal()); |
472 | /// assert_eq!(green_foreground, Colour::Green.into()); |
473 | /// assert_eq!(green_foreground, Style::from(Colour::Green)); |
474 | /// ``` |
475 | fn from(colour: Colour) -> Style { |
476 | colour.normal() |
477 | } |
478 | } |
479 | |
480 | #[cfg (test)] |
481 | #[cfg (feature = "derive_serde_style" )] |
482 | mod serde_json_tests { |
483 | use super::{Style, Colour}; |
484 | |
485 | #[test ] |
486 | fn colour_serialization() { |
487 | |
488 | let colours = &[ |
489 | Colour::Red, |
490 | Colour::Blue, |
491 | Colour::RGB(123, 123, 123), |
492 | Colour::Fixed(255), |
493 | ]; |
494 | |
495 | assert_eq!(serde_json::to_string(&colours).unwrap(), String::from("[ \"Red \", \"Blue \",{ \"RGB \":[123,123,123]},{ \"Fixed \":255}]" )); |
496 | } |
497 | |
498 | #[test ] |
499 | fn colour_deserialization() { |
500 | let colours = &[ |
501 | Colour::Red, |
502 | Colour::Blue, |
503 | Colour::RGB(123, 123, 123), |
504 | Colour::Fixed(255), |
505 | ]; |
506 | |
507 | for colour in colours.into_iter() { |
508 | let serialized = serde_json::to_string(&colour).unwrap(); |
509 | let deserialized: Colour = serde_json::from_str(&serialized).unwrap(); |
510 | |
511 | assert_eq!(colour, &deserialized); |
512 | } |
513 | } |
514 | |
515 | #[test ] |
516 | fn style_serialization() { |
517 | let style = Style::default(); |
518 | |
519 | assert_eq!(serde_json::to_string(&style).unwrap(), "{ \"foreground \":null, \"background \":null, \"is_bold \":false, \"is_dimmed \":false, \"is_italic \":false, \"is_underline \":false, \"is_blink \":false, \"is_reverse \":false, \"is_hidden \":false, \"is_strikethrough \":false}" .to_string()); |
520 | } |
521 | } |
522 | |