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