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