diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 02e7daa..980aefd 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -17,6 +17,11 @@ pub enum Element<'a> { Text(&'a str), /// #hashtag Tag(&'a str), + /// [label](#tag) + LabelledTag { + label: Box>, + tag: &'a str + }, /// Represents a linebreak - \n Linebreak, Link { diff --git a/src/parser/parse_from_text/text_elements.rs b/src/parser/parse_from_text/text_elements.rs index 5853f82..6279fdc 100644 --- a/src/parser/parse_from_text/text_elements.rs +++ b/src/parser/parse_from_text/text_elements.rs @@ -9,7 +9,7 @@ use nom::{ streaming::take_till1, }, character::complete::char, - combinator::{peek, recognize, verify}, + combinator::{peek, recognize, verify, consumed}, sequence::tuple, AsChar, IResult, Offset, Slice, }; @@ -253,6 +253,20 @@ fn bot_command_suggestion(input: &str) -> IResult<&str, Element, CustomError<&st } } +fn labelled_tag(input: &str) -> IResult<&str, Element, CustomError<&str>> { + let (input, label) = delimited(char('['), is_not("["), char(']'))(input)?; + let (_, label) = parse_text_element(label, None)?; + let (input, tag) = delimited(char('('), is_not("("), char(')'))(input)?; + let (_, tag) = consumed(hashtag)(tag)?; + Ok(( + input, + Element::LabelledTag { + label: Box::new(label), + tag + } + )) +} + pub(crate) fn parse_text_element( input: &str, prev_char: Option, @@ -266,6 +280,8 @@ pub(crate) fn parse_text_element( if let Ok((i, elm)) = hashtag(input) { Ok((i, elm)) + } else if let Ok((i, elm)) = labelled_tag(input) { + Ok((i, elm)) } else if let Ok((i, elm)) = { if prev_char == Some(' ') || prev_char.is_none() { bot_command_suggestion(input) diff --git a/tests/text_to_ast/mod.rs.orig b/tests/text_to_ast/mod.rs.orig deleted file mode 100644 index a1a809d..0000000 --- a/tests/text_to_ast/mod.rs.orig +++ /dev/null @@ -1,63 +0,0 @@ -use deltachat_message_parser::parser::Element::*; -use deltachat_message_parser::parser::LinkDestination; - -fn gopher_link_no_puny<'a>(target: &'a str, hostname: &'a str) -> LinkDestination<'a> { - LinkDestination { - target, - hostname: Some(hostname), - scheme: "gopher", - punycode: None, - } -} - -<<<<<<< HEAD -======= -fn internal_link(target: &str) -> LinkDestination<'_> { - LinkDestination { - target, - hostname: None, - scheme: "", - punycode: None, - } -} - ->>>>>>> a0203f4363e504cbe5d32a846a9c8770d6442cf7 -fn http_link_no_puny<'a>(target: &'a str, hostname: &'a str) -> LinkDestination<'a> { - LinkDestination { - target, - hostname: Some(hostname), - scheme: "http", - punycode: None, - } -} - -fn ftp_link_no_puny<'a>(target: &'a str, hostname: &'a str) -> LinkDestination<'a> { - LinkDestination { - target, - hostname: Some(hostname), - scheme: "ftp", - punycode: None, - } -} - -fn https_link_no_puny<'a>(target: &'a str, hostname: &'a str) -> LinkDestination<'a> { - LinkDestination { - target, - hostname: Some(hostname), - scheme: "https", - punycode: None, - } -} - -fn mailto_link_no_puny(target: &str) -> LinkDestination<'_> { - LinkDestination { - target, - hostname: None, - scheme: "mailto", - punycode: None, - } -} - -mod desktop_set; -mod markdown; -mod text_only; diff --git a/tests/text_to_ast/text_only.rs b/tests/text_to_ast/text_only.rs index 09b6c40..1866328 100644 --- a/tests/text_to_ast/text_only.rs +++ b/tests/text_to_ast/text_only.rs @@ -173,6 +173,34 @@ fn persian_hashtag_with_underline() { ); } +#[test] +fn labelled_hashtag() { + let input = "[Hello](#hello) #world"; + + assert_eq!( + parse_only_text(input), + vec![ + LabelledTag { + label: vec![Text("Hello")], + tag: "#hello", + }, + Tag("#world"), + ] + ); + + let input_bold = "[**Hello**](#hi) "; + assert_eq!( + parse_only_text(input_bold), + vec![ + LaballedTag { + label: vec![Bold(vec![Text(Hello)])], + tag: "#hi", + }, + Text(" ") + ] + ); +} + #[test] fn email_address_standalone() { let test_cases = vec![