Fix handling of search option for plain links when parenthesis are involved.

This commit is contained in:
Tom Alexander 2023-10-08 10:48:34 -04:00
parent b64c1c944b
commit ceb5376b21
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -3,9 +3,11 @@ use nom::bytes::complete::is_not;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::bytes::complete::tag_no_case; use nom::bytes::complete::tag_no_case;
use nom::bytes::complete::take; use nom::bytes::complete::take;
use nom::bytes::complete::take_until;
use nom::character::complete::anychar; use nom::character::complete::anychar;
use nom::character::complete::none_of; use nom::character::complete::none_of;
use nom::character::complete::one_of; use nom::character::complete::one_of;
use nom::combinator::all_consuming;
use nom::combinator::consumed; use nom::combinator::consumed;
use nom::combinator::eof; use nom::combinator::eof;
use nom::combinator::flat_map; use nom::combinator::flat_map;
@ -127,6 +129,44 @@ pub(crate) fn parse_file_and_application<'s>(
Ok((remaining, application)) 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>, (OrgSource<'s>, Option<OrgSource<'s>>)> {
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>, (OrgSource<'s>, Option<OrgSource<'s>>)> {
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>, (OrgSource<'s>, Option<OrgSource<'s>>)> {
map(rest, |path| (path, None))(input)
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn file_path_plain<'b, 'g, 'r, 's>( fn file_path_plain<'b, 'g, 'r, 's>(
context: RefContext<'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, exit_matcher: &path_plain_end,
}); });
let parser_context = context.with_additional_node(&parser_context); let parser_context = context.with_additional_node(&parser_context);
let (remaining, (raw_link, (_, application, _, _, path, search_option))) = consumed(tuple(( let (remaining, (raw_link, (_, application, _, _, (path, search_option)))) =
peek(tag("file")), consumed(tuple((
map_parser( peek(tag("file")),
parser_with_context!(protocol)(&parser_context), map_parser(
parse_file_and_application, parser_with_context!(protocol)(&parser_context),
), parse_file_and_application,
tag(":"), ),
opt(flat_map( tag(":"),
peek(map(verify(many1_count(tag("/")), |c| *c >= 3), |c| c - 1)), opt(flat_map(
take, 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)
}),
)), )),
|(_, search_option)| search_option, map_parser(
)), parser_with_context!(path_plain)(&parser_context),
)))(input)?; parse_path_and_search_option,
),
)))(input)?;
Ok(( Ok((
remaining, remaining,
PathPlain { PathPlain {
@ -256,15 +289,9 @@ fn impl_path_plain_end<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>, context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
starting_parenthesis_depth: BracketDepth, starting_parenthesis_depth: BracketDepth,
enable_search_option: bool, _enable_search_option: bool,
) -> Res<OrgSource<'s>, OrgSource<'s>> { ) -> Res<OrgSource<'s>, OrgSource<'s>> {
let current_depth = input.get_parenthesis_depth() - starting_parenthesis_depth; 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| { let (remaining, _leading_punctuation) = many0(verify(anychar, |c| {
!" \t\r\n[]<>()/".contains(*c) && c.is_ascii_punctuation() !" \t\r\n[]<>()/".contains(*c) && c.is_ascii_punctuation()