From 52dc491a47cd8c5a62a24b4ad03dda2e928df513 Mon Sep 17 00:00:00 2001 From: Natty Date: Thu, 5 Oct 2023 20:05:03 +0200 Subject: [PATCH] Mention parsing --- magnetar_mmm_parser/src/lib.rs | 67 +++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/magnetar_mmm_parser/src/lib.rs b/magnetar_mmm_parser/src/lib.rs index 62d7116..d4e9d6e 100644 --- a/magnetar_mmm_parser/src/lib.rs +++ b/magnetar_mmm_parser/src/lib.rs @@ -4,7 +4,7 @@ use nom::character::complete::{ alpha1, alphanumeric1, anychar, char as one_char, line_ending, not_line_ending, one_of, space1, tab, }; -use nom::combinator::{eof, fail, not, opt, recognize}; +use nom::combinator::{eof, fail, map, not, opt, recognize}; use nom::error::ErrorKind; use nom::multi::{many0, many0_count, many1, many1_count, separated_list1}; use nom::sequence::tuple; @@ -13,6 +13,21 @@ use nom_locate::LocatedSpan; use std::borrow::Cow; use std::collections::HashMap; +#[derive(Copy, Clone, Debug)] +pub enum MentionType { + Community, + User, +} + +impl MentionType { + pub fn to_char(&self) -> char { + match self { + MentionType::Community => '!', + MentionType::User => '@', + } + } +} + #[derive(Clone, Debug)] pub enum Token<'a> { PlainText(Cow<'a, str>), @@ -45,6 +60,11 @@ pub enum Token<'a> { params: HashMap, Option>>, inner: Box>, }, + Mention { + name: Cow<'a, str>, + host: Option>, + mention_type: MentionType, + }, } impl Token<'_> { @@ -92,6 +112,15 @@ impl Token<'_> { .collect(), inner: Box::new(inner.owned()), }, + Token::Mention { + name, + host, + mention_type, + } => Token::Mention { + name: Cow::Owned(name.clone().into_owned()), + host: host.as_ref().map(|v| Cow::Owned(v.clone().into_owned())), + mention_type: *mention_type, + }, } } } @@ -613,6 +642,42 @@ impl Context { }, )) } + + fn mention<'a>(&self, input: Span<'a>) -> IResult, Token<'a>> { + // TODO: Escaping and skip when preceded by alphanumerics + + let tags = one_of("@!"); + let (input, mention_type) = map(tags, |c| match c { + '@' => MentionType::User, + '!' => MentionType::Community, + _ => unreachable!(), + })(input)?; + + let (input, name) = map( + recognize(many1(alt((alphanumeric1, recognize(one_of("-_")))))), + Span::into_fragment, + )(input)?; + + let (input, 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)?; + + Ok(( + input, + Token::Mention { + mention_type, + name: name.into(), + host: host.map(|h| h.into()), + }, + )) + } } #[inline]