]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
reformat, doc, and test for wordwrap 766/head
authorDavid Lord <davidism@gmail.com>
Fri, 1 Nov 2019 14:55:51 +0000 (07:55 -0700)
committerDavid Lord <davidism@gmail.com>
Fri, 1 Nov 2019 15:08:38 +0000 (08:08 -0700)
CHANGES.rst
jinja2/filters.py
tests/test_filters.py

index 108f4879ce1857a75c17a6ec68fd2360b06cadae..22c1567248657612d887e7c2f2daf3c1bb31f4ab 100644 (file)
@@ -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
index feb00eb5caad399d94b9cfa4be4f2e6fff170eb5..7c546493bfdb1886f15a935fe08187fda1552131 100644 (file)
@@ -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):
index 33123f971a04e712648049428016db39c4805c07..456412f60d37e26e2b5ab0125403c4db0a4a9448 100644 (file)
@@ -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."