1use 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)]
18pub 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
26impl Style {
27 /// No effects enabled
28 ///
29 /// # Examples
30 ///
31 /// ```rust
32 /// let style = anstyle::Style::new();
33 /// ```
34 #[inline]
35 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]
53 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]
67 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]
81 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]
95 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]
104 pub fn render(self) -> impl core::fmt::Display + Copy + Clone {
105 StyleDisplay(self)
106 }
107
108 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")]
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]
153 pub fn render_reset(self) -> impl core::fmt::Display + Copy + Clone {
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")]
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
176impl Style {
177 /// Apply `bold` effect
178 ///
179 /// # Examples
180 ///
181 /// ```rust
182 /// let style = anstyle::Style::new().bold();
183 /// ```
184 #[must_use]
185 #[inline]
186 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]
200 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]
214 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]
228 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]
242 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]
256 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]
270 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]
284 pub const fn strikethrough(mut self) -> Self {
285 self.effects = self.effects.insert(crate::Effects::STRIKETHROUGH);
286 self
287 }
288}
289
290/// # Reflection
291impl Style {
292 #[inline]
293 pub const fn get_fg_color(self) -> Option<crate::Color> {
294 self.fg
295 }
296
297 #[inline]
298 pub const fn get_bg_color(self) -> Option<crate::Color> {
299 self.bg
300 }
301
302 #[inline]
303 pub const fn get_underline_color(self) -> Option<crate::Color> {
304 self.underline
305 }
306
307 #[inline]
308 pub const fn get_effects(self) -> crate::Effects {
309 self.effects
310 }
311
312 /// Check if no effects are enabled
313 #[inline]
314 pub const fn is_plain(self) -> bool {
315 self.fg.is_none()
316 && self.bg.is_none()
317 && self.underline.is_none()
318 && self.effects.is_plain()
319 }
320}
321
322/// # Examples
323///
324/// ```rust
325/// let style: anstyle::Style = anstyle::Effects::BOLD.into();
326/// ```
327impl From<crate::Effects> for Style {
328 #[inline]
329 fn from(effects: crate::Effects) -> Self {
330 Self::new().effects(effects)
331 }
332}
333
334/// # Examples
335///
336/// ```rust
337/// let style = anstyle::Style::new() | anstyle::Effects::BOLD.into();
338/// ```
339impl core::ops::BitOr<crate::Effects> for Style {
340 type Output = Self;
341
342 #[inline(always)]
343 fn bitor(mut self, rhs: crate::Effects) -> Self {
344 self.effects |= rhs;
345 self
346 }
347}
348
349/// # Examples
350///
351/// ```rust
352/// let mut style = anstyle::Style::new();
353/// style |= anstyle::Effects::BOLD.into();
354/// ```
355impl core::ops::BitOrAssign<crate::Effects> for Style {
356 #[inline]
357 fn bitor_assign(&mut self, other: crate::Effects) {
358 self.effects |= other;
359 }
360}
361
362/// # Examples
363///
364/// ```rust
365/// let style = anstyle::Style::new().bold().underline() - anstyle::Effects::BOLD.into();
366/// ```
367impl core::ops::Sub<crate::Effects> for Style {
368 type Output = Self;
369
370 #[inline]
371 fn sub(mut self, other: crate::Effects) -> Self {
372 self.effects -= other;
373 self
374 }
375}
376
377/// # Examples
378///
379/// ```rust
380/// let mut style = anstyle::Style::new().bold().underline();
381/// style -= anstyle::Effects::BOLD.into();
382/// ```
383impl core::ops::SubAssign<crate::Effects> for Style {
384 #[inline]
385 fn sub_assign(&mut self, other: crate::Effects) {
386 self.effects -= other;
387 }
388}
389
390/// # Examples
391///
392/// ```rust
393/// let effects = anstyle::Effects::BOLD;
394/// assert_eq!(anstyle::Style::new().effects(effects), effects);
395/// assert_ne!(anstyle::Effects::UNDERLINE | effects, effects);
396/// assert_ne!(anstyle::RgbColor(0, 0, 0).on_default() | effects, effects);
397/// ```
398impl core::cmp::PartialEq<crate::Effects> for Style {
399 #[inline]
400 fn eq(&self, other: &crate::Effects) -> bool {
401 let other: Style = Self::from(*other);
402 *self == other
403 }
404}
405
406impl core::fmt::Display for Style {
407 #[inline]
408 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
409 if f.alternate() {
410 self.render_reset().fmt(f)
411 } else {
412 self.fmt_to(f)
413 }
414 }
415}
416
417#[derive(Copy, Clone, Default, Debug)]
418struct StyleDisplay(Style);
419
420impl core::fmt::Display for StyleDisplay {
421 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
422 self.0.fmt_to(f)
423 }
424}
425
426#[test]
427fn print_size_of() {
428 use std::mem::size_of;
429 dbg!(size_of::<Style>());
430 dbg!(size_of::<StyleDisplay>());
431}
432