diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 480cd68..5d0b7ab 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -88,6 +88,11 @@ pub struct Span<'a> { pub contents: &'a str, } +#[derive(Clone, Debug, PartialEq)] +pub struct NewSpan<'a> { + pub contents: Vec<&'a str>, +} + #[derive(Clone, Debug, PartialEq)] pub struct Container<'a> { pub path: Path<'a>, @@ -475,6 +480,34 @@ fn filter(i: &str) -> IResult<&str, Filter> { )(i) } +/// Whitespace at the beginning of lines is ignored so inside a span +/// we are matching a newline character followed by as much contiguous +/// whitespace as possible, all of which will be thrown away by other +/// parsers. +fn span_end_of_line(i: &str) -> IResult<&str, (&str, &str)> { + tuple((line_ending, multispace0))(i) +} + +fn span_line(i: &str) -> IResult<&str, &str> { + verify( + take_until_parser_matches(alt(( + tag("{"), + line_ending, + recognize(all_consuming(eof_whitespace)), + ))), + |s: &str| s.len() > 0, + )(i) +} + +/// Any text that is not a Dust element +fn new_span(i: &str) -> IResult<&str, NewSpan> { + let (remaining, lines) = preceded( + opt(span_end_of_line), + many1(terminated(span_line, opt(span_end_of_line))), + )(i)?; + Ok((remaining, NewSpan { contents: lines })) +} + /// Any text that is not a Dust element fn span(i: &str) -> IResult<&str, Span> { let (remaining, body) = verify( @@ -620,6 +653,74 @@ mod tests { ); } + #[test] + fn test_span_end_of_line() { + assert_eq!( + super::span_end_of_line("\n \t \n\nfoo"), + Ok(("foo", ("\n", " \t \n\n"))) + ); + } + + #[test] + fn test_span_line() { + assert_eq!( + super::span_line("this is just some text"), + Ok(("", "this is just some text")) + ); + assert_eq!( + super::span_line("this is just some text {~lb}"), + Ok(("{~lb}", "this is just some text ")) + ); + assert_eq!( + super::span_line("{~lb}"), + Err(Error(("{~lb}", ErrorKind::Verify))) + ); + } + + #[test] + fn test_new_span() { + assert_eq!( + super::new_span("this is just some text"), + Ok(( + "", + NewSpan { + contents: vec!["this is just some text"] + } + )) + ); + assert_eq!( + super::new_span("this is just some text {~lb}"), + Ok(( + "{~lb}", + NewSpan { + contents: vec!["this is just some text "] + } + )) + ); + assert_eq!( + super::new_span("{~lb}"), + Err(Error(("{~lb}", ErrorKind::Verify))) + ); + assert_eq!( + super::new_span("this is \t \n\n \t \n \t multiline text\n {foo}"), + Ok(( + "{foo}", + NewSpan { + contents: vec!["this is \t ", "multiline text"] + } + )) + ); + assert_eq!( + super::new_span("\n leading whitespace"), + Ok(( + "", + NewSpan { + contents: vec!["leading whitespace"] + } + )) + ); + } + #[test] fn test_section_mismatched_paths() { assert_eq!(