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 std::mem::size_of;
435 dbg!(size_of::<Style>());
436 dbg!(size_of::<StyleDisplay>());
437}