diff --git a/src/parser/plain_link.rs b/src/parser/plain_link.rs index 3fd26a2..aa4f1a2 100644 --- a/src/parser/plain_link.rs +++ b/src/parser/plain_link.rs @@ -3,9 +3,11 @@ use nom::bytes::complete::is_not; use nom::bytes::complete::tag; use nom::bytes::complete::tag_no_case; use nom::bytes::complete::take; +use nom::bytes::complete::take_until; use nom::character::complete::anychar; use nom::character::complete::none_of; use nom::character::complete::one_of; +use nom::combinator::all_consuming; use nom::combinator::consumed; use nom::combinator::eof; use nom::combinator::flat_map; @@ -127,6 +129,44 @@ pub(crate) fn parse_file_and_application<'s>( Ok((remaining, application)) } +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +pub(crate) fn parse_path_and_search_option<'s>( + input: OrgSource<'s>, +) -> Res, (OrgSource<'s>, Option>)> { + alt(( + all_consuming(parse_path_and_search_option_with_search_option), + all_consuming(parse_path_and_search_option_without_search_option), + ))(input) +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +pub(crate) fn parse_path_and_search_option_with_search_option<'s>( + input: OrgSource<'s>, +) -> Res, (OrgSource<'s>, Option>)> { + let (remaining, path) = take_until("::")(input)?; + let (remaining, search_option) = opt(map( + tuple(( + tag("::"), + verify(is_not(" \t\r\n"), |search_option| { + Into::<&str>::into(search_option) + .chars() + .any(char::is_alphanumeric) + }), + )), + |(_, search_option)| search_option, + ))(remaining)?; + // Assert we consumed the entire protocol. + not(anychar)(remaining)?; + Ok((remaining, (path, search_option))) +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +pub(crate) fn parse_path_and_search_option_without_search_option<'s>( + input: OrgSource<'s>, +) -> Res, (OrgSource<'s>, Option>)> { + map(rest, |path| (path, None))(input) +} + #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn file_path_plain<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, @@ -138,30 +178,23 @@ fn file_path_plain<'b, 'g, 'r, 's>( exit_matcher: &path_plain_end, }); let parser_context = context.with_additional_node(&parser_context); - let (remaining, (raw_link, (_, application, _, _, path, search_option))) = consumed(tuple(( - peek(tag("file")), - map_parser( - parser_with_context!(protocol)(&parser_context), - parse_file_and_application, - ), - tag(":"), - opt(flat_map( - peek(map(verify(many1_count(tag("/")), |c| *c >= 3), |c| c - 1)), - take, - )), - parser_with_context!(path_plain)(&parser_context), - opt(map( - tuple(( - tag("::"), - verify(is_not(" \t\r\n"), |search_option| { - Into::<&str>::into(search_option) - .chars() - .any(char::is_alphanumeric) - }), + let (remaining, (raw_link, (_, application, _, _, (path, search_option)))) = + consumed(tuple(( + peek(tag("file")), + map_parser( + parser_with_context!(protocol)(&parser_context), + parse_file_and_application, + ), + tag(":"), + opt(flat_map( + peek(map(verify(many1_count(tag("/")), |c| *c >= 3), |c| c - 1)), + take, )), - |(_, search_option)| search_option, - )), - )))(input)?; + map_parser( + parser_with_context!(path_plain)(&parser_context), + parse_path_and_search_option, + ), + )))(input)?; Ok(( remaining, PathPlain { @@ -256,15 +289,9 @@ fn impl_path_plain_end<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, starting_parenthesis_depth: BracketDepth, - enable_search_option: bool, + _enable_search_option: bool, ) -> Res, OrgSource<'s>> { let current_depth = input.get_parenthesis_depth() - starting_parenthesis_depth; - if enable_search_option { - let search_option = peek(tag("::"))(input); - if search_option.is_ok() { - return search_option; - } - } let (remaining, _leading_punctuation) = many0(verify(anychar, |c| { !" \t\r\n[]<>()/".contains(*c) && c.is_ascii_punctuation()