2023-04-22 02:33:10 +00:00
|
|
|
use nom::branch::alt;
|
2023-04-22 02:36:21 +00:00
|
|
|
use nom::bytes::complete::is_not;
|
2023-04-22 02:33:10 +00:00
|
|
|
use nom::bytes::complete::tag;
|
2023-04-22 02:49:00 +00:00
|
|
|
use nom::bytes::complete::tag_no_case;
|
2023-08-29 21:01:35 +00:00
|
|
|
use nom::bytes::complete::take_while1;
|
2023-08-29 20:56:07 +00:00
|
|
|
use nom::character::complete::anychar;
|
2023-04-22 02:33:10 +00:00
|
|
|
use nom::character::complete::line_ending;
|
|
|
|
use nom::character::complete::space0;
|
2023-04-22 02:36:21 +00:00
|
|
|
use nom::character::complete::space1;
|
2023-09-04 23:17:23 +00:00
|
|
|
use nom::combinator::consumed;
|
2023-04-22 02:33:10 +00:00
|
|
|
use nom::combinator::eof;
|
2023-04-22 02:49:00 +00:00
|
|
|
use nom::combinator::not;
|
|
|
|
use nom::combinator::peek;
|
2023-04-22 02:33:10 +00:00
|
|
|
use nom::combinator::recognize;
|
2023-08-29 20:56:07 +00:00
|
|
|
use nom::multi::many_till;
|
2023-04-22 02:33:10 +00:00
|
|
|
use nom::sequence::tuple;
|
|
|
|
|
2023-08-29 20:56:07 +00:00
|
|
|
use super::org_source::BracketDepth;
|
2023-08-23 04:30:26 +00:00
|
|
|
use super::org_source::OrgSource;
|
2023-09-04 23:17:23 +00:00
|
|
|
use crate::context::Matcher;
|
2023-09-03 16:23:18 +00:00
|
|
|
use crate::context::RefContext;
|
2023-08-29 20:56:07 +00:00
|
|
|
use crate::error::CustomError;
|
|
|
|
use crate::error::MyError;
|
2023-04-22 02:33:10 +00:00
|
|
|
use crate::error::Res;
|
|
|
|
use crate::parser::util::start_of_line;
|
2023-09-03 16:23:18 +00:00
|
|
|
use crate::types::Keyword;
|
2023-04-22 02:33:10 +00:00
|
|
|
|
2023-08-29 20:56:07 +00:00
|
|
|
const ORG_ELEMENT_AFFILIATED_KEYWORDS: [&'static str; 13] = [
|
|
|
|
"caption", "data", "header", "headers", "label", "name", "plot", "resname", "result",
|
|
|
|
"results", "source", "srcname", "tblname",
|
|
|
|
];
|
|
|
|
const ORG_ELEMENT_DUAL_KEYWORDS: [&'static str; 2] = ["caption", "results"];
|
|
|
|
|
2023-09-04 23:17:23 +00:00
|
|
|
pub fn filtered_keyword<F: Matcher>(
|
|
|
|
key_parser: F,
|
|
|
|
) -> impl for<'s> Fn(OrgSource<'s>) -> Res<OrgSource<'s>, Keyword<'s>> {
|
|
|
|
move |input| _filtered_keyword(&key_parser, input)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(
|
|
|
|
feature = "tracing",
|
|
|
|
tracing::instrument(ret, level = "debug", skip(key_parser))
|
|
|
|
)]
|
|
|
|
fn _filtered_keyword<'s, F: Matcher>(
|
|
|
|
key_parser: F,
|
2023-08-23 04:30:26 +00:00
|
|
|
input: OrgSource<'s>,
|
|
|
|
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
2023-08-24 23:29:00 +00:00
|
|
|
start_of_line(input)?;
|
2023-04-22 02:36:21 +00:00
|
|
|
// TODO: When key is a member of org-element-parsed-keywords, value can contain the standard set objects, excluding footnote references.
|
2023-09-05 01:46:40 +00:00
|
|
|
let (remaining, (consumed_input, (_, _, parsed_key, _))) =
|
|
|
|
consumed(tuple((space0, tag("#+"), key_parser, tag(":"))))(input)?;
|
|
|
|
match tuple((space0, alt((line_ending, eof))))(remaining) {
|
|
|
|
Ok((remaining, _)) => {
|
|
|
|
return Ok((
|
|
|
|
remaining,
|
|
|
|
Keyword {
|
|
|
|
source: consumed_input.into(),
|
|
|
|
key: parsed_key.into(),
|
|
|
|
value: "".into(),
|
|
|
|
},
|
|
|
|
));
|
|
|
|
}
|
|
|
|
err @ Err(_) => err?,
|
|
|
|
};
|
|
|
|
let (remaining, _ws) = space1(remaining)?;
|
|
|
|
let (remaining, parsed_value) = is_not("\r\n")(remaining)?;
|
|
|
|
let (remaining, _ws) = tuple((space0, alt((line_ending, eof))))(remaining)?;
|
2023-08-23 04:30:26 +00:00
|
|
|
Ok((
|
|
|
|
remaining,
|
|
|
|
Keyword {
|
2023-09-04 23:17:23 +00:00
|
|
|
source: consumed_input.into(),
|
|
|
|
key: parsed_key.into(),
|
|
|
|
value: parsed_value.into(),
|
2023-08-23 04:30:26 +00:00
|
|
|
},
|
|
|
|
))
|
2023-04-22 02:33:10 +00:00
|
|
|
}
|
2023-08-29 20:56:07 +00:00
|
|
|
|
2023-09-04 23:17:23 +00:00
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
pub fn keyword<'b, 'g, 'r, 's>(
|
|
|
|
_context: RefContext<'b, 'g, 'r, 's>,
|
|
|
|
input: OrgSource<'s>,
|
|
|
|
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
|
|
|
filtered_keyword(regular_keyword_key)(input)
|
|
|
|
}
|
|
|
|
|
2023-08-29 20:56:07 +00:00
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
2023-09-03 19:44:18 +00:00
|
|
|
pub fn affiliated_keyword<'b, 'g, 'r, 's>(
|
|
|
|
_context: RefContext<'b, 'g, 'r, 's>,
|
2023-08-29 20:56:07 +00:00
|
|
|
input: OrgSource<'s>,
|
|
|
|
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
2023-09-04 23:17:23 +00:00
|
|
|
filtered_keyword(affiliated_key)(input)
|
|
|
|
}
|
2023-08-29 20:56:07 +00:00
|
|
|
|
2023-09-04 23:17:23 +00:00
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
fn regular_keyword_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
|
|
recognize(tuple((
|
|
|
|
not(peek(tag_no_case("call"))),
|
|
|
|
not(peek(tag_no_case("begin"))),
|
|
|
|
is_not(" \t\r\n:"),
|
|
|
|
)))(input)
|
2023-08-29 20:56:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
fn affiliated_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
|
|
alt((
|
|
|
|
recognize(tuple((dual_affiliated_key, tag("["), optval, tag("]")))),
|
|
|
|
plain_affiliated_key,
|
2023-08-29 21:19:13 +00:00
|
|
|
export_keyword,
|
2023-08-29 20:56:07 +00:00
|
|
|
))(input)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
fn plain_affiliated_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
|
|
for keyword in ORG_ELEMENT_AFFILIATED_KEYWORDS {
|
|
|
|
let result = tag_no_case::<_, _, CustomError<_>>(keyword)(input);
|
|
|
|
match result {
|
|
|
|
Ok((remaining, ent)) => {
|
|
|
|
return Ok((remaining, ent));
|
|
|
|
}
|
|
|
|
Err(_) => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(nom::Err::Error(CustomError::MyError(MyError(
|
|
|
|
"NoKeywordKey".into(),
|
|
|
|
))))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
fn dual_affiliated_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
|
|
for keyword in ORG_ELEMENT_DUAL_KEYWORDS {
|
|
|
|
let result = tag_no_case::<_, _, CustomError<_>>(keyword)(input);
|
|
|
|
match result {
|
|
|
|
Ok((remaining, ent)) => {
|
|
|
|
return Ok((remaining, ent));
|
|
|
|
}
|
|
|
|
Err(_) => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(nom::Err::Error(CustomError::MyError(MyError(
|
|
|
|
"NoKeywordKey".into(),
|
|
|
|
))))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
fn optval<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
|
|
recognize(many_till(
|
|
|
|
anychar,
|
|
|
|
peek(optval_end(input.get_bracket_depth())),
|
|
|
|
))(input)
|
|
|
|
}
|
|
|
|
|
|
|
|
const fn optval_end(
|
|
|
|
starting_bracket_depth: BracketDepth,
|
|
|
|
) -> impl for<'s> Fn(OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
|
|
move |input: OrgSource<'_>| _optval_end(input, starting_bracket_depth)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
fn _optval_end<'s>(
|
|
|
|
input: OrgSource<'s>,
|
|
|
|
starting_bracket_depth: BracketDepth,
|
|
|
|
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
|
|
|
let current_depth = input.get_bracket_depth() - starting_bracket_depth;
|
|
|
|
if current_depth < 0 {
|
|
|
|
// This shouldn't be possible because if depth is 0 then a closing bracket should end the opval.
|
|
|
|
unreachable!("Exceeded optval bracket depth.")
|
|
|
|
}
|
|
|
|
if current_depth == 0 {
|
2023-08-29 21:19:13 +00:00
|
|
|
let close_bracket = tag::<_, _, CustomError<_>>("]")(input);
|
2023-08-29 20:56:07 +00:00
|
|
|
if close_bracket.is_ok() {
|
|
|
|
return close_bracket;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tag("\n")(input)
|
|
|
|
}
|
2023-08-29 21:01:35 +00:00
|
|
|
|
|
|
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
|
|
fn export_keyword<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
2023-08-29 21:19:13 +00:00
|
|
|
recognize(tuple((
|
|
|
|
tag_no_case("attr_"),
|
|
|
|
take_while1(|c: char| c.is_alphanumeric() || "-_".contains(c)),
|
|
|
|
)))(input)
|
2023-08-29 21:01:35 +00:00
|
|
|
}
|