use regex::Regex;
use std::fmt;
use std::sync::LazyLock;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Hash)]
pub enum EmphasisStyle {
#[default]
Consistent,
Asterisk,
Underscore,
}
impl fmt::Display for EmphasisStyle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EmphasisStyle::Asterisk => write!(f, "asterisk"),
EmphasisStyle::Underscore => write!(f, "underscore"),
EmphasisStyle::Consistent => write!(f, "consistent"),
}
}
}
impl From<&str> for EmphasisStyle {
fn from(s: &str) -> Self {
match s.trim().to_ascii_lowercase().as_str() {
"asterisk" => EmphasisStyle::Asterisk,
"underscore" => EmphasisStyle::Underscore,
_ => EmphasisStyle::Consistent,
}
}
}
pub fn get_emphasis_pattern(style: EmphasisStyle) -> &'static Regex {
static ASTERISK_EMPHASIS: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"\*([^\s*][^*]*?[^\s*]|[^\s*])\*").unwrap());
static UNDERSCORE_EMPHASIS: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"_([^\s_][^_]*?[^\s_]|[^\s_])_").unwrap());
match style {
EmphasisStyle::Asterisk => &ASTERISK_EMPHASIS,
EmphasisStyle::Underscore => &UNDERSCORE_EMPHASIS,
EmphasisStyle::Consistent => &ASTERISK_EMPHASIS, }
}
pub fn get_emphasis_style(marker: &str) -> Option<EmphasisStyle> {
match marker {
"*" => Some(EmphasisStyle::Asterisk),
"_" => Some(EmphasisStyle::Underscore),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_emphasis_style_from_str() {
assert_eq!(EmphasisStyle::from("asterisk"), EmphasisStyle::Asterisk);
assert_eq!(EmphasisStyle::from("underscore"), EmphasisStyle::Underscore);
assert_eq!(EmphasisStyle::from(""), EmphasisStyle::Consistent);
assert_eq!(EmphasisStyle::from("unknown"), EmphasisStyle::Consistent);
}
#[test]
fn test_get_emphasis_pattern() {
let asterisk_pattern = get_emphasis_pattern(EmphasisStyle::Asterisk);
assert!(asterisk_pattern.is_match("*text*"));
assert!(asterisk_pattern.is_match("*t*"));
assert!(!asterisk_pattern.is_match("* text*"));
assert!(!asterisk_pattern.is_match("*text *"));
let underscore_pattern = get_emphasis_pattern(EmphasisStyle::Underscore);
assert!(underscore_pattern.is_match("_text_"));
assert!(underscore_pattern.is_match("_t_"));
assert!(!underscore_pattern.is_match("_ text_"));
assert!(!underscore_pattern.is_match("_text _"));
let consistent_pattern = get_emphasis_pattern(EmphasisStyle::Consistent);
assert!(consistent_pattern.is_match("*text*"));
assert!(!consistent_pattern.is_match("_text_"));
}
#[test]
fn test_get_emphasis_style() {
assert_eq!(get_emphasis_style("*"), Some(EmphasisStyle::Asterisk));
assert_eq!(get_emphasis_style("_"), Some(EmphasisStyle::Underscore));
assert_eq!(get_emphasis_style(""), None);
assert_eq!(get_emphasis_style("**"), None);
assert_eq!(get_emphasis_style("__"), None);
}
}