3 from itertools
import groupby
19 if isinstance(text, str)
and sys.version_info < (3, 0):
21 combining_correction = sum([-1
for c
in text
22 if unicodedata.combining(c)])
24 width = sum([east_asian_widths[unicodedata.east_asian_width(c)]
26 except AttributeError:
28 return width + combining_correction
34 """_wrap_chunks(chunks : [string]) -> [string]
36 Original _wrap_chunks use len() to calculate width.
37 This method respect to wide/fullwidth characters for width adjustment.
41 raise ValueError(
"invalid width %r (must be > 0)" % self.width)
50 indent = self.subsequent_indent
52 indent = self.initial_indent
56 if self.drop_whitespace
and chunks[-1].strip() ==
'' and lines:
62 if cur_len + c_l <= width:
63 cur_line.append(chunks.pop())
72 if (self.drop_whitespace
and cur_line
73 and cur_line[-1].strip() ==
''):
77 lines.append(indent +
''.join(cur_line))
82 """_break_word(word : string, space_left : int) -> (string, string)
84 Break line by unicode width instead of len(word).
87 for i, c
in enumerate(word):
89 if total > space_left:
90 return word[:i-1], word[i-1:]
94 """_split(text : string) -> [string]
96 Override original method that only split by 'wordsep_re'.
97 This '_split' split wide-characters into chunk by one character.
99 split =
lambda t: textwrap.TextWrapper._split(self, t)
101 for chunk
in split(text):
102 for w, g
in groupby(chunk, column_width):
104 chunks.extend(split(
''.join(g)))
106 chunks.extend(list(g))
110 """_handle_long_word(chunks : [string], cur_line : [string], cur_len : int, width : int)
112 Override original method for using self._break_word() instead of slice.
114 space_left = max(width - cur_len, 1)
115 if self.break_long_words:
116 l, r = self.
_break_word(reversed_chunks[-1], space_left)
118 reversed_chunks[-1] = r
121 cur_line.append(reversed_chunks.pop())