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 + Copy + Clone104 pub fn render(self) -> impl core::fmt::Display + Copy + Clone {
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 + Copy + Clone153 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")]
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 #[inline]
get_fg_color(self) -> Option<crate::Color>293 pub const fn get_fg_color(self) -> Option<crate::Color> {
294 self.fg
295 }
296
297 #[inline]
get_bg_color(self) -> Option<crate::Color>298 pub const fn get_bg_color(self) -> Option<crate::Color> {
299 self.bg
300 }
301
302 #[inline]
get_underline_color(self) -> Option<crate::Color>303 pub const fn get_underline_color(self) -> Option<crate::Color> {
304 self.underline
305 }
306
307 #[inline]
get_effects(self) -> crate::Effects308 pub const fn get_effects(self) -> crate::Effects {
309 self.effects
310 }
311
312 /// Check if no effects are enabled
313 #[inline]
is_plain(self) -> bool314 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 /// ```
327 impl From<crate::Effects> for Style {
328 #[inline]
from(effects: crate::Effects) -> Self329 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 /// ```
339 impl core::ops::BitOr<crate::Effects> for Style {
340 type Output = Self;
341
342 #[inline(always)]
bitor(mut self, rhs: crate::Effects) -> Self343 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 /// ```
355 impl core::ops::BitOrAssign<crate::Effects> for Style {
356 #[inline]
bitor_assign(&mut self, other: crate::Effects)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 /// ```
367 impl core::ops::Sub<crate::Effects> for Style {
368 type Output = Self;
369
370 #[inline]
sub(mut self, other: crate::Effects) -> Self371 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 /// ```
383 impl core::ops::SubAssign<crate::Effects> for Style {
384 #[inline]
sub_assign(&mut self, other: crate::Effects)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 /// ```
398 impl core::cmp::PartialEq<crate::Effects> for Style {
399 #[inline]
eq(&self, other: &crate::Effects) -> bool400 fn eq(&self, other: &crate::Effects) -> bool {
401 let other = Self::from(*other);
402 *self == other
403 }
404 }
405
406 impl core::fmt::Display for Style {
407 #[inline]
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result408 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)]
418 struct StyleDisplay(Style);
419
420 impl core::fmt::Display for StyleDisplay {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result421 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
422 self.0.fmt_to(f)
423 }
424 }
425
426 #[test]
print_size_of()427 fn print_size_of() {
428 use std::mem::size_of;
429 dbg!(size_of::<Style>());
430 dbg!(size_of::<StyleDisplay>());
431 }
432