diff --git a/CHANGES.rst b/CHANGES.rst index b3b667d60..63ad274f3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,8 +16,11 @@ unreleased - The ``map`` filter in async mode now automatically awaits - Added a new ``ChainableUndefined`` class to support getitem and getattr on an undefined object. (`#977`_) +- Allow `'{%+'` syntax (with NOP behavior) when + `lstrip_blocks == False` (`#748`_) .. _#765: https://github.com/pallets/jinja/issues/765 +.. _#748: https://github.com/pallets/jinja/issues/748 .. _#977: https://github.com/pallets/jinja/issues/977 @@ -28,6 +31,7 @@ _Unreleased_ - Fix Python 3.7 deprecation warnings. + Version 2.10.1 -------------- diff --git a/jinja2/lexer.py b/jinja2/lexer.py index 6fd135dd5..e23a9987d 100644 --- a/jinja2/lexer.py +++ b/jinja2/lexer.py @@ -445,22 +445,21 @@ def __init__(self, environment): # strip leading spaces if lstrip_blocks is enabled prefix_re = {} + no_lstrip_re = e('+') + # detect overlap between block and variable or comment strings + block_diff = c(r'^%s(.*)' % e(environment.block_start_string)) + # make sure we don't mistake a block for a variable or a comment + m = block_diff.match(environment.comment_start_string) + no_lstrip_re += m and r'|%s' % e(m.group(1)) or '' + m = block_diff.match(environment.variable_start_string) + no_lstrip_re += m and r'|%s' % e(m.group(1)) or '' + # detect overlap between comment and variable strings + comment_diff = c(r'^%s(.*)' % e(environment.comment_start_string)) + m = comment_diff.match(environment.variable_start_string) + no_variable_re = m and r'(?!%s)' % e(m.group(1)) or '' + if environment.lstrip_blocks: # use '{%+' to manually disable lstrip_blocks behavior - no_lstrip_re = e('+') - # detect overlap between block and variable or comment strings - block_diff = c(r'^%s(.*)' % e(environment.block_start_string)) - # make sure we don't mistake a block for a variable or a comment - m = block_diff.match(environment.comment_start_string) - no_lstrip_re += m and r'|%s' % e(m.group(1)) or '' - m = block_diff.match(environment.variable_start_string) - no_lstrip_re += m and r'|%s' % e(m.group(1)) or '' - - # detect overlap between comment and variable strings - comment_diff = c(r'^%s(.*)' % e(environment.comment_start_string)) - m = comment_diff.match(environment.variable_start_string) - no_variable_re = m and r'(?!%s)' % e(m.group(1)) or '' - lstrip_re = r'^[ \t]*' block_prefix_re = r'%s%s(?!%s)|%s\+?' % ( lstrip_re, @@ -474,10 +473,21 @@ def __init__(self, environment): no_variable_re, e(environment.comment_start_string), ) - prefix_re['block'] = block_prefix_re - prefix_re['comment'] = comment_prefix_re else: - block_prefix_re = '%s' % e(environment.block_start_string) + # If lstrip_blocks is False, then '{%+' is allowed but a NOP + block_prefix_re = r'%s(?!%s)|%s\+?' % ( + e(environment.block_start_string), + no_lstrip_re, + e(environment.block_start_string), + ) + comment_prefix_re = r'%s%s|%s\+?' % ( + e(environment.comment_start_string), + no_variable_re, + e(environment.comment_start_string), + ) + + prefix_re['block'] = block_prefix_re + prefix_re['comment'] = comment_prefix_re self.newline_sequence = environment.newline_sequence self.keep_trailing_newline = environment.keep_trailing_newline diff --git a/tests/test_lexnparse.py b/tests/test_lexnparse.py index a61c1467c..f3adeb46f 100644 --- a/tests/test_lexnparse.py +++ b/tests/test_lexnparse.py @@ -503,6 +503,14 @@ def test_no_lstrip(self, env): tmpl = env.from_string(''' {%+ if True %}\n {%+ endif %}''') assert tmpl.render() == " \n " + def test_lstrip_blocks_false_with_no_lstrip(self, env): + # Test that + is a NOP (but does not cause an error) if lstrip_blocks=False + env = Environment(lstrip_blocks=False, trim_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 " + def test_lstrip_endline(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) tmpl = env.from_string(