From 7b4f1dc907e0329c6c434e1d69ced35b747ab46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Tue, 10 Sep 2024 00:00:31 +0200 Subject: [PATCH] parser: add optional `{% endwhen %}` --- rinja_parser/src/node.rs | 33 ++++++++++++++++++++++++++++++++- testing/tests/matches.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/rinja_parser/src/node.rs b/rinja_parser/src/node.rs index 9d27ec49..d9d501f3 100644 --- a/rinja_parser/src/node.rs +++ b/rinja_parser/src/node.rs @@ -204,6 +204,33 @@ impl<'a> When<'a> { #[allow(clippy::self_named_constructors)] fn when(i: &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> { let start = i; + let endwhen = map( + consumed(ws(pair( + delimited( + |i| s.tag_block_start(i), + opt(Whitespace::parse), + ws(keyword("endwhen")), + ), + cut(tuple(( + opt(Whitespace::parse), + |i| s.tag_block_end(i), + many0(value((), ws(|i| Comment::parse(i, s)))), + ))), + ))), + |(span, (pws, _))| { + // A comment node is used to pass the whitespace suppressing information to the + // generator. This way we don't have to fix up the next `when` node or the closing + // `endmatch`. Any whitespaces after `endwhen` are to be suppressed. Actually, they + // don't wind up in the AST anyway. + Node::Comment(WithSpan::new( + Comment { + ws: Ws(pws, Some(Whitespace::Suppress)), + content: "", + }, + span, + )) + }, + ); let mut p = tuple(( |i| s.tag_block_start(i), opt(Whitespace::parse), @@ -213,9 +240,13 @@ impl<'a> When<'a> { opt(Whitespace::parse), |i| s.tag_block_end(i), cut(|i| Node::many(i, s)), + opt(endwhen), ))), )); - let (i, (_, pws, _, (target, nws, _, nodes))) = p(i)?; + let (i, (_, pws, _, (target, nws, _, mut nodes, endwhen))) = p(i)?; + if let Some(endwhen) = endwhen { + nodes.push(endwhen); + } Ok(( i, WithSpan::new( diff --git a/testing/tests/matches.rs b/testing/tests/matches.rs index 6102b237..65ac0d24 100644 --- a/testing/tests/matches.rs +++ b/testing/tests/matches.rs @@ -265,3 +265,38 @@ fn test_match_with_patterns() { let s = MatchPatterns { n: 12 }; assert_eq!(s.render().unwrap(), "12"); } + +#[derive(Template)] +#[template(in_doc = true, ext = "html")] +/// ```rinja +/// {% match result %} +/// {% when Some(Ok(s)) -%} +/// good: {{s}} +/// {%- endwhen +%} +/// {# This is not good: #} +/// {%+ when Some(Err(s)) -%} +/// bad: {{s}} +/// {%- endwhen +%} +/// {%+ else -%} +/// unprocessed +/// {% endmatch %} +/// ``` +struct EndWhen<'a> { + result: Option>, +} + +#[test] +fn test_end_when() { + let tmpl = EndWhen { + result: Some(Ok("msg")), + }; + assert_eq!(tmpl.to_string(), "good: msg"); + + let tmpl = EndWhen { + result: Some(Err("msg")), + }; + assert_eq!(tmpl.to_string(), "bad: msg"); + + let tmpl = EndWhen { result: None }; + assert_eq!(tmpl.to_string(), "unprocessed\n"); +}