organic/src/parser/paragraph.rs

63 lines
1.9 KiB
Rust
Raw Normal View History

2022-12-18 07:53:26 +00:00
use super::combinator::context_many_till;
2022-12-18 07:59:41 +00:00
use super::error::Res;
2022-12-18 07:53:26 +00:00
use super::parser_context::ChainBehavior;
use super::parser_context::ContextElement;
use super::parser_context::ExitMatcherNode;
use super::text::blank_line;
use super::text::line_break;
use super::text::text_element;
use super::token::Paragraph;
use super::token::TextElement;
2022-12-18 07:53:26 +00:00
use super::token::Token;
use super::Context;
use nom::branch::alt;
use nom::combinator::eof;
use nom::combinator::map;
use nom::combinator::not;
use nom::combinator::recognize;
use nom::multi::many1;
use nom::sequence::tuple;
pub fn paragraph<'r, 's>(context: Context<'r, 's>, i: &'s str) -> Res<&'s str, Paragraph<'s>> {
2022-12-18 07:53:26 +00:00
// Add a not(eof) check because many_till cannot match a zero-length string
not(eof)(i)?;
let paragraph_context = context
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
exit_matcher: ChainBehavior::AndParent(Some(&context_paragraph_end)),
}))
.with_additional_node(ContextElement::StartOfParagraph);
let (remaining, (many, till)) =
context_many_till(&paragraph_context, text_element, context_paragraph_end)(i)?;
2022-12-18 07:53:26 +00:00
let many = many
.into_iter()
.filter_map(|token| match token {
Token::TextElement(text_element) => Some(text_element),
Token::Paragraph(_) => panic!("There should only be text elements in paragraphs."),
})
.collect();
Ok((
remaining,
Paragraph {
contents: many,
paragraph_end: till,
},
))
}
fn context_paragraph_end<'r, 's>(
2022-12-18 07:53:26 +00:00
context: Context<'r, 's>,
input: &'s str,
) -> Res<&'s str, &'s str> {
paragraph_end(input)
}
fn paragraph_end(input: &str) -> Res<&str, &str> {
alt((
recognize(tuple((
map(line_break, TextElement::LineBreak),
many1(blank_line),
))),
eof,
))(input)
}