1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
use std::fmt::Display;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use super::super::SetAttribute;

// This macro generates the Attribute enum, its iterator
// function, and the static array containing the sgr code
// of each attribute
macro_rules! Attribute {
    (
        $(
            $(#[$inner:ident $($args:tt)*])*
            $name:ident = $sgr:expr,
        )*
    ) => {
        /// Represents an attribute.
        ///
        /// # Platform-specific Notes
        ///
        /// * Only UNIX and Windows 10 terminals do support text attributes.
        /// * Keep in mind that not all terminals support all attributes.
        /// * Crossterm implements almost all attributes listed in the
        ///   [SGR parameters](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters).
        ///
        /// | Attribute | Windows | UNIX | Notes |
        /// | :-- | :--: | :--: | :-- |
        /// | `Reset` | ✓ | ✓ | |
        /// | `Bold` | ✓ | ✓ | |
        /// | `Dim` | ✓ | ✓ | |
        /// | `Italic` | ? | ? | Not widely supported, sometimes treated as inverse. |
        /// | `Underlined` | ✓ | ✓ | |
        /// | `SlowBlink` | ? | ? | Not widely supported, sometimes treated as inverse. |
        /// | `RapidBlink` | ? | ? | Not widely supported. MS-DOS ANSI.SYS; 150+ per minute. |
        /// | `Reverse` | ✓ | ✓ | |
        /// | `Hidden` | ✓ | ✓ | Also known as Conceal. |
        /// | `Fraktur` | ✗ | ✓ | Legible characters, but marked for deletion. |
        /// | `DefaultForegroundColor` | ? | ? | Implementation specific (according to standard). |
        /// | `DefaultBackgroundColor` | ? | ? | Implementation specific (according to standard). |
        /// | `Framed` | ? | ? | Not widely supported. |
        /// | `Encircled` | ? | ? | This should turn on the encircled attribute. |
        /// | `OverLined` | ? | ? | This should draw a line at the top of the text. |
        ///
        /// # Examples
        ///
        /// Basic usage:
        ///
        /// ```no_run
        /// use crossterm::style::Attribute;
        ///
        /// println!(
        ///     "{} Underlined {} No Underline",
        ///     Attribute::Underlined,
        ///     Attribute::NoUnderline
        /// );
        /// ```
        ///
        /// Style existing text:
        ///
        /// ```no_run
        /// use crossterm::style::Stylize;
        ///
        /// println!("{}", "Bold text".bold());
        /// println!("{}", "Underlined text".underlined());
        /// println!("{}", "Negative text".negative());
        /// ```
        #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
        #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
        #[non_exhaustive]
        pub enum Attribute {
            $(
                $(#[$inner $($args)*])*
                $name,
            )*
        }

        pub static SGR: &'static[i16] = &[
            $($sgr,)*
        ];

        impl Attribute {
            /// Iterates over all the variants of the Attribute enum.
            pub fn iterator() -> impl Iterator<Item = Attribute> {
                use self::Attribute::*;
                [ $($name,)* ].iter().copied()
            }
        }
    }
}

Attribute! {
    /// Resets all the attributes.
    Reset = 0,
    /// Increases the text intensity.
    Bold = 1,
    /// Decreases the text intensity.
    Dim = 2,
    /// Emphasises the text.
    Italic = 3,
    /// Underlines the text.
    Underlined = 4,

    // Other types of underlining
    /// Double underlines the text.
    DoubleUnderlined = 2,
    /// Undercurls the text.
    Undercurled = 3,
    /// Underdots the text.
    Underdotted = 4,
    /// Underdashes the text.
    Underdashed = 5,

    /// Makes the text blinking (< 150 per minute).
    SlowBlink = 5,
    /// Makes the text blinking (>= 150 per minute).
    RapidBlink = 6,
    /// Swaps foreground and background colors.
    Reverse = 7,
    /// Hides the text (also known as Conceal).
    Hidden = 8,
    /// Crosses the text.
    CrossedOut = 9,
    /// Sets the [Fraktur](https://en.wikipedia.org/wiki/Fraktur) typeface.
    ///
    /// Mostly used for [mathematical alphanumeric symbols](https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols).
    Fraktur = 20,
    /// Turns off the `Bold` attribute. - Inconsistent - Prefer to use NormalIntensity
    NoBold = 21,
    /// Switches the text back to normal intensity (no bold, italic).
    NormalIntensity = 22,
    /// Turns off the `Italic` attribute.
    NoItalic = 23,
    /// Turns off the `Underlined` attribute.
    NoUnderline = 24,
    /// Turns off the text blinking (`SlowBlink` or `RapidBlink`).
    NoBlink = 25,
    /// Turns off the `Reverse` attribute.
    NoReverse = 27,
    /// Turns off the `Hidden` attribute.
    NoHidden = 28,
    /// Turns off the `CrossedOut` attribute.
    NotCrossedOut = 29,
    /// Makes the text framed.
    Framed = 51,
    /// Makes the text encircled.
    Encircled = 52,
    /// Draws a line at the top of the text.
    OverLined = 53,
    /// Turns off the `Frame` and `Encircled` attributes.
    NotFramedOrEncircled = 54,
    /// Turns off the `OverLined` attribute.
    NotOverLined = 55,
}

impl Display for Attribute {
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", SetAttribute(*self))?;
        Ok(())
    }
}

impl Attribute {
    /// Returns a u32 with one bit set, which is the
    /// signature of this attribute in the Attributes
    /// bitset.
    ///
    /// The +1 enables storing Reset (whose index is 0)
    ///  in the bitset Attributes.
    #[inline(always)]
    pub const fn bytes(self) -> u32 {
        1 << ((self as u32) + 1)
    }
    /// Returns the SGR attribute value.
    ///
    /// See <https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters>
    pub fn sgr(self) -> String {
        if (self as usize) > 4 && (self as usize) < 9 {
            return "4:".to_string() + SGR[self as usize].to_string().as_str();
        }
        SGR[self as usize].to_string()
    }
}