organic/trash/paragraph.rs

68 lines
2.0 KiB
Rust

use super::combinator::context_many_till;
use super::error::Res;
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;
use super::token::Token;
use super::Context;
use nom::branch::alt;
use nom::combinator::consumed;
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>> {
// 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, (source, (many, till))) = consumed(context_many_till(
&paragraph_context,
text_element,
context_paragraph_end,
))(i)?;
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,
source,
},
))
}
fn context_paragraph_end<'r, 's>(
context: Context<'r, 's>,
input: &'s str,
) -> Res<&'s str, &'s str> {
paragraph_end(input)
}
pub fn paragraph_end(input: &str) -> Res<&str, &str> {
alt((
recognize(tuple((
map(line_break, TextElement::LineBreak),
many1(blank_line),
))),
eof,
))(input)
}