diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index 08b7e89..7311048 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -6,6 +6,7 @@ use nom::character::complete::one_of; use nom::character::complete::space0; use nom::character::complete::space1; use nom::combinator::eof; +use nom::combinator::opt; use nom::combinator::peek; use nom::combinator::recognize; use nom::combinator::verify; @@ -30,6 +31,7 @@ use crate::parser::parser_context::ExitMatcherNode; use crate::parser::util::blank_line; use crate::parser::util::exit_matcher_parser; use crate::parser::util::get_consumed; +use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting; use crate::parser::util::start_of_line; #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] @@ -45,10 +47,6 @@ pub fn plain_list<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s s let mut remaining = input; loop { - let maybe_exit = parser_with_context!(exit_matcher_parser)(&parser_context)(remaining); - if maybe_exit.is_ok() { - break; - } let list_item = parser_with_context!(plain_list_item)(&parser_context)(remaining); match list_item { Ok((remain, item)) @@ -56,12 +54,16 @@ pub fn plain_list<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s s { remaining = remain; children.push(item); - continue; } Ok(_) | Err(_) => { break; } }; + + let maybe_exit = parser_with_context!(exit_matcher_parser)(&parser_context)(remaining); + if maybe_exit.is_ok() { + break; + } } if children.is_empty() { @@ -121,6 +123,9 @@ pub fn plain_list_item<'r, 's>( |(children, _exit_contents)| !children.is_empty(), )(remaining)?; + let (remaining, _trailing_ws) = + maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; + let source = get_consumed(input, remaining); return Ok(( remaining, @@ -159,7 +164,11 @@ fn plain_list_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s s #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn plain_list_item_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { - recognize(parser_with_context!(line_indented_lte)(context))(input) + start_of_line(context, input)?; + recognize(tuple(( + opt(blank_line), + parser_with_context!(line_indented_lte)(context), + )))(input) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] @@ -169,8 +178,6 @@ fn line_indented_lte<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&' "Not inside a plain list item", ))))?; - start_of_line(context, input)?; - let matched = recognize(verify( tuple((space0::<&str, _>, non_whitespace_character)), // It is fine that we get the indent level using the number of bytes rather than the number of characters because nom's space0 only matches space and tab (0x20 and 0x09)