/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/utextwrap.py

  • Committer: Jelmer Vernooij
  • Date: 2020-05-06 02:13:25 UTC
  • mfrom: (7490.7.21 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200506021325-awbmmqu1zyorz7sj
Merge 3.1 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
# along with this program; if not, write to the Free Software
24
24
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25
25
 
26
 
from __future__ import absolute_import
27
 
 
28
 
import sys
29
26
import textwrap
30
27
from unicodedata import east_asian_width as _eawidth
31
28
 
33
30
 
34
31
__all__ = ["UTextWrapper", "fill", "wrap"]
35
32
 
 
33
 
36
34
class UTextWrapper(textwrap.TextWrapper):
37
35
    """
38
36
    Extend TextWrapper for Unicode.
60
58
    def __init__(self, width=None, **kwargs):
61
59
        if width is None:
62
60
            width = (osutils.terminal_width() or
63
 
                        osutils.default_terminal_width) - 1
 
61
                     osutils.default_terminal_width) - 1
64
62
 
65
63
        ambi_width = kwargs.pop('ambiguous_width', 1)
66
64
        if ambi_width == 1:
70
68
        else:
71
69
            raise ValueError("ambiguous_width should be 1 or 2")
72
70
 
 
71
        self.max_lines = kwargs.get('max_lines', None)
73
72
        textwrap.TextWrapper.__init__(self, width, **kwargs)
74
73
 
75
74
    def _unicode_char_width(self, uc):
117
116
        to use unicode always.
118
117
        """
119
118
        i = 0
120
 
        L = len(chunks)-1
 
119
        L = len(chunks) - 1
121
120
        patsearch = self.sentence_end_re.search
122
121
        while i < L:
123
 
            if chunks[i+1] == u" " and patsearch(chunks[i]):
124
 
                chunks[i+1] = u"  "
 
122
            if chunks[i + 1] == u" " and patsearch(chunks[i]):
 
123
                chunks[i + 1] = u"  "
125
124
                i += 2
126
125
            else:
127
126
                i += 1
160
159
        lines = []
161
160
        if self.width <= 0:
162
161
            raise ValueError("invalid width %r (must be > 0)" % self.width)
 
162
        if self.max_lines is not None:
 
163
            if self.max_lines > 1:
 
164
                indent = self.subsequent_indent
 
165
            else:
 
166
                indent = self.initial_indent
 
167
            if self._width(indent) + self._width(self.placeholder.lstrip()) > self.width:
 
168
                raise ValueError("placeholder too large for max width")
163
169
 
164
170
        # Arrange in reverse order so items can be efficiently popped
165
171
        # from a stack of chucks.
203
209
            # fit on *any* line (not just this one).
204
210
            if chunks and self._width(chunks[-1]) > width:
205
211
                self._handle_long_word(chunks, cur_line, cur_len, width)
 
212
                cur_len = sum(map(len, cur_line))
206
213
 
207
214
            # If the last chunk on this line is all whitespace, drop it.
208
215
            if self.drop_whitespace and cur_line and not cur_line[-1].strip():
211
218
            # Convert current line back to a string and store it in list
212
219
            # of all lines (return value).
213
220
            if cur_line:
214
 
                lines.append(indent + u''.join(cur_line))
 
221
                if (self.max_lines is None or
 
222
                    len(lines) + 1 < self.max_lines or
 
223
                    (not chunks or
 
224
                        self.drop_whitespace and
 
225
                     len(chunks) == 1 and
 
226
                     not chunks[0].strip()) and cur_len <= width):
 
227
                    # Convert current line back to a string and store it in
 
228
                    # list of all lines (return value).
 
229
                    lines.append(indent + u''.join(cur_line))
 
230
                else:
 
231
                    while cur_line:
 
232
                        if (cur_line[-1].strip() and
 
233
                                cur_len + self._width(self.placeholder) <= width):
 
234
                            cur_line.append(self.placeholder)
 
235
                            lines.append(indent + ''.join(cur_line))
 
236
                            break
 
237
                        cur_len -= self._width(cur_line[-1])
 
238
                        del cur_line[-1]
 
239
                    else:
 
240
                        if lines:
 
241
                            prev_line = lines[-1].rstrip()
 
242
                            if (self._width(prev_line) + self._width(self.placeholder) <=
 
243
                                    self.width):
 
244
                                lines[-1] = prev_line + self.placeholder
 
245
                                break
 
246
                        lines.append(indent + self.placeholder.lstrip())
 
247
                    break
215
248
 
216
249
        return lines
217
250
 
218
251
    def _split(self, text):
219
 
        chunks = textwrap.TextWrapper._split(self, unicode(text))
 
252
        chunks = textwrap.TextWrapper._split(self, osutils.safe_unicode(text))
220
253
        cjk_split_chunks = []
221
254
        for chunk in chunks:
222
255
            prev_pos = 0
225
258
                    if prev_pos < pos:
226
259
                        cjk_split_chunks.append(chunk[prev_pos:pos])
227
260
                    cjk_split_chunks.append(char)
228
 
                    prev_pos = pos+1
 
261
                    prev_pos = pos + 1
229
262
            if prev_pos < len(chunk):
230
263
                cjk_split_chunks.append(chunk[prev_pos:])
231
264
        return cjk_split_chunks
232
265
 
233
266
    def wrap(self, text):
234
267
        # ensure text is unicode
235
 
        return textwrap.TextWrapper.wrap(self, unicode(text))
 
268
        return textwrap.TextWrapper.wrap(self, osutils.safe_unicode(text))
236
269
 
237
270
# -- Convenience interface ---------------------------------------------
238
271
 
 
272
 
239
273
def wrap(text, width=None, **kwargs):
240
274
    """Wrap a single paragraph of text, returning a list of wrapped lines.
241
275
 
248
282
    """
249
283
    return UTextWrapper(width=width, **kwargs).wrap(text)
250
284
 
 
285
 
251
286
def fill(text, width=None, **kwargs):
252
287
    """Fill a single paragraph of text, returning a new string.
253
288
 
258
293
    available keyword args to customize wrapping behaviour.
259
294
    """
260
295
    return UTextWrapper(width=width, **kwargs).fill(text)
261