1use crate::reset::RESET;
2
3/// ANSI Text styling
4///
5/// # Examples
6///
7/// ```rust
8/// let style = anstyle::Style::new().bold();
9/// ```
10#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Style {
12 fg: Option<crate::Color>,
13 bg: Option<crate::Color>,
14 underline: Option<crate::Color>,
15 effects: crate::Effects,
16}
17
18/// # Core
19impl Style {
20 /// No effects enabled
21 ///
22 /// # Examples
23 ///
24 /// ```rust
25 /// let style = anstyle::Style::new();
26 /// ```
27 #[inline]
28 pub const fn new() -> Self {
29 Self {
30 fg: None,
31 bg: None,
32 underline: None,
33 effects: crate::Effects::new(),
34 }
35 }
36
37 /// Set foreground color
38 ///
39 /// # Examples
40 ///
41 /// ```rust
42 /// let style = anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into()));
43 /// ```
44 #[must_use]
45 #[inline]
46 pub const fn fg_color(mut self, fg: Option<crate::Color>) -> Self {
47 self.fg = fg;
48 self
49 }
50
51 /// Set background color
52 ///
53 /// # Examples
54 ///
55 /// ```rust
56 /// let style = anstyle::Style::new().bg_color(Some(anstyle::AnsiColor::Red.into()));
57 /// ```
58 #[must_use]
59 #[inline]
60 pub const fn bg_color(mut self, bg: Option<crate::Color>) -> Self {
61 self.bg = bg;
62 self
63 }
64
65 /// Set underline color
66 ///
67 /// # Examples
68 ///
69 /// ```rust
70 /// let style = anstyle::Style::new().underline_color(Some(anstyle::AnsiColor::Red.into()));
71 /// ```
72 #[must_use]
73 #[inline]
74 pub const fn underline_color(mut self, underline: Option<crate::Color>) -> Self {
75 self.underline = underline;
76 self
77 }
78
79 /// Set text effects
80 ///
81 /// # Examples
82 ///
83 /// ```rust
84 /// let style = anstyle::Style::new().effects(anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE);
85 /// ```
86 #[must_use]
87 #[inline]
88 pub const fn effects(mut self, effects: crate::Effects) -> Self {
89 self.effects = effects;
90 self
91 }
92
93 /// Render the ANSI code
94 #[inline]
95 pub fn render(self) -> impl core::fmt::Display + Copy + Clone {
96 StyleDisplay(self)
97 }
98
99 /// Write the ANSI code
100 #[inline]
101 #[cfg(feature = "std")]
102 pub fn write_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> {
103 self.effects.write_to(write)?;
104
105 if let Some(fg) = self.fg {
106 fg.write_fg_to(write)?;
107 }
108
109 if let Some(bg) = self.bg {
110 bg.write_bg_to(write)?;
111 }
112
113 if let Some(underline) = self.underline {
114 underline.write_underline_to(write)?;
115 }
116
117 Ok(())
118 }
119
120 /// Renders the relevant [`Reset`][crate::Reset] code
121 ///
122 /// Unlike [`Reset::render`][crate::Reset::render], this will elide the code if there is nothing to reset.
123 #[inline]
124 pub fn render_reset(self) -> impl core::fmt::Display + Copy + Clone {
125 if self != Self::new() {
126 RESET
127 } else {
128 ""
129 }
130 }
131
132 /// Write the relevant [`Reset`][crate::Reset] code
133 ///
134 /// Unlike [`Reset::render`][crate::Reset::render], this will elide the code if there is nothing to reset.
135 #[inline]
136 #[cfg(feature = "std")]
137 pub fn write_reset_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> {
138 if self != Self::new() {
139 write.write_all(RESET.as_bytes())
140 } else {
141 Ok(())
142 }
143 }
144}
145
146/// # Convenience
147impl Style {
148 /// Apply `bold` effect
149 ///
150 /// # Examples
151 ///
152 /// ```rust
153 /// let style = anstyle::Style::new().bold();
154 /// ```
155 #[must_use]
156 #[inline]
157 pub const fn bold(mut self) -> Self {
158 self.effects = self.effects.insert(crate::Effects::BOLD);
159 self
160 }
161
162 /// Apply `dimmed` effect
163 ///
164 /// # Examples
165 ///
166 /// ```rust
167 /// let style = anstyle::Style::new().dimmed();
168 /// ```
169 #[must_use]
170 #[inline]
171 pub const fn dimmed(mut self) -> Self {
172 self.effects = self.effects.insert(crate::Effects::DIMMED);
173 self
174 }
175
176 /// Apply `italic` effect
177 ///
178 /// # Examples
179 ///
180 /// ```rust
181 /// let style = anstyle::Style::new().italic();
182 /// ```
183 #[must_use]
184 #[inline]
185 pub const fn italic(mut self) -> Self {
186 self.effects = self.effects.insert(crate::Effects::ITALIC);
187 self
188 }
189
190 /// Apply `underline` effect
191 ///
192 /// # Examples
193 ///
194 /// ```rust
195 /// let style = anstyle::Style::new().underline();
196 /// ```
197 #[must_use]
198 #[inline]
199 pub const fn underline(mut self) -> Self {
200 self.effects = self.effects.insert(crate::Effects::UNDERLINE);
201 self
202 }
203
204 /// Apply `blink` effect
205 ///
206 /// # Examples
207 ///
208 /// ```rust
209 /// let style = anstyle::Style::new().blink();
210 /// ```
211 #[must_use]
212 #[inline]
213 pub const fn blink(mut self) -> Self {
214 self.effects = self.effects.insert(crate::Effects::BLINK);
215 self
216 }
217
218 /// Apply `invert` effect
219 ///
220 /// # Examples
221 ///
222 /// ```rust
223 /// let style = anstyle::Style::new().invert();
224 /// ```
225 #[must_use]
226 #[inline]
227 pub const fn invert(mut self) -> Self {
228 self.effects = self.effects.insert(crate::Effects::INVERT);
229 self
230 }
231
232 /// Apply `hidden` effect
233 ///
234 /// # Examples
235 ///
236 /// ```rust
237 /// let style = anstyle::Style::new().hidden();
238 /// ```
239 #[must_use]
240 #[inline]
241 pub const fn hidden(mut self) -> Self {
242 self.effects = self.effects.insert(crate::Effects::HIDDEN);
243 self
244 }
245
246 /// Apply `strikethrough` effect
247 ///
248 /// # Examples
249 ///
250 /// ```rust
251 /// let style = anstyle::Style::new().strikethrough();
252 /// ```
253 #[must_use]
254 #[inline]
255 pub const fn strikethrough(mut self) -> Self {
256 self.effects = self.effects.insert(crate::Effects::STRIKETHROUGH);
257 self
258 }
259}
260
261/// # Reflection
262impl Style {
263 #[inline]
264 pub const fn get_fg_color(self) -> Option<crate::Color> {
265 self.fg
266 }
267
268 #[inline]
269 pub const fn get_bg_color(self) -> Option<crate::Color> {
270 self.bg
271 }
272
273 #[inline]
274 pub const fn get_underline_color(self) -> Option<crate::Color> {
275 self.underline
276 }
277
278 #[inline]
279 pub const fn get_effects(self) -> crate::Effects {
280 self.effects
281 }
282
283 /// Check if no effects are enabled
284 #[inline]
285 pub const fn is_plain(self) -> bool {
286 self.fg.is_none()
287 && self.bg.is_none()
288 && self.underline.is_none()
289 && self.effects.is_plain()
290 }
291}
292
293/// # Examples
294///
295/// ```rust
296/// let style: anstyle::Style = anstyle::Effects::BOLD.into();
297/// ```
298impl From<crate::Effects> for Style {
299 #[inline]
300 fn from(effects: crate::Effects) -> Self {
301 Self::new().effects(effects)
302 }
303}
304
305/// # Examples
306///
307/// ```rust
308/// let style = anstyle::Style::new() | anstyle::Effects::BOLD.into();
309/// ```
310impl core::ops::BitOr<crate::Effects> for Style {
311 type Output = Self;
312
313 #[inline(always)]
314 fn bitor(mut self, rhs: crate::Effects) -> Self {
315 self.effects |= rhs;
316 self
317 }
318}
319
320/// # Examples
321///
322/// ```rust
323/// let mut style = anstyle::Style::new();
324/// style |= anstyle::Effects::BOLD.into();
325/// ```
326impl core::ops::BitOrAssign<crate::Effects> for Style {
327 #[inline]
328 fn bitor_assign(&mut self, other: crate::Effects) {
329 self.effects |= other;
330 }
331}
332
333/// # Examples
334///
335/// ```rust
336/// let style = anstyle::Style::new().bold().underline() - anstyle::Effects::BOLD.into();
337/// ```
338impl core::ops::Sub<crate::Effects> for Style {
339 type Output = Self;
340
341 #[inline]
342 fn sub(mut self, other: crate::Effects) -> Self {
343 self.effects -= other;
344 self
345 }
346}
347
348/// # Examples
349///
350/// ```rust
351/// let mut style = anstyle::Style::new().bold().underline();
352/// style -= anstyle::Effects::BOLD.into();
353/// ```
354impl core::ops::SubAssign<crate::Effects> for Style {
355 #[inline]
356 fn sub_assign(&mut self, other: crate::Effects) {
357 self.effects -= other;
358 }
359}
360
361/// # Examples
362///
363/// ```rust
364/// let effects = anstyle::Effects::BOLD;
365/// assert_eq!(anstyle::Style::new().effects(effects), effects);
366/// assert_ne!(anstyle::Effects::UNDERLINE | effects, effects);
367/// assert_ne!(anstyle::RgbColor(0, 0, 0).on_default() | effects, effects);
368/// ```
369impl core::cmp::PartialEq<crate::Effects> for Style {
370 #[inline]
371 fn eq(&self, other: &crate::Effects) -> bool {
372 let other: Style = Self::from(*other);
373 *self == other
374 }
375}
376
377#[derive(Copy, Clone, Default, Debug)]
378struct StyleDisplay(Style);
379
380impl core::fmt::Display for StyleDisplay {
381 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
382 self.0.effects.render().fmt(f)?;
383
384 if let Some(fg: Color) = self.0.fg {
385 fg.render_fg().fmt(f)?;
386 }
387
388 if let Some(bg: Color) = self.0.bg {
389 bg.render_bg().fmt(f)?;
390 }
391
392 if let Some(underline: Color) = self.0.underline {
393 underline.render_underline().fmt(f)?;
394 }
395
396 Ok(())
397 }
398}
399