mod stack;
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, ParseWarning>;
pub fn gather_paragraphs<'r, 't, F>(
log: &slog::Logger,
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, ParseWarning>,
{
info!(log, "Gathering paragraphs until ending");
parser.set_rule(rule);
let mut stack = ParagraphStack::new(log);
loop {
let (elements, mut exceptions) = match parser.current().token {
Token::InputEnd => {
if close_condition_fn.is_some() {
debug!(log, "Hit the end of input, producing warning");
return Err(parser.make_warn(ParseWarningKind::EndOfInput));
} else {
debug!(log, "Hit the end of input, terminating token iteration");
break;
}
}
Token::ParagraphBreak => {
debug!(
log,
"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 {
if close_condition_fn(parser).unwrap_or(false) {
debug!(
log,
"Hit closing condition for paragraphs, terminating token iteration",
);
break;
}
}
debug!(log, "Trying to consume tokens to produce element");
consume(log, parser)
}
}?
.into();
debug!(log, "Tokens consumed to produce element");
push_elements(&mut stack, elements);
stack.push_exceptions(&mut exceptions);
}
stack.into_result()
}
fn push_elements<'t>(stack: &mut ParagraphStack<'t>, elements: Elements<'t>) {
stack.reserve_elements(elements.len());
for element in elements {
if stack.current_empty() && element == Element::LineBreak {
continue;
}
stack.push_element(element);
}
}