/ ust / style.rs
style.rs
  1  use std::fmt;
  2  
  3  use derive_more::{
  4     Deref,
  5     DerefMut,
  6  };
  7  use enumflags2::{
  8     BitFlags,
  9     bitflags,
 10  };
 11  
 12  use crate::{
 13     Display,
 14     Write,
 15     with,
 16  };
 17  
 18  #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
 19  pub enum Color {
 20     #[default]
 21     Primary,
 22     Fixed(u8),
 23     Rgb(u8, u8, u8),
 24     Black,
 25     Red,
 26     Green,
 27     Yellow,
 28     Blue,
 29     Magenta,
 30     Cyan,
 31     White,
 32     BrightBlack,
 33     BrightRed,
 34     BrightGreen,
 35     BrightYellow,
 36     BrightBlue,
 37     BrightMagenta,
 38     BrightCyan,
 39     BrightWhite,
 40  }
 41  
 42  impl Color {
 43     #[must_use]
 44     pub const fn fg(self) -> Style {
 45        Style::new().fg(self)
 46     }
 47  
 48     #[must_use]
 49     pub const fn bg(self) -> Style {
 50        Style::new().bg(self)
 51     }
 52  }
 53  
 54  #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 55  #[bitflags]
 56  #[repr(u16)]
 57  pub enum Attr {
 58     Bold       = 1 << 0,
 59     Dim        = 1 << 1,
 60     Italic     = 1 << 2,
 61     Underline  = 1 << 3,
 62     Blink      = 1 << 4,
 63     RapidBlink = 1 << 5,
 64     Invert     = 1 << 6,
 65     Conceal    = 1 << 7,
 66     Strike     = 1 << 8,
 67  }
 68  
 69  impl Attr {
 70     #[must_use]
 71     pub const fn style(self) -> Style {
 72        Style::new().attr(self)
 73     }
 74  }
 75  
 76  #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
 77  pub struct Style {
 78     pub fg:    Color,
 79     pub bg:    Color,
 80     pub attrs: BitFlags<Attr>,
 81  }
 82  
 83  macro_rules! set {
 84     ($($name:ident : $field:ident $symbol:tt $value:expr;)*) => {
 85        $(
 86           #[must_use]
 87           pub const fn $name(mut self) -> Style {
 88              self.$field $symbol $value;
 89              self
 90           }
 91        )*
 92     };
 93  }
 94  
 95  macro_rules! set_attr {
 96     ($($name:ident : $attr:expr;)*) => {
 97        $(
 98           #[must_use]
 99           pub const fn $name(mut self) -> Style {
100              self.attrs = self.attrs.union_c(BitFlags::<Attr>::from_bits_truncate_c(
101                 $attr as u16,
102                 BitFlags::CONST_TOKEN,
103              ));
104              self
105           }
106        )*
107     };
108  }
109  
110  impl Style {
111     #[must_use]
112     pub const fn new() -> Self {
113        Self {
114           fg:    Color::Primary,
115           bg:    Color::Primary,
116           attrs: BitFlags::EMPTY,
117        }
118     }
119  
120     #[must_use]
121     pub const fn fg(mut self, color: Color) -> Self {
122        self.fg = color;
123        self
124     }
125  
126     #[must_use]
127     pub const fn unfg(mut self) -> Self {
128        self.fg = Color::Primary;
129        self
130     }
131  
132     #[must_use]
133     pub const fn bg(mut self, color: Color) -> Self {
134        self.bg = color;
135        self
136     }
137  
138     #[must_use]
139     pub const fn unbg(mut self) -> Self {
140        self.bg = Color::Primary;
141        self
142     }
143  
144     #[must_use]
145     pub const fn attr(mut self, attr: Attr) -> Self {
146        self.attrs = self.attrs.union_c(BitFlags::<Attr>::from_bits_truncate_c(
147           attr as u16,
148           BitFlags::CONST_TOKEN,
149        ));
150        self
151     }
152  
153     #[must_use]
154     pub const fn unattr(mut self, attr: Attr) -> Self {
155        self.attrs = self.attrs.intersection_c(
156           BitFlags::<Attr>::from_bits_truncate_c(attr as u16, BitFlags::CONST_TOKEN)
157              .not_c(BitFlags::CONST_TOKEN),
158        );
159        self
160     }
161  
162     #[must_use]
163     pub const fn fixed(mut self, color: u8) -> Self {
164        self.fg = Color::Fixed(color);
165        self
166     }
167  
168     #[must_use]
169     pub const fn on_fixed(mut self, color: u8) -> Self {
170        self.bg = Color::Fixed(color);
171        self
172     }
173  
174     #[must_use]
175     pub const fn rgb(mut self, r: u8, g: u8, b: u8) -> Self {
176        self.fg = Color::Rgb(r, g, b);
177        self
178     }
179  
180     #[must_use]
181     pub const fn on_rgb(mut self, r: u8, g: u8, b: u8) -> Self {
182        self.bg = Color::Rgb(r, g, b);
183        self
184     }
185  
186     set! {
187        black:   fg = Color::Black;
188        red:     fg = Color::Red;
189        green:   fg = Color::Green;
190        yellow:  fg = Color::Yellow;
191        blue:    fg = Color::Blue;
192        magenta: fg = Color::Magenta;
193        cyan:    fg = Color::Cyan;
194        white:   fg = Color::White;
195  
196        on_black:   bg = Color::Black;
197        on_red:     bg = Color::Red;
198        on_green:   bg = Color::Green;
199        on_yellow:  bg = Color::Yellow;
200        on_blue:    bg = Color::Blue;
201        on_magenta: bg = Color::Magenta;
202        on_cyan:    bg = Color::Cyan;
203        on_white:   bg = Color::White;
204  
205        bright_black:   fg = Color::BrightBlack;
206        bright_red:     fg = Color::BrightRed;
207        bright_green:   fg = Color::BrightGreen;
208        bright_yellow:  fg = Color::BrightYellow;
209        bright_blue:    fg = Color::BrightBlue;
210        bright_magenta: fg = Color::BrightMagenta;
211        bright_cyan:    fg = Color::BrightCyan;
212        bright_white:   fg = Color::BrightWhite;
213  
214        on_bright_black:   bg = Color::BrightBlack;
215        on_bright_red:     bg = Color::BrightRed;
216        on_bright_green:   bg = Color::BrightGreen;
217        on_bright_yellow:  bg = Color::BrightYellow;
218        on_bright_blue:    bg = Color::BrightBlue;
219        on_bright_magenta: bg = Color::BrightMagenta;
220        on_bright_cyan:    bg = Color::BrightCyan;
221        on_bright_white:   bg = Color::BrightWhite;
222     }
223  
224     set_attr! {
225        bold:        Attr::Bold;
226        dim:         Attr::Dim;
227        italic:      Attr::Italic;
228        underline:   Attr::Underline;
229        blink:       Attr::Blink;
230        rapid_blink: Attr::RapidBlink;
231        invert:      Attr::Invert;
232        conceal:     Attr::Conceal;
233        strike:      Attr::Strike;
234     }
235  }
236  
237  #[derive(Deref, DerefMut, Debug, Clone, PartialEq, Eq)]
238  pub struct Styled<T> {
239     #[deref]
240     #[deref_mut]
241     pub value: T,
242     pub style: Style,
243  }
244  
245  macro_rules! styled {
246     ($($method:ident),* $(,)?) => {
247        $(
248           #[must_use]
249           pub const fn $method(mut self) -> Self {
250              self.style = self.style.$method();
251              self
252           }
253        )*
254     };
255  }
256  
257  impl<T> Styled<T> {
258     pub const fn new(value: T) -> Self {
259        Self {
260           value,
261           style: Style::new(),
262        }
263     }
264  
265     #[must_use]
266     pub const fn fg(mut self, color: Color) -> Self {
267        self.style = self.style.fg(color);
268        self
269     }
270  
271     #[must_use]
272     pub const fn bg(mut self, color: Color) -> Self {
273        self.style = self.style.bg(color);
274        self
275     }
276  
277     #[must_use]
278     pub const fn attr(mut self, attr: Attr) -> Self {
279        self.style = self.style.attr(attr);
280        self
281     }
282  
283     #[must_use]
284     pub const fn fixed(mut self, color: u8) -> Self {
285        self.style = self.style.fixed(color);
286        self
287     }
288  
289     #[must_use]
290     pub const fn on_fixed(mut self, color: u8) -> Self {
291        self.style = self.style.on_fixed(color);
292        self
293     }
294  
295     #[must_use]
296     pub const fn rgb(mut self, r: u8, g: u8, b: u8) -> Self {
297        self.style = self.style.rgb(r, g, b);
298        self
299     }
300  
301     #[must_use]
302     pub const fn on_rgb(mut self, r: u8, g: u8, b: u8) -> Self {
303        self.style = self.style.on_rgb(r, g, b);
304        self
305     }
306  
307     styled! {
308        black,
309        red,
310        green,
311        yellow,
312        blue,
313        magenta,
314        cyan,
315        white,
316  
317        on_black,
318        on_red,
319        on_green,
320        on_yellow,
321        on_blue,
322        on_magenta,
323        on_cyan,
324        on_white,
325  
326        bright_black,
327        bright_red,
328        bright_green,
329        bright_yellow,
330        bright_blue,
331        bright_magenta,
332        bright_cyan,
333        bright_white,
334  
335        on_bright_black,
336        on_bright_red,
337        on_bright_green,
338        on_bright_yellow,
339        on_bright_blue,
340        on_bright_magenta,
341        on_bright_cyan,
342        on_bright_white,
343  
344        bold,
345        dim,
346        italic,
347        underline,
348        blink,
349        rapid_blink,
350        invert,
351        conceal,
352        strike,
353     }
354  }
355  
356  macro_rules! wrap_styled {
357     ($($method:ident),* $(,)?) => {
358        $(
359           #[must_use]
360           fn $method(self) -> Styled<Self> {
361              let mut styled = self.styled();
362              styled.style = styled.style.$method();
363              styled
364           }
365        )*
366     };
367  }
368  
369  impl<D: fmt::Display> Display for Styled<D> {
370     fn display_styled(&self, writer: &mut dyn Write) -> fmt::Result {
371        with(writer, self.style, |writer| {
372           write!(writer, "{value}", value = **self)
373        })
374     }
375  }
376  
377  pub trait StyledExt
378  where
379     Self: Sized,
380  {
381     fn styled(self) -> Styled<Self> {
382        Styled::new(self)
383     }
384  
385     fn style(self, style: Style) -> Styled<Self> {
386        let mut styled = self.styled();
387        styled.style = style;
388        styled
389     }
390  
391     #[must_use]
392     fn fg(self, color: Color) -> Styled<Self> {
393        let mut styled = self.styled();
394        styled.style = styled.style.fg(color);
395        styled
396     }
397  
398     #[must_use]
399     fn bg(self, color: Color) -> Styled<Self> {
400        let mut styled = self.styled();
401        styled.style = styled.style.bg(color);
402        styled
403     }
404  
405     #[must_use]
406     fn attr(self, attr: Attr) -> Styled<Self> {
407        let mut styled = self.styled();
408        styled.style = styled.style.attr(attr);
409        styled
410     }
411  
412     #[must_use]
413     fn fixed(self, color: u8) -> Styled<Self> {
414        let mut styled = self.styled();
415        styled.style = styled.style.fixed(color);
416        styled
417     }
418  
419     #[must_use]
420     fn on_fixed(self, color: u8) -> Styled<Self> {
421        let mut styled = self.styled();
422        styled.style = styled.style.on_fixed(color);
423        styled
424     }
425  
426     #[must_use]
427     fn rgb(self, r: u8, g: u8, b: u8) -> Styled<Self> {
428        let mut styled = self.styled();
429        styled.style = styled.style.rgb(r, g, b);
430        styled
431     }
432  
433     #[must_use]
434     fn on_rgb(self, r: u8, g: u8, b: u8) -> Styled<Self> {
435        let mut styled = self.styled();
436        styled.style = styled.style.on_rgb(r, g, b);
437        styled
438     }
439  
440     wrap_styled! {
441        black,
442        red,
443        green,
444        yellow,
445        blue,
446        magenta,
447        cyan,
448        white,
449  
450        on_black,
451        on_red,
452        on_green,
453        on_yellow,
454        on_blue,
455        on_magenta,
456        on_cyan,
457        on_white,
458  
459        bright_black,
460        bright_red,
461        bright_green,
462        bright_yellow,
463        bright_blue,
464        bright_magenta,
465        bright_cyan,
466        bright_white,
467  
468        on_bright_black,
469        on_bright_red,
470        on_bright_green,
471        on_bright_yellow,
472        on_bright_blue,
473        on_bright_magenta,
474        on_bright_cyan,
475        on_bright_white,
476  
477        bold,
478        dim,
479        italic,
480        underline,
481        blink,
482        rapid_blink,
483        invert,
484        conceal,
485        strike,
486     }
487  }
488  
489  impl<T> StyledExt for T {}