Skip to content

Commit 57dd785

Browse files
Full-width characters compatibility and max_width adjustability
1 parent 3db622c commit 57dd785

File tree

1 file changed

+55
-14
lines changed

1 file changed

+55
-14
lines changed

cowsay/main.py

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22
import re
3+
import string
34

45
from .characters import CHARS
56

@@ -15,26 +16,65 @@ class CowsayError(LookupError):
1516

1617
def wrap_lines(lines: list, max_width: int = 49) -> list:
1718

19+
# Buffers that will be used in the last.
1820
new_lines = []
21+
new_lines_width = []
22+
1923
for line in lines:
20-
for line_part in [
21-
line[i: i+max_width] for i in range(0, len(line), max_width)
22-
]:
23-
new_lines.append(line_part)
24-
return new_lines
2524

25+
# Check whether the line width is overflow (greater than
26+
# max_width) because of half-width and full-width characters.
27+
line_buffer = ""
28+
line_width = 0
29+
30+
# Loop over the characters in the line.
31+
for i in range(len(line)):
32+
33+
character = line[i]
34+
35+
if character in list(string.printable):
36+
# Half width characters.
37+
char_width = 1
38+
else:
39+
# Full width characters.
40+
char_width = 2
41+
42+
# Check whether the `line_buffer` is overflowed.
43+
overflow = (line_width + char_width > max_width)
44+
45+
if overflow:
46+
# Add `line_buffer` and `line_width`.
47+
new_lines.append(line_buffer)
48+
new_lines_width.append(line_width)
2649

27-
def generate_bubble(text: str) -> list:
50+
# Reinitialize the `line_buffer` and `line_width`.
51+
line_buffer = character
52+
line_width = char_width
53+
else:
54+
# Add this character to `line_buffer` if not overflowed.
55+
line_buffer += character
56+
line_width += char_width
57+
58+
if (i == (len(line) - 1)):
59+
# Last character.
60+
new_lines.append(line_buffer)
61+
new_lines_width.append(line_width)
62+
63+
return new_lines, new_lines_width
64+
65+
66+
def generate_bubble(text: str, max_width: int = 49) -> list:
2867

2968
lines = [line.strip() for line in text.split('\n')]
30-
lines = wrap_lines([line for line in lines if line])
31-
text_width = max([len(line) for line in lines])
69+
lines, lines_width = wrap_lines(
70+
lines=[line for line in lines if line], max_width=max_width)
71+
text_width = max(lines_width)
3272

3373
output = [" " + "_" * text_width]
3474
if len(lines) > 1:
3575
output.append(" /" + " " * text_width + "\\")
36-
for line in lines:
37-
output.append("| " + line + " " * (text_width - len(line) + 1) + "|")
76+
for line, line_width in zip(lines, lines_width):
77+
output.append("| " + line + " " * (text_width - line_width + 1) + "|")
3878
if len(lines) > 1:
3979
output.append(" \\" + " " * text_width + "/")
4080
output.append(" " + "=" * text_width)
@@ -52,12 +92,13 @@ def generate_char(char_lines: str, text_width: int) -> list:
5292
return output
5393

5494

55-
def draw(text: str, char_lines: str, to_console: bool = True) -> None | str:
95+
def draw(text: str, char_lines: str, to_console: bool = True,
96+
max_width: int = 49) -> None | str:
5697

5798
if len(re.sub(r'\s', '', text)) == 0:
5899
raise CowsayError('Pass something meaningful to cowsay')
59100

60-
output = generate_bubble(text)
101+
output = generate_bubble(text, max_width=max_width)
61102
text_width = max([len(line) for line in output]) - 4 # 4 is the frame
62103
output += generate_char(char_lines, text_width)
63104
if to_console:
@@ -67,9 +108,9 @@ def draw(text: str, char_lines: str, to_console: bool = True) -> None | str:
67108
return '\n'.join(output)
68109

69110

70-
def get_output_string(char: str, text: str) -> str:
111+
def get_output_string(char: str, text: str, max_width: int = 49) -> str:
71112

72113
if char in CHARS:
73-
return draw(text, CHARS[char], to_console=False)
114+
return draw(text, CHARS[char], to_console=False, max_width=max_width)
74115
else:
75116
raise CowsayError(f'Available Characters: {char_names}')

0 commit comments

Comments
 (0)