Keats / tera

A template engine for Rust based on Jinja2/Django
http://keats.github.io/tera/
MIT License
3.56k stars 286 forks source link

[Feature Request] Nested expressions #539

Open Kixiron opened 4 years ago

Kixiron commented 4 years ago

To my knowledge variables & expressions are rather "flat"; That is, they don't allow very much nesting which really limits their usefulness For example, take this code:

{%- set release_url = "/crate/" ~ name | escape ~ "/" ~ release.version | escape -%}

Making a variable containing a string built out of parts that needs escaping, a reasonably common occurrence. Unfortunately, the above won't compile and produces the following error

  --> 91:57
     |
  91 |         {%- set release_url = "/crate/" ~ name | escape ~ "/" ~ release.version  | escape -%}
     |                                                         ^---
     |
     = expected `or`, `and`, `not`, `<=`, `>=`, `<`, `>`, `==`, `!=`, a filter, or `%}` or `-%}`

I then tried multiple variations to no avail

{%- set release_url = "/crate/" ~ (name | escape) ~ "/" ~ (release.version | escape) -%}
{%- set release_url = "/crate/" ~ {{ name | escape }} ~ "/" ~ {{ release.version | escape }} -%}

The only solution I could find was to break everything into individual variables that were then incorporated in, which isn't ideal

{%- set name = name | escape -%}
{%- set version = release.version | escape -%}
{%- set release_url = "/crate/" ~ name ~ "/" ~ version -%}
Keats commented 4 years ago

I believe Tera could handle it and this is just an issue at the parser level. I was waiting for pest3 for some parser improvements but it seems like this isn't happening anymore :(

I might need to invest some time looking at other parser combinators libs but I'm not looking forward to it/have time anytime soon for that.

sytherax commented 1 week ago

I am running into the same problem, and unsure how to solve it.

{% for item in items %}
{{ markets::render_symbol_list_item(
    item=item,
    onclick_action="selectedSymbol = '" ~ item.symbol | upper ~ "'; selectedIcon = '" ~ item.base_icon_url ~ "'; UIkit.toggle('#cmd2').toggle()"
) }}
{% endfor %}
52:65\n   |\n52 |       onclick_action=\"selectedSymbol = '\" ~ item.symbol | upper ~ \"'; selectedIcon = '\" ~ item.base_icon_url ~ \"'; UIkit.toggle('#cmd2').toggle()\"\n   |                                                                 ^---\n   |\n   = expected `or`, `and`, `not`, `<=`, `>=`, `<`, `>`, `==`, `!=`, or a filter"), source: None })
Keats commented 1 week ago

FYI I believe this works as expected in https://github.com/Keats/tera2

{% set symbol = "a" %}
{% set base_icon_url = "http://google.com" %}
{{ "selectedSymbol = '" ~ (symbol | upper) ~ "'; selectedIcon = '" ~ base_icon_url ~ "'; UIkit.toggle('#cmd2').toggle()" | safe }}

gives me:

selectedSymbol = 'A'; selectedIcon = 'http://google.com'; UIkit.toggle('#cmd2').toggle()

You need the parentheses around (symbol | upper) because ~ has a higher precedence than filters so it would uppercase the whole concatenated string otherwise.

sytherax commented 1 week ago

Can't wait for Tera2. That will be awesome