]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
ignore trim_blocks using '+%}' 1240/head
authorAmy <leiamy12@gmail.com>
Wed, 17 Jun 2020 18:12:57 +0000 (14:12 -0400)
committerDavid Lord <davidism@gmail.com>
Mon, 22 Jun 2020 17:21:47 +0000 (10:21 -0700)
CHANGES.rst
docs/templates.rst
src/jinja2/lexer.py
tests/test_lexnparse.py

index d42f213c1feb016224249833e0b37a84b37fc71e..298cf0ab854eb4eae21b1dd4a359deaa44dfae6a 100644 (file)
@@ -13,7 +13,7 @@ Unreleased
     :class:`~loaders.PackageLoader`. :issue:`1168`
 -   Fix a bug that caused imported macros to not have access to the
     current template's globals. :issue:`688`
-
+-   Add ability to ignore ``trim_blocks`` using ``+%}``. :issue:`1036`
 
 Version 2.11.2
 --------------
index a346ef2332b1c96d2bd30417410b2a6cd4bd1a1e..3101d0ed04e9cad48805990fefd39f4c731d94f5 100644 (file)
@@ -230,6 +230,15 @@ plus sign (``+``) at the start of a block::
             {%+ if something %}yay{% endif %}
     </div>
 
+Similarly, you can manually disable the ``trim_blocks`` behavior by
+putting a plus sign (``+``) at the end of a block::
+
+    <div>
+        {% if something +%}
+            yay
+        {% endif %}
+    </div>
+
 You can also strip whitespace in templates by hand.  If you add a minus
 sign (``-``) to the start or end of a block (e.g. a :ref:`for-loop` tag), a
 comment, or a variable expression, the whitespaces before or after
index 0a992073e7e3d7b36eb9aab3495e30b2c9884e4c..082a051de8bdb39140f1774c9bed4548bd657aa0 100644 (file)
@@ -509,8 +509,8 @@ class Lexer:
             TOKEN_COMMENT_BEGIN: [
                 (
                     c(
-                        fr"(.*?)((?:\-{comment_end_re}\s*"
-                        fr"|{comment_end_re}){block_suffix_re})"
+                        fr"(.*?)((?:\+{comment_end_re}|\-{comment_end_re}\s*"
+                        fr"|{comment_end_re}{block_suffix_re}))"
                     ),
                     (TOKEN_COMMENT, TOKEN_COMMENT_END),
                     "#pop",
@@ -520,7 +520,10 @@ class Lexer:
             # blocks
             TOKEN_BLOCK_BEGIN: [
                 (
-                    c(fr"(?:\-{block_end_re}\s*|{block_end_re}){block_suffix_re}"),
+                    c(
+                        fr"(?:\+{block_end_re}|\-{block_end_re}\s*"
+                        fr"|{block_end_re}{block_suffix_re})"
+                    ),
                     TOKEN_BLOCK_END,
                     "#pop",
                 ),
@@ -540,7 +543,8 @@ class Lexer:
                 (
                     c(
                         fr"(.*?)((?:{block_start_re}(\-|\+|))\s*endraw\s*"
-                        fr"(?:\-{block_end_re}\s*|{block_end_re}{block_suffix_re}))"
+                        fr"(?:\+{block_end_re}|\-{block_end_re}\s*"
+                        fr"|{block_end_re}{block_suffix_re}))"
                     ),
                     OptionalLStrip(TOKEN_DATA, TOKEN_RAW_END),
                     "#pop",
index c0257cf1d9a4660d5ac9600d34de751debdb6424..96e134d11440e80189cfd0a3bbfdc26ec04e8b2f 100644 (file)
@@ -903,3 +903,121 @@ ${item} ## the rest of the stuff
 <!--- endfor -->"""
         )
         assert tmpl.render(seq=range(5)) == "01234"
+
+
+class TestTrimBlocks:
+    def test_trim(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=False)
+        tmpl = env.from_string("    {% if True %}\n    {% endif %}")
+        assert tmpl.render() == "        "
+
+    def test_no_trim(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=False)
+        tmpl = env.from_string("    {% if True +%}\n    {% endif %}")
+        assert tmpl.render() == "    \n    "
+
+    def test_no_trim_outer(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=False)
+        tmpl = env.from_string("{% if True %}X{% endif +%}\nmore things")
+        assert tmpl.render() == "X\nmore things"
+
+    def test_lstrip_no_trim(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=True)
+        tmpl = env.from_string("    {% if True +%}\n    {% endif %}")
+        assert tmpl.render() == "\n"
+
+    def test_trim_blocks_false_with_no_trim(self, env):
+        # Test that + is a NOP (but does not cause an error) if trim_blocks=False
+        env = Environment(trim_blocks=False, lstrip_blocks=False)
+        tmpl = env.from_string("    {% if True %}\n    {% endif %}")
+        assert tmpl.render() == "    \n    "
+        tmpl = env.from_string("    {% if True +%}\n    {% endif %}")
+        assert tmpl.render() == "    \n    "
+
+        tmpl = env.from_string("    {# comment #}\n    ")
+        assert tmpl.render() == "    \n    "
+        tmpl = env.from_string("    {# comment +#}\n    ")
+        assert tmpl.render() == "    \n    "
+
+        tmpl = env.from_string("    {% raw %}{% endraw %}\n    ")
+        assert tmpl.render() == "    \n    "
+        tmpl = env.from_string("    {% raw %}{% endraw +%}\n    ")
+        assert tmpl.render() == "    \n    "
+
+    def test_trim_nested(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=True)
+        tmpl = env.from_string(
+            "    {% if True %}\na {% if True %}\nb {% endif %}\nc {% endif %}"
+        )
+        assert tmpl.render() == "a b c "
+
+    def test_no_trim_nested(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=True)
+        tmpl = env.from_string(
+            "    {% if True +%}\na {% if True +%}\nb {% endif +%}\nc {% endif %}"
+        )
+        assert tmpl.render() == "\na \nb \nc "
+
+    def test_comment_trim(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=True)
+        tmpl = env.from_string("""    {# comment #}\n\n  """)
+        assert tmpl.render() == "\n  "
+
+    def test_comment_no_trim(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=True)
+        tmpl = env.from_string("""    {# comment +#}\n\n  """)
+        assert tmpl.render() == "\n\n  "
+
+    def test_multiple_comment_trim_lstrip(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=True)
+        tmpl = env.from_string(
+            "   {# comment #}\n\n{# comment2 #}\n   \n{# comment3 #}\n\n "
+        )
+        assert tmpl.render() == "\n   \n\n "
+
+    def test_multiple_comment_no_trim_lstrip(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=True)
+        tmpl = env.from_string(
+            "   {# comment +#}\n\n{# comment2 +#}\n   \n{# comment3 +#}\n\n "
+        )
+        assert tmpl.render() == "\n\n\n   \n\n\n "
+
+    def test_raw_trim_lstrip(self, env):
+        env = Environment(trim_blocks=True, lstrip_blocks=True)
+        tmpl = env.from_string("{{x}}{% raw %}\n\n    {% endraw %}\n\n{{ y }}")
+        assert tmpl.render(x=1, y=2) == "1\n\n\n2"
+
+    def test_raw_no_trim_lstrip(self, env):
+        env = Environment(trim_blocks=False, lstrip_blocks=True)
+        tmpl = env.from_string("{{x}}{% raw %}\n\n      {% endraw +%}\n\n{{ y }}")
+        assert tmpl.render(x=1, y=2) == "1\n\n\n\n2"
+
+        # raw blocks do not process inner text, so start tag cannot ignore trim
+        with pytest.raises(TemplateSyntaxError):
+            tmpl = env.from_string("{{x}}{% raw +%}\n\n  {% endraw +%}\n\n{{ y }}")
+
+    def test_no_trim_angle_bracket(self, env):
+        env = Environment(
+            "<%", "%>", "${", "}", "<%#", "%>", lstrip_blocks=True, trim_blocks=True,
+        )
+        tmpl = env.from_string("    <% if True +%>\n\n    <% endif %>")
+        assert tmpl.render() == "\n\n"
+
+        tmpl = env.from_string("    <%# comment +%>\n\n   ")
+        assert tmpl.render() == "\n\n   "
+
+    def test_no_trim_php_syntax(self, env):
+        env = Environment(
+            "<?",
+            "?>",
+            "<?=",
+            "?>",
+            "<!--",
+            "-->",
+            lstrip_blocks=False,
+            trim_blocks=True,
+        )
+        tmpl = env.from_string("    <? if True +?>\n\n    <? endif ?>")
+        assert tmpl.render() == "    \n\n    "
+        tmpl = env.from_string("    <!-- comment +-->\n\n    ")
+        assert tmpl.render() == "    \n\n    "