use ::std::iter::Peekable;
use ::pulldown_cmark::{Event, Tag};
use ::types::*;
use ::errors::ParseError;
use ::to_md::md;
macro_rules! not {
(start $tag:pat) => (not!(Event::Start($tag)));
(end $tag:pat) => (not!(Event::End($tag)));
($tag:pat) => (
|event| {
if let $tag = *event {
false
} else {
true
}
}
);
}
pub fn teaser<'a, I>(events: &mut I) -> Result<String, ParseError> where
I: Iterator<Item=Event<'a>>,
{
if let Some(Event::Start(Tag::Paragraph)) = events.next() {
Ok(md(events.take_while(not!(end Tag::Paragraph))))
} else {
Err(ParseError::NoTeaser)
}
}
pub fn description<'a, I>(events: &mut I) -> Result<Option<String>, ParseError> where
I: Iterator<Item=Event<'a>>,
{
let description = md(events.take_while(not!(start Tag::Header(1))));
if description.is_empty() {
return Ok(None);
}
Ok(Some(description))
}
pub fn sections<'a, I>(events: &mut Peekable<I>) -> Result<Vec<DocSection>, ParseError> where
I: Iterator<Item=Event<'a>>,
{
let mut sections: Vec<DocSection> = vec![];
loop {
let go_on = {
if let Some(&Event::Text(_)) = events.peek() {
true
} else {
false
}
};
if go_on {
sections.push(try!(section(events)));
continue;
}
match events.next() {
None => break,
Some(Event::Start(Tag::Header(1))) =>
sections.push(try!(section(events))),
Some(unexpected) =>
return Err(ParseError::UnexpectedMarkdown(
"Sections".into(), format!("{:?}", unexpected))),
}
}
Ok(sections)
}
fn section<'a, I>(events: &mut I) -> Result<DocSection, ParseError> where
I: Iterator<Item=Event<'a>>,
{
let headline = md(events.take_while(not!(end Tag::Header(1))));
let section = match &headline.trim().to_lowercase()[..] {
"parameters" =>
DocSection::Parameters(try!(list(events, &headline))),
"type parameters" =>
DocSection::TypeParameters(try!(list(events, &headline))),
"lifetime parameters" | "lifetimes" =>
DocSection::LifetimeParameters(try!(list(events, &headline))),
"returns" =>
DocSection::Returns(
md(events.take_while(not!(start Tag::List(_)))),
try!(list(events, &headline))),
_ =>
DocSection::Custom(
headline,
md(events.take_while(not!(start Tag::Header(1))))),
};
Ok(section)
}
fn list<'a, I>(events: &mut I, section: &str) -> Result<Vec<(Identifier, Documentation)>, ParseError> where
I: Iterator<Item=Event<'a>>,
{
let mut list = vec![];
loop {
match events.next() {
Some(Event::Start(Tag::List(_))) => continue,
None | Some(Event::End(Tag::List(_))) => break,
Some(Event::Start(Tag::Item)) => list.push(try!(list_item(events))),
Some(unexpected) => return Err(ParseError::UnexpectedMarkdown(
section.into(), format!("{:?}", unexpected))),
}
}
Ok(list)
}
fn list_item<'a, I>(events: &mut I) -> Result<(Identifier, Documentation), ParseError> where
I: Iterator<Item=Event<'a>>,
{
let ident = if let Some(Event::Start(Tag::Code)) = events.next() {
md(events.take_while(not!(end Tag::Code)))
} else {
return Err(ParseError::NoIdent);
};
let mut docs = md(events.take_while(not!(end Tag::Item)));
if docs.starts_with(": ") {
docs = docs.trim_left_matches(": ").into();
} else {
return Err(ParseError::WrongIdentDocsSeparator);
}
Ok((ident, docs))
}