Move consuming trailing element whitespace inside the parsers.

This ensures the parsers can take into account the affiliated keywords when setting their source without needing the SetSource trait.
This commit is contained in:
Tom Alexander 2023-10-06 11:45:15 -04:00
parent f79606047e
commit 758e224e6d
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
19 changed files with 185 additions and 79 deletions

View File

@ -2497,11 +2497,11 @@ fn compare_latex_environment<'b, 's>(
// Compare value
let value = get_property_quoted_string(emacs, ":value")?;
if value.as_ref().map(String::as_str) != Some(rust.source) {
if value.as_ref().map(String::as_str) != Some(rust.value) {
this_status = DiffStatus::Bad;
message = Some(format!(
"Value mismatch (emacs != rust) {:?} != {:?}",
value, rust.source
value, rust.value
));
}

View File

@ -17,6 +17,7 @@ use nom::InputTake;
use super::keyword::affiliated_keyword;
use super::org_source::BracketDepth;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::start_of_line;
use super::OrgSource;
use crate::context::Matcher;
@ -30,15 +31,17 @@ use crate::types::BabelCall;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn babel_call<'b, 'g, 'r, 's>(
_context: RefContext<'b, 'g, 'r, 's>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, BabelCall<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
let (remaining, _) = tuple((space0, tag("#+"), tag_no_case("call"), tag(":")))(input)?;
start_of_line(remaining)?;
let (remaining, _) = tuple((space0, tag("#+"), tag_no_case("call"), tag(":")))(remaining)?;
if let Ok((remaining, (_, line_break))) = tuple((space0, org_line_ending))(remaining) {
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
return Ok((
remaining,
@ -59,6 +62,8 @@ pub(crate) fn babel_call<'b, 'g, 'r, 's>(
consumed(babel_call_value)(remaining)?;
let (remaining, _ws) = tuple((space0, org_line_ending))(remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((

View File

@ -13,6 +13,7 @@ use super::org_source::OrgSource;
use super::timestamp::inactive_date_range_timestamp;
use super::timestamp::inactive_time_range_timestamp;
use super::timestamp::inactive_timestamp;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::org_line_ending;
use crate::context::parser_with_context;
use crate::context::RefContext;
@ -36,6 +37,8 @@ pub(crate) fn clock<'b, 'g, 'r, 's>(
let (remaining, (timestamp, duration)) = clock_timestamp(context, remaining)?;
let (remaining, _) = tuple((space0, org_line_ending))(remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,

View File

@ -13,6 +13,7 @@ use nom::sequence::tuple;
use super::org_source::OrgSource;
use super::util::get_consumed;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::org_line_ending;
use crate::context::parser_with_context;
use crate::context::ContextElement;
@ -43,6 +44,8 @@ pub(crate) fn comment<'b, 'g, 'r, 's>(
let (remaining, mut remaining_lines) =
many0(preceded(not(exit_matcher), comment_line_matcher))(remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
let mut value = Vec::with_capacity(remaining_lines.len() + 1);
let last_line = remaining_lines.pop();

View File

@ -7,6 +7,7 @@ use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::org_line_ending;
use crate::context::RefContext;
use crate::error::Res;
@ -16,14 +17,16 @@ use crate::types::DiarySexp;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn diary_sexp<'b, 'g, 'r, 's>(
_context: RefContext<'b, 'g, 'r, 's>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, DiarySexp<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
let (remaining, value) = recognize(tuple((tag("%%("), is_not("\r\n"))))(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(remaining)?;
let (remaining, value) = recognize(tuple((tag("%%("), is_not("\r\n"))))(remaining)?;
let (remaining, _eol) = org_line_ending(remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,

View File

@ -14,6 +14,7 @@ use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::parser_with_context;
use crate::context::ContextElement;
use crate::context::ExitClass;
@ -44,9 +45,9 @@ pub(crate) fn drawer<'b, 'g, 'r, 's>(
"Cannot nest objects of the same element".into(),
))));
}
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
let (remaining, _leading_whitespace) = space0(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(remaining)?;
let (remaining, _leading_whitespace) = space0(remaining)?;
let (remaining, (_open_colon, drawer_name, _close_colon, _new_line)) = tuple((
tag(":"),
name,
@ -88,6 +89,8 @@ pub(crate) fn drawer<'b, 'g, 'r, 's>(
};
let (remaining, _end) = drawer_end(&parser_context, remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((

View File

@ -20,6 +20,7 @@ use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::parser_with_context;
use crate::context::ContextElement;
use crate::context::ExitClass;
@ -49,10 +50,10 @@ pub(crate) fn dynamic_block<'b, 'g, 'r, 's>(
"Cannot nest objects of the same element".into(),
))));
}
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
let (remaining, _leading_whitespace) = space0(input)?;
start_of_line(remaining)?;
let (remaining, _leading_whitespace) = space0(remaining)?;
let (remaining, (_, name, parameters, _, _)) = tuple((
recognize(tuple((tag_no_case("#+begin:"), space1))),
name,
@ -96,6 +97,8 @@ pub(crate) fn dynamic_block<'b, 'g, 'r, 's>(
let (remaining, _end) = dynamic_block_end(&parser_context, remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,

View File

@ -21,6 +21,7 @@ use super::footnote_definition::footnote_definition;
use super::greater_block::greater_block;
use super::horizontal_rule::horizontal_rule;
use super::keyword::affiliated_keyword;
use super::keyword::affiliated_keyword_as_regular_keyword;
use super::keyword::keyword;
use super::latex_environment::latex_environment;
use super::lesser_block::comment_block;
@ -33,8 +34,6 @@ use super::paragraph::paragraph;
use super::plain_list::detect_plain_list;
use super::plain_list::plain_list;
use super::table::detect_table;
use super::util::get_consumed;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::parser_with_context;
use crate::context::RefContext;
use crate::error::CustomError;
@ -42,7 +41,6 @@ use crate::error::MyError;
use crate::error::Res;
use crate::parser::table::org_mode_table;
use crate::types::Element;
use crate::types::SetSource;
pub(crate) const fn element(
can_be_paragraph: bool,
@ -137,7 +135,10 @@ fn _element<'b, 'g, 'r, 's>(
#[cfg(feature = "tracing")]
let _enter = span.enter();
let (remain, kw) = opt(map(affiliated_keyword, Element::Keyword))(remaining)?;
let (remain, kw) = opt(map(
parser_with_context!(affiliated_keyword_as_regular_keyword)(context),
Element::Keyword,
))(remaining)?;
if kw.is_some() {
maybe_element = kw;
remaining = remain;
@ -164,13 +165,7 @@ fn _element<'b, 'g, 'r, 's>(
"No element.",
))));
}
let mut element = maybe_element.expect("The above if-statement ensures this is Some().");
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
element.set_source(source.into());
let element = maybe_element.expect("The above if-statement ensures this is Some().");
Ok((remaining, element))
}

View File

@ -12,6 +12,7 @@ use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::org_line_ending;
use crate::context::parser_with_context;
use crate::context::RefContext;
@ -26,13 +27,15 @@ pub(crate) fn fixed_width_area<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, FixedWidthArea<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let fixed_width_area_line_matcher = parser_with_context!(fixed_width_area_line)(context);
let exit_matcher = parser_with_context!(exit_matcher_parser)(context);
let (remaining, first_line) = fixed_width_area_line_matcher(input)?;
let (remaining, first_line) = fixed_width_area_line_matcher(remaining)?;
let (remaining, mut remaining_lines) =
many0(preceded(not(exit_matcher), fixed_width_area_line_matcher))(remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
let mut value = Vec::with_capacity(remaining_lines.len() + 1);
let last_line = remaining_lines.pop();

View File

@ -15,6 +15,7 @@ use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_name;
use super::util::include_input;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::WORD_CONSTITUENT_CHARACTERS;
use crate::context::parser_with_context;
use crate::context::ContextElement;
@ -43,8 +44,8 @@ pub(crate) fn footnote_definition<'b, 'g, 'r, 's>(
"Cannot nest objects of the same element".into(),
))));
}
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(remaining)?;
// Cannot be indented.
let (remaining, (_, lbl, _, _, _)) = tuple((
tag_no_case("[fn:"),
@ -54,7 +55,7 @@ pub(crate) fn footnote_definition<'b, 'g, 'r, 's>(
opt(verify(many0(blank_line), |lines: &Vec<OrgSource<'_>>| {
lines.len() <= 2
})),
))(input)?;
))(remaining)?;
let contexts = [
ContextElement::ConsumeTrailingWhitespace(true),
ContextElement::Context("footnote definition"),
@ -83,6 +84,8 @@ pub(crate) fn footnote_definition<'b, 'g, 'r, 's>(
}
}
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,

View File

@ -21,6 +21,7 @@ use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_name;
use super::util::in_section;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::parser_with_context;
use crate::context::ContextElement;
use crate::context::ContextMatcher;
@ -48,6 +49,7 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Element<'s>> {
let pre_affiliated_keywords_input = input;
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
let (remaining, _leading_whitespace) = space0(input)?;
@ -62,9 +64,24 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>(
))(remaining)?;
let name = Into::<&str>::into(name);
let (remaining, element) = match name.to_lowercase().as_str() {
"center" => center_block(context, remaining, input, &affiliated_keywords)?,
"quote" => quote_block(context, remaining, input, &affiliated_keywords)?,
_ => special_block(name)(context, remaining, input, &affiliated_keywords)?,
"center" => center_block(
context,
remaining,
pre_affiliated_keywords_input,
&affiliated_keywords,
)?,
"quote" => quote_block(
context,
remaining,
pre_affiliated_keywords_input,
&affiliated_keywords,
)?,
_ => special_block(name)(
context,
remaining,
pre_affiliated_keywords_input,
&affiliated_keywords,
)?,
};
Ok((remaining, element))
}
@ -73,11 +90,16 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>(
fn center_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
original_input: OrgSource<'s>,
pre_affiliated_keywords_input: OrgSource<'s>,
affiliated_keywords: &Vec<Keyword<'s>>,
) -> Res<OrgSource<'s>, Element<'s>> {
let (remaining, (source, children)) =
greater_block_body(context, input, original_input, "center", "center block")?;
let (remaining, (source, children)) = greater_block_body(
context,
input,
pre_affiliated_keywords_input,
"center",
"center block",
)?;
Ok((
remaining,
Element::CenterBlock(CenterBlock {
@ -92,11 +114,16 @@ fn center_block<'b, 'g, 'r, 's>(
fn quote_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
original_input: OrgSource<'s>,
pre_affiliated_keywords_input: OrgSource<'s>,
affiliated_keywords: &Vec<Keyword<'s>>,
) -> Res<OrgSource<'s>, Element<'s>> {
let (remaining, (source, children)) =
greater_block_body(context, input, original_input, "quote", "quote block")?;
let (remaining, (source, children)) = greater_block_body(
context,
input,
pre_affiliated_keywords_input,
"quote",
"quote block",
)?;
Ok((
remaining,
Element::QuoteBlock(QuoteBlock {
@ -117,11 +144,11 @@ fn special_block<'s>(
) -> Res<OrgSource<'s>, Element<'s>>
+ 's {
let context_name = format!("special block {}", name);
move |context, input, original_input, affiliated_keywords| {
move |context, input, pre_affiliated_keywords_input, affiliated_keywords| {
_special_block(
context,
input,
original_input,
pre_affiliated_keywords_input,
name,
context_name.as_str(),
affiliated_keywords,
@ -133,14 +160,19 @@ fn special_block<'s>(
fn _special_block<'c, 'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
original_input: OrgSource<'s>,
pre_affiliated_keywords_input: OrgSource<'s>,
name: &'s str,
context_name: &'c str,
affiliated_keywords: &Vec<Keyword<'s>>,
) -> Res<OrgSource<'s>, Element<'s>> {
let (remaining, parameters) = opt(tuple((space1, parameters)))(input)?;
let (remaining, (source, children)) =
greater_block_body(context, remaining, original_input, name, context_name)?;
let (remaining, (source, children)) = greater_block_body(
context,
remaining,
pre_affiliated_keywords_input,
name,
context_name,
)?;
Ok((
remaining,
Element::SpecialBlock(SpecialBlock {
@ -157,7 +189,7 @@ fn _special_block<'c, 'b, 'g, 'r, 's>(
fn greater_block_body<'c, 'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
original_input: OrgSource<'s>,
pre_affiliated_keywords_input: OrgSource<'s>,
name: &'c str,
context_name: &'c str,
) -> Res<OrgSource<'s>, (&'s str, Vec<Element<'s>>)> {
@ -202,7 +234,9 @@ fn greater_block_body<'c, 'b, 'g, 'r, 's>(
// Not checking if parent exit matcher is causing exit because the greater_block_end matcher asserts we matched a full greater block
let source = get_consumed(original_input, remaining);
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(pre_affiliated_keywords_input, remaining);
Ok((remaining, (Into::<&str>::into(source), children)))
}

View File

@ -11,7 +11,9 @@ use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_consumed;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::RefContext;
use crate::error::Res;
use crate::parser::util::start_of_line;
@ -19,21 +21,24 @@ use crate::types::HorizontalRule;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn horizontal_rule<'b, 'g, 'r, 's>(
_context: RefContext<'b, 'g, 'r, 's>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, HorizontalRule<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
let (remaining, rule) = recognize(tuple((
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(remaining)?;
let (remaining, _rule) = recognize(tuple((
space0,
verify(many1_count(tag("-")), |dashes| *dashes >= 5),
space0,
alt((line_ending, eof)),
)))(input)?;
)))(remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,
HorizontalRule {
source: rule.into(),
source: source.into(),
name: get_name(&affiliated_keywords),
},
))

View File

@ -19,7 +19,9 @@ use nom::sequence::tuple;
use super::org_source::BracketDepth;
use super::org_source::OrgSource;
use super::util::get_consumed;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::Matcher;
use crate::context::RefContext;
use crate::error::CustomError;
@ -89,12 +91,29 @@ fn _filtered_keyword<'s, F: Matcher>(
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn keyword<'b, 'g, 'r, 's>(
_context: RefContext<'b, 'g, 'r, 's>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Keyword<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, mut kw) = filtered_keyword(regular_keyword_key)(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, mut kw) = filtered_keyword(regular_keyword_key)(remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
kw.name = get_name(&affiliated_keywords);
kw.source = Into::<&str>::into(source);
Ok((remaining, kw))
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn affiliated_keyword_as_regular_keyword<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Keyword<'s>> {
let (remaining, mut kw) = affiliated_keyword(input)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
kw.source = Into::<&str>::into(source);
Ok((remaining, kw))
}

View File

@ -16,6 +16,7 @@ use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_consumed;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::parser_with_context;
use crate::context::ContextElement;
use crate::context::ContextMatcher;
@ -32,9 +33,10 @@ pub(crate) fn latex_environment<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, LatexEnvironment<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
let (remaining, _leading_whitespace) = space0(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let value_start = remaining;
start_of_line(remaining)?;
let (remaining, _leading_whitespace) = space0(remaining)?;
let (remaining, (_opening, name, _open_close_brace, _ws, _line_ending)) = tuple((
tag_no_case(r#"\begin{"#),
name,
@ -52,13 +54,18 @@ pub(crate) fn latex_environment<'b, 'g, 'r, 's>(
let (remaining, _contents) = contents(&latex_environment_end_specialized)(context, remaining)?;
let (remaining, _end) = latex_environment_end_specialized(&parser_context, remaining)?;
let value_end = remaining;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
let value = get_consumed(value_start, value_end);
Ok((
remaining,
LatexEnvironment {
source: source.into(),
name: get_name(&affiliated_keywords),
value: value.into(),
},
))
}

View File

@ -20,6 +20,7 @@ use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::parser_with_context;
use crate::context::ContextElement;
use crate::context::ContextMatcher;
@ -52,8 +53,8 @@ pub(crate) fn verse_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, VerseBlock<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("verse")(context, input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("verse")(context, remaining)?;
let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?;
let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?;
let lesser_block_end_specialized = lesser_block_end("verse");
@ -91,6 +92,8 @@ pub(crate) fn verse_block<'b, 'g, 'r, 's>(
};
let (remaining, _end) = lesser_block_end_specialized(&parser_context, remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,
@ -108,8 +111,8 @@ pub(crate) fn comment_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, CommentBlock<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("comment")(context, input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("comment")(context, remaining)?;
let (remaining, _parameters) = opt(tuple((space1, data)))(remaining)?;
let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?;
let lesser_block_end_specialized = lesser_block_end("comment");
@ -128,6 +131,8 @@ pub(crate) fn comment_block<'b, 'g, 'r, 's>(
let (remaining, contents) = parser_with_context!(text_until_exit)(&parser_context)(remaining)?;
let (remaining, _end) = lesser_block_end_specialized(&parser_context, remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,
@ -144,8 +149,8 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ExampleBlock<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("example")(context, input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("example")(context, remaining)?;
let (remaining, parameters) = opt(tuple((space1, example_switches)))(remaining)?;
let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?;
let lesser_block_end_specialized = lesser_block_end("example");
@ -165,6 +170,8 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>(
let (remaining, contents) = content(&parser_context, remaining)?;
let (remaining, _end) = lesser_block_end_specialized(&parser_context, remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
let (switches, number_lines, preserve_indent, retain_labels, use_labels, label_format) = {
if let Some(parameters) = parameters {
@ -205,8 +212,8 @@ pub(crate) fn export_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ExportBlock<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("export")(context, input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("export")(context, remaining)?;
// https://orgmode.org/worg/org-syntax.html#Blocks claims that export blocks must have a single word for data but testing shows no data and multi-word data still parses as an export block.
let (remaining, export_type) = opt(map(
tuple((space1, switch_word, peek(tuple((space0, line_ending))))),
@ -231,6 +238,8 @@ pub(crate) fn export_block<'b, 'g, 'r, 's>(
let (remaining, contents) = content(&parser_context, remaining)?;
let (remaining, _end) = lesser_block_end_specialized(&parser_context, remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,
@ -249,8 +258,8 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, SrcBlock<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("src")(context, input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, _) = lesser_block_begin("src")(context, remaining)?;
// https://orgmode.org/worg/org-syntax.html#Blocks claims that data is mandatory and must follow the LANGUAGE SWITCHES ARGUMENTS pattern but testing has shown that no data and incorrect data here will still parse to a src block.
let (remaining, language) =
opt(map(tuple((space1, switch_word)), |(_, language)| language))(remaining)?;
@ -274,6 +283,8 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>(
let (remaining, contents) = content(&parser_context, remaining)?;
let (remaining, _end) = lesser_block_end_specialized(&parser_context, remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
let (switches, number_lines, preserve_indent, retain_labels, use_labels, label_format) = {
if let Some(switches) = switches {

View File

@ -14,6 +14,7 @@ use super::util::blank_line;
use super::util::get_consumed;
use super::util::get_has_affiliated_keyword;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use crate::context::parser_with_context;
use crate::context::ContextElement;
use crate::context::ExitClass;
@ -33,10 +34,10 @@ pub(crate) fn paragraph<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Paragraph<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let contexts = [
ContextElement::HasAffiliatedKeyword(HasAffiliatedKeywordInner {
start_after_affiliated_keywords: input,
start_after_affiliated_keywords: remaining,
keywords: &affiliated_keywords,
}),
ContextElement::ExitMatcherNode(ExitMatcherNode {
@ -52,10 +53,12 @@ pub(crate) fn paragraph<'b, 'g, 'r, 's>(
let (remaining, (children, _exit_contents)) = verify(
many_till(standard_set_object_matcher, exit_matcher),
|(children, _exit_contents)| !children.is_empty(),
)(input)?;
)(remaining)?;
// Not checking parent exit matcher because if there are any children matched then we have a valid paragraph.
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((

View File

@ -81,7 +81,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, PlainList<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
let contexts = [
ContextElement::Context("plain list"),
@ -99,7 +99,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>(
let mut children = Vec::new();
let mut first_item_indentation: Option<IndentationLevel> = None;
let mut first_item_list_type: Option<PlainListType> = None;
let mut remaining = input;
let mut remaining = remaining;
// The final list item does not consume trailing blank lines (which instead get consumed by the list). We have three options here:
//
@ -150,6 +150,8 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>(
parser_with_context!(plain_list_item)(&final_item_context)(final_child_start)?;
children.push((final_child_start, reparsed_final_item));
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,

View File

@ -19,6 +19,7 @@ use super::object_parser::table_cell_set_object;
use super::org_source::OrgSource;
use super::util::exit_matcher_parser;
use super::util::get_name;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::org_line_ending;
use crate::context::parser_with_context;
use crate::context::ContextElement;
@ -40,9 +41,9 @@ pub(crate) fn org_mode_table<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Table<'s>> {
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(input)?;
peek(tuple((space0, tag("|"))))(input)?;
let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?;
start_of_line(remaining)?;
peek(tuple((space0, tag("|"))))(remaining)?;
let contexts = [
ContextElement::ConsumeTrailingWhitespace(true),
@ -60,11 +61,13 @@ pub(crate) fn org_mode_table<'b, 'g, 'r, 's>(
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
let (remaining, (children, _exit_contents)) =
many_till(org_mode_table_row_matcher, exit_matcher)(input)?;
many_till(org_mode_table_row_matcher, exit_matcher)(remaining)?;
let (remaining, formulas) =
many0(parser_with_context!(table_formula_keyword)(context))(remaining)?;
let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((

View File

@ -149,6 +149,7 @@ pub struct BabelCall<'s> {
pub struct LatexEnvironment<'s> {
pub source: &'s str,
pub name: Option<&'s str>,
pub value: &'s str,
}
/// A line number used in switches to lesser blocks.