diff --git a/magnetar_mmm_parser/src/lib.rs b/magnetar_mmm_parser/src/lib.rs index 52c5e84..fc9b06d 100644 --- a/magnetar_mmm_parser/src/lib.rs +++ b/magnetar_mmm_parser/src/lib.rs @@ -29,6 +29,7 @@ use unicode_segmentation::UnicodeSegmentation; pub enum MentionType { Community, User, + MatrixUser, } impl MentionType { @@ -36,6 +37,14 @@ impl MentionType { match self { MentionType::Community => '!', MentionType::User => '@', + MentionType::MatrixUser => ':', + } + } + + pub fn separator(&self) -> char { + match self { + MentionType::Community | MentionType::User => '@', + MentionType::MatrixUser => ':', } } } @@ -1460,7 +1469,6 @@ impl Context { return Ok((plain_out, Token::PlainText(plain.into()))); } - let start = input; let tags = one_of("@!"); let (input, mention_type) = map(tags, |c| match c { '@' => MentionType::User, @@ -1474,29 +1482,28 @@ impl Context { )(input)?; let before = input; - let (_, host) = map( - opt(tuple(( - tag("@"), - map( - recognize(many1(alt((alphanumeric1, recognize(one_of("-_.")))))), - Span::into_fragment, - ), - ))), - |maybe_tag_host| maybe_tag_host.map(|(_, host)| host), - )(input)?; + let (_, host_opt) = opt(tuple(( + one_of(if matches!(mention_type, MentionType::User) { + "@:" + } else { + "@" + }), + map( + recognize(many1(alt((alphanumeric1, recognize(one_of("-_.")))))), + Span::into_fragment, + ), + )))(input)?; - let host = host.map(|h| h.trim_end_matches(|c| matches!(c, '.' | '-' | '_'))); + // Promote tags with a colon separator to Matrix handles + let mention_type = if let Some((':', _)) = host_opt { + MentionType::MatrixUser + } else { + mention_type + }; + let host = + host_opt.map(|(_, name)| name.trim_end_matches(|c| matches!(c, '.' | '-' | '_'))); let input = host.map(|c| before.slice(c.len() + 1..)).unwrap_or(before); - if let (input, Some(_)) = - peek(opt(tuple((recognize(tag(":")), alphanumeric1_unicode))))(input)? - { - return Ok(( - input, - Token::PlainText(start.up_to(&input).into_fragment().into()), - )); - } - Ok(( input, Token::Mention { @@ -2182,7 +2189,11 @@ text"# assert_eq!( parse_full("@tag:domain.com"), - Token::PlainText("@tag:domain.com".into()) + Token::Mention { + mention_type: crate::MentionType::MatrixUser, + name: "tag".into(), + host: Some("domain.com".into()) + }, ); }