Mention parsing

This commit is contained in:
Natty 2023-10-05 20:05:03 +02:00
parent 9b26691ff4
commit 52dc491a47
Signed by: natty
GPG Key ID: BF6CB659ADEE60EC
1 changed files with 66 additions and 1 deletions

View File

@ -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<Cow<'a, str>, Option<Cow<'a, str>>>,
inner: Box<Token<'a>>,
},
Mention {
name: Cow<'a, str>,
host: Option<Cow<'a, str>>,
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<Span<'a>, 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]