1use crate::reset::RESET;
2
3#[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
25impl Style {
27    #[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    #[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    #[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    #[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    #[must_use]
94    #[inline]
95    pub const fn effects(mut self, effects: crate::Effects) -> Self {
96        self.effects = effects;
97        self
98    }
99
100    #[inline]
104    pub fn render(self) -> impl core::fmt::Display + Copy {
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    #[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    #[inline]
153    pub fn render_reset(self) -> impl core::fmt::Display + Copy {
154        if self != Self::new() {
155            RESET
156        } else {
157            ""
158        }
159    }
160
161    #[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
175impl Style {
177    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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
290impl Style {
292    #[inline]
294    pub const fn get_fg_color(self) -> Option<crate::Color> {
295        self.fg
296    }
297
298    #[inline]
300    #[allow(missing_docs)]
301    pub const fn get_bg_color(self) -> Option<crate::Color> {
302        self.bg
303    }
304
305    #[inline]
306    #[allow(missing_docs)]
307    pub const fn get_underline_color(self) -> Option<crate::Color> {
308        self.underline
309    }
310
311    #[inline]
312    #[allow(missing_docs)]
313    pub const fn get_effects(self) -> crate::Effects {
314        self.effects
315    }
316
317    #[inline]
319    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
327impl From<crate::Effects> for Style {
333    #[inline]
334    fn from(effects: crate::Effects) -> Self {
335        Self::new().effects(effects)
336    }
337}
338
339impl core::ops::BitOr<crate::Effects> for Style {
345    type Output = Self;
346
347    #[inline(always)]
348    fn bitor(mut self, rhs: crate::Effects) -> Self {
349        self.effects |= rhs;
350        self
351    }
352}
353
354impl core::ops::BitOrAssign<crate::Effects> for Style {
361    #[inline]
362    fn bitor_assign(&mut self, other: crate::Effects) {
363        self.effects |= other;
364    }
365}
366
367impl core::ops::Sub<crate::Effects> for Style {
373    type Output = Self;
374
375    #[inline]
376    fn sub(mut self, other: crate::Effects) -> Self {
377        self.effects -= other;
378        self
379    }
380}
381
382impl core::ops::SubAssign<crate::Effects> for Style {
389    #[inline]
390    fn sub_assign(&mut self, other: crate::Effects) {
391        self.effects -= other;
392    }
393}
394
395impl PartialEq<crate::Effects> for Style {
404    #[inline]
405    fn eq(&self, other: &crate::Effects) -> bool {
406        let other = Self::from(*other);
407        *self == other
408    }
409}
410
411impl core::fmt::Display for Style {
412    #[inline]
413    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)]
423struct StyleDisplay(Style);
424
425impl core::fmt::Display for StyleDisplay {
426    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")]
433fn print_size_of() {
434    use core::mem::size_of;
435    dbg!(size_of::<Style>());
436    dbg!(size_of::<StyleDisplay>());
437}