Repository: rinja-rs/askama (language: rust)

Issue:
Rust macro has no access to parameters passed into `{% macro f(param) %}`
Not sure if this is a question, feature request or a bug.

From the documentation it's not clear to me in what scope rust macros are evaluated.
For instance, I have this Askama macro, which calls a Rust macro internally:

```jinja
{% macro stop(entity) %}
    {{ create_action!(entity, LightOn, {brightness:Some(0.1), color_temperature: None})|json }}
{% endmacro %}
```

In some situations this works perfectly, while in other situations this does not and results in a "cannot find value `entity` in this scope". (`entity` being the argument passed to the Askama macro.)

It does work for one situation where this macro is called in another template within a loop like this: `{% for entity in entities.values() %}`. In any case, I've the impression that it doesn't pick up the argument passed to the Askama macro.

Is that understanding correct? Is there something we can improve here to make this possible?



Discussion / hints:
That certainly sounds surprising. Do you have a minimal reproducing example?
This is the simplest reproducing example I could get:

```rs

macro_rules! test_macro{
    ($entity:expr) => {
        {
            println!("{:?}", &$entity);
        }
    }
}

#[derive(Template)]
#[template(source = "{{ test_macro!(entity) }}", ext = "txt")]
struct TestTemplate<'a> {
    entity: &'a str,
}
```

which results in:

```
error[E0425]: cannot find value `entity` in this scope
  --> src/.../main.rs:29:10
   |
29 | #[derive(Template)]
```

It looks like it works if I call the macro using `self.entity`, but this is not what I want, because I'd like to reuse the template in a situation where it's nested in a loop.
Oh I see the issue. Since it's a macro, we can't know if `entity` is from `self` or just a token (for a name you're generating for example?). I think this code would work in all cases:

```jinja
let entity = entity;
{{ test_macro!(entity) }}
```
I assume you meant:
```jinja
{% let entity = entity; %}
{{ test_macro!(entity) }}
```
which seems to work indeed.

Would it be possible for Askama to automatically bind all struct fields from the template struct to local variables with the same name so that macros will work automatically?
> I assume you meant:
> ...

Yes I did. ^^'

> Would it be possible for Askama to automatically bind all struct fields from the template struct to local variables with the same name so that macros will work automatically?

It'd be problematic for different reasons:
 * If you have a big struct, it'll generate a lot of variables that might not be used. Lot of dead code in short, meaning bigger code to compile, meaning longer compile time.
 * It could lead to surprising/unwanted usage of variables. For example you use a variable named `x` in a template you include. Variable you're supposed to define yourself which you do normally because of the error. But if you type has an `x` field, then it'll just be a surprising (and likely unwanted) result.

What I suggest is instead to add your use case as an example for macros in the askama book. What do you think?
Thanks for the feedback! I understand. Feel free to add it to the book!

Fix patch:
diff --git a/book/src/template_syntax.md b/book/src/template_syntax.md
index 31b1eaa14..8a77d12a5 100644
--- a/book/src/template_syntax.md
+++ b/book/src/template_syntax.md
@@ -642,3 +642,38 @@ In here it's invalid because `arg2` is the second argument and would be used by
 {# Equivalent of: #}
 {% call heading("something", "title", "b", arg4="ah") %}
 ```
+
+## Calling Rust macros
+
+It is possible to call rust macros directly in your templates:
+
+```jinja
+{% let s = format!("{}", 12) %}
+```
+
+One important thing to note is that contrary to the rest of the expressions,
+Askama cannot know if a token given to a macro is a variable or something
+else, so it will always default to generate it "as is". So if you have:
+
+```rust
+macro_rules! test_macro{
+    ($entity:expr) => {
+        println!("{:?}", &$entity);
+    }
+}
+
+#[derive(Template)]
+#[template(source = "{{ test_macro!(entity) }}", ext = "txt")]
+struct TestTemplate<'a> {
+    entity: &'a str,
+}
+```
+
+It will not compile, telling you it doesn't know `entity`. It didn't infer
+that `entity` was a field of the current type unlike usual. You can go
+around this limitation by binding your field's value into a variable:
+
+```jinja
+{% let entity = entity; %}
+{{ test_macro!(entity) }}
+```


Test patch: