From: David Lord Date: Fri, 1 Nov 2019 14:55:51 +0000 (-0700) Subject: reformat, doc, and test for wordwrap X-Git-Tag: 2.11.0~26^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f6e539831fd5dd51ad6ec59a8973e9159c4cc0c7;p=thirdparty%2Fjinja.git reformat, doc, and test for wordwrap --- diff --git a/CHANGES.rst b/CHANGES.rst index 108f4879..22c15672 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -62,6 +62,9 @@ Unreleased the correct queue. :issue:`843` - Compiling templates always writes UTF-8 instead of defaulting to the system encoding. :issue:`889` +- ``|wordwrap`` filter treats existing newlines as separate paragraphs + to be wrapped individually, rather than creating short intermediate + lines. :issue:`175` Version 2.10.3 diff --git a/jinja2/filters.py b/jinja2/filters.py index feb00eb5..7c546493 100644 --- a/jinja2/filters.py +++ b/jinja2/filters.py @@ -684,39 +684,46 @@ def do_truncate(env, s, length=255, killwords=False, end='...', leeway=None): @environmentfilter -def do_wordwrap(environment, s, width=79, break_long_words=True, - wrapstring=None): - """ - Return a copy of the string passed to the filter wrapped after - ``79`` characters. You can override this default using the first - parameter. If you set the second parameter to `false` Jinja will not - split words apart if they are longer than `width`. By default, the newlines - will be the default newlines for the environment, but this can be changed - using the wrapstring keyword argument. +def do_wordwrap(environment, s, width=79, break_long_words=True, wrapstring=None): + """Wrap a string to the given width. Existing newlines are treated + as paragraphs to be wrapped separately. - .. versionadded:: 2.7 - Added support for the `wrapstring` parameter. + :param s: Original text to wrap. + :param width: Maximum length of wrapped lines. + :param break_long_words: If a word is longer than ``width``, break + it across lines. + :param wrapstring: String to join each wrapped line. Defaults to + :attr:`Environment.newline_sequence`. + + .. versionchanged:: 2.11 + Existing newlines are treated as paragraphs wrapped separately. + + .. versionchanged:: 2.7 + Added the ``wrapstring`` parameter. """ + import textwrap + if not wrapstring: wrapstring = environment.newline_sequence - import textwrap - # Work around textwrap.wrap()'s unexpected behaviour when wrapping multiple - # paragraphs. I.e. if your first paragraph ends on col 75, the next - # next paragraph would be wrapped on col 5 already, so we're going to wrap - # each paragraph individually. - paragraphs = str.splitlines(s) - paragraphs_wrapped = [] - for paragraph in paragraphs: - paragraph_wrapped = wrapstring.join( - textwrap.wrap(paragraph, - width=width, - expand_tabs=False, - replace_whitespace=False, - break_long_words=break_long_words - ) + + # textwrap.wrap doesn't consider existing newlines when wrapping. + # If the string has a newline before width, wrap will still insert + # a newline at width, resulting in a short line. Instead, split and + # wrap each paragraph individually. + return wrapstring.join( + [ + wrapstring.join( + textwrap.wrap( + line, + width=width, + expand_tabs=False, + replace_whitespace=False, + break_long_words=break_long_words, + ) ) - paragraphs_wrapped.append(paragraph_wrapped) - return wrapstring.join(paragraphs_wrapped) + for line in s.splitlines() + ] + ) def do_wordcount(s): diff --git a/tests/test_filters.py b/tests/test_filters.py index 33123f97..456412f6 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -757,3 +757,9 @@ class TestFilter(object): env.policies['json.dumps_function'] = my_dumps env.policies['json.dumps_kwargs'] = {'foo': 'bar'} assert t.render(x=23) == '42' + + def test_wordwrap(self, env): + env.newline_sequence = "\n" + t = env.from_string("{{ s|wordwrap(20) }}") + result = t.render(s="Hello!\nThis is Jinja saying something.") + assert result == "Hello!\nThis is Jinja saying\nsomething."