use regex::Regex;
use std::sync::LazyLock;
static ICON_SHORTCODE_PATTERN: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r":([a-z][a-z0-9_]*(?:-[a-z0-9_]+)+):").unwrap());
static EMOJI_SHORTCODE_PATTERN: LazyLock<Regex> = LazyLock::new(|| Regex::new(r":([a-zA-Z0-9_+-]+):").unwrap());
pub fn is_in_any_shortcode(line: &str, position: usize) -> bool {
if !line.contains(':') {
return false;
}
for m in ICON_SHORTCODE_PATTERN.find_iter(line) {
if m.start() <= position && position < m.end() {
return true;
}
}
for m in EMOJI_SHORTCODE_PATTERN.find_iter(line) {
if m.start() <= position && position < m.end() {
return true;
}
}
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_in_any_shortcode_emoji() {
let line = ":smile: and :material-check:";
assert!(is_in_any_shortcode(line, 0));
assert!(is_in_any_shortcode(line, 3));
assert!(is_in_any_shortcode(line, 6));
}
#[test]
fn test_is_in_any_shortcode_between() {
let line = ":smile: and :material-check:";
assert!(!is_in_any_shortcode(line, 7));
assert!(!is_in_any_shortcode(line, 10));
}
#[test]
fn test_is_in_any_shortcode_icon() {
let line = ":smile: and :material-check:";
assert!(is_in_any_shortcode(line, 12));
assert!(is_in_any_shortcode(line, 20));
}
#[test]
fn test_is_in_any_shortcode_no_colon() {
assert!(!is_in_any_shortcode("plain text", 3));
}
}