summaryrefslogtreecommitdiff
path: root/jinja2
diff options
context:
space:
mode:
authorArmin Ronacher <armin.ronacher@active-4.com>2013-05-19 11:09:19 +0100
committerArmin Ronacher <armin.ronacher@active-4.com>2013-05-19 11:09:19 +0100
commitf3acf0b7b37876775a6f4d8bb3b9b8469c693ba9 (patch)
tree3871f4d32338b66d3c54f9de170c6c0bc554d498 /jinja2
parent840e7e060e3537172c57a8a96cf5bc502f55b67f (diff)
parent7e912c6dfa7a17dd1334ecb1a8d57dd5722b633a (diff)
downloadjinja2-f3acf0b7b37876775a6f4d8bb3b9b8469c693ba9.tar.gz
Merge remote-tracking branch 'wking/keep-trailing-newline'
Diffstat (limited to 'jinja2')
-rw-r--r--jinja2/defaults.py1
-rw-r--r--jinja2/environment.py17
-rw-r--r--jinja2/ext.py4
-rw-r--r--jinja2/lexer.py13
-rw-r--r--jinja2/testsuite/lexnparse.py13
5 files changed, 42 insertions, 6 deletions
diff --git a/jinja2/defaults.py b/jinja2/defaults.py
index 3201271..8216450 100644
--- a/jinja2/defaults.py
+++ b/jinja2/defaults.py
@@ -23,6 +23,7 @@ LINE_STATEMENT_PREFIX = None
LINE_COMMENT_PREFIX = None
TRIM_BLOCKS = False
NEWLINE_SEQUENCE = '\n'
+KEEP_TRAILING_NEWLINE = False
# default filters, tests and namespace
diff --git a/jinja2/environment.py b/jinja2/environment.py
index 58573a2..23d00aa 100644
--- a/jinja2/environment.py
+++ b/jinja2/environment.py
@@ -15,7 +15,8 @@ from jinja2.defaults import BLOCK_START_STRING, \
BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \
COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \
LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \
- DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE
+ DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE, \
+ KEEP_TRAILING_NEWLINE
from jinja2.lexer import get_lexer, TokenStream
from jinja2.parser import Parser
from jinja2.optimizer import optimize
@@ -147,6 +148,13 @@ class Environment(object):
useful default for Linux and OS X systems as well as web
applications.
+ `keep_trailing_newline`
+ Preserve the trailing newline when rendering templates.
+ The default is ``False``, which causes a single newline,
+ if present, to be stripped from the end of the template.
+
+ .. versionadded:: 2.7
+
`extensions`
List of Jinja extensions to use. This can either be import paths
as strings or extension classes. For more information have a
@@ -232,6 +240,7 @@ class Environment(object):
line_comment_prefix=LINE_COMMENT_PREFIX,
trim_blocks=TRIM_BLOCKS,
newline_sequence=NEWLINE_SEQUENCE,
+ keep_trailing_newline=KEEP_TRAILING_NEWLINE,
extensions=(),
optimized=True,
undefined=Undefined,
@@ -263,6 +272,7 @@ class Environment(object):
self.line_comment_prefix = line_comment_prefix
self.trim_blocks = trim_blocks
self.newline_sequence = newline_sequence
+ self.keep_trailing_newline = keep_trailing_newline
# runtime information
self.undefined = undefined
@@ -828,6 +838,7 @@ class Template(object):
line_comment_prefix=LINE_COMMENT_PREFIX,
trim_blocks=TRIM_BLOCKS,
newline_sequence=NEWLINE_SEQUENCE,
+ keep_trailing_newline=KEEP_TRAILING_NEWLINE,
extensions=(),
optimized=True,
undefined=Undefined,
@@ -837,8 +848,8 @@ class Template(object):
block_start_string, block_end_string, variable_start_string,
variable_end_string, comment_start_string, comment_end_string,
line_statement_prefix, line_comment_prefix, trim_blocks,
- newline_sequence, frozenset(extensions), optimized, undefined,
- finalize, autoescape, None, 0, False, None)
+ newline_sequence, keep_trailing_newline, frozenset(extensions),
+ optimized, undefined, finalize, autoescape, None, 0, False, None)
return env.from_string(source, template_class=cls)
@classmethod
diff --git a/jinja2/ext.py b/jinja2/ext.py
index 495e643..651ee98 100644
--- a/jinja2/ext.py
+++ b/jinja2/ext.py
@@ -589,7 +589,9 @@ def babel_extract(fileobj, keywords, comment_tags, options):
options.get('line_statement_prefix') or LINE_STATEMENT_PREFIX,
options.get('line_comment_prefix') or LINE_COMMENT_PREFIX,
getbool(options, 'trim_blocks', TRIM_BLOCKS),
- NEWLINE_SEQUENCE, frozenset(extensions),
+ NEWLINE_SEQUENCE,
+ getbool(options, 'keep_trailing_newline', KEEP_TRAILING_NEWLINE),
+ frozenset(extensions),
cache_size=0,
auto_reload=False
)
diff --git a/jinja2/lexer.py b/jinja2/lexer.py
index bd2e861..5594e0a 100644
--- a/jinja2/lexer.py
+++ b/jinja2/lexer.py
@@ -391,7 +391,8 @@ def get_lexer(environment):
environment.line_statement_prefix,
environment.line_comment_prefix,
environment.trim_blocks,
- environment.newline_sequence)
+ environment.newline_sequence,
+ environment.keep_trailing_newline)
lexer = _lexer_cache.get(key)
if lexer is None:
lexer = Lexer(environment)
@@ -434,6 +435,7 @@ class Lexer(object):
block_suffix_re = environment.trim_blocks and '\\n?' or ''
self.newline_sequence = environment.newline_sequence
+ self.keep_trailing_newline = environment.keep_trailing_newline
# global lexing rules
self.rules = {
@@ -557,7 +559,14 @@ class Lexer(object):
"""This method tokenizes the text and returns the tokens in a
generator. Use this method if you just want to tokenize a template.
"""
- source = '\n'.join(six.text_type(source).splitlines())
+ source = six.text_type(source)
+ lines = source.splitlines()
+ if self.keep_trailing_newline and source:
+ for newline in ('\r\n', '\r', '\n'):
+ if source.endswith(newline):
+ lines.append('')
+ break
+ source = '\n'.join(lines)
pos = 0
lineno = 1
stack = ['root']
diff --git a/jinja2/testsuite/lexnparse.py b/jinja2/testsuite/lexnparse.py
index f05f601..7022e23 100644
--- a/jinja2/testsuite/lexnparse.py
+++ b/jinja2/testsuite/lexnparse.py
@@ -108,6 +108,19 @@ class LexerTestCase(JinjaTestCase):
result = tmpl.render()
assert result.replace(seq, 'X') == '1X2X3X4'
+ def test_trailing_newline(self):
+ for keep in [True, False]:
+ env = Environment(keep_trailing_newline=keep)
+ for template,expected in [
+ ('', {}),
+ ('no\nnewline', {}),
+ ('with\nnewline\n', {False: 'with\nnewline'}),
+ ('with\nseveral\n\n\n', {False: 'with\nseveral\n\n'}),
+ ]:
+ tmpl = env.from_string(template)
+ expect = expected.get(keep, template)
+ result = tmpl.render()
+ assert result == expect, (keep, template, result, expect)
class ParserTestCase(JinjaTestCase):