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 = 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 #[must_use]
120 const fn $set_name(mut self, $name: bool) -> Self {
121 self.0 = (self.0 & !(1 << $shift)) | (($name as u8) << $shift);
122 self
123 }
124 )*
125 };
126}
127
128impl StyleFlags {
129 const fn new() -> Self {
130 Self(0)
131 }
132
133 style_flags_methods! {
134 (DIMMED_SHIFT, dimmed, set_dimmed),
135 (ITALIC_SHIFT, italic, set_italic),
136 (UNDERLINE_SHIFT, underline, set_underline),
137 (BLINK_SHIFT, blink, set_blink),
138 (BLINK_FAST_SHIFT, blink_fast, set_blink_fast),
139 (REVERSED_SHIFT, reversed, set_reversed),
140 (HIDDEN_SHIFT, hidden, set_hidden),
141 (STRIKETHROUGH_SHIFT, strikethrough, set_strikethrough),
142 }
143}
144
145impl Default for StyleFlags {
146 fn default() -> Self {
147 Self::new()
148 }
149}
150
151impl Style {
152 #[must_use]
154 pub const fn new() -> Self {
155 Self {
156 fg: None,
157 bg: None,
158 bold: false,
159 style_flags: StyleFlags::new(),
160 }
161 }
162
163 pub const fn style<T>(&self, target: T) -> Styled<T> {
178 Styled {
179 target,
180 style: *self,
181 }
182 }
183
184 #[must_use]
192 pub const fn fg<C: Color>(mut self) -> Self {
193 self.fg = Some(C::DYN_COLORS_EQUIVALENT);
194 self
195 }
196
197 #[must_use]
205 pub const fn bg<C: Color>(mut self) -> Self {
206 self.bg = Some(C::DYN_COLORS_EQUIVALENT);
207 self
208 }
209
210 #[must_use]
216 pub const fn remove_fg(mut self) -> Self {
217 self.fg = None;
218 self
219 }
220
221 #[must_use]
227 pub const fn remove_bg(mut self) -> Self {
228 self.bg = None;
229 self
230 }
231
232 color_methods! {
233 Black black on_black,
236 Red red on_red,
239 Green green on_green,
242 Yellow yellow on_yellow,
245 Blue blue on_blue,
248 Magenta magenta on_magenta,
251 Magenta purple on_purple,
254 Cyan cyan on_cyan,
257 White white on_white,
260
261 Default default_color on_default_color,
264
265 BrightBlack bright_black on_bright_black,
268 BrightRed bright_red on_bright_red,
271 BrightGreen bright_green on_bright_green,
274 BrightYellow bright_yellow on_bright_yellow,
277 BrightBlue bright_blue on_bright_blue,
280 BrightMagenta bright_magenta on_bright_magenta,
283 BrightMagenta bright_purple on_bright_purple,
286 BrightCyan bright_cyan on_bright_cyan,
289 BrightWhite bright_white on_bright_white,
292 }
293
294 #[must_use]
296 pub const fn bold(mut self) -> Self {
297 self.bold = true;
298 self
299 }
300
301 style_methods! {
302 (dimmed, set_dimmed),
304 (italic, set_italic),
306 (underline, set_underline),
308 (blink, set_blink),
310 (blink_fast, set_blink_fast),
312 (reversed, set_reversed),
314 (hidden, set_hidden),
316 (strikethrough, set_strikethrough),
318 }
319
320 #[must_use]
321 const fn set_effect(mut self, effect: Effect, to: bool) -> Self {
322 use Effect::*;
323 match effect {
324 Bold => {
325 self.bold = to;
326 }
327 Dimmed => {
328 self.style_flags = self.style_flags.set_dimmed(to);
331 }
332 Italic => {
333 self.style_flags = self.style_flags.set_italic(to);
334 }
335 Underline => {
336 self.style_flags = self.style_flags.set_underline(to);
337 }
338 Blink => {
339 self.style_flags = self.style_flags.set_blink(to);
340 }
341 BlinkFast => {
342 self.style_flags = self.style_flags.set_blink_fast(to);
343 }
344 Reversed => {
345 self.style_flags = self.style_flags.set_reversed(to);
346 }
347 Hidden => {
348 self.style_flags = self.style_flags.set_hidden(to);
349 }
350 Strikethrough => {
351 self.style_flags = self.style_flags.set_strikethrough(to);
352 }
353 }
354 self
355 }
356
357 #[must_use]
358 const fn set_effects(mut self, mut effects: &[Effect], to: bool) -> Self {
359 while let [first, rest @ ..] = effects {
361 self = self.set_effect(*first, to);
362 effects = rest;
363 }
364 self
365 }
366
367 #[must_use]
369 pub const fn effect(self, effect: Effect) -> Self {
370 self.set_effect(effect, true)
371 }
372
373 #[must_use]
375 pub const fn remove_effect(self, effect: Effect) -> Self {
376 self.set_effect(effect, false)
377 }
378
379 #[must_use]
381 pub const fn effects(self, effects: &[Effect]) -> Self {
382 self.set_effects(effects, true)
383 }
384
385 #[must_use]
387 pub const fn remove_effects(self, effects: &[Effect]) -> Self {
388 self.set_effects(effects, false)
389 }
390
391 #[must_use]
393 pub const fn remove_all_effects(mut self) -> Self {
394 self.bold = false;
395 self.style_flags = StyleFlags::new();
396 self
397 }
398
399 #[must_use]
409 pub fn color<Color: DynColor>(mut self, color: Color) -> Self {
410 self.fg = Some(color.get_dyncolors_fg());
412 self
413 }
414
415 #[must_use]
425 pub fn on_color<Color: DynColor>(mut self, color: Color) -> Self {
426 self.bg = Some(color.get_dyncolors_bg());
428 self
429 }
430
431 #[must_use]
433 pub const fn fg_rgb<const R: u8, const G: u8, const B: u8>(mut self) -> Self {
434 self.fg = Some(DynColors::Rgb(R, G, B));
435
436 self
437 }
438
439 #[must_use]
441 pub const fn bg_rgb<const R: u8, const G: u8, const B: u8>(mut self) -> Self {
442 self.bg = Some(DynColors::Rgb(R, G, B));
443
444 self
445 }
446
447 #[must_use]
449 pub const fn truecolor(mut self, r: u8, g: u8, b: u8) -> Self {
450 self.fg = Some(DynColors::Rgb(r, g, b));
451 self
452 }
453
454 #[must_use]
456 pub const fn on_truecolor(mut self, r: u8, g: u8, b: u8) -> Self {
457 self.bg = Some(DynColors::Rgb(r, g, b));
458 self
459 }
460
461 #[must_use]
463 #[inline]
464 pub const fn is_plain(&self) -> bool {
465 let s = &self;
466 !(s.fg.is_some() || s.bg.is_some() || s.bold) && s.style_flags.is_plain()
467 }
468
469 pub const fn prefix_formatter(&self) -> StylePrefixFormatter {
492 StylePrefixFormatter(*self)
493 }
494
495 pub const fn suffix_formatter(&self) -> StyleSuffixFormatter {
503 StyleSuffixFormatter(*self)
504 }
505
506 #[inline]
508 #[allow(unused_assignments)]
509 pub fn fmt_prefix(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510 let s = self;
511 let format_less_important_effects = s.style_flags != StyleFlags::default();
512 let format_effect = s.bold || format_less_important_effects;
513 let format_any = !self.is_plain();
514
515 let mut semicolon = false;
516
517 if format_any {
518 f.write_str("\x1b[")?;
519 }
520
521 if let Some(fg) = s.fg {
522 <DynColors as DynColor>::fmt_raw_ansi_fg(&fg, f)?;
523 semicolon = true;
524 }
525
526 if let Some(bg) = s.bg {
527 if s.fg.is_some() {
528 f.write_str(";")?;
529 }
530 <DynColors as DynColor>::fmt_raw_ansi_bg(&bg, f)?;
531 }
532
533 if format_effect {
534 if s.bold {
535 if semicolon {
536 f.write_str(";")?;
537 }
538
539 f.write_str("1")?;
540
541 semicolon = true;
542 }
543
544 macro_rules! text_effect_fmt {
545 ($style:ident, $formatter:ident, $semicolon:ident, $(($attr:ident, $value:literal)),* $(,)?) => {
546 $(
547 if $style.style_flags.$attr() {
548 if $semicolon {
549 $formatter.write_str(";")?;
550 }
551 $formatter.write_str($value)?;
552
553 $semicolon = true;
554 }
555 )+
556 }
557 }
558
559 if format_less_important_effects {
560 text_effect_fmt! {
561 s, f, semicolon,
562 (dimmed, "2"),
563 (italic, "3"),
564 (underline, "4"),
565 (blink, "5"),
566 (blink_fast, "6"),
567 (reversed, "7"),
568 (hidden, "8"),
569 (strikethrough, "9"),
570 }
571 }
572 }
573
574 if format_any {
575 f.write_str("m")?;
576 }
577 Ok(())
578 }
579
580 #[inline]
582 pub fn fmt_suffix(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583 if !self.is_plain() {
584 f.write_str("\x1b[0m")?;
585 }
586 Ok(())
587 }
588}
589
590#[derive(Debug, Clone, Copy, PartialEq)]
595#[must_use = "this formatter does nothing unless displayed"]
596pub struct StylePrefixFormatter(Style);
597
598impl fmt::Display for StylePrefixFormatter {
599 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600 self.0.fmt_prefix(f)
601 }
602}
603
604#[derive(Debug, Clone, Copy, PartialEq)]
609#[must_use = "this formatter does nothing unless displayed"]
610pub struct StyleSuffixFormatter(Style);
611
612impl fmt::Display for StyleSuffixFormatter {
613 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
614 self.0.fmt_suffix(f)
615 }
616}
617
618impl Default for Style {
619 fn default() -> Self {
620 Self::new()
621 }
622}
623
624pub const fn style() -> Style {
626 Style::new()
627}
628
629impl<T> Styled<T> {
630 pub const fn inner(&self) -> &T {
632 &self.target
633 }
634
635 #[cfg(const_mut_refs)]
639 pub const fn inner_mut(&mut self) -> &mut T {
640 &mut self.target
641 }
642
643 #[cfg(not(const_mut_refs))]
647 pub fn inner_mut(&mut self) -> &mut T {
648 &mut self.target
649 }
650}
651
652macro_rules! impl_fmt {
653 ($($trait:path),* $(,)?) => {
654 $(
655 impl<T: $trait> $trait for Styled<T> {
656 #[allow(unused_assignments)]
657 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
658 self.style.fmt_prefix(f)?;
659 <T as $trait>::fmt(&self.target, f)?;
660 self.style.fmt_suffix(f)
661 }
662 }
663 )*
664 };
665}
666
667impl_fmt! {
668 fmt::Display,
669 fmt::Debug,
670 fmt::UpperHex,
671 fmt::LowerHex,
672 fmt::Binary,
673 fmt::UpperExp,
674 fmt::LowerExp,
675 fmt::Octal,
676 fmt::Pointer,
677}
678
679#[cfg(test)]
680mod tests {
681 use super::*;
682 use crate::{AnsiColors, OwoColorize};
683
684 #[test]
685 fn size_of() {
686 let size = std::mem::size_of::<Style>();
687 assert_eq!(size, 10, "size of Style should be 10 bytes");
688 }
689
690 #[test]
691 fn test_it() {
692 let style = Style::new()
693 .bright_white()
694 .on_blue()
695 .bold()
696 .dimmed()
697 .italic()
698 .underline()
699 .blink()
700 .strikethrough();
704 let s = style.style("TEST");
705 let s2 = format!("{}", &s);
706 println!("{}", &s2);
707 assert_eq!(&s2, "\u{1b}[97;44;1;2;3;4;5;9mTEST\u{1b}[0m");
708
709 let prefix = format!("{}", style.prefix_formatter());
710 assert_eq!(&prefix, "\u{1b}[97;44;1;2;3;4;5;9m");
711
712 let suffix = format!("{}", style.suffix_formatter());
713 assert_eq!(&suffix, "\u{1b}[0m");
714 }
715
716 #[test]
717 fn test_effects() {
718 use Effect::*;
719 let style = Style::new().effects(&[Strikethrough, Underline]);
720
721 let s = style.style("TEST");
722 let s2 = format!("{}", &s);
723 println!("{}", &s2);
724 assert_eq!(&s2, "\u{1b}[4;9mTEST\u{1b}[0m");
725 }
726
727 #[test]
728 fn test_color() {
729 let style = Style::new()
730 .color(AnsiColors::White)
731 .on_color(AnsiColors::Black);
732
733 let s = style.style("TEST");
734 let s2 = format!("{}", &s);
735 println!("{}", &s2);
736 assert_eq!(&s2, "\u{1b}[37;40mTEST\u{1b}[0m");
737 }
738
739 #[test]
740 fn test_truecolor() {
741 let style = Style::new().truecolor(255, 255, 255).on_truecolor(0, 0, 0);
742
743 let s = style.style("TEST");
744 let s2 = format!("{}", &s);
745 println!("{}", &s2);
746 assert_eq!(&s2, "\u{1b}[38;2;255;255;255;48;2;0;0;0mTEST\u{1b}[0m");
747 }
748
749 #[test]
750 fn test_string_reference() {
751 let style = Style::new().truecolor(255, 255, 255).on_truecolor(0, 0, 0);
752
753 let string = String::from("TEST");
754 let s = style.style(&string);
755 let s2 = format!("{}", &s);
756 println!("{}", &s2);
757 assert_eq!(&s2, "\u{1b}[38;2;255;255;255;48;2;0;0;0mTEST\u{1b}[0m");
758 }
759
760 #[test]
761 fn test_owocolorize() {
762 let style = Style::new().bright_white().on_blue();
763
764 let s = "TEST".style(style);
765 let s2 = format!("{}", &s);
766 println!("{}", &s2);
767 assert_eq!(&s2, "\u{1b}[97;44mTEST\u{1b}[0m");
768 }
769
770 #[test]
771 fn test_is_plain() {
772 let style = Style::new().bright_white().on_blue();
773
774 assert!(!style.is_plain());
775 assert!(Style::default().is_plain());
776
777 let string = String::from("TEST");
778 let s = Style::default().style(&string);
779 let s2 = format!("{}", &s);
780
781 assert_eq!(string, s2)
782 }
783
784 #[test]
785 fn test_inner() {
786 let style = Style::default();
787
788 let mut s = "TEST".style(style);
789
790 assert_eq!(&&"TEST", s.inner());
791
792 *s.inner_mut() = &"changed";
793 assert_eq!(&&"changed", s.inner());
794 assert_eq!("changed", format!("{}", s));
795 }
796}