From bfc9e7f58d1785cf0fba175445fd174c551dcdec Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 31 Aug 2023 17:08:21 -0400 Subject: [PATCH 1/2] When re-parsing last item in list, only disable white space consumption for last element in item. --- .../plain_list/trailing_whitespace_eof.org | 2 ++ src/parser/plain_list.rs | 36 +++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 org_mode_samples/greater_element/plain_list/trailing_whitespace_eof.org diff --git a/org_mode_samples/greater_element/plain_list/trailing_whitespace_eof.org b/org_mode_samples/greater_element/plain_list/trailing_whitespace_eof.org new file mode 100644 index 00000000..4ca3d0e4 --- /dev/null +++ b/org_mode_samples/greater_element/plain_list/trailing_whitespace_eof.org @@ -0,0 +1,2 @@ +- foo + diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index 75bdbd00..ea4d54f6 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -69,6 +69,7 @@ pub fn plain_list<'r, 's>( ) -> Res, PlainList<'s>> { let parser_context = context .with_additional_node(ContextElement::Context("plain list")) + .with_additional_node(ContextElement::ConsumeTrailingWhitespace(true)) .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Beta, exit_matcher: &plain_list_end, @@ -175,14 +176,23 @@ pub fn plain_list_item<'r, 's>( exit_matcher: &exit_matcher, })); - let (remaining, (children, _exit_contents)) = many_till( - parser_with_context!(element(true))(&parser_context), - alt(( - peek(recognize(tuple((start_of_line, many0(blank_line), eof)))), - parser_with_context!(exit_matcher_parser)(&parser_context), - )), + let (mut remaining, (mut children, _exit_contents)) = many_till( + include_input(parser_with_context!(element(true))(&parser_context)), + parser_with_context!(exit_matcher_parser)(&parser_context), )(remaining)?; + if !children.is_empty() && !context.should_consume_trailing_whitespace() { + let final_item_context = + parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false)); + let (final_child_start, _original_final_child) = children.pop().expect("if-statement already checked that children was non-empty."); + let (remain, reparsed_final_element) = + include_input(parser_with_context!(element(true))(&final_item_context))( + final_child_start, + )?; + remaining = remain; + children.push(reparsed_final_element); + } + let (remaining, _trailing_ws) = maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; @@ -196,11 +206,23 @@ pub fn plain_list_item<'r, 's>( tag: maybe_tag .map(|(_ws, item_tag, _divider)| item_tag) .unwrap_or(Vec::new()), - children, + children: children.into_iter().map(|(_start, item)| item).collect(), }, )); } +fn include_input<'s, F, O>( + mut inner: F, +) -> impl FnMut(OrgSource<'s>) -> Res, (OrgSource<'s>, O)> +where + F: FnMut(OrgSource<'s>) -> Res, O>, +{ + move |input: OrgSource<'_>| { + let (remaining, output) = inner(input)?; + Ok((remaining, (input, output))) + } +} + #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn bullet<'s>(i: OrgSource<'s>) -> Res, OrgSource<'s>> { alt(( From 0fcb3f73f9d9326115af262bb63f715640f94e05 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 31 Aug 2023 17:25:42 -0400 Subject: [PATCH 2/2] Move handling of contentless item to handle contentless description item. --- src/parser/plain_list.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index ea4d54f6..a2cc7c2e 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -144,29 +144,32 @@ pub fn plain_list_item<'r, 's>( Into::<&str>::into(bull) != "*" || indent_level > 0 })(remaining)?; - let maybe_contentless_item: Res, OrgSource<'_>> = eof(remaining); + let (remaining, maybe_tag) = opt(tuple(( + space1, + parser_with_context!(item_tag)(context), + tag(" ::"), + )))(remaining)?; + let maybe_contentless_item: Res, OrgSource<'_>> = + peek(recognize(tuple((many0(blank_line), eof))))(remaining); match maybe_contentless_item { - Ok((rem, _ws)) => { - let source = get_consumed(input, rem); + Ok((_rem, _ws)) => { + let (remaining, _trailing_ws) = opt(blank_line)(remaining)?; + let source = get_consumed(input, remaining); return Ok(( - rem, + remaining, PlainListItem { source: source.into(), indentation: indent_level, bullet: bull.into(), - tag: Vec::new(), + tag: maybe_tag + .map(|(_ws, item_tag, _divider)| item_tag) + .unwrap_or(Vec::new()), children: Vec::new(), }, )); } Err(_) => {} }; - - let (remaining, maybe_tag) = opt(tuple(( - space1, - parser_with_context!(item_tag)(context), - tag(" ::"), - )))(remaining)?; let (remaining, _ws) = item_tag_post_gap(context, remaining)?; let exit_matcher = plain_list_item_end(indent_level); let parser_context = context @@ -184,11 +187,12 @@ pub fn plain_list_item<'r, 's>( if !children.is_empty() && !context.should_consume_trailing_whitespace() { let final_item_context = parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false)); - let (final_child_start, _original_final_child) = children.pop().expect("if-statement already checked that children was non-empty."); - let (remain, reparsed_final_element) = - include_input(parser_with_context!(element(true))(&final_item_context))( - final_child_start, - )?; + let (final_child_start, _original_final_child) = children + .pop() + .expect("if-statement already checked that children was non-empty."); + let (remain, reparsed_final_element) = include_input(parser_with_context!(element(true))( + &final_item_context, + ))(final_child_start)?; remaining = remain; children.push(reparsed_final_element); }