mod stack;
pub use self::stack::ParagraphStack;
use super::consume::consume;
use super::parser::Parser;
use super::prelude::*;
use super::rule::Rule;
use super::token::Token;
pub const NO_CLOSE_CONDITION: Option<CloseConditionFn> = None;
type CloseConditionFn = fn(&mut Parser) -> Result<bool, ParseError>;
pub fn gather_paragraphs<'r, 't, F>(
parser: &mut Parser<'r, 't>,
rule: Rule,
mut close_condition_fn: Option<F>,
) -> ParseResult<'r, 't, Vec<Element<'t>>>
where
'r: 't,
F: FnMut(&mut Parser<'r, 't>) -> Result<bool, ParseError>,
{
debug!("Gathering paragraphs until ending");
parser.set_rule(rule);
let mut stack = ParagraphStack::new();
loop {
let (elements, mut errors, paragraph_safe) = match parser.current().token {
Token::InputEnd => {
if close_condition_fn.is_some() {
warn!("Hit the end of input, producing an error");
return Err(parser.make_err(ParseErrorKind::EndOfInput));
} else {
warn!("Hit the end of input, terminating token iteration");
break;
}
}
Token::ParagraphBreak => {
debug!("Hit a paragraph break, creating a new paragraph container");
stack.end_paragraph();
parser.step()?;
continue;
}
_ => {
if let Some(ref mut close_condition_fn) = close_condition_fn &&
close_condition_fn(parser).unwrap_or(false) {
debug!("Hit closing condition for paragraphs, terminating token iteration");
break;
}
trace!("Trying to consume tokens to produce element");
consume(parser)
}
}?
.into();
trace!("Tokens consumed to produce element");
push_elements(&mut stack, elements, paragraph_safe);
stack.push_errors(&mut errors);
}
stack.into_result()
}
fn push_elements<'t>(
stack: &mut ParagraphStack<'t>,
elements: Elements<'t>,
paragraph_safe: bool,
) {
stack.reserve_elements(elements.len());
for element in elements {
if stack.current_empty() && element == Element::LineBreak {
continue;
}
stack.push_element(element, paragraph_safe);
}
}