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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
use crate::Style;

/// Enum representing text attributes, largely for text formatting.
///
/// Text attributes are typically applied to a [`Style`], [`Color`], or
/// [`Painted`] struct via the corresponding chainable builder methods such as
/// [`bold()`] or [`italic()`]. The returned value will apply the attribute(s)
/// when rendered or printed.
///
/// Attributes are idempotent, so applying an attribute more than once has no
/// more affect than applying it once.
///
/// # Terminal Support
///
/// Whether an applied attribute actually has an effect on how text is rendered
/// in a terminal depends on the terminal's support for the attribute as well as
/// the terminal's configuration. Common attributes, such as `bold`, `dim`,
/// `italic`, `underline`, and `strike` typically have good support and are
/// largely reliable. Less commonly supported attributes like `conceal` and
/// `invert` will _usually_ be supported by "modern" terminals. Rarely supprted
/// attributes, like  `blink` and `rapid blink` will usually have no effect when
/// applied.
///
/// # Example
///
/// ```rust
/// use yansi::{Style, Color::Red};
///
/// /// A style with red foreground and every "common" attribute applied.
/// static MAD: Style = Red.bold().dim().italic().underline().strike();
/// ```
///
/// [`Style`]: crate::Style
/// [`Painted`]: crate::Painted
/// [`Color`]: crate::Painted
/// [`bold()`]: crate::Style::bold()
/// [`italic()`]: crate::Style::italic()
#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord, Hash)]
pub enum Attribute {
    /// Makes text <b>bold</b>.
    ///
    /// Typically used via the [`bold()`](crate::Style::bold()) builder method.
    Bold,
    /// Makes text <span style="opacity: 50%">dim</span>.
    ///
    /// Typically used via the [`dim()`](crate::Style::dim()) builder method.
    Dim,
    /// Display text in <i>italics</i>.
    ///
    /// Typically used via the [`italic()`](crate::Style::italic()) builder
    /// method.
    Italic,
    /// <u>Underline</u> text.
    ///
    /// Typically used via the [`underline()`](crate::Style::underline())
    /// builder method.
    Underline,
    /// <style>@keyframes blinker { 50% { opacity: 0; } }</style>
    /// <span style="animation: blinker 1s linear infinite;">Blink.</span>
    ///
    /// Typically used via the [`blink()`](crate::Style::blink()) builder
    /// method.
    Blink,
    /// <style>@keyframes blinker { 50% { opacity: 0; } }</style>
    /// <span style="animation: blinker 0.5s linear infinite;">Blink rapidly.</span>
    ///
    /// Typically used via the [`rapid_blink()`](crate::Style::rapid_blink())
    /// builder method.
    RapidBlink,
    /// <span style="background: black; color: white;">Invert</span>
    /// (flip) the foreground and background colors.
    ///
    /// Typically used via the [`invert()`](crate::Style::invert()) builder
    /// method.
    Invert,
    /// <span style="color: #333; background: #000;">Conceal</span> text.
    ///
    /// Typically used via the [`conceal()`](crate::Style::conceal()) builder
    /// method.
    Conceal,
    /// Display text with a <s>strike</s> through it.
    ///
    /// Typically used via the [`strike()`](crate::Style::strike()) builder
    /// method.
    Strike,
}

/// Enum representing a `yansi` quirk.
///
/// See the [crate level docs](crate#quirks) for details.
#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord, Hash)]
pub enum Quirk {
    /// Mask: omit when painting is disabled.
    ///
    /// Typically applied via the [`mask()`](crate::Painted::mask()) builder
    /// method.
    ///
    /// See the [crate level docs](crate#masking) for details.
    Mask,
    /// Wrap the value: replace resets with the wrapped styling.
    ///
    /// Typically applied via the [`wrap()`](crate::Painted::wrap()) builder
    /// method.
    ///
    /// See the [crate level docs](crate#wrapping) for details.
    Wrap,
    /// Linger: do not clear the style after it is applied.
    ///
    /// Typically applied via the [`linger()`](crate::Painted::linger()) builder
    /// method.
    ///
    /// See the [crate level docs](crate#lingering) for details.
    Linger,
    /// Always clear styling afterwards, even if no actual styling was applied.
    ///
    /// Overrides the [`Linger`](Quirk::Linger) quirk if present.
    ///
    /// Typically applied via the [`clear()`](crate::Painted::clear()) builder
    /// method.
    Clear,
    /// Brighten the foreground color if it is not already bright.
    ///
    /// Typically applied via the [`bright()`](crate::Painted::bright()) builder
    /// method.
    ///
    /// See the [crate level docs](crate#brightening) for details.
    Bright,
    /// Brighten the background color if it is not already bright.
    ///
    /// Typically applied via the [`on_bright()`](crate::Painted::on_bright())
    /// builder
    /// method.
    ///
    /// See the [crate level docs](crate#brightening) for details.
    OnBright,
}

set_enum! {
    Attribute { Bold, Dim, Italic, Underline, Blink, RapidBlink, Invert, Conceal, Strike }
}

set_enum! {
    Quirk { Mask, Wrap, Linger, Clear, Bright, OnBright }
}

impl Attribute {
    pub(crate) fn fmt(&self, f: &mut dyn core::fmt::Write) -> core::fmt::Result {
        write!(f, "{}", match self {
            Attribute::Bold => 1,
            Attribute::Dim => 2,
            Attribute::Italic => 3,
            Attribute::Underline => 4,
            Attribute::Blink => 5,
            Attribute::RapidBlink => 6,
            Attribute::Invert => 7,
            Attribute::Conceal => 8,
            Attribute::Strike => 9,
        })
    }

    /// Returns a `Style` with the attribute `self` enabled.
    ///
    /// # Example
    ///
    /// ```rust
    /// use yansi::{Style, Attribute::Bold};
    ///
    /// static EMBOLDEN: Style = Bold.style();
    /// ```
    pub const fn style(self) -> Style {
        Style::new().attr(self)
    }
}

impl Quirk {
    /// Returns a `Style` with the quirk `self` enabled.
    ///
    /// # Example
    ///
    /// ```rust
    /// use yansi::{Style, Quirk::Mask};
    ///
    /// static MASKED: Style = Mask.style();
    /// ```
    pub const fn style(self) -> Style {
        Style::new().quirk(self)
    }
}

impl From<Attribute> for crate::Style {
    fn from(attr: Attribute) -> Self {
        attr.style()
    }
}

impl From<Quirk> for crate::Style {
    fn from(quirk: Quirk) -> Self {
        quirk.style()
    }
}