Merge branch 'bug_tags_separated_by_whitespace' into render
This commit is contained in:
		
						commit
						7f65e73229
					
				| @ -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; | ||||
| @ -53,6 +51,11 @@ pub enum Special { | ||||
|     RightCurlyBrace, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq)] | ||||
| pub enum IgnoredWhitespace<'a> { | ||||
|     StartOfLine(&'a str), | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq)] | ||||
| pub struct Comment<'a> { | ||||
|     value: &'a str, | ||||
| @ -85,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)] | ||||
| @ -132,7 +135,7 @@ pub struct Body<'a> { | ||||
|     pub elements: Vec<TemplateElement<'a>>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| #[derive(Clone, Debug, PartialEq)] | ||||
| pub struct Template<'a> { | ||||
|     pub contents: Body<'a>, | ||||
| } | ||||
| @ -141,6 +144,7 @@ pub struct Template<'a> { | ||||
| pub enum TemplateElement<'a> { | ||||
|     TESpan(Span<'a>), | ||||
|     TETag(DustTag<'a>), | ||||
|     TEIgnoredWhitespace(IgnoredWhitespace<'a>), | ||||
| } | ||||
| 
 | ||||
| /// Any element significant to dust that isn't plain text
 | ||||
| @ -475,36 +479,35 @@ 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) | ||||
| /// 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 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)?; | ||||
| @ -613,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"))) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
| @ -641,7 +628,7 @@ mod tests { | ||||
|             Ok(( | ||||
|                 "", | ||||
|                 Span { | ||||
|                     contents: vec!["this is just some text"] | ||||
|                     contents: "this is just some text" | ||||
|                 } | ||||
|             )) | ||||
|         ); | ||||
| @ -650,7 +637,7 @@ mod tests { | ||||
|             Ok(( | ||||
|                 "{~lb}", | ||||
|                 Span { | ||||
|                     contents: vec!["this is just some text "] | ||||
|                     contents: "this is just some text " | ||||
|                 } | ||||
|             )) | ||||
|         ); | ||||
| @ -659,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" | ||||
|                         }), | ||||
|                     ] | ||||
|                 } | ||||
|             )) | ||||
|         ); | ||||
| @ -732,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() | ||||
| @ -759,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() | ||||
| @ -771,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"] }, | ||||
| @ -808,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() | ||||
| @ -846,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() | ||||
| @ -935,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 | ||||
| @ -976,4 +977,79 @@ mod tests { | ||||
|             )) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_full_document_new_line_equality() { | ||||
|         assert_eq!( | ||||
|             super::template( | ||||
|                 "- simple -{~n}
 | ||||
| {#names}{.}{/names} | ||||
| {~n}- new lines -{~n} | ||||
| {#names} | ||||
| {.} | ||||
| {/names}" | ||||
|             ), | ||||
|             Ok::<_, nom::Err<(&str, ErrorKind)>>(( | ||||
|                 "", | ||||
|                 Template { | ||||
|                     contents: Body { | ||||
|                         elements: vec![ | ||||
|                             TemplateElement::TESpan(Span { | ||||
|                                 contents: "- simple -" | ||||
|                             }), | ||||
|                             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 { | ||||
|                                             path: Path { keys: vec![] }, | ||||
|                                             filters: vec![] | ||||
|                                         } | ||||
|                                     ))] | ||||
|                                 }), | ||||
|                                 else_contents: None, | ||||
|                             })), | ||||
|                             TemplateElement::TEIgnoredWhitespace(IgnoredWhitespace::StartOfLine( | ||||
|                                 "\n" | ||||
|                             )), | ||||
|                             TemplateElement::TETag(DustTag::DTSpecial(Special::NewLine)), | ||||
|                             TemplateElement::TESpan(Span { | ||||
|                                 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::TEIgnoredWhitespace( | ||||
|                                             IgnoredWhitespace::StartOfLine("\n") | ||||
|                                         ), | ||||
|                                         TemplateElement::TETag(DustTag::DTReference(Reference { | ||||
|                                             path: Path { keys: vec![] }, | ||||
|                                             filters: vec![] | ||||
|                                         })), | ||||
|                                         TemplateElement::TEIgnoredWhitespace( | ||||
|                                             IgnoredWhitespace::StartOfLine("\n") | ||||
|                                         ) | ||||
|                                     ] | ||||
|                                 }), | ||||
|                                 else_contents: None, | ||||
|                             })), | ||||
|                         ] | ||||
|                     } | ||||
|                 } | ||||
|             )) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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)?); | ||||
|                 } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander