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