djlint / djLint

✨ HTML Template Linter and Formatter. Django - Jinja - Nunjucks - Handlebars - GoLang
https://djLint.com
GNU General Public License v3.0
690 stars 84 forks source link

[BUG] [Formatter] Refactor inline conditions #182

Open sondrelg opened 2 years ago

sondrelg commented 2 years ago

System Info

Issue

All conditions seem to be reformatted - even inline conditions that matter for string formatting:

❯ djlint test.html --reformat --indent 2

Reformatting 1/1 files ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 00:00    

test.html
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
@@ -1 +1,2 @@

-Dog{% if another_condition != 1 %}s{% endif %}
+Dog
+{% if another_condition != 1 %}s{% endif %}

1 file was updated.

In this example, the HTML goes from displaying Dogs to Dog s. Would it be possible to only refactor conditions on column index zero?

How To Reproduce

christopherpickering commented 2 years ago

Thanks, the trick is to know when the {% if %} is intentionally "inline", like div vs span (for example from prettier): image

I don't think we can use the line index, but maybe there is something else we can use. Maybe a regex [a-z]{% or something like this, for cases to ignore.

sondrelg commented 2 years ago

I think for our case, it's fair to say that a condition is intentionally inlined if the {% tag doesn't start on column index 0, where the column index 0 means it's the first non-whitespace character on a line, or it's the first character after an opening HTML tag.

In other words, this is intentionally inline

Dog{% if condition %}s{% endif %}

and this is not

{% if condition %}s{% endif %}

Similarly, this is intentional

<p>Dog{% if condition %}s{% endif %}</p>

and this is not

<p>{% if condition %}s{% endif %}</p>

Not sure if there are other cases to consider that contradict this logic, but that's my first though 👍

christopherpickering commented 2 years ago

Yeah, its a hard problem to solve. What if, for example, someone wants to format minified html? In all our example so far, if we minify it, everything will be on a single line. So nothing is on index 0. If you are starting with "pre-formatted" html then you just need an indenter like djhtml, right?

I'm thinking in general that {% almost never comes after a alpha character unless it is supposed to stay there. The more I see this the more I like the jinja and njk {%- tag 😀 I wish dj would pick that up!

sondrelg commented 2 years ago

Yeah the regex would certainly fix it in that sense. Maybe matching on any alphanumeric previous character, not counting whitespace would be more robust, to also handle examples like 0 {% if plural %}dogs{% else %}dog{% endif %}?

Maybe not the best example, but think the point stands 😄