ansiterm/
debug.rs

1use std::fmt;
2
3use crate::style::Style;
4
5/// Styles have a special `Debug` implementation that only shows the fields that
6/// are set. Fields that haven’t been touched aren’t included in the output.
7///
8/// This behaviour gets bypassed when using the alternate formatting mode
9/// `format!("{:#?}")`.
10///
11/// ```
12/// use ansiterm::Colour::{Red, Blue};
13///
14/// assert_eq!(
15///     "Style { fg(Red), on(Blue), bold, italic }",
16///     format!("{:?}", Red.on(Blue).bold().italic())
17/// );
18/// ```
19impl fmt::Debug for Style {
20    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
21        if fmt.alternate() {
22            fmt.debug_struct("Style")
23               .field("foreground",    &self.foreground)
24               .field("background",    &self.background)
25               .field("blink",         &self.is_blink)
26               .field("bold",          &self.is_bold)
27               .field("dimmed",        &self.is_dimmed)
28               .field("hidden",        &self.is_hidden)
29               .field("italic",        &self.is_italic)
30               .field("reverse",       &self.is_reverse)
31               .field("strikethrough", &self.is_strikethrough)
32               .field("underline",     &self.is_underline)
33               .finish()
34        }
35        else if self.is_plain() {
36            fmt.write_str("Style {}")
37        }
38        else {
39            fmt.write_str("Style { ")?;
40
41            let mut written_anything = false;
42
43            if let Some(fg) = self.foreground {
44                if written_anything { fmt.write_str(", ")? }
45                written_anything = true;
46                write!(fmt, "fg({:?})", fg)?
47            }
48
49            if let Some(bg) = self.background {
50                if written_anything { fmt.write_str(", ")? }
51                written_anything = true;
52                write!(fmt, "on({:?})", bg)?
53            }
54
55            {
56                let mut write_flag = |name| {
57                    if written_anything { fmt.write_str(", ")? }
58                    written_anything = true;
59                    fmt.write_str(name)
60                };
61
62                if self.is_blink          { write_flag("blink")? }
63                if self.is_bold           { write_flag("bold")? }
64                if self.is_dimmed         { write_flag("dimmed")? }
65                if self.is_hidden         { write_flag("hidden")? }
66                if self.is_italic         { write_flag("italic")? }
67                if self.is_reverse        { write_flag("reverse")? }
68                if self.is_strikethrough  { write_flag("strikethrough")? }
69                if self.is_underline      { write_flag("underline")? }
70            }
71
72            write!(fmt, " }}")
73        }
74    }
75}
76
77
78#[cfg(test)]
79mod test {
80    use crate::style::Colour::*;
81    use crate::style::Style;
82
83    fn style() -> Style {
84        Style::new()
85    }
86
87    macro_rules! test {
88        ($name: ident: $obj: expr => $result: expr) => {
89            #[test]
90            fn $name() {
91                assert_eq!($result, format!("{:?}", $obj));
92            }
93        };
94    }
95
96    test!(empty:   style()                  => "Style {}");
97    test!(bold:    style().bold()           => "Style { bold }");
98    test!(italic:  style().italic()         => "Style { italic }");
99    test!(both:    style().bold().italic()  => "Style { bold, italic }");
100
101    test!(red:     Red.normal()                     => "Style { fg(Red) }");
102    test!(redblue: Red.normal().on(RGB(3, 2, 4))    => "Style { fg(Red), on(RGB(3, 2, 4)) }");
103
104    test!(everything:
105            Red.on(Blue).blink().bold().dimmed().hidden().italic().reverse().strikethrough().underline() =>
106            "Style { fg(Red), on(Blue), blink, bold, dimmed, hidden, italic, reverse, strikethrough, underline }");
107
108    #[test]
109    fn long_and_detailed() {
110        let expected_debug = "Style { fg(Blue), bold }";
111        let expected_pretty_repat = r##"(?x)
112        Style\s+\{\s+
113            foreground:\s+Some\(\s+
114                Blue,?\s+
115            \),\s+
116            background:\s+None,\s+
117            blink:\s+false,\s+
118            bold:\s+true,\s+
119            dimmed:\s+false,\s+
120            hidden:\s+false,\s+
121            italic:\s+false,\s+
122            reverse:\s+false,\s+
123            strikethrough:\s+
124            false,\s+
125            underline:\s+false,?\s+
126            \}"##;
127        let re = regex::Regex::new(expected_pretty_repat).unwrap();
128
129        let style = Blue.bold();
130        let style_fmt_debug = format!("{:?}", style);
131        let style_fmt_pretty = format!("{:#?}", style);
132        println!("style_fmt_debug:\n{}", style_fmt_debug);
133        println!("style_fmt_pretty:\n{}", style_fmt_pretty);
134
135        assert_eq!(expected_debug, style_fmt_debug);
136        assert!(re.is_match(&style_fmt_pretty));
137    }
138}