Skip to main content

cba/bog/
fmt.rs

1// ----- MESSAGE FORMATTING --------
2
3#[derive(Clone, Copy, Debug)]
4pub enum BogLevel {
5    ///
6    NOTE,
7    ERROR,
8    WARN,
9    INFO,
10    /// Low priority warn
11    _WRN,
12    /// Low priority info
13    _NFO,
14    DEBUG,
15    EMPTY,
16    /// A "never" level.
17    ///
18    /// # Note
19    /// This should be kept at priority 0 in [`BogFmter::priority`].
20    ___,
21
22    CUSTOM(&'static str), // e.g. trace
23}
24
25/// Trait for formatting bog messages, passed to [`init_with`]
26///
27/// Also see: [`Fg`] and [`Bg`].
28pub trait BogFmter {
29    fn tag(&self, level: BogLevel, tag: &str) -> String;
30
31    fn format(&self, level: BogLevel, tag: &str, msg: &str) -> String {
32        let mut s = self.tag(level, tag);
33
34        if !msg.is_empty() {
35            s.push(' ');
36            s.push_str(msg);
37        }
38
39        s
40    }
41
42    /// Order the levels with numeric values.
43    /// The values are used for [`downcasting`](super::BOGGER::downcast_above) and [`filtering`](super::BOGGER::filter_below).
44    ///
45    /// Note that the value of [`BogLevel::___`] is expected to be 0.
46    fn priority(&self, level: &BogLevel) -> u8 {
47        match level {
48            BogLevel::NOTE => 120,
49            BogLevel::ERROR => 100,
50            BogLevel::WARN => 80,
51            BogLevel::INFO => 60,
52            BogLevel::DEBUG => 20,
53            BogLevel::___ => 0, // don't change
54
55            // usually you'll want to change these
56            BogLevel::_WRN | BogLevel::_NFO => 40,
57            BogLevel::EMPTY => 120,
58            BogLevel::CUSTOM(_) => 120,
59        }
60    }
61}
62
63// -------- IMPL ---------
64pub struct Fg {}
65impl BogFmter for Fg {
66    fn tag(&self, level: BogLevel, tag: &str) -> String {
67        let (code, lvl) = match level {
68            BogLevel::NOTE => ("34", "NOTE"),                  // blue
69            BogLevel::ERROR => ("31", "ERRO"),                 // red
70            BogLevel::WARN | BogLevel::_WRN => ("33", "WARN"), // yellow
71            BogLevel::INFO | BogLevel::_NFO => ("32", "INFO"), // green
72            BogLevel::DEBUG => ("35", "DBUG"),                 // magenta
73            BogLevel::EMPTY => ("30", ""),                     // black
74            BogLevel::___ => ("", ""),                         // unreachable
75            BogLevel::CUSTOM(s) => ("34", s),                  // blue
76        };
77        let mut s = format!("\x1b[{code}m[{lvl}");
78        if !tag.is_empty() {
79            s.push_str(": ");
80            s.push_str(tag);
81        } else if matches!(level, BogLevel::EMPTY) {
82            s.push_str(tag);
83        };
84
85        s.push_str("]\x1b[0m");
86        s
87    }
88}
89
90pub struct Bg {}
91impl BogFmter for Bg {
92    fn tag(&self, level: BogLevel, tag: &str) -> String {
93        let (code, lvl) = match level {
94            BogLevel::NOTE => ("44", "NOTE "),                  // blue
95            BogLevel::ERROR => ("41", "ERROR"),                 // red
96            BogLevel::WARN | BogLevel::_WRN => ("43", "WARN "), // yellow
97            BogLevel::INFO | BogLevel::_NFO => ("42", "INFO "), // green
98            BogLevel::DEBUG => ("45", "DEBUG"),                 // purple
99            BogLevel::EMPTY => ("47", ""),                      // white
100            BogLevel::___ => ("", ""),                          // unreachable
101            BogLevel::CUSTOM(s) => ("44", s),                   // blue
102        };
103
104        let mut start = format!("\x1b[30;{code}m{lvl}"); // colored bg with black text (white also looks bad/worse)
105        if !tag.is_empty() {
106            start.push_str("| ");
107            start.push_str(tag);
108        } else if matches!(level, BogLevel::EMPTY) {
109            start.push_str(tag);
110        };
111        start.push_str(" \x1b[0m");
112
113        start
114    }
115}