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
|
.PHONY: test
|
||||||
test:
|
test:
|
||||||
> cargo test
|
> cargo test --bin toy
|
||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
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")]
|
#[tracing::instrument(ret, level = "debug")]
|
||||||
pub fn element<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Element<'s>> {
|
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);
|
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::ChainBehavior;
|
||||||
use crate::parser::parser_context::ContextElement;
|
use crate::parser::parser_context::ContextElement;
|
||||||
use crate::parser::parser_context::ExitMatcherNode;
|
use crate::parser::parser_context::ExitMatcherNode;
|
||||||
|
use crate::parser::util::blank_line;
|
||||||
use crate::parser::util::exit_matcher_parser;
|
use crate::parser::util::exit_matcher_parser;
|
||||||
use crate::parser::util::get_consumed;
|
use crate::parser::util::get_consumed;
|
||||||
use crate::parser::util::start_of_line;
|
use crate::parser::util::start_of_line;
|
||||||
@ -24,15 +25,20 @@ use nom::character::complete::space1;
|
|||||||
use nom::combinator::eof;
|
use nom::combinator::eof;
|
||||||
use nom::combinator::recognize;
|
use nom::combinator::recognize;
|
||||||
use nom::combinator::verify;
|
use nom::combinator::verify;
|
||||||
|
use nom::multi::many1;
|
||||||
use nom::multi::many_till;
|
use nom::multi::many_till;
|
||||||
use nom::sequence::tuple;
|
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>> {
|
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 parser_context =
|
||||||
let (mut remaining, first_item) = plain_list_item(context, input)?;
|
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 first_item_indentation = first_item.indentation;
|
||||||
let plain_list_item_matcher = parser_with_context!(plain_list_item)(context);
|
let plain_list_item_matcher = parser_with_context!(plain_list_item)(&parser_context);
|
||||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(context);
|
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
children.push(first_item);
|
children.push(first_item);
|
||||||
loop {
|
loop {
|
||||||
@ -125,6 +131,15 @@ fn counter<'s>(i: &'s str) -> Res<&'s str, &'s str> {
|
|||||||
alt((recognize(one_of("abcdefghijklmnopqrstuvwxyz")), digit1))(i)
|
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")]
|
#[tracing::instrument(ret, level = "debug")]
|
||||||
fn plain_list_item_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> {
|
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 =
|
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
|
pli.indentation <= *current_item_indent_level
|
||||||
})),
|
})),
|
||||||
recognize(line_indented_lte_matcher),
|
recognize(line_indented_lte_matcher),
|
||||||
eof,
|
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,6 +189,7 @@ mod tests {
|
|||||||
use crate::parser::parser_context::ContextElement;
|
use crate::parser::parser_context::ContextElement;
|
||||||
use crate::parser::parser_context::ContextTree;
|
use crate::parser::parser_context::ContextTree;
|
||||||
use crate::parser::parser_with_context::parser_with_context;
|
use crate::parser::parser_with_context::parser_with_context;
|
||||||
|
use crate::parser::Source;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -249,4 +264,34 @@ mod tests {
|
|||||||
let result = plain_list_matcher(input);
|
let result = plain_list_matcher(input);
|
||||||
assert!(result.is_ok());
|
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…
x
Reference in New Issue
Block a user