djc / askama

Type-safe, compiled Jinja-like templates for Rust
Apache License 2.0
3.35k stars 215 forks source link

Support endcall #996

Closed alexandervantrijffel closed 4 months ago

alexandervantrijffel commented 5 months ago

It would be great if endcall is supported to close a call block. I'm using djlint for formatting html template files. Because endcall is not supported by Askama, the djlint formatter processes call tags as unclosed call blocks which leads to incorrect indenting in files.

Example:

image

When endcall tags are added the code is correctly indented by djlint:

image

But this is not supported by Askama:

image
djc commented 5 months ago

Happy to review a PR for this, are you able to submit one?

Kijewski commented 5 months ago

Hm, our {% call %} does not work the same as the same statement in jinja. I guess it's too late to rename our keyword for calling a macro.

I wonder how {% endcall %} can be added without breaking things. We could simply make it an alias for an empty comment block. This would make it easy to suppress whitespaces around {%- endcall -%}, and we would not have to change anything in the generator.

alexandervantrijffel commented 5 months ago

For ensuring backwards compatibility, an approach could be:

Let the Call node scan nodes until it finds either an endcall tag, a call tag or until it reaches the end of the document. If another call tag is found or the end of the document is reached before encountering an endcall tag, treat this call node as an unclosed call block. If an endcall tag is found, it's a valid call block.

I've tried to implement this in node.rs but didn't figure it out yet as I am not familiar with nom.

At least I did write a test case for this, perhaps that helps.

GuillaumeGomez commented 5 months ago

Wouldn't it be fine to make a breaking change and update the crate version accordingly?

djc commented 5 months ago

Wouldn't it be fine to make a breaking change and update the crate version accordingly?

Depends on the size of the breaking change... I don't want to break everyone unless there's a very good reason.

Hm, our {% call %} does not work the same as the same statement in jinja. I guess it's too late to rename our keyword for calling a macro.

Not entirely clear to me what they do -- they pass the content of the block to the macro as the first/last argument?

Generating a noop comment node for {% endcall %} seems like a reasonably low-complexity solution.

Kijewski commented 5 months ago

Not entirely clear to me what they do -- they pass the content of the block to the macro as the first/last argument?

The called macro can use {{ caller() }} to insert the content between {%call%} and {%endcall%} of the caller.

If a macro {% call(arg1) macro1() %} calls {{ call macro2() }}, then macro2 can pass an argument arg1 back to the body of macro1.

djc commented 5 months ago

Pff, that seems like a lot of complexity that seems like a bad fit for Askama.

antifuchs commented 4 months ago

I ran into this as well (and imagine how happy I was to find djlint, which seems like the only tool that's semi-reasonably able to indent askama's syntax), and found the "ignore_blocks": "call" djlint directive, which I treats call blocks correctly, by letting djlint know that it's not a block that needs indentation.

alexandervantrijffel commented 4 months ago

Ignoring the call block is indeed a solution to my issue @antifuchs , thanks for sharing!

@maintainers feel free to close this issue if you like.