aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lord <davidism@gmail.com>2020-04-13 07:09:31 -0700
committerGitHub <noreply@github.com>2020-04-13 07:09:31 -0700
commitf1756a3b44a6fd791954bd8d610cd9211d682518 (patch)
treed01904e74f2b795830f2e49f4941755903b0cb78
parent4a70cd480f46da7004cc58b14be3b9966652954a (diff)
parent7163513a352cb7eda328fedb2bfcd987510929af (diff)
downloadjinja-f1756a3b44a6fd791954bd8d610cd9211d682518.tar.gz
Merge pull request #1183 from exponea/1138-fix-unintended-lstrip-behavior-change
Fix unintended lstrip_blocks behavior
-rw-r--r--CHANGES.rst2
-rw-r--r--src/jinja2/lexer.py13
-rw-r--r--tests/test_lexnparse.py92
3 files changed, 102 insertions, 5 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 579b80b9..e6608f45 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -25,6 +25,8 @@ Unreleased
:pr:`1178`
- The special ``namespace()`` assignment object in templates works in
async environments. :issue:`1180`
+- Fix whitespace being removed before tags in the middle of lines when
+ ``lstrip_blocks`` is enabled. :issue:`1138`
Version 2.11.1
diff --git a/src/jinja2/lexer.py b/src/jinja2/lexer.py
index 5fa940d9..552356a1 100644
--- a/src/jinja2/lexer.py
+++ b/src/jinja2/lexer.py
@@ -682,6 +682,7 @@ class Lexer(object):
balancing_stack = []
lstrip_unless_re = self.lstrip_unless_re
newlines_stripped = 0
+ line_starting = True
while 1:
# tokenizer loop
@@ -731,11 +732,11 @@ class Lexer(object):
):
# The start of text between the last newline and the tag.
l_pos = text.rfind("\n") + 1
-
- # If there's only whitespace between the newline and the
- # tag, strip it.
- if not lstrip_unless_re.search(text, l_pos):
- groups = (text[:l_pos],) + groups[1:]
+ if l_pos > 0 or line_starting:
+ # If there's only whitespace between the newline and the
+ # tag, strip it.
+ if not lstrip_unless_re.search(text, l_pos):
+ groups = (text[:l_pos],) + groups[1:]
for idx, token in enumerate(tokens):
# failure group
@@ -794,6 +795,8 @@ class Lexer(object):
yield lineno, tokens, data
lineno += data.count("\n")
+ line_starting = m.group()[-1:] == "\n"
+
# fetch new position into new variable so that we can check
# if there is a internal parsing error which would result
# in an infinite loop
diff --git a/tests/test_lexnparse.py b/tests/test_lexnparse.py
index 3355791a..83ae75e0 100644
--- a/tests/test_lexnparse.py
+++ b/tests/test_lexnparse.py
@@ -729,6 +729,98 @@ ${item} ## the rest of the stuff
)
assert tmpl.render(seq=range(5)) == "".join("%s\n" % x for x in range(5))
+ def test_lstrip_blocks_outside_with_new_line(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
+ tmpl = env.from_string(
+ " {% if kvs %}(\n"
+ " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}\n"
+ " ){% endif %}"
+ )
+ out = tmpl.render(kvs=[("a", 1), ("b", 2)])
+ assert out == "(\na=1 b=2 \n )"
+
+ def test_lstrip_trim_blocks_outside_with_new_line(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=True)
+ tmpl = env.from_string(
+ " {% if kvs %}(\n"
+ " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}\n"
+ " ){% endif %}"
+ )
+ out = tmpl.render(kvs=[("a", 1), ("b", 2)])
+ assert out == "(\na=1 b=2 )"
+
+ def test_lstrip_blocks_inside_with_new_line(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
+ tmpl = env.from_string(
+ " ({% if kvs %}\n"
+ " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}\n"
+ " {% endif %})"
+ )
+ out = tmpl.render(kvs=[("a", 1), ("b", 2)])
+ assert out == " (\na=1 b=2 \n)"
+
+ def test_lstrip_trim_blocks_inside_with_new_line(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=True)
+ tmpl = env.from_string(
+ " ({% if kvs %}\n"
+ " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}\n"
+ " {% endif %})"
+ )
+ out = tmpl.render(kvs=[("a", 1), ("b", 2)])
+ assert out == " (a=1 b=2 )"
+
+ def test_lstrip_blocks_without_new_line(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
+ tmpl = env.from_string(
+ " {% if kvs %}"
+ " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}"
+ " {% endif %}"
+ )
+ out = tmpl.render(kvs=[("a", 1), ("b", 2)])
+ assert out == " a=1 b=2 "
+
+ def test_lstrip_trim_blocks_without_new_line(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=True)
+ tmpl = env.from_string(
+ " {% if kvs %}"
+ " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}"
+ " {% endif %}"
+ )
+ out = tmpl.render(kvs=[("a", 1), ("b", 2)])
+ assert out == " a=1 b=2 "
+
+ def test_lstrip_blocks_consume_after_without_new_line(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
+ tmpl = env.from_string(
+ " {% if kvs -%}"
+ " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor -%}"
+ " {% endif -%}"
+ )
+ out = tmpl.render(kvs=[("a", 1), ("b", 2)])
+ assert out == "a=1 b=2 "
+
+ def test_lstrip_trim_blocks_consume_before_without_new_line(self):
+ env = Environment(lstrip_blocks=False, trim_blocks=False)
+ tmpl = env.from_string(
+ " {%- if kvs %}"
+ " {%- for k, v in kvs %}{{ k }}={{ v }} {% endfor -%}"
+ " {%- endif %}"
+ )
+ out = tmpl.render(kvs=[("a", 1), ("b", 2)])
+ assert out == "a=1 b=2 "
+
+ def test_lstrip_trim_blocks_comment(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=True)
+ tmpl = env.from_string(" {# 1 space #}\n {# 2 spaces #} {# 4 spaces #}")
+ out = tmpl.render()
+ assert out == " " * 4
+
+ def test_lstrip_trim_blocks_raw(self):
+ env = Environment(lstrip_blocks=True, trim_blocks=True)
+ tmpl = env.from_string("{{x}}\n{%- raw %} {% endraw -%}\n{{ y }}")
+ out = tmpl.render(x=1, y=2)
+ assert out == "1 2"
+
def test_php_syntax_with_manual(self, env):
env = Environment(
"<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True