use parser::block::parse_blocks;
use parser::Block;
use parser::Block::{Paragraph, UnorderedList};
use parser::ListItem;
use regex::Regex;
pub fn parse_unordered_list(lines: &[&str]) -> Option<(Block, usize)> {
lazy_static! {
static ref LIST_BEGIN: Regex =
Regex::new(r"^(?P<indent> *)(-|\+|\*) (?P<content>.*)").unwrap();
static ref NEW_PARAGRAPH: Regex = Regex::new(r"^ +").unwrap();
static ref INDENTED: Regex = Regex::new(r"^ {0,4}(?P<content>.*)").unwrap();
}
if !LIST_BEGIN.is_match(lines[0]) {
return None;
}
let mut contents = vec![];
let mut prev_newline = false;
let mut is_paragraph = false;
let mut i = 0;
let mut line_iter = lines.iter();
let mut line = line_iter.next();
loop {
if line.is_none() || !LIST_BEGIN.is_match(line.unwrap()) {
break;
}
if prev_newline {
is_paragraph = true;
prev_newline = false;
}
let caps = LIST_BEGIN.captures(line.unwrap()).unwrap();
let mut content = caps.name("content").unwrap().as_str().to_owned();
let last_indent = caps.name("indent").unwrap().as_str().len();
i += 1;
loop {
line = line_iter.next();
if line.is_none() || (prev_newline && !NEW_PARAGRAPH.is_match(line.unwrap())) {
break;
}
if LIST_BEGIN.is_match(line.unwrap()) {
let caps = LIST_BEGIN.captures(line.unwrap()).unwrap();
let indent = caps.name("indent").unwrap().as_str().len();
if indent < 2 || indent <= last_indent {
break;
}
}
if line.unwrap().is_empty() {
prev_newline = true;
} else {
prev_newline = false;
}
content.push('\n');
let caps = INDENTED.captures(line.unwrap()).unwrap();
content.push_str(&caps.name("content").unwrap().as_str());
i += 1;
}
contents.push(parse_blocks(&content));
}
let mut list_contents = vec![];
for c in contents {
if is_paragraph || c.len() > 1 {
list_contents.push(ListItem::Paragraph(c));
} else if let Paragraph(content) = c[0].clone() {
list_contents.push(ListItem::Simple(content));
}
}
if i > 0 {
return Some((UnorderedList(list_contents), i));
}
None
}
#[cfg(test)]
mod test {
use super::parse_unordered_list;
use parser::Block::UnorderedList;
#[test]
fn finds_list() {
match parse_unordered_list(&vec!["* A list", "* is good"]) {
Some((UnorderedList(_), 2)) => (),
x => panic!("Found {:?}", x),
}
match parse_unordered_list(&vec!["* A list", "* is good", "laksjdnflakdsjnf"]) {
Some((UnorderedList(_), 3)) => (),
x => panic!("Found {:?}", x),
}
}
#[test]
fn knows_when_to_stop() {
match parse_unordered_list(&vec!["* A list", "* is good", "", "laksjdnflakdsjnf"]) {
Some((UnorderedList(_), 3)) => (),
x => panic!("Found {:?}", x),
}
match parse_unordered_list(&vec!["* A list", "", "laksjdnflakdsjnf"]) {
Some((UnorderedList(_), 2)) => (),
x => panic!("Found {:?}", x),
}
}
#[test]
fn no_false_positives() {
assert_eq!(parse_unordered_list(&vec!["test * test"]), None);
}
#[test]
fn no_early_matching() {
assert_eq!(
parse_unordered_list(&vec!["test", "* whot", "* a list"]),
None
);
}
}