diff options
author | René Kijewski <kijewski@library.vetmed.fu-berlin.de> | 2021-07-18 16:32:49 +0200 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2021-11-11 15:35:45 +0100 |
commit | 10b2d9c615460c9dbb241b887d0e6e17e3c001ca (patch) | |
tree | 4ec234cf416f7bcdc0bc037f787ebbd7ac4cb67e /askama_shared/src/parser.rs | |
parent | a8503e0fa2d6065b1c471becf76dde68571b7984 (diff) | |
download | askama-10b2d9c615460c9dbb241b887d0e6e17e3c001ca.tar.gz askama-10b2d9c615460c9dbb241b887d0e6e17e3c001ca.tar.bz2 askama-10b2d9c615460c9dbb241b887d0e6e17e3c001ca.zip |
Implement for-else
This PR implements for-else statements like in Jinja. They make it easy
to print an alternative message if the loop iterator was empty. E.g.
```rs
{% for result in result %}
<li>{{ result }}</li>
{% else %}
<li><em>no results</em></li>
{% endfor %}
```
Diffstat (limited to '')
-rw-r--r-- | askama_shared/src/parser.rs | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs index d1bc425..90c2fe3 100644 --- a/askama_shared/src/parser.rs +++ b/askama_shared/src/parser.rs @@ -22,7 +22,7 @@ pub enum Node<'a> { Let(Ws, Target<'a>, Expr<'a>), Cond(Vec<Cond<'a>>, Ws), Match(Ws, Expr<'a>, Vec<When<'a>>, Ws), - Loop(Ws, Target<'a>, Expr<'a>, Vec<Node<'a>>, Ws), + Loop(Loop<'a>), Extends(Expr<'a>), BlockDef(Ws, &'a str, Vec<Node<'a>>, Ws), Include(Ws, &'a str), @@ -34,6 +34,17 @@ pub enum Node<'a> { } #[derive(Debug, PartialEq)] +pub struct Loop<'a> { + pub ws1: Ws, + pub var: Target<'a>, + pub iter: Expr<'a>, + pub body: Vec<Node<'a>>, + pub ws2: Ws, + pub else_block: Vec<Node<'a>>, + pub ws3: Ws, +} + +#[derive(Debug, PartialEq)] pub enum Expr<'a> { BoolLit(&'a str), NumLit(&'a str), @@ -897,12 +908,28 @@ fn block_let(i: &[u8]) -> IResult<&[u8], Node<'_>> { fn parse_loop_content<'a>(i: &'a [u8], s: &State<'_>) -> IResult<&'a [u8], Vec<Node<'a>>> { s.loop_depth.set(s.loop_depth.get() + 1); - let (i, node) = parse_template(i, s)?; + let result = parse_template(i, s); s.loop_depth.set(s.loop_depth.get() - 1); - Ok((i, node)) + result } fn block_for<'a>(i: &'a [u8], s: &State<'_>) -> IResult<&'a [u8], Node<'a>> { + let else_block = |i| { + let mut p = preceded( + ws(tag("else")), + cut(tuple(( + opt(tag("-")), + delimited( + |i| tag_block_end(i, s), + |i| parse_template(i, s), + |i| tag_block_start(i, s), + ), + opt(tag("-")), + ))), + ); + let (i, (pws, nodes, nws)) = p(i)?; + Ok((i, (pws.is_some(), nodes, nws.is_some()))) + }; let mut p = tuple(( opt(char('-')), ws(tag("for")), @@ -918,6 +945,7 @@ fn block_for<'a>(i: &'a [u8], s: &State<'_>) -> IResult<&'a [u8], Node<'a>> { cut(tuple(( |i| tag_block_start(i, s), opt(char('-')), + opt(else_block), ws(tag("endfor")), opt(char('-')), ))), @@ -925,16 +953,19 @@ fn block_for<'a>(i: &'a [u8], s: &State<'_>) -> IResult<&'a [u8], Node<'a>> { ))), ))), )); - let (i, (pws1, _, (var, _, (iter, nws1, _, (block, (_, pws2, _, nws2)))))) = p(i)?; + let (i, (pws1, _, (var, _, (iter, nws1, _, (body, (_, pws2, else_block, _, nws2)))))) = p(i)?; + let (nws3, else_block, pws3) = else_block.unwrap_or_default(); Ok(( i, - Node::Loop( - Ws(pws1.is_some(), nws1.is_some()), + Node::Loop(Loop { + ws1: Ws(pws1.is_some(), nws1.is_some()), var, iter, - block, - Ws(pws2.is_some(), nws2.is_some()), - ), + body, + ws2: Ws(pws2.is_some(), nws3), + else_block, + ws3: Ws(pws3, nws2.is_some()), + }), )) } |