Finished transitioning to the new top-level ignored whitespace template element.

This commit is contained in:
Tom Alexander 2020-05-03 14:44:09 -04:00
parent 908ae078b0
commit bafff8e7a0
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
2 changed files with 97 additions and 91 deletions

View File

@ -2,9 +2,7 @@ use nom::branch::alt;
use nom::bytes::complete::escaped_transform;
use nom::bytes::complete::is_a;
use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_until;
use nom::bytes::complete::take_until_parser_matches;
use nom::bytes::complete::{tag, take_until, take_until_parser_matches};
use nom::character::complete::line_ending;
use nom::character::complete::multispace0;
use nom::character::complete::one_of;
@ -90,7 +88,7 @@ pub enum Filter {
#[derive(Clone, Debug, PartialEq)]
pub struct Span<'a> {
pub contents: Vec<&'a str>,
pub contents: &'a str,
}
#[derive(Clone, Debug, PartialEq)]
@ -153,26 +151,23 @@ pub enum TemplateElement<'a> {
///
/// These elements are always wrapped in curly braces
fn dust_tag(i: &str) -> IResult<&str, DustTag> {
preceded(
opt(span_end_of_line),
alt((
map(special, DustTag::DTSpecial),
map(comment, DustTag::DTComment),
map(reference, DustTag::DTReference),
conditional("{#", DustTag::DTSection),
conditional("{?", DustTag::DTExists),
conditional("{^", DustTag::DTNotExists),
named_block("{+", DustTag::DTBlock),
named_block("{<", DustTag::DTInlinePartial),
partial("{>", DustTag::DTPartial),
parameterized_block("{@", "gte", DustTag::DTHelperGreaterThenOrEquals),
parameterized_block("{@", "lte", DustTag::DTHelperLessThenOrEquals),
parameterized_block("{@", "eq", DustTag::DTHelperEquals),
parameterized_block("{@", "ne", DustTag::DTHelperNotEquals),
parameterized_block("{@", "gt", DustTag::DTHelperGreaterThan),
parameterized_block("{@", "lt", DustTag::DTHelperLessThan),
)),
)(i)
alt((
map(special, DustTag::DTSpecial),
map(comment, DustTag::DTComment),
map(reference, DustTag::DTReference),
conditional("{#", DustTag::DTSection),
conditional("{?", DustTag::DTExists),
conditional("{^", DustTag::DTNotExists),
named_block("{+", DustTag::DTBlock),
named_block("{<", DustTag::DTInlinePartial),
partial("{>", DustTag::DTPartial),
parameterized_block("{@", "gte", DustTag::DTHelperGreaterThenOrEquals),
parameterized_block("{@", "lte", DustTag::DTHelperLessThenOrEquals),
parameterized_block("{@", "eq", DustTag::DTHelperEquals),
parameterized_block("{@", "ne", DustTag::DTHelperNotEquals),
parameterized_block("{@", "gt", DustTag::DTHelperGreaterThan),
parameterized_block("{@", "lt", DustTag::DTHelperLessThan),
))(i)
}
/// Special characters
@ -487,32 +482,32 @@ fn filter(i: &str) -> IResult<&str, Filter> {
/// Whitespace at the beginning of lines is ignored so 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 ignore_new_line_leading_whitespace(i: &str) -> IResult<&str, IgnoredWhitespace> {
map(
recognize(tuple((line_ending, multispace0))),
IgnoredWhitespace::StartOfLine,
)(i)
}
fn span_line(i: &str) -> IResult<&str, &str> {
verify(
/// Any text that is not a Dust element or ignored whitespace
fn span(i: &str) -> IResult<&str, Span> {
let (remaining, line) = 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 span(i: &str) -> IResult<&str, Span> {
let (remaining, lines) = preceded(
opt(span_end_of_line),
many1(terminated(span_line, opt(span_end_of_line))),
)(i)?;
Ok((remaining, Span { contents: lines }))
Ok((remaining, Span { contents: line }))
}
fn body(i: &str) -> IResult<&str, Body> {
let (remaining, template_elements) = many1(alt((
map(
ignore_new_line_leading_whitespace,
TemplateElement::TEIgnoredWhitespace,
),
map(span, TemplateElement::TESpan),
map(dust_tag, TemplateElement::TETag),
)))(i)?;
@ -621,24 +616,8 @@ 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)))
super::ignore_new_line_leading_whitespace("\n \t \n\nfoo"),
Ok(("foo", IgnoredWhitespace::StartOfLine("\n \t \n\n")))
);
}
@ -649,7 +628,7 @@ mod tests {
Ok((
"",
Span {
contents: vec!["this is just some text"]
contents: "this is just some text"
}
))
);
@ -658,7 +637,7 @@ mod tests {
Ok((
"{~lb}",
Span {
contents: vec!["this is just some text "]
contents: "this is just some text "
}
))
);
@ -667,20 +646,44 @@ mod tests {
Err(Error(("{~lb}", ErrorKind::Verify)))
);
assert_eq!(
super::span("this is \t \n\n \t \n \t multiline text\n {foo}"),
super::body("this is \t \n\n \t \n \t multiline text\n {foo}"),
Ok((
"{foo}",
Span {
contents: vec!["this is \t ", "multiline text"]
"",
Body {
elements: vec![
TemplateElement::TESpan(Span {
contents: "this is \t "
}),
TemplateElement::TEIgnoredWhitespace(IgnoredWhitespace::StartOfLine(
"\n\n \t \n \t "
)),
TemplateElement::TESpan(Span {
contents: "multiline text"
}),
TemplateElement::TEIgnoredWhitespace(IgnoredWhitespace::StartOfLine(
"\n "
)),
TemplateElement::TETag(DustTag::DTReference(Reference {
path: Path { keys: vec!["foo"] },
filters: vec![]
}))
]
}
))
);
assert_eq!(
super::span("\n leading whitespace"),
super::body("\n leading whitespace"),
Ok((
"",
Span {
contents: vec!["leading whitespace"]
Body {
elements: vec![
TemplateElement::TEIgnoredWhitespace(IgnoredWhitespace::StartOfLine(
"\n "
)),
TemplateElement::TESpan(Span {
contents: "leading whitespace"
}),
]
}
))
);
@ -740,9 +743,7 @@ mod tests {
},
contents: Some(Body {
elements: vec![
TemplateElement::TESpan(Span {
contents: vec!["hello "]
}),
TemplateElement::TESpan(Span { contents: "hello " }),
TemplateElement::TETag(DustTag::DTReference(Reference {
path: Path { keys: vec!["name"] },
filters: Vec::new()
@ -767,9 +768,7 @@ mod tests {
},
contents: Some(Body {
elements: vec![
TemplateElement::TESpan(Span {
contents: vec!["hello "]
}),
TemplateElement::TESpan(Span { contents: "hello " }),
TemplateElement::TETag(DustTag::DTReference(Reference {
path: Path { keys: vec!["name"] },
filters: Vec::new()
@ -779,7 +778,7 @@ mod tests {
else_contents: Some(Body {
elements: vec![
TemplateElement::TESpan(Span {
contents: vec!["goodbye "]
contents: "goodbye "
}),
TemplateElement::TETag(DustTag::DTReference(Reference {
path: Path { keys: vec!["name"] },
@ -816,9 +815,7 @@ mod tests {
name: "foo",
contents: Some(Body {
elements: vec![
TemplateElement::TESpan(Span {
contents: vec!["hello "]
}),
TemplateElement::TESpan(Span { contents: "hello " }),
TemplateElement::TETag(DustTag::DTReference(Reference {
path: Path { keys: vec!["name"] },
filters: Vec::new()
@ -854,9 +851,7 @@ mod tests {
name: "foo",
contents: Some(Body {
elements: vec![
TemplateElement::TESpan(Span {
contents: vec!["hello "]
}),
TemplateElement::TESpan(Span { contents: "hello " }),
TemplateElement::TETag(DustTag::DTReference(Reference {
path: Path { keys: vec!["name"] },
filters: Vec::new()
@ -943,15 +938,13 @@ mod tests {
contents: Some(Body {
elements: vec![
TemplateElement::TESpan(Span {
contents: vec!["Pet the "]
contents: "Pet the "
}),
TemplateElement::TETag(DustTag::DTReference(Reference {
path: Path { keys: vec!["name"] },
filters: Vec::new()
})),
TemplateElement::TESpan(Span {
contents: vec!["!"]
})
TemplateElement::TESpan(Span { contents: "!" })
]
}),
else_contents: None
@ -1002,9 +995,12 @@ mod tests {
contents: Body {
elements: vec![
TemplateElement::TESpan(Span {
contents: vec!["- simple -"]
contents: "- simple -"
}),
TemplateElement::TETag(DustTag::DTSpecial(Special::NewLine)),
TemplateElement::TEIgnoredWhitespace(IgnoredWhitespace::StartOfLine(
"\n"
)),
TemplateElement::TETag(DustTag::DTSection(Container {
path: Path {
keys: vec!["names"]
@ -1019,22 +1015,34 @@ mod tests {
}),
else_contents: None,
})),
TemplateElement::TEIgnoredWhitespace(IgnoredWhitespace::StartOfLine(
"\n"
)),
TemplateElement::TETag(DustTag::DTSpecial(Special::NewLine)),
TemplateElement::TESpan(Span {
contents: vec!["- new lines -"]
contents: "- new lines -"
}),
TemplateElement::TETag(DustTag::DTSpecial(Special::NewLine)),
TemplateElement::TEIgnoredWhitespace(IgnoredWhitespace::StartOfLine(
"\n"
)),
TemplateElement::TETag(DustTag::DTSection(Container {
path: Path {
keys: vec!["names"]
},
contents: Some(Body {
elements: vec![TemplateElement::TETag(DustTag::DTReference(
Reference {
elements: vec![
TemplateElement::TEIgnoredWhitespace(
IgnoredWhitespace::StartOfLine("\n")
),
TemplateElement::TETag(DustTag::DTReference(Reference {
path: Path { keys: vec![] },
filters: vec![]
}
))]
})),
TemplateElement::TEIgnoredWhitespace(
IgnoredWhitespace::StartOfLine("\n")
)
]
}),
else_contents: None,
})),

View File

@ -85,10 +85,8 @@ impl<'a> DustRenderer<'a> {
let mut output = String::new();
for elem in &body.elements {
match elem {
TemplateElement::TESpan(span) => span
.contents
.iter()
.for_each(|line: &&str| output.push_str(line)),
TemplateElement::TEIgnoredWhitespace(_) => {}
TemplateElement::TESpan(span) => output.push_str(span.contents),
TemplateElement::TETag(dt) => {
output.push_str(&self.render_tag(dt, context)?);
}