nu_ansi_term/
style.rs

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