Allow matched parenthesis inside plain links.
This commit is contained in:
parent
5716cbccea
commit
9b2348c0ef
@ -0,0 +1,9 @@
|
||||
foo_(bar)
|
||||
|
||||
foo_(b(ar)
|
||||
|
||||
foo_(b{ar)
|
||||
|
||||
foo_{b(ar}
|
||||
|
||||
foo_(b(a)r)
|
@ -5,10 +5,14 @@ use nom::character::complete::anychar;
|
||||
use nom::character::complete::none_of;
|
||||
use nom::character::complete::one_of;
|
||||
use nom::combinator::eof;
|
||||
use nom::combinator::not;
|
||||
use nom::combinator::peek;
|
||||
use nom::combinator::recognize;
|
||||
use nom::combinator::verify;
|
||||
use nom::multi::many0;
|
||||
use nom::multi::many1;
|
||||
use nom::multi::many_till;
|
||||
use nom::sequence::tuple;
|
||||
|
||||
use super::org_source::BracketDepth;
|
||||
use super::org_source::OrgSource;
|
||||
@ -18,6 +22,7 @@ use crate::context::ContextElement;
|
||||
use crate::context::ContextMatcher;
|
||||
use crate::context::ExitClass;
|
||||
use crate::context::ExitMatcherNode;
|
||||
use crate::context::Matcher;
|
||||
use crate::context::RefContext;
|
||||
use crate::error::CustomError;
|
||||
use crate::error::MyError;
|
||||
@ -132,17 +137,77 @@ fn path_plain<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
// TODO: "optionally containing parenthesis-wrapped non-whitespace non-bracket substrings up to a depth of two. The string must end with either a non-punctation non-whitespace character, a forwards slash, or a parenthesis-wrapped substring"
|
||||
let path_plain_end = path_plain_end(input.get_parenthesis_depth());
|
||||
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
class: ExitClass::Gamma,
|
||||
exit_matcher: &path_plain_end,
|
||||
});
|
||||
let parser_context = context.with_additional_node(&parser_context);
|
||||
|
||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||
let (remaining, _components) = many1(alt((
|
||||
parser_with_context!(path_plain_no_parenthesis)(&parser_context),
|
||||
parser_with_context!(path_plain_parenthesis)(&parser_context),
|
||||
)))(input)?;
|
||||
|
||||
let source = get_consumed(input, remaining);
|
||||
Ok((remaining, source))
|
||||
}
|
||||
|
||||
fn path_plain_end(starting_parenthesis_depth: BracketDepth) -> impl ContextMatcher {
|
||||
move |context, input: OrgSource<'_>| _path_plain_end(context, input, starting_parenthesis_depth)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn _path_plain_end<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
starting_parenthesis_depth: BracketDepth,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let (remaining, _leading_punctuation) = many0(verify(anychar, |c| {
|
||||
!" \t\r\n[]<>()/".contains(*c) && c.is_ascii_punctuation()
|
||||
}))(input)?;
|
||||
|
||||
let disallowed_character = recognize(one_of(" \t\r\n[]<>"))(remaining);
|
||||
if disallowed_character.is_ok() {
|
||||
return disallowed_character;
|
||||
}
|
||||
|
||||
let current_depth = remaining.get_parenthesis_depth() - starting_parenthesis_depth;
|
||||
if current_depth == 0 {
|
||||
let close_parenthesis =
|
||||
tag::<&str, OrgSource<'_>, CustomError<OrgSource<'_>>>(")")(remaining);
|
||||
if close_parenthesis.is_ok() {
|
||||
return close_parenthesis;
|
||||
}
|
||||
|
||||
let open_parenthesis_without_match = recognize(tuple((
|
||||
peek(tag("(")),
|
||||
not(parser_with_context!(path_plain_parenthesis)(context)),
|
||||
)))(remaining);
|
||||
if open_parenthesis_without_match.is_ok() {
|
||||
return open_parenthesis_without_match;
|
||||
}
|
||||
}
|
||||
|
||||
// many0 punctuation
|
||||
Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||
"No path plain end".into(),
|
||||
))))
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn path_plain_no_parenthesis<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let (remaining, path) = recognize(verify(
|
||||
many_till(anychar, exit_matcher),
|
||||
many_till(
|
||||
anychar,
|
||||
alt((
|
||||
peek(path_plain_no_parenthesis_disallowed_character),
|
||||
parser_with_context!(exit_matcher_parser)(context),
|
||||
)),
|
||||
),
|
||||
|(children, _exit_contents)| !children.is_empty(),
|
||||
))(input)?;
|
||||
|
||||
@ -150,14 +215,72 @@ fn path_plain<'b, 'g, 'r, 's>(
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn path_plain_end<'b, 'g, 'r, 's>(
|
||||
_context: RefContext<'b, 'g, 'r, 's>,
|
||||
fn path_plain_no_parenthesis_disallowed_character<'s>(
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
recognize(many_till(
|
||||
verify(anychar, |c| {
|
||||
*c != '/' && (c.is_ascii_punctuation() || c.is_whitespace())
|
||||
}),
|
||||
one_of(" \t\r\n()[]<>"),
|
||||
))(input)
|
||||
recognize(verify(anychar, |c| {
|
||||
c.is_whitespace() || "()[]<>".contains(*c)
|
||||
}))(input)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn path_plain_parenthesis<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let (remaining, _opening) = tag("(")(input)?;
|
||||
let starting_depth = remaining.get_parenthesis_depth();
|
||||
|
||||
let (remaining, _path) = recognize(verify(
|
||||
many_till(
|
||||
anychar,
|
||||
alt((
|
||||
peek(path_plain_parenthesis_end(starting_depth)),
|
||||
parser_with_context!(exit_matcher_parser)(context),
|
||||
)),
|
||||
),
|
||||
|(children, _exit_contents)| !children.is_empty(),
|
||||
))(remaining)?;
|
||||
let (remaining, _opening) = tag(")")(remaining)?;
|
||||
let source = get_consumed(input, remaining);
|
||||
|
||||
Ok((remaining, source))
|
||||
}
|
||||
|
||||
fn path_plain_parenthesis_end(starting_parenthesis_depth: BracketDepth) -> impl Matcher {
|
||||
move |input: OrgSource<'_>| _path_plain_parenthesis_end(input, starting_parenthesis_depth)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn _path_plain_parenthesis_end<'s>(
|
||||
input: OrgSource<'s>,
|
||||
starting_parenthesis_depth: BracketDepth,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let current_depth = input.get_parenthesis_depth() - starting_parenthesis_depth;
|
||||
eprintln!(
|
||||
"current_depth: {}, starting: {}, now: {}, remaining input: {}",
|
||||
current_depth,
|
||||
starting_parenthesis_depth,
|
||||
input.get_parenthesis_depth(),
|
||||
input
|
||||
);
|
||||
if current_depth < 0 {
|
||||
// This shouldn't be possible because if depth is 0 then a closing parenthesis should end the link.
|
||||
unreachable!("Exceeded plain link parenthesis depth.")
|
||||
}
|
||||
if current_depth == 0 {
|
||||
let close_parenthesis = tag::<&str, OrgSource<'_>, CustomError<OrgSource<'_>>>(")")(input);
|
||||
if close_parenthesis.is_ok() {
|
||||
return close_parenthesis;
|
||||
}
|
||||
}
|
||||
if current_depth == 1 {
|
||||
let open_parenthesis = tag::<&str, OrgSource<'_>, CustomError<OrgSource<'_>>>("(")(input);
|
||||
if open_parenthesis.is_ok() {
|
||||
return open_parenthesis;
|
||||
}
|
||||
}
|
||||
Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||
"No closing parenthesis".into(),
|
||||
))))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user