Skip to content

Commit b811049

Browse files
authored
Merge pull request #2 from tiptenbrink/textwrap-len
_find_width_index and _handle_long_word change
2 parents 68e8098 + 7b32d0b commit b811049

2 files changed

Lines changed: 47 additions & 2 deletions

File tree

Lib/test/test_textwrap.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,5 +1118,31 @@ def test_shorten_placeholder(self):
11181118
text_len=self.text_len)
11191119

11201120

1121+
class CustomWidthTestCase(BaseTestCase):
1122+
def text_len(self, text):
1123+
lengths = {
1124+
'A': 4,
1125+
'B': 2,
1126+
'Q': 0,
1127+
}
1128+
1129+
return sum(
1130+
lengths[c] if c in lengths else 1
1131+
for c in text
1132+
)
1133+
1134+
def test_zero_width_text_len(self):
1135+
text = "0QQ1234QQ56789"
1136+
self.check_wrap(text, 6, ["0QQ1234QQ5", "6789"], text_len=self.text_len)
1137+
1138+
def test_char_longer_than_width(self):
1139+
text = "AA0123"
1140+
self.check_wrap(text, 3, ["A", "A", "012", "3"], text_len=self.text_len)
1141+
1142+
def test_next_char_overflow(self):
1143+
text = "BB0123"
1144+
self.check_wrap(text, 3, ["B", "B0", "123"], text_len=self.text_len)
1145+
1146+
11211147
if __name__ == '__main__':
11221148
unittest.main()

Lib/textwrap.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,25 @@ def _fix_sentence_endings(self, chunks):
199199
else:
200200
i += 1
201201

202+
def _find_width_index(self, text, width):
203+
"""_find_length_index(text : string, width : int)
204+
205+
Find at which index the text has the required width, since when using a
206+
different text_len, this index will not be equal to the required width.
207+
"""
208+
# When using default len as self.text_len, the required index and width
209+
# will be equal, this prevents calculation time.
210+
if self.text_len(text[:width]) == width:
211+
# For character widths greater than one, width can be more than the
212+
# number of characters
213+
return min(width, len(text))
214+
cur_text = ''
215+
for i, c in enumerate(text):
216+
cur_text += c
217+
cur_width = self.text_len(cur_text)
218+
if cur_width > width:
219+
return max(i, 1)
220+
202221
def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
203222
"""_handle_long_word(chunks : [string],
204223
cur_line : [string],
@@ -217,12 +236,12 @@ def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
217236
# If we're allowed to break long words, then do so: put as much
218237
# of the next chunk onto the current line as will fit.
219238
if self.break_long_words:
220-
end = space_left
221239
chunk = reversed_chunks[-1]
240+
end = self._find_width_index(chunk, space_left)
222241
if self.break_on_hyphens and self.text_len(chunk) > space_left:
223242
# break after last hyphen, but only if there are
224243
# non-hyphens before it
225-
hyphen = chunk.rfind('-', 0, space_left)
244+
hyphen = chunk.rfind('-', 0, end)
226245
if hyphen > 0 and any(c != '-' for c in chunk[:hyphen]):
227246
end = hyphen + 1
228247
cur_line.append(chunk[:end])

0 commit comments

Comments
 (0)