1use std::fmt;
6use crate::def_strings;
7
8#[cps::cps]
9macro_rules! pass_file {
12 ($macro:ident!($source:expr)) =>
13 let $($file:tt)* = cps::include!($source) in
14 {
15 $macro! { $($file)* }
16 };
17}
18
19def_strings! {
20 #[doc = "Reset all styles"]
21 RESET = "0";
22 #[doc = "Increase the font weight"]
23 BOLD = "1";
24 #[doc = "Decrease the font weight"]
25 BOLD_OFF = "22";
26 #[doc = "Decrease the intensity"]
27 FAINT = "2";
28 #[doc = "Reset the intensity"]
29 FAINT_OFF = "22";
30 ITALICS = "3";
31 ITALICS_OFF = "23";
32 UNDERLINE = "4";
33 DOUBLE_UNDERLINE = "21";
34 UNDERLINE_OFF = "24";
35 #[doc = "Make the text blink"]
36 SLOW_BLINK = "5";
37 #[doc = "Make the text blink"]
38 FAST_BLINK = "6";
39 #[doc = "Reset the blink"]
40 BLINK_OFF = "25";
41 INVERSE = "7";
42 INVERSE_OFF = "27";
43 INVISIBLE = "8";
44 INVISIBLE_OFF = "28";
45 STRIKETHROUGH = "9";
46 STRIKETHROUGH_OFF = "29";
47 OVERLINE = "53";
48 OVERLINE_OFF = "55";
49
50 BLACK = "30";
51 RED = "31";
52 GREEN = "32";
53 YELLOW = "33";
54 BLUE = "34";
55 MAGENTA = "35";
56 CYAN = "36";
57 WHITE = "37";
58 BRIGHT_BLACK = "90";
59 BRIGHT_RED = "91";
60 BRIGHT_GREEN = "92";
61 BRIGHT_YELLOW = "93";
62 BRIGHT_BLUE = "94";
63 BRIGHT_MAGENTA = "95";
64 BRIGHT_CYAN = "96";
65 BRIGHT_WHITE = "97";
66 FOREGROUND_OFF = "39";
67
68 BLACK_BG = "40";
69 RED_BG = "41";
70 GREEN_BG = "42";
71 YELLOW_BG = "43";
72 BLUE_BG = "44";
73 MAGENTA_BG = "45";
74 CYAN_BG = "46";
75 WHITE_BG = "47";
76 BRIGHT_BLACK_BG = "100";
77 BRIGHT_RED_BG = "101";
78 BRIGHT_GREEN_BG = "102";
79 BRIGHT_YELLOW_BG = "103";
80 BRIGHT_BLUE_BG = "104";
81 BRIGHT_MAGENTA_BG = "105";
82 BRIGHT_CYAN_BG = "106";
83 BRIGHT_WHITE_BG = "107";
84 END_BG = "49";
85
86 ORANGE = "38;2;230;126;20";
87 ORANGE_BG = "48;2;230;126;20";
88 BLUEBERRY = "38;2;80;80;255";
89 BLUEBERRY_BG = "48;2;80;80;255";
90 PINK = "38;2;255;0;200";
91 PINK_BG = "48;2;255;0;200";
92}
93
94#[inline(always)]
95pub fn reset() -> String {
97 format!("\x1b[{}m", RESET)
98}
99
100#[derive(Debug, Clone, Copy)]
101pub struct Rgb(pub u8, pub u8, pub u8);
102
103macro_rules! style_fn {
104 ($($(#[$tag:meta])? fn $fn_name:ident() -> ($start:ident, $end:ident);)*) => {
105 $(
106 $(#[$tag])?
107 #[inline(always)]
108 fn $fn_name(&self) -> String {
110 format!("\x1b[{}m{}\x1b[{}m", $start, self, $end)
111 }
112 )*
113 }
114}
115
116pub trait Stylize: fmt::Display {
118 pass_file!(style_fn!("src/styles.in"));
119
120 #[inline(always)]
121 fn rgb(&self, Rgb(red, green, blue): Rgb) -> String {
123 format!(
124 "\x1b[38;2;{};{};{}m{}\x1b[{}m",
125 red, green, blue,
126 self,
127 FOREGROUND_OFF
128 )
129 }
130 #[inline(always)]
131 fn rgb_bg(&self, Rgb(red, green, blue): Rgb) -> String {
133 format!(
134 "\x1b[48;2;{};{};{}m{}\x1b[{}m",
135 red, green, blue,
136 self,
137 END_BG
138 )
139 }
140
141 #[inline(always)]
142 fn style(&self) -> StyleBuilder {
144 StyleBuilder::new(self.to_string())
145 }
146
147 #[inline(always)]
148 fn deprecated(&self) -> String {
150 format!("\x1b[3;9m{}\x1b[23;29m", self)
151 }
152 #[inline(always)]
153 fn error(&self) -> String {
155 self.style().red().bold().build()
156 }
157 #[inline(always)]
158 fn warning(&self) -> String {
160 self.style().yellow().bold().build()
161 }
162 #[inline(always)]
163 fn success(&self) -> String {
165 self.style().green().bold().build()
166 }
167}
168
169impl Stylize for String {}
170impl Stylize for &str {}
171impl Stylize for Box<str> {}
172
173#[derive(Debug)]
174pub struct StyleBuilder {
175 text: String,
176 start: Vec<Box<str>>,
177 end: Vec<Box<str>>,
178}
179
180macro_rules! lazy_style_fn {
181 ($($(#[$tag:meta])? fn $fn_name:ident() -> ($start:ident, $end:ident);)*) => {
182 $(
183 $(#[$tag])?
184 #[inline(always)]
185 pub fn $fn_name(mut self) -> Self {
188 self.start.push($start.into());
189 self.end.push($end.into());
190 self
191 }
192 )*
193 }
194}
195
196impl StyleBuilder {
197 #[inline]
198 fn new(text: String) -> Self {
199 Self {
200 text,
201 start: vec![],
202 end: vec![],
203 }
204 }
205 #[inline(always)]
206 pub fn build(self) -> String {
207 format!("\x1b[{}m{}\x1b[{}m", self.start.join(";"), self.text, self.end.join(";"))
208 }
209 pass_file!(lazy_style_fn!("src/styles.in"));
210
211 pub fn rgb(mut self, Rgb(red, green, blue): Rgb) -> Self {
212 self.start.push(format!("38;2;{};{};{}", red, green, blue).into_boxed_str());
213 self.end.push(FOREGROUND_OFF.into());
214 self
215 }
216 pub fn rgb_bg(mut self, Rgb(red, green, blue): Rgb) -> Self {
217 self.start.push(format!("48;2;{};{};{}", red, green, blue).into_boxed_str());
218 self.end.push(END_BG.into());
219 self
220 }
221}