diff --git a/CHANGELOG.md b/CHANGELOG.md index 19a2b28..00a3ceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Procedure when bumping the version number: ### Added - All emoji known to the vanilla client +- Finding emoji in text - `State` conversion utility methods - `Time::new` constructor diff --git a/src/emoji.rs b/src/emoji.rs index eb610a2..93b3535 100644 --- a/src/emoji.rs +++ b/src/emoji.rs @@ -1,6 +1,7 @@ //! All emoji the vanilla euphoria.io client knows. use std::collections::HashMap; +use std::ops::RangeInclusive; const EMOJI_RAW: &str = include_str!("emoji.txt"); @@ -30,6 +31,34 @@ impl Emoji { .collect(); Self(map) } + + pub fn get(&self, name: &str) -> Option> { + match self.0.get(name) { + Some(Some(replace)) => Some(Some(replace)), + Some(None) => Some(None), + None => None, + } + } + + pub fn find(&self, text: &str) -> Vec<(RangeInclusive, Option<&str>)> { + let mut result = vec![]; + + let mut prev_colon_idx = None; + for (colon_idx, _) in text.match_indices(':') { + if let Some(prev_idx) = prev_colon_idx { + let name = &text[prev_idx + 1..colon_idx]; + if let Some(replace) = self.get(name) { + let range = prev_idx..=colon_idx; + result.push((range, replace)); + prev_colon_idx = None; + continue; + } + } + prev_colon_idx = Some(colon_idx); + } + + result + } } #[cfg(test)] @@ -40,4 +69,22 @@ mod test { fn load_without_panic() { Emoji::load(); } + + #[test] + fn find() { + let emoji = Emoji::load(); + + // :bad: does not exist, while :x: and :o: do. + + assert_eq!(emoji.find(":bad:x:o:"), vec![(4..=6, Some("❌"))]); + assert_eq!( + emoji.find(":x:bad:o:"), + vec![(0..=2, Some("❌")), (6..=8, Some("⭕"))] + ); + assert_eq!(emoji.find("ab:bad:x:o:cd"), vec![(6..=8, Some("❌"))]); + assert_eq!( + emoji.find("ab:x:bad:o:cd"), + vec![(2..=4, Some("❌")), (8..=10, Some("⭕"))] + ); + } }