End plain lists when there are two blank lines.
This commit is contained in:
parent
7d5eb7c6bb
commit
f27965001d
2
Makefile
2
Makefile
@ -20,7 +20,7 @@ clean:
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
> cargo test
|
||||
> cargo test --bin toy
|
||||
|
||||
.PHONY: run
|
||||
run:
|
||||
|
@ -38,6 +38,12 @@ impl<'s> Source<'s> for Paragraph<'s> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> Source<'s> for PlainList<'s> {
|
||||
fn get_source(&'s self) -> &'s str {
|
||||
self.source
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(ret, level = "debug")]
|
||||
pub fn element<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Element<'s>> {
|
||||
let non_paragraph_matcher = parser_with_context!(non_paragraph_element)(context);
|
||||
|
@ -11,6 +11,7 @@ use crate::parser::element::element;
|
||||
use crate::parser::parser_context::ChainBehavior;
|
||||
use crate::parser::parser_context::ContextElement;
|
||||
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::start_of_line;
|
||||
@ -24,15 +25,20 @@ use nom::character::complete::space1;
|
||||
use nom::combinator::eof;
|
||||
use nom::combinator::recognize;
|
||||
use nom::combinator::verify;
|
||||
use nom::multi::many1;
|
||||
use nom::multi::many_till;
|
||||
use nom::sequence::tuple;
|
||||
|
||||
#[tracing::instrument(ret, level = "debug")]
|
||||
pub fn plain_list<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, PlainList<'s>> {
|
||||
// TODO: Are we handling 2 blank lines causing the end of all plain lists?
|
||||
let (mut remaining, first_item) = plain_list_item(context, input)?;
|
||||
let parser_context =
|
||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
exit_matcher: ChainBehavior::AndParent(Some(&plain_list_end)),
|
||||
}));
|
||||
let (mut remaining, first_item) = plain_list_item(&parser_context, input)?;
|
||||
let first_item_indentation = first_item.indentation;
|
||||
let plain_list_item_matcher = parser_with_context!(plain_list_item)(context);
|
||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(context);
|
||||
let plain_list_item_matcher = parser_with_context!(plain_list_item)(&parser_context);
|
||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||
let mut children = Vec::new();
|
||||
children.push(first_item);
|
||||
loop {
|
||||
@ -125,6 +131,15 @@ fn counter<'s>(i: &'s str) -> Res<&'s str, &'s str> {
|
||||
alt((recognize(one_of("abcdefghijklmnopqrstuvwxyz")), digit1))(i)
|
||||
}
|
||||
|
||||
#[tracing::instrument(ret, level = "debug")]
|
||||
fn plain_list_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> {
|
||||
let start_of_line_matcher = parser_with_context!(start_of_line)(context);
|
||||
recognize(tuple((
|
||||
start_of_line_matcher,
|
||||
verify(many1(blank_line), |lines: &Vec<&str>| lines.len() >= 2),
|
||||
)))(input)
|
||||
}
|
||||
|
||||
#[tracing::instrument(ret, level = "debug")]
|
||||
fn plain_list_item_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> {
|
||||
let current_item_indent_level: &usize =
|
||||
@ -138,7 +153,6 @@ fn plain_list_item_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<
|
||||
pli.indentation <= *current_item_indent_level
|
||||
})),
|
||||
recognize(line_indented_lte_matcher),
|
||||
eof,
|
||||
))(input)
|
||||
}
|
||||
|
||||
@ -175,6 +189,7 @@ mod tests {
|
||||
use crate::parser::parser_context::ContextElement;
|
||||
use crate::parser::parser_context::ContextTree;
|
||||
use crate::parser::parser_with_context::parser_with_context;
|
||||
use crate::parser::Source;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -249,4 +264,34 @@ mod tests {
|
||||
let result = plain_list_matcher(input);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_blank_lines_ends_list() {
|
||||
// Plain lists with an asterisk bullet must be indented or else they would be a headline
|
||||
let input = r#"1. foo
|
||||
2. bar
|
||||
baz
|
||||
3. lorem
|
||||
|
||||
|
||||
ipsum
|
||||
"#;
|
||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
||||
let document_context =
|
||||
initial_context.with_additional_node(ContextElement::DocumentRoot(input));
|
||||
let plain_list_matcher = parser_with_context!(plain_list)(&document_context);
|
||||
let (remaining, result) =
|
||||
plain_list_matcher(input).expect("Should parse the plain list successfully.");
|
||||
assert_eq!(remaining, " ipsum\n");
|
||||
assert_eq!(
|
||||
result.get_source(),
|
||||
r#"1. foo
|
||||
2. bar
|
||||
baz
|
||||
3. lorem
|
||||
|
||||
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user