yogthos / Selmer

A fast, Django inspired template system in Clojure.
Eclipse Public License 1.0
986 stars 114 forks source link

Add whitespace control? #115

Open rduplain opened 8 years ago

rduplain commented 8 years ago

Jinja has a useful feature where you can strip out whitespace that you've added to make your template more readable:

{% for item in seq -%}
    {{ item }}
{%- endfor %}

This will yield all elements without whitespace between them. If seq was a list of numbers from 1 to 9, the output would be 123456789.

http://jinja.pocoo.org/docs/dev/templates/#whitespace-control

In other words, adding a - to get -%} will indicate that all whitespace should be removed between the for/if/other statement and the next character.

Feature request: any interest in adding this to Selmer?

yogthos commented 8 years ago

I'm not opposed to the feature, but I likely wouldn't have time to look at it in the near future. I could help with a pr if you're up for taking a look at it though.

borkdude commented 3 years ago

One obvervation made during a short experimental session:

The node structure looks like this (when printed from render-template:

user=> (selmer/render "{% if foo %} {{foo \n\n|json}} {% endif %}" {:foo 1})
:node #object[selmer.node.FunctionNode 0x648fa5b1 "selmer.node.FunctionNode@648fa5b1"]
:node #object[selmer.node.TextNode 0x74b5bb08 " "]
:node #object[selmer.node.FunctionNode 0x1da81d82 "selmer.node.FunctionNode@1da81d82"]
:node #object[selmer.node.TextNode 0x46d7ae7a " "]
:node #object[selmer.node.TextNode 0x151f9ad7 ""]

Maybe we can introduce a new type of node called a SkipTextNode which ignores text nodes (or only blank text nodes?) during rendering, until the next SkipTextNode. And this SkipTextNode gets inserted during parsing after reading the -% sign?

Or maybe we could avoid generating these text nodes to begin with during parsing, when you encounter the minus signs.

Maybe I'm already thinking too much about the implementation, but it seems that this feature is possible to implement.

yogthos commented 3 years ago

Yeah I think we could just skip emitting these nodes during parsing.

yogthos commented 3 years ago

I think the relevant bit of code for this is here.

borkdude commented 3 years ago

I have a very hacky version here:

https://github.com/yogthos/Selmer/compare/master...borkdude:whitespace-control

user=> (selmer/render "{% if foo %} \n hello \n {% endif %}" {:foo 1})
" \n hello \n "
user=> (selmer/render "{% if foo -%} \n hello \n {% endif %}" {:foo 1})
"hello"

I'm not sure if that's going into the right direction and also not sure if I'm a big fan of this magic syntax...

Would some other syntax work, like:

{% if foo }{% trim %}

Yolo. All the whitespace you want!

{% endtrim %}
{% endif %}

or is such a construct already possible, somehow?

yogthos commented 3 years ago

Adding a trim tag should work, but there's still a problem of the tags themselves leaving a blank line. With the way the parser works currently, there would be blank lines where the tags which I assume wouldn't be desirable.

yogthos commented 3 years ago

based on our slack brainstorming, let's go with {% if(trim, x, y) foo %} syntax where tag name could be followed by some arguments in parens akin to a function call. These could provide hints for how tag body would be further manipulated, such as trimming white space or empty lines.

borkdude commented 3 years ago

Adding this for posterity:

Screenshot 2021-05-10 at 21 23 11

/cc @roklenarcic

RokLenarcic commented 2 years ago

Any progress on this feature? The proposed solutions don't work because they control whitespace inside the tag, when the problem is the whitespace outside the tag. Here's a minimal example of a block of text that cannot be produced by the current Selmer version:

- Level: {{ level }}
- Color: {{ color }}
- Shape: {{ shape }}

Where level, color and shape are all optional, and if missing their line shouldn't be rendered and there must be no empty lines.

yogthos commented 2 years ago

I likely won't have a chance to look at this in the near future, but I'm definitely open for a PR to add the feature. I agree that it would be useful to provide hints to control the space outside the tags.

Ramblurr commented 2 years ago

Throwing another use case in here. Lines containing only selmer tags (e.g., {% for thing in things %}) end up as blank lines in the rendered output. For rendering plain-text (my use case) this is quite unfortunate.

In jinja this is handled with the trim_blocks and lstrip_blocks options (see https://jinja.palletsprojects.com/en/3.0.x/templates/#whitespace-control)

Btw, with the unlimited slack history.. here's the link to the thread screenshotted above: https://clojurians.slack.com/archives/C06MAR553/p1620329458137300

yogthos commented 2 years ago

This is a use case I'd be most interested in addressing as well.