node_emoji/
lib.rs

1use regex::{Captures, Regex};
2use std::borrow::Cow;
3
4#[cfg(feature = "emojidb")]
5mod data_generated_expanded;
6#[cfg(feature = "emojidb")]
7use crate::data_generated_expanded::EMOJI;
8
9#[cfg(not(feature = "emojidb"))]
10mod data_generated_genmoji;
11#[cfg(not(feature = "emojidb"))]
12use crate::data_generated_genmoji::EMOJI;
13
14/// Find Unicode representation for given emoji name
15///
16/// The name should be without `:`, e.g. `smile`.
17///
18/// Case sensitive. Returns `None` if the name is not recognized.
19pub fn get(name: &str) -> Option<&str> {
20    EMOJI.get(name).map(|s| *s)
21}
22
23/// List all known emoji
24///
25/// Returns iterator of `(name, unicode)`
26pub fn all() -> impl Iterator<Item = (&'static str, &'static str)> {
27    EMOJI.entries.iter().map(|&x| x)
28}
29
30/// Replaces `:emoji:` in strings
31///
32/// ```rust
33/// let r = gh_emoji_expanded::Replacer::new();
34/// let unicode_text = r.replace_all("Hello :cat:!");
35/// ```
36pub struct Replacer {
37    regex: Regex,
38}
39
40impl Replacer {
41    /// There is some small setup cost
42    pub fn new() -> Self {
43        Self {
44            regex: Regex::new(r":([a-z1238+-][a-z0-9_-]*):").unwrap(),
45        }
46    }
47
48    /// Replaces all occurrences of `:emoji_names:` in the string
49    ///
50    /// It may return `Cow::Borrowed` if there were no emoji-like
51    /// patterns in the string. Call `.to_string()` if you need
52    /// `String` or `.as_ref()` to get `&str`.
53    pub fn replace_all<'a>(&self, text: &'a str) -> Cow<'a, str> {
54        self.regex.replace_all(text, EmojiRegexReplacer)
55    }
56}
57
58struct EmojiRegexReplacer;
59impl regex::Replacer for EmojiRegexReplacer {
60    fn replace_append(&mut self, capts: &Captures<'_>, dst: &mut String) {
61        dst.push_str(EMOJI.get(&capts[1]).copied().unwrap_or_else(|| &capts[0]));
62    }
63}
64
65#[test]
66fn replacer() {
67    let r = Replacer::new();
68    assert_eq!(
69        "hello 😄 :not_emoji_404:",
70        r.replace_all("hello :smile: :not_emoji_404:")
71    );
72    assert_eq!(
73        Replacer::new().replace_all(":cat: make me :smile:"),
74        "\u{01F431} make me \u{01F604}"
75    );
76}
77
78#[test]
79fn get_existing() {
80    assert_eq!(get("smile"), Some("\u{01F604}"));
81    assert_eq!(get("poop"), Some("\u{01F4A9}"));
82    assert_eq!(get("cat"), Some("\u{01F431}"));
83    assert_eq!(get("+1"), Some("👍"));
84    assert_eq!(get("-1"), Some("\u{01F44E}"));
85    assert_eq!(get("8ball"), Some("\u{01F3B1}"));
86}
87
88#[test]
89fn get_nonexistent() {
90    assert_eq!(get("stuff"), None);
91    assert_eq!(get("++"), None);
92    assert_eq!(get("--"), None);
93    assert_eq!(get("666"), None);
94}
95
96#[cfg(not(feature = "emojidb"))]
97mod genmoji_only_tests {
98    #[test]
99    fn get_nonexistent() {
100        assert_eq!(super::get("robot_face"), None);
101    }
102}
103
104#[cfg(feature = "emojidb")]
105mod emojidb_only_tests {
106    #[test]
107    fn get_emojidb_only_codes() {
108        assert_eq!(super::get("robot_face"), Some("🤖"));
109    }
110}