Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Whitespace control - Trim left spaces #3683

Open
brain-diminished opened this issue Apr 14, 2022 · 6 comments
Open

Whitespace control - Trim left spaces #3683

brain-diminished opened this issue Apr 14, 2022 · 6 comments

Comments

@brain-diminished
Copy link

If an expression {{ }} or statement {% %} is directly followed by a linebreak, which is pretty often, it seems to be automatically removed.
For instance:

<tag>
{% set nothing = 42 %}
</tag>

would output:

<tag>
</tag>

and not:

<tag>

</tag>

If we extend this reasoning, wouldn't it make sense to also trim spaces at the left of the expression/statement, in the case there are only spaces at the start of the line?
To illustrate, let's reuse previous example with indentation:

    <tag>
    {% set nothing = 42 %}
    </tag>

It now outputs:

    <tag>
        </tag>

Currently, to maintain a good indentation, I always use a left space-only trim ~:

    <tag>
    {%~ set nothing = 42 %}
    </tag>

The use of ~ being pretty much systematic, I think it would be fully legitimate to infer it when the left part of the current line contains only spaces. I would agree that deciding to remove left spaces would mean that we would force the removal of "information" that, in some case that I cannot think of at the moment, some might actually want to preserve. Then, once again, Twig already does something similar by implicitly removing some linebreaks.

Therefore, I think a more natural way to deduce removable content would be to arbitrate on the whole line: if only composed of spaces apart from the statement, the whole line would be trimmed, including the ending linebreak, otherwise none of it. Moreover, this rule makes sense on a statement or comment, but not so much on an expression, which is expected to output something.

Two last exemples:

  <tag>{% for n in 0..3 %}
    {{ n }}
  {% endfor %}</tag>

outputs:

  <tag>    0
      1
      2
      3
  </tag>

whilst I believe one could legitimately expect to obtain instead:

  <tag>
    0
    1
    2
    3
  </tag>

And:

<tag>{# Some comment #}
</tag>

outputs:

<tag></tag>

whilst we could expect instead:

<tag>
</tag>

To sum up, the idea is quite simple: if a whole line (including the finishing CR/LF) is only composed of spaces, comments and statements, it shouldn't be rendered. Otherwise, everything should be preserved (including the finishing CR/LF).

What do you think?

@stof
Copy link
Member

stof commented Apr 14, 2022

@pudovmaxim
Copy link

pudovmaxim commented Apr 13, 2023

See https://twig.symfony.com/doc/3.x/templates.html#whitespace-control

I have question about whitespace control related to this. My test scenario:

--TEST--
Test line ending
--TEMPLATE--
{# without modifiers #}
first line {% if 1 > 0 %}1{% endif %}
and second line on new line

first line {% if 1 > 0 %}2{% endif %}{# with comment at end line #}
and second line on new line

{# with triminig whitespace except newline #}
first line {%~ if 1 > 0 %}3{% endif ~%}
and second line on new line

{# with whitespace at end of line #}
first line {% if 1 > 0 %}4{% endif %} 
and second line on new line

line before for
{% for i in range(1, 9) %}
	{{- i -}}
{% endfor %}
new line after endfor
--DATA--
return []
--EXPECT--
first line 1
and second line on new line

first line 2
and second line on new line

first line 3
and second line on new line

first line 4 
and second line on new line

line before for
123456789
new line after endfor

And output is

Test line ending (in whitespace/trim_line_ending.test)
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'first line 1\n
-and second line on new line\n
+'first line 1and second line on new line\n
 \n
-first line 2\n
-and second line on new line\n
+first line 2and second line on new line\n
 \n
-first line 3\n
+first line3\n
 and second line on new line\n
 \n
 first line 4 \n
@@ @@
 and second line on new line\n
 \n
 line before for\n
-123456789\n
-new line after endfor'
+123456789new line after endfor'

It not documented and lead to some kinds of errors. For example it can be dangerous in js:

var isFoo = {% if o.isFoo %}true{% else %}false{% endif %}
var isBar = true

and instead

var isFoo = true
var isBar = true

we got a wrong js-code

var isFoo = truevar isBar = true

@pudovmaxim
Copy link

I make demo on raw php and twig
https://onlinephp.io/c/d6084
https://twigfiddle.com/9h6dsl

And twig already uses different approaches for removing line endings after output and execution tags. In php, removing line endings is useful for a few reasons. This was discussed on the mailing list in 1998 (25 years ago!) https://marc.info/?t=90279165800002&r=1&w=2

But why does this rule about deleting a newline after closing a tag exist in Twig?

@stof
Copy link
Member

stof commented Apr 14, 2023

It not documented and lead to some kinds of errors.

This is actually documented. It is the first sentence in the documentation section that I linked to you:

The first newline after a template tag is removed automatically (like in PHP).

@pudovmaxim
Copy link

This is actually documented. It is the first sentence in the documentation section that I linked to you:

Yes, sorry about that. Misunderstood the meaning and thought about the line ending at end of template.

But the question is still open:

Why is this principle from php is used in twig? And how is it possible to disable it globally?

@stof
Copy link
Member

stof commented Apr 14, 2023

you cannot disable it globally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants