1use crate::{AnsiColors, Color, DynColor, DynColors};
2use core::fmt;
3
4#[cfg(doc)]
5use crate::OwoColorize;
6
7#[allow(missing_docs)]
9#[derive(Debug, Copy, Clone)]
10pub enum Effect {
11 Bold,
12 Dimmed,
13 Italic,
14 Underline,
15 Blink,
16 BlinkFast,
17 Reversed,
18 Hidden,
19 Strikethrough,
20}
21
22macro_rules! color_methods {
23 ($(
24 #[$fg_meta:meta] #[$bg_meta:meta] $color:ident $fg_method:ident $bg_method:ident
25 ),* $(,)?) => {
26 $(
27 #[$fg_meta]
28 #[must_use]
29 pub const fn $fg_method(mut self) -> Self {
30 self.fg = Some(DynColors::Ansi(AnsiColors::$color));
31 self
32 }
33
34 #[$fg_meta]
35 #[must_use]
36 pub const fn $bg_method(mut self) -> Self {
37 self.bg = Some(DynColors::Ansi(AnsiColors::$color));
38 self
39 }
40 )*
41 };
42}
43
44macro_rules! style_methods {
45 ($(#[$meta:meta] ($name:ident, $set_name:ident)),* $(,)?) => {
46 $(
47 #[$meta]
48 #[must_use]
49 pub const fn $name(mut self) -> Self {
50 self.style_flags.$set_name(true);
51 self
52 }
53 )*
54 };
55}
56
57const _: () = (); pub struct Styled<T> {
61 pub(crate) target: T,
63 pub style: Style,
65}
66
67#[derive(Debug, Copy, Clone, PartialEq)]
83pub struct Style {
84 pub(crate) fg: Option<DynColors>,
85 pub(crate) bg: Option<DynColors>,
86 pub(crate) bold: bool,
87 pub(crate) style_flags: StyleFlags,
88}
89
90#[repr(transparent)]
91#[derive(Debug, Copy, Clone, PartialEq)]
92pub(crate) struct StyleFlags(pub(crate) u8);
93
94impl StyleFlags {
95 #[must_use]
96 #[inline]
97 const fn is_plain(&self) -> bool {
98 self.0 == 0
99 }
100}
101
102const DIMMED_SHIFT: u8 = 0;
103const ITALIC_SHIFT: u8 = 1;
104const UNDERLINE_SHIFT: u8 = 2;
105const BLINK_SHIFT: u8 = 3;
106const BLINK_FAST_SHIFT: u8 = 4;
107const REVERSED_SHIFT: u8 = 5;
108const HIDDEN_SHIFT: u8 = 6;
109const STRIKETHROUGH_SHIFT: u8 = 7;
110
111macro_rules! style_flags_methods {
112 ($(($shift:ident, $name:ident, $set_name:ident)),* $(,)?) => {
113 $(
114 #[must_use]
115 const fn $name(&self) -> bool {
116 ((self.0 >> $shift) & 1) != 0
117 }
118
119 const fn $set_name(&mut self, $name: bool) {
120 self.0 = (self.0 & !(1 << $shift)) | (($name as u8) << $shift);
121 }
122 )*
123 };
124}
125
126impl StyleFlags {
127 const fn new() -> Self {
128 Self(0)
129 }
130
131 style_flags_methods! {
132 (DIMMED_SHIFT, dimmed, set_dimmed),
133 (ITALIC_SHIFT, italic, set_italic),
134 (UNDERLINE_SHIFT, underline, set_underline),
135 (BLINK_SHIFT, blink, set_blink),
136 (BLINK_FAST_SHIFT, blink_fast, set_blink_fast),
137 (REVERSED_SHIFT, reversed, set_reversed),
138 (HIDDEN_SHIFT, hidden, set_hidden),
139 (STRIKETHROUGH_SHIFT, strikethrough, set_strikethrough),
140 }
141}
142
143impl Default for StyleFlags {
144 fn default() -> Self {
145 Self::new()
146 }
147}
148
149impl Style {
150 #[must_use]
152 pub const fn new() -> Self {
153 Self {
154 fg: None,
155 bg: None,
156 bold: false,
157 style_flags: StyleFlags::new(),
158 }
159 }
160
161 pub const fn style<T>(&self, target: T) -> Styled<T> {
176 Styled {
177 target,
178 style: *self,
179 }
180 }
181
182 #[must_use]
190 pub const fn fg<C: Color>(mut self) -> Self {
191 self.fg = Some(C::DYN_COLORS_EQUIVALENT);
192 self
193 }
194
195 #[must_use]
203 pub const fn bg<C: Color>(mut self) -> Self {
204 self.bg = Some(C::DYN_COLORS_EQUIVALENT);
205 self
206 }
207
208 #[must_use]
214 pub const fn remove_fg(mut self) -> Self {
215 self.fg = None;
216 self
217 }
218
219 #[must_use]
225 pub const fn remove_bg(mut self) -> Self {
226 self.bg = None;
227 self
228 }
229
230 color_methods! {
231 Black black on_black,
234 Red red on_red,
237 Green green on_green,
240 Yellow yellow on_yellow,
243 Blue blue on_blue,
246 Magenta magenta on_magenta,
249 Magenta purple on_purple,
252 Cyan cyan on_cyan,
255 White white on_white,
258
259 Default default_color on_default_color,
262
263 BrightBlack bright_black on_bright_black,
266 BrightRed bright_red on_bright_red,
269 BrightGreen bright_green on_bright_green,
272 BrightYellow bright_yellow on_bright_yellow,
275 BrightBlue bright_blue on_bright_blue,
278 BrightMagenta bright_magenta on_bright_magenta,
281 BrightMagenta bright_purple on_bright_purple,
284 BrightCyan bright_cyan on_bright_cyan,
287 BrightWhite bright_white on_bright_white,
290 }
291
292 #[must_use]
294 pub const fn bold(mut self) -> Self {
295 self.bold = true;
296 self
297 }
298
299 style_methods! {
300 (dimmed, set_dimmed),
302 (italic, set_italic),
304 (underline, set_underline),
306 (blink, set_blink),
308 (blink_fast, set_blink_fast),
310 (reversed, set_reversed),
312 (hidden, set_hidden),
314 (strikethrough, set_strikethrough),
316 }
317
318 #[must_use]
319 const fn set_effect(mut self, effect: Effect, to: bool) -> Self {
320 use Effect::*;
321 match effect {
322 Bold => {
323 self.bold = to;
324 }
325 Dimmed => {
326 self.style_flags.set_dimmed(to);
327 }
328 Italic => {
329 self.style_flags.set_italic(to);
330 }
331 Underline => {
332 self.style_flags.set_underline(to);
333 }
334 Blink => {
335 self.style_flags.set_blink(to);
336 }
337 BlinkFast => {
338 self.style_flags.set_blink_fast(to);
339 }
340 Reversed => {
341 self.style_flags.set_reversed(to);
342 }
343 Hidden => {
344 self.style_flags.set_hidden(to);
345 }
346 Strikethrough => {
347 self.style_flags.set_strikethrough(to);
348 }
349 }
350 self
351 }
352
353 #[must_use]
354 const fn set_effects(mut self, mut effects: &[Effect], to: bool) -> Self {
355 while let [first, rest @ ..] = effects {
357 self = self.set_effect(*first, to);
358 effects = rest;
359 }
360 self
361 }
362
363 #[must_use]
365 pub const fn effect(self, effect: Effect) -> Self {
366 self.set_effect(effect, true)
367 }
368
369 #[must_use]
371 pub const fn remove_effect(self, effect: Effect) -> Self {
372 self.set_effect(effect, false)
373 }
374
375 #[must_use]
377 pub const fn effects(self, effects: &[Effect]) -> Self {
378 self.set_effects(effects, true)
379 }
380
381 #[must_use]
383 pub const fn remove_effects(self, effects: &[Effect]) -> Self {
384 self.set_effects(effects, false)
385 }
386
387 #[must_use]
389 pub const fn remove_all_effects(mut self) -> Self {
390 self.bold = false;
391 self.style_flags = StyleFlags::new();
392 self
393 }
394
395 #[must_use]
405 pub fn color<Color: DynColor>(mut self, color: Color) -> Self {
406 self.fg = Some(color.get_dyncolors_fg());
408 self
409 }
410
411 #[must_use]
421 pub fn on_color<Color: DynColor>(mut self, color: Color) -> Self {
422 self.bg = Some(color.get_dyncolors_bg());
424 self
425 }
426
427 #[must_use]
429 pub const fn fg_rgb<const R: u8, const G: u8, const B: u8>(mut self) -> Self {
430 self.fg = Some(DynColors::Rgb(R, G, B));
431
432 self
433 }
434
435 #[must_use]
437 pub const fn bg_rgb<const R: u8, const G: u8, const B: u8>(mut self) -> Self {
438 self.bg = Some(DynColors::Rgb(R, G, B));
439
440 self
441 }
442
443 #[must_use]
445 pub const fn truecolor(mut self, r: u8, g: u8, b: u8) -> Self {
446 self.fg = Some(DynColors::Rgb(r, g, b));
447 self
448 }
449
450 #[must_use]
452 pub const fn on_truecolor(mut self, r: u8, g: u8, b: u8) -> Self {
453 self.bg = Some(DynColors::Rgb(r, g, b));
454 self
455 }
456
457 #[must_use]
459 #[inline]
460 pub const fn is_plain(&self) -> bool {
461 let s = &self;
462 !(s.fg.is_some() || s.bg.is_some() || s.bold) && s.style_flags.is_plain()
463 }
464
465 pub const fn prefix_formatter(&self) -> StylePrefixFormatter {
488 StylePrefixFormatter(*self)
489 }
490
491 pub const fn suffix_formatter(&self) -> StyleSuffixFormatter {
499 StyleSuffixFormatter(*self)
500 }
501
502 #[inline]
504 #[allow(unused_assignments)]
505 pub fn fmt_prefix(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
506 let s = self;
507 let format_less_important_effects = s.style_flags != StyleFlags::default();
508 let format_effect = s.bold || format_less_important_effects;
509 let format_any = !self.is_plain();
510
511 let mut semicolon = false;
512
513 if format_any {
514 f.write_str("\x1b[")?;
515 }
516
517 if let Some(fg) = s.fg {
518 <DynColors as DynColor>::fmt_raw_ansi_fg(&fg, f)?;
519 semicolon = true;
520 }
521
522 if let Some(bg) = s.bg {
523 if s.fg.is_some() {
524 f.write_str(";")?;
525 }
526 <DynColors as DynColor>::fmt_raw_ansi_bg(&bg, f)?;
527 semicolon = true;
528 }
529
530 if format_effect {
531 if s.bold {
532 if semicolon {
533 f.write_str(";")?;
534 }
535
536 f.write_str("1")?;
537
538 semicolon = true;
539 }
540
541 macro_rules! text_effect_fmt {
542 ($style:ident, $formatter:ident, $semicolon:ident, $(($attr:ident, $value:literal)),* $(,)?) => {
543 $(
544 if $style.style_flags.$attr() {
545 if $semicolon {
546 $formatter.write_str(";")?;
547 }
548 $formatter.write_str($value)?;
549
550 $semicolon = true;
551 }
552 )+
553 }
554 }
555
556 if format_less_important_effects {
557 text_effect_fmt! {
558 s, f, semicolon,
559 (dimmed, "2"),
560 (italic, "3"),
561 (underline, "4"),
562 (blink, "5"),
563 (blink_fast, "6"),
564 (reversed, "7"),
565 (hidden, "8"),
566 (strikethrough, "9"),
567 }
568 }
569 }
570
571 if format_any {
572 f.write_str("m")?;
573 }
574 Ok(())
575 }
576
577 #[inline]
579 pub fn fmt_suffix(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580 if !self.is_plain() {
581 f.write_str("\x1b[0m")?;
582 }
583 Ok(())
584 }
585}
586
587#[derive(Debug, Clone, Copy, PartialEq)]
592#[must_use = "this formatter does nothing unless displayed"]
593pub struct StylePrefixFormatter(Style);
594
595impl fmt::Display for StylePrefixFormatter {
596 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
597 self.0.fmt_prefix(f)
598 }
599}
600
601#[derive(Debug, Clone, Copy, PartialEq)]
606#[must_use = "this formatter does nothing unless displayed"]
607pub struct StyleSuffixFormatter(Style);
608
609impl fmt::Display for StyleSuffixFormatter {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 self.0.fmt_suffix(f)
612 }
613}
614
615impl Default for Style {
616 fn default() -> Self {
617 Self::new()
618 }
619}
620
621pub const fn style() -> Style {
623 Style::new()
624}
625
626impl<T> Styled<T> {
627 pub const fn inner(&self) -> &T {
629 &self.target
630 }
631
632 pub const fn inner_mut(&mut self) -> &mut T {
634 &mut self.target
635 }
636}
637
638macro_rules! impl_fmt {
639 ($($trait:path),* $(,)?) => {
640 $(
641 impl<T: $trait> $trait for Styled<T> {
642 #[allow(unused_assignments)]
643 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
644 self.style.fmt_prefix(f)?;
645 <T as $trait>::fmt(&self.target, f)?;
646 self.style.fmt_suffix(f)
647 }
648 }
649 )*
650 };
651}
652
653impl_fmt! {
654 fmt::Display,
655 fmt::Debug,
656 fmt::UpperHex,
657 fmt::LowerHex,
658 fmt::Binary,
659 fmt::UpperExp,
660 fmt::LowerExp,
661 fmt::Octal,
662 fmt::Pointer,
663}
664
665#[cfg(test)]
666mod tests {
667 use super::*;
668 use crate::{AnsiColors, OwoColorize};
669
670 #[test]
671 fn size_of() {
672 let size = std::mem::size_of::<Style>();
673 assert_eq!(size, 10, "size of Style should be 10 bytes");
674 }
675
676 #[test]
677 fn test_it() {
678 let style = Style::new()
679 .bright_white()
680 .on_blue()
681 .bold()
682 .dimmed()
683 .italic()
684 .underline()
685 .blink()
686 .strikethrough();
690 let s = style.style("TEST");
691 let s2 = format!("{}", &s);
692 println!("{}", &s2);
693 assert_eq!(&s2, "\u{1b}[97;44;1;2;3;4;5;9mTEST\u{1b}[0m");
694
695 let prefix = format!("{}", style.prefix_formatter());
696 assert_eq!(&prefix, "\u{1b}[97;44;1;2;3;4;5;9m");
697
698 let suffix = format!("{}", style.suffix_formatter());
699 assert_eq!(&suffix, "\u{1b}[0m");
700 }
701
702 #[test]
703 fn test_effects() {
704 use Effect::*;
705 let style = Style::new().effects(&[Strikethrough, Underline]);
706
707 let s = style.style("TEST");
708 let s2 = format!("{}", &s);
709 println!("{}", &s2);
710 assert_eq!(&s2, "\u{1b}[4;9mTEST\u{1b}[0m");
711 }
712
713 #[test]
714 fn test_color() {
715 let style = Style::new()
716 .color(AnsiColors::White)
717 .on_color(AnsiColors::Black);
718
719 let s = style.style("TEST");
720 let s2 = format!("{}", &s);
721 println!("{}", &s2);
722 assert_eq!(&s2, "\u{1b}[37;40mTEST\u{1b}[0m");
723 }
724
725 #[test]
726 fn test_truecolor() {
727 let style = Style::new().truecolor(255, 255, 255).on_truecolor(0, 0, 0);
728
729 let s = style.style("TEST");
730 let s2 = format!("{}", &s);
731 println!("{}", &s2);
732 assert_eq!(&s2, "\u{1b}[38;2;255;255;255;48;2;0;0;0mTEST\u{1b}[0m");
733 }
734
735 #[test]
736 fn test_string_reference() {
737 let style = Style::new().truecolor(255, 255, 255).on_truecolor(0, 0, 0);
738
739 let string = String::from("TEST");
740 let s = style.style(&string);
741 let s2 = format!("{}", &s);
742 println!("{}", &s2);
743 assert_eq!(&s2, "\u{1b}[38;2;255;255;255;48;2;0;0;0mTEST\u{1b}[0m");
744 }
745
746 #[test]
747 fn test_owocolorize() {
748 let style = Style::new().bright_white().on_blue();
749
750 let s = "TEST".style(style);
751 let s2 = format!("{}", &s);
752 println!("{}", &s2);
753 assert_eq!(&s2, "\u{1b}[97;44mTEST\u{1b}[0m");
754 }
755
756 #[test]
757 fn test_is_plain() {
758 let style = Style::new().bright_white().on_blue();
759
760 assert!(!style.is_plain());
761 assert!(Style::default().is_plain());
762
763 let string = String::from("TEST");
764 let s = Style::default().style(&string);
765 let s2 = format!("{}", &s);
766
767 assert_eq!(string, s2)
768 }
769
770 #[test]
771 fn test_inner() {
772 let style = Style::default();
773
774 let mut s = "TEST".style(style);
775
776 assert_eq!(&&"TEST", s.inner());
777
778 *s.inner_mut() = &"changed";
779 assert_eq!(&&"changed", s.inner());
780 assert_eq!("changed", format!("{}", s));
781 }
782}