1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! Contains icons that can be used when
//! outputting to the terminal. All icons are printable
//! and can be converted to strings.
//!
//! There are no tags that can be used
//! in log strings on the other hand. So you can't
//! write `<info>` in a string and expect it to
//! be replaced with the info icon.
use super::keys::FromKey;
use std::fmt::{Display, Formatter, Result as DisplayResult};
use std::str::FromStr;

/// Contains definitions for icons that can be
/// used in the terminal. See [this github repo](https://github.com/sindresorhus/figures)
/// for an entire list. Use this in combination with printing macros.
pub enum LogIcon {
    /// A check mark, use when things go well
    ///
    /// # Example
    /// ```
    /// use paris::LogIcon;
    ///
    /// println!("{} Everything went well", LogIcon::Tick);
    /// // ✔ Everything went well
    /// ```
    Tick,

    /// A cross, use when things go bad, or be creative
    ///
    /// # Example
    /// ```
    /// # use paris::LogIcon;
    /// println!("{} Oops, try again!", LogIcon::Cross);
    /// // ✖ Oops, try again!
    /// ```
    Cross,

    /// A fancy 'i', for information
    ///
    /// # Example
    /// ```
    /// # use paris::LogIcon;
    /// println!("{} In Switzerland it is illegal to own just one guinea pig", LogIcon::Info);
    /// // ℹ In Switzerland it is illegal to own just one guinea pig.
    /// ```
    Info,

    /// A triangle with an exclamation mark in it, dangerous
    ///
    /// # Example
    /// ```
    /// # use paris::LogIcon;
    /// println!("{} Things are starting to catch fire!", LogIcon::Warning);
    /// // ⚠ Things are starting to catch fire!
    /// ```
    Warning,

    /// ❤️🦄
    /// # Example
    /// ```
    /// // You get it...
    /// ```
    Heart,

    /// No icon. Empty string. Nada.
    /// This is here to return something
    /// for the parser when it doesn't match
    /// any given keys
    None,
}

impl LogIcon {
    /// Match the enum value and return the equivalent icon.
    /// See [this github repo](https://github.com/sindresorhus/figures)
    /// for all icons
    pub fn to_str<'a>(&self) -> &'a str {
        match self {
            LogIcon::Info => "ℹ",
            LogIcon::Cross => "✖",
            LogIcon::Warning => "⚠",
            LogIcon::Tick => "✔",
            LogIcon::Heart => "♥",
            LogIcon::None => "",
        }
    }
}

impl Display for LogIcon {
    fn fmt(&self, f: &mut Formatter<'_>) -> DisplayResult {
        write!(f, "{}", self.to_str())
    }
}

impl<'a> From<&'a str> for LogIcon {
    fn from(s: &'a str) -> Self {
        s.parse().unwrap_or(LogIcon::None)
    }
}

impl FromStr for LogIcon {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let s = s.to_lowercase();

        match s.as_ref() {
            "info" => Ok(LogIcon::Info),
            "cross" => Ok(LogIcon::Cross),
            "warn" => Ok(LogIcon::Warning),
            "tick" => Ok(LogIcon::Tick),
            "heart" => Ok(LogIcon::Heart),
            _ => Err(()),
        }
    }
}

impl FromKey for LogIcon {
    fn from_key(key: &str) -> Option<String> {
        let i = LogIcon::from(key);

        match i {
            LogIcon::None => None,
            _ => Some(i.to_string()),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    macro_rules! icon_test {
        ($name:ident, $value:expr) => {
            #[test]
            fn $name() {
                let v = String::from(stringify!($name));
                let c = LogIcon::from_key(&v).unwrap();

                assert_eq!(c, $value);
            }
        };
    }

    icon_test!(tick, "✔");
    icon_test!(cross, "✖");
    icon_test!(info, "ℹ");
    icon_test!(warn, "⚠");
    icon_test!(heart, "♥");
}