Code

Ticket #6668: faster_wrap.diff

File faster_wrap.diff, 3.3 KB (added by SmileyChris, 6 years ago)

and here's the patch

Line 
1Index: django/utils/text.py
2===================================================================
3--- django/utils/text.py        (revision 7141)
4+++ django/utils/text.py        (working copy)
5@@ -10,29 +10,33 @@
6 
7 def wrap(text, width):
8     """
9-    A word-wrap function that preserves existing line breaks and most spaces in
10-    the text. Expects that existing line breaks are posix newlines.
11+    A word-wrap function that preserves existing line breaks. Expects that
12+    existing line breaks are posix newlines.
13+
14+    All white space is preserved except added line breaks consume the space on
15+    which they break the line.
16+
17+    Long words are not wrapped, so the output text may have lines longer than
18+    ``width``.
19     """
20     text = force_unicode(text)
21     def _generator():
22-        it = iter(text.split(' '))
23-        word = it.next()
24-        yield word
25-        pos = len(word) - word.rfind('\n') - 1
26-        for word in it:
27-            if "\n" in word:
28-                lines = word.split('\n')
29-            else:
30-                lines = (word,)
31-            pos += len(lines[0]) + 1
32-            if pos > width:
33-                yield '\n'
34-                pos = len(lines[-1])
35-            else:
36-                yield ' '
37-                if len(lines) > 1:
38-                    pos = len(lines[-1])
39-            yield word
40+        for line in text.splitlines(True):   # True keeps trailing linebreaks
41+            quote = ''
42+            max_width = (line.endswith('\n') and width + 1 or width)
43+            while len(line) > max_width:
44+                space = line[:max_width+1].rfind(' ') + 1
45+                if space == 0:
46+                    space = line.find(' ') + 1
47+                    if space == 0:
48+                        yield line
49+                        line = ''
50+                        break
51+                yield '%s\n' % line[:space-1]
52+                line = line[space:]
53+                max_width = (line.endswith('\n') and width + 1 or width)
54+            if line:
55+                yield line
56     return u''.join(_generator())
57 wrap = allow_lazy(wrap, unicode)
58 
59Index: tests/regressiontests/utils/tests.py
60===================================================================
61--- tests/regressiontests/utils/tests.py        (revision 7141)
62+++ tests/regressiontests/utils/tests.py        (working copy)
63@@ -8,11 +8,13 @@
64 
65 import timesince
66 import datastructures
67+import text
68 
69 # Extra tests
70 __test__ = {
71     'timesince': timesince,
72     'datastructures': datastructures,
73+    'text': text,
74 }
75 
76 class TestUtilsHtml(TestCase):
77Index: tests/regressiontests/utils/text.py
78===================================================================
79--- tests/regressiontests/utils/text.py (revision 0)
80+++ tests/regressiontests/utils/text.py (revision 0)
81@@ -0,0 +1,23 @@
82+r"""
83+>>> from django.utils.text import wrap
84+
85+>>> wrap('1234 67 9', 100)
86+u'1234 67 9'
87+>>> wrap('1234 67 9', 9)
88+u'1234 67 9'
89+>>> wrap('1234 67 9', 8)
90+u'1234 67\n9'
91+
92+>>> wrap('short\na long line', 7)
93+u'short\na long\nline'
94+
95+>>> wrap('do-not-break-long-words please? ok', 8)
96+u'do-not-break-long-words\nplease?\nok'
97+
98+>>> long_word = 'l%sng' % ('0123456789'*100)
99+>>> wrap(long_word, 50) == long_word
100+True
101+>>> out = wrap('a %s word' % long_word, 10)
102+>>> '%s...%s' % (out[:20], out[-20:])
103+u'a\nl01234567890123456...7890123456789ng\nword'
104+"""