11from __future__ import annotations
22import re
3+ import string
34
45from .characters import CHARS
56
@@ -15,26 +16,65 @@ class CowsayError(LookupError):
1516
1617def 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