1use std::{fmt::Display, io};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct Styled<T: ?Sized> {
12 fg: Option<Color>,
13 bg: Option<Color>,
14 attributes: Attributes,
15 content: T,
16}
17
18impl<T: Display> Styled<T> {
19 pub fn new(content: T) -> Self {
21 Self {
22 fg: None,
23 bg: None,
24 attributes: Attributes::empty(),
25 content,
26 }
27 }
28}
29
30impl<T: Display + ?Sized> Styled<T> {
31 pub(super) fn write<B: crate::backend::Backend + ?Sized>(
32 &self,
33 backend: &mut B,
34 ) -> io::Result<()> {
35 if let Some(fg) = self.fg {
36 backend.set_fg(fg)?;
37 }
38 if let Some(bg) = self.bg {
39 backend.set_bg(bg)?;
40 }
41 if !self.attributes.is_empty() {
42 backend.set_attributes(self.attributes)?;
43 }
44
45 write!(backend, "{}", &self.content)?;
46
47 if self.fg.is_some() {
48 backend.set_fg(Color::Reset)?;
49 }
50 if self.bg.is_some() {
51 backend.set_bg(Color::Reset)?;
52 }
53 if !self.attributes.is_empty() {
54 backend.set_attributes(Attributes::empty())?;
55 }
56 Ok(())
57 }
58}
59
60impl<T: Display> From<T> for Styled<T> {
61 fn from(content: T) -> Self {
62 Self::new(content)
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69#[allow(missing_docs)]
70pub enum Color {
71 Reset,
72 Black,
73 Red,
74 Green,
75 Yellow,
76 Blue,
77 Magenta,
78 Cyan,
79 Grey,
80 DarkGrey,
81 LightRed,
82 LightGreen,
83 LightYellow,
84 LightBlue,
85 LightMagenta,
86 LightCyan,
87 White,
88 Rgb(u8, u8, u8),
89 Ansi(u8),
90}
91
92bitflags::bitflags! {
93 pub struct Attributes: u16 {
95 const BOLD = 0b0000_0000_0001;
97 const DIM = 0b0000_0000_0010;
99 const ITALIC = 0b0000_0000_0100;
101 const UNDERLINED = 0b0000_0000_1000;
103 const SLOW_BLINK = 0b0000_0001_0000;
105 const RAPID_BLINK = 0b0000_0010_0000;
107 const REVERSED = 0b0000_0100_0000;
109 const HIDDEN = 0b0000_1000_0000;
111 const CROSSED_OUT = 0b0001_0000_0000;
113 }
114}
115
116impl Attributes {
117 pub fn diff(self, to: Attributes) -> AttributeDiff {
120 let diff = self ^ to;
121 AttributeDiff {
122 to_remove: diff & self,
123 to_add: diff & to,
124 }
125 }
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
130#[allow(missing_docs)]
131pub struct AttributeDiff {
132 pub to_add: Attributes,
133 pub to_remove: Attributes,
134}
135
136#[allow(missing_docs)]
147pub trait Stylize<T> {
148 fn black(self) -> Styled<T>;
149 fn dark_grey(self) -> Styled<T>;
150 fn light_red(self) -> Styled<T>;
151 fn red(self) -> Styled<T>;
152 fn light_green(self) -> Styled<T>;
153 fn green(self) -> Styled<T>;
154 fn light_yellow(self) -> Styled<T>;
155 fn yellow(self) -> Styled<T>;
156 fn light_blue(self) -> Styled<T>;
157 fn blue(self) -> Styled<T>;
158 fn light_magenta(self) -> Styled<T>;
159 fn magenta(self) -> Styled<T>;
160 fn light_cyan(self) -> Styled<T>;
161 fn cyan(self) -> Styled<T>;
162 fn white(self) -> Styled<T>;
163 fn grey(self) -> Styled<T>;
164 fn rgb(self, r: u8, g: u8, b: u8) -> Styled<T>;
165 fn ansi(self, ansi: u8) -> Styled<T>;
166
167 fn on_black(self) -> Styled<T>;
168 fn on_dark_grey(self) -> Styled<T>;
169 fn on_light_red(self) -> Styled<T>;
170 fn on_red(self) -> Styled<T>;
171 fn on_light_green(self) -> Styled<T>;
172 fn on_green(self) -> Styled<T>;
173 fn on_light_yellow(self) -> Styled<T>;
174 fn on_yellow(self) -> Styled<T>;
175 fn on_light_blue(self) -> Styled<T>;
176 fn on_blue(self) -> Styled<T>;
177 fn on_light_magenta(self) -> Styled<T>;
178 fn on_magenta(self) -> Styled<T>;
179 fn on_light_cyan(self) -> Styled<T>;
180 fn on_cyan(self) -> Styled<T>;
181 fn on_white(self) -> Styled<T>;
182 fn on_grey(self) -> Styled<T>;
183 fn on_rgb(self, r: u8, g: u8, b: u8) -> Styled<T>;
184 fn on_ansi(self, ansi: u8) -> Styled<T>;
185
186 fn bold(self) -> Styled<T>;
187 fn underlined(self) -> Styled<T>;
188 fn reverse(self) -> Styled<T>;
189 fn dim(self) -> Styled<T>;
190 fn italic(self) -> Styled<T>;
191 fn slow_blink(self) -> Styled<T>;
192 fn rapid_blink(self) -> Styled<T>;
193 fn hidden(self) -> Styled<T>;
194 fn crossed_out(self) -> Styled<T>;
195}
196
197impl<T, I: Into<Styled<T>>> Stylize<T> for I {
198 fn black(self) -> Styled<T> {
199 let mut styled = self.into();
200 styled.fg = Some(Color::Black);
201 styled
202 }
203 fn dark_grey(self) -> Styled<T> {
204 let mut styled = self.into();
205 styled.fg = Some(Color::DarkGrey);
206 styled
207 }
208 fn light_red(self) -> Styled<T> {
209 let mut styled = self.into();
210 styled.fg = Some(Color::LightRed);
211 styled
212 }
213 fn red(self) -> Styled<T> {
214 let mut styled = self.into();
215 styled.fg = Some(Color::Red);
216 styled
217 }
218 fn light_green(self) -> Styled<T> {
219 let mut styled = self.into();
220 styled.fg = Some(Color::LightGreen);
221 styled
222 }
223 fn green(self) -> Styled<T> {
224 let mut styled = self.into();
225 styled.fg = Some(Color::Green);
226 styled
227 }
228 fn light_yellow(self) -> Styled<T> {
229 let mut styled = self.into();
230 styled.fg = Some(Color::LightYellow);
231 styled
232 }
233 fn yellow(self) -> Styled<T> {
234 let mut styled = self.into();
235 styled.fg = Some(Color::Yellow);
236 styled
237 }
238 fn light_blue(self) -> Styled<T> {
239 let mut styled = self.into();
240 styled.fg = Some(Color::LightBlue);
241 styled
242 }
243 fn blue(self) -> Styled<T> {
244 let mut styled = self.into();
245 styled.fg = Some(Color::Blue);
246 styled
247 }
248 fn light_magenta(self) -> Styled<T> {
249 let mut styled = self.into();
250 styled.fg = Some(Color::LightMagenta);
251 styled
252 }
253 fn magenta(self) -> Styled<T> {
254 let mut styled = self.into();
255 styled.fg = Some(Color::Magenta);
256 styled
257 }
258 fn light_cyan(self) -> Styled<T> {
259 let mut styled = self.into();
260 styled.fg = Some(Color::LightCyan);
261 styled
262 }
263 fn cyan(self) -> Styled<T> {
264 let mut styled = self.into();
265 styled.fg = Some(Color::Cyan);
266 styled
267 }
268 fn white(self) -> Styled<T> {
269 let mut styled = self.into();
270 styled.fg = Some(Color::White);
271 styled
272 }
273 fn grey(self) -> Styled<T> {
274 let mut styled = self.into();
275 styled.fg = Some(Color::Grey);
276 styled
277 }
278 fn rgb(self, r: u8, g: u8, b: u8) -> Styled<T> {
279 let mut styled = self.into();
280 styled.fg = Some(Color::Rgb(r, g, b));
281 styled
282 }
283 fn ansi(self, ansi: u8) -> Styled<T> {
284 let mut styled = self.into();
285 styled.fg = Some(Color::Ansi(ansi));
286 styled
287 }
288
289 fn on_black(self) -> Styled<T> {
290 let mut styled = self.into();
291 styled.bg = Some(Color::Black);
292 styled
293 }
294 fn on_dark_grey(self) -> Styled<T> {
295 let mut styled = self.into();
296 styled.bg = Some(Color::DarkGrey);
297 styled
298 }
299 fn on_light_red(self) -> Styled<T> {
300 let mut styled = self.into();
301 styled.bg = Some(Color::LightRed);
302 styled
303 }
304 fn on_red(self) -> Styled<T> {
305 let mut styled = self.into();
306 styled.bg = Some(Color::Red);
307 styled
308 }
309 fn on_light_green(self) -> Styled<T> {
310 let mut styled = self.into();
311 styled.bg = Some(Color::LightGreen);
312 styled
313 }
314 fn on_green(self) -> Styled<T> {
315 let mut styled = self.into();
316 styled.bg = Some(Color::Green);
317 styled
318 }
319 fn on_light_yellow(self) -> Styled<T> {
320 let mut styled = self.into();
321 styled.bg = Some(Color::LightYellow);
322 styled
323 }
324 fn on_yellow(self) -> Styled<T> {
325 let mut styled = self.into();
326 styled.bg = Some(Color::Yellow);
327 styled
328 }
329 fn on_light_blue(self) -> Styled<T> {
330 let mut styled = self.into();
331 styled.bg = Some(Color::LightBlue);
332 styled
333 }
334 fn on_blue(self) -> Styled<T> {
335 let mut styled = self.into();
336 styled.bg = Some(Color::Blue);
337 styled
338 }
339 fn on_light_magenta(self) -> Styled<T> {
340 let mut styled = self.into();
341 styled.bg = Some(Color::LightMagenta);
342 styled
343 }
344 fn on_magenta(self) -> Styled<T> {
345 let mut styled = self.into();
346 styled.bg = Some(Color::Magenta);
347 styled
348 }
349 fn on_light_cyan(self) -> Styled<T> {
350 let mut styled = self.into();
351 styled.bg = Some(Color::LightCyan);
352 styled
353 }
354 fn on_cyan(self) -> Styled<T> {
355 let mut styled = self.into();
356 styled.bg = Some(Color::Cyan);
357 styled
358 }
359 fn on_white(self) -> Styled<T> {
360 let mut styled = self.into();
361 styled.bg = Some(Color::White);
362 styled
363 }
364 fn on_grey(self) -> Styled<T> {
365 let mut styled = self.into();
366 styled.bg = Some(Color::Grey);
367 styled
368 }
369 fn on_rgb(self, r: u8, g: u8, b: u8) -> Styled<T> {
370 let mut styled = self.into();
371 styled.bg = Some(Color::Rgb(r, g, b));
372 styled
373 }
374 fn on_ansi(self, ansi: u8) -> Styled<T> {
375 let mut styled = self.into();
376 styled.bg = Some(Color::Ansi(ansi));
377 styled
378 }
379
380 fn bold(self) -> Styled<T> {
381 let mut styled = self.into();
382 styled.attributes |= Attributes::BOLD;
383 styled
384 }
385 fn underlined(self) -> Styled<T> {
386 let mut styled = self.into();
387 styled.attributes |= Attributes::UNDERLINED;
388 styled
389 }
390 fn reverse(self) -> Styled<T> {
391 let mut styled = self.into();
392 styled.attributes |= Attributes::REVERSED;
393 styled
394 }
395 fn dim(self) -> Styled<T> {
396 let mut styled = self.into();
397 styled.attributes |= Attributes::DIM;
398 styled
399 }
400 fn italic(self) -> Styled<T> {
401 let mut styled = self.into();
402 styled.attributes |= Attributes::ITALIC;
403 styled
404 }
405 fn slow_blink(self) -> Styled<T> {
406 let mut styled = self.into();
407 styled.attributes |= Attributes::SLOW_BLINK;
408 styled
409 }
410 fn rapid_blink(self) -> Styled<T> {
411 let mut styled = self.into();
412 styled.attributes |= Attributes::RAPID_BLINK;
413 styled
414 }
415 fn hidden(self) -> Styled<T> {
416 let mut styled = self.into();
417 styled.attributes |= Attributes::HIDDEN;
418 styled
419 }
420 fn crossed_out(self) -> Styled<T> {
421 let mut styled = self.into();
422 styled.attributes |= Attributes::CROSSED_OUT;
423 styled
424 }
425}