txtwrap 1.0.0__tar.gz → 1.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
txtwrap-1.1.1/PKG-INFO ADDED
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.1
2
+ Name: txtwrap
3
+ Version: 1.1.1
4
+ Summary: A simple text wrapping tool.
5
+ Author: azzammuhyala
6
+ License: MIT
7
+ Keywords: wrap,wrapper,wrapping,wrapped,wrapping tool,text wrap,text wrapper,simple wrap,align,aligner,aligning,aligned
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+
15
+ # TxTWrap🔡
16
+ A tool for wrapping a text.🔨
17
+
18
+ > **⚠️All documents are in the each module.⚠️**
19
+
20
+ All constants and functions❕:
21
+ - `LOREM_IPSUM_W`
22
+ - `LOREM_IPSUM_S`
23
+ - `LOREM_IPSUM_P`
24
+ - `mono`
25
+ - `word`
26
+ - `wrap`
27
+ - `align` (Updated!)
28
+ - `fillstr`
29
+ - `printwrap`
30
+ - `shorten`
31
+
32
+ Mod `python -m txtwrap` Commands❗:
33
+ ```shell
34
+ python -m txtwrap --help
35
+ ```
36
+
37
+ Examples❓:
38
+ ## Render a wrap text in PyGame🎮
39
+ ```py
40
+ from typing import Literal, Optional
41
+ from txtwrap import align, LOREM_IPSUM_P
42
+ import pygame
43
+
44
+ def render_wrap(
45
+
46
+ font: pygame.Font,
47
+ text: str,
48
+ width: int,
49
+ antialias: bool,
50
+ color: pygame.Color,
51
+ background: Optional[pygame.Color] = None,
52
+ linegap: int = 0,
53
+ alignment: Literal['left', 'center', 'right', 'fill'] = 'left',
54
+ method: Literal['word', 'mono'] = 'word',
55
+ preserve_empty: bool = True,
56
+ use_min_width: bool = True
57
+
58
+ ) -> pygame.Surface:
59
+
60
+ # Only supports in txtwrap 1.1.1+
61
+ align_info = align(
62
+ text=text,
63
+ width=width,
64
+ linegap=linegap,
65
+ sizefunc=font.size,
66
+ method=method,
67
+ alignment=alignment,
68
+ preserve_empty=preserve_empty,
69
+ use_min_width=use_min_width,
70
+ return_details=True
71
+ )
72
+
73
+ surface = pygame.Surface(align_info['size'], pygame.SRCALPHA)
74
+
75
+ if background is not None:
76
+ surface.fill(background)
77
+
78
+ for x, y, text in align_info['aligned']:
79
+ surface.blit(font.render(text, antialias, color), (x, y))
80
+
81
+ return surface
82
+
83
+ # Example usage:
84
+ pygame.init()
85
+ pygame.display.set_caption("Lorem Ipsum")
86
+
87
+ running = True
88
+ wscrn, hscrn = 600, 600
89
+ screen = pygame.display.set_mode((wscrn, hscrn))
90
+ clock = pygame.time.Clock()
91
+ surface = render_wrap(
92
+ font=pygame.font.Font(None, 20),
93
+ text=LOREM_IPSUM_P,
94
+ width=wscrn,
95
+ antialias=True,
96
+ color='#ffffff',
97
+ background='#303030',
98
+ alignment='fill'
99
+ )
100
+
101
+ wsurf, hsurf = surface.get_size()
102
+ pos = ((wscrn - wsurf) / 2, (hscrn - hsurf) / 2)
103
+
104
+ while running:
105
+ for event in pygame.event.get():
106
+ if event.type == pygame.QUIT:
107
+ running = False
108
+ screen.fill('#000000')
109
+ screen.blit(surface, pos)
110
+ pygame.display.flip()
111
+ clock.tick(60)
112
+ ```
113
+
114
+ ## Print a wrap text to terminal🔡
115
+ ```py
116
+ # Only supports in txtwrap 1.1.0+
117
+ from txtwrap import printwrap, LOREM_IPSUM_W
118
+
119
+ printwrap(LOREM_IPSUM_W, width=20, alignment='left')
120
+ print('=' * 20)
121
+ printwrap(LOREM_IPSUM_W, width=20, alignment='center')
122
+ print('=' * 20)
123
+ printwrap(LOREM_IPSUM_W, width=20, alignment='right')
124
+ print('=' * 20)
125
+ printwrap(LOREM_IPSUM_W, width=20, alignment='fill')
126
+ ```
127
+
128
+ ## Short a long text🔤
129
+ ```py
130
+ from txtwrap import shorten, LOREM_IPSUM_S
131
+
132
+ short_lorem = shorten(LOREM_IPSUM_S, width=20, placeholder='…')
133
+ # Only supports in txtwrap 1.1.0+
134
+ test = shorten(' Helllo, \t\r\n World!! \f', width=20, placeholder='…', strip_space=True)
135
+
136
+ print(short_lorem)
137
+ print(test)
138
+ ```
139
+
140
+ ## Bonus🎁 - Print a colorfull text to terminal🔥
141
+ ```py
142
+ # Run this code in a terminal that supports ansi characters
143
+
144
+ from re import compile
145
+ from random import randint
146
+ from txtwrap import printwrap, LOREM_IPSUM_P
147
+
148
+ # Set the text to be printed here
149
+ text = LOREM_IPSUM_P
150
+
151
+ remove_ansi_regex = compile(r'\x1b\[[0-9;]*[mK]').sub
152
+
153
+ def ralen(s: str) -> int:
154
+ return len(remove_ansi_regex('', s))
155
+
156
+ while True:
157
+ # Only supports in txtwrap 1.1.0+
158
+ printwrap(
159
+ ''.join(f'\x1b[{randint(31, 36)}m{char}' for char in text) + '\x1b[0m',
160
+ end='\x1b[H\x1b[J',
161
+ alignment='fill',
162
+ lenfunc=ralen
163
+ )
164
+ ```
@@ -0,0 +1,150 @@
1
+ # TxTWrap🔡
2
+ A tool for wrapping a text.🔨
3
+
4
+ > **⚠️All documents are in the each module.⚠️**
5
+
6
+ All constants and functions❕:
7
+ - `LOREM_IPSUM_W`
8
+ - `LOREM_IPSUM_S`
9
+ - `LOREM_IPSUM_P`
10
+ - `mono`
11
+ - `word`
12
+ - `wrap`
13
+ - `align` (Updated!)
14
+ - `fillstr`
15
+ - `printwrap`
16
+ - `shorten`
17
+
18
+ Mod `python -m txtwrap` Commands❗:
19
+ ```shell
20
+ python -m txtwrap --help
21
+ ```
22
+
23
+ Examples❓:
24
+ ## Render a wrap text in PyGame🎮
25
+ ```py
26
+ from typing import Literal, Optional
27
+ from txtwrap import align, LOREM_IPSUM_P
28
+ import pygame
29
+
30
+ def render_wrap(
31
+
32
+ font: pygame.Font,
33
+ text: str,
34
+ width: int,
35
+ antialias: bool,
36
+ color: pygame.Color,
37
+ background: Optional[pygame.Color] = None,
38
+ linegap: int = 0,
39
+ alignment: Literal['left', 'center', 'right', 'fill'] = 'left',
40
+ method: Literal['word', 'mono'] = 'word',
41
+ preserve_empty: bool = True,
42
+ use_min_width: bool = True
43
+
44
+ ) -> pygame.Surface:
45
+
46
+ # Only supports in txtwrap 1.1.1+
47
+ align_info = align(
48
+ text=text,
49
+ width=width,
50
+ linegap=linegap,
51
+ sizefunc=font.size,
52
+ method=method,
53
+ alignment=alignment,
54
+ preserve_empty=preserve_empty,
55
+ use_min_width=use_min_width,
56
+ return_details=True
57
+ )
58
+
59
+ surface = pygame.Surface(align_info['size'], pygame.SRCALPHA)
60
+
61
+ if background is not None:
62
+ surface.fill(background)
63
+
64
+ for x, y, text in align_info['aligned']:
65
+ surface.blit(font.render(text, antialias, color), (x, y))
66
+
67
+ return surface
68
+
69
+ # Example usage:
70
+ pygame.init()
71
+ pygame.display.set_caption("Lorem Ipsum")
72
+
73
+ running = True
74
+ wscrn, hscrn = 600, 600
75
+ screen = pygame.display.set_mode((wscrn, hscrn))
76
+ clock = pygame.time.Clock()
77
+ surface = render_wrap(
78
+ font=pygame.font.Font(None, 20),
79
+ text=LOREM_IPSUM_P,
80
+ width=wscrn,
81
+ antialias=True,
82
+ color='#ffffff',
83
+ background='#303030',
84
+ alignment='fill'
85
+ )
86
+
87
+ wsurf, hsurf = surface.get_size()
88
+ pos = ((wscrn - wsurf) / 2, (hscrn - hsurf) / 2)
89
+
90
+ while running:
91
+ for event in pygame.event.get():
92
+ if event.type == pygame.QUIT:
93
+ running = False
94
+ screen.fill('#000000')
95
+ screen.blit(surface, pos)
96
+ pygame.display.flip()
97
+ clock.tick(60)
98
+ ```
99
+
100
+ ## Print a wrap text to terminal🔡
101
+ ```py
102
+ # Only supports in txtwrap 1.1.0+
103
+ from txtwrap import printwrap, LOREM_IPSUM_W
104
+
105
+ printwrap(LOREM_IPSUM_W, width=20, alignment='left')
106
+ print('=' * 20)
107
+ printwrap(LOREM_IPSUM_W, width=20, alignment='center')
108
+ print('=' * 20)
109
+ printwrap(LOREM_IPSUM_W, width=20, alignment='right')
110
+ print('=' * 20)
111
+ printwrap(LOREM_IPSUM_W, width=20, alignment='fill')
112
+ ```
113
+
114
+ ## Short a long text🔤
115
+ ```py
116
+ from txtwrap import shorten, LOREM_IPSUM_S
117
+
118
+ short_lorem = shorten(LOREM_IPSUM_S, width=20, placeholder='…')
119
+ # Only supports in txtwrap 1.1.0+
120
+ test = shorten(' Helllo, \t\r\n World!! \f', width=20, placeholder='…', strip_space=True)
121
+
122
+ print(short_lorem)
123
+ print(test)
124
+ ```
125
+
126
+ ## Bonus🎁 - Print a colorfull text to terminal🔥
127
+ ```py
128
+ # Run this code in a terminal that supports ansi characters
129
+
130
+ from re import compile
131
+ from random import randint
132
+ from txtwrap import printwrap, LOREM_IPSUM_P
133
+
134
+ # Set the text to be printed here
135
+ text = LOREM_IPSUM_P
136
+
137
+ remove_ansi_regex = compile(r'\x1b\[[0-9;]*[mK]').sub
138
+
139
+ def ralen(s: str) -> int:
140
+ return len(remove_ansi_regex('', s))
141
+
142
+ while True:
143
+ # Only supports in txtwrap 1.1.0+
144
+ printwrap(
145
+ ''.join(f'\x1b[{randint(31, 36)}m{char}' for char in text) + '\x1b[0m',
146
+ end='\x1b[H\x1b[J',
147
+ alignment='fill',
148
+ lenfunc=ralen
149
+ )
150
+ ```
@@ -5,7 +5,7 @@ with open('README.md', encoding='utf-8') as readme:
5
5
 
6
6
  setup(
7
7
  name='txtwrap',
8
- version='1.0.0',
8
+ version='1.1.1',
9
9
  description='A simple text wrapping tool.',
10
10
  long_description=long_description,
11
11
  long_description_content_type='text/markdown',
@@ -14,8 +14,8 @@ setup(
14
14
  python_requires='>=3.8',
15
15
  packages=find_packages(),
16
16
  include_package_data=True,
17
- keywords=['wrap', 'wrapper', 'wrapping', 'wrapping tool', 'text wrap', 'text wrapper',
18
- 'simple wrap', 'align', 'aligner', 'aligning'],
17
+ keywords=['wrap', 'wrapper', 'wrapping', 'wrapped', 'wrapping tool', 'text wrap',
18
+ 'text wrapper', 'simple wrap', 'align', 'aligner', 'aligning', 'aligned'],
19
19
  classifiers=[
20
20
  'Programming Language :: Python :: 3',
21
21
  'Programming Language :: Python :: 3.8',
@@ -5,14 +5,15 @@ A simple text wrapping tool
5
5
  # Supports only in Python 3.8+
6
6
 
7
7
  from .txtwrap import (
8
+ version,
8
9
  LOREM_IPSUM_W, LOREM_IPSUM_S, LOREM_IPSUM_P,
9
- mono, word, wrap, align,
10
+ mono, word, wrap, align, fillstr, printwrap,
10
11
  shorten
11
12
  )
12
13
 
13
- __version__ = '1.0.0'
14
+ __version__ = version
15
+ __author__ = 'azzammuhyala'
14
16
  __license__ = 'MIT'
15
- __author__ = 'Azzam Muhyala'
16
17
  __all__ = [
17
18
  'LOREM_IPSUM_W',
18
19
  'LOREM_IPSUM_S',
@@ -21,5 +22,7 @@ __all__ = [
21
22
  'word',
22
23
  'wrap',
23
24
  'align',
25
+ 'fillstr',
26
+ 'printwrap',
24
27
  'shorten'
25
28
  ]
@@ -0,0 +1,111 @@
1
+ from argparse import ArgumentParser
2
+ from txtwrap import version, printwrap, shorten
3
+
4
+ parser = ArgumentParser(
5
+ description='Command-line tool for wrapping, aligning, or shortening text.'
6
+ )
7
+
8
+ parser.add_argument(
9
+ 'text',
10
+ type=str,
11
+ help='Text to be wrapped, aligned, or shorted'
12
+ )
13
+
14
+ parser.add_argument(
15
+ '-v', '--version',
16
+ action='version',
17
+ version=version,
18
+ help='Show the version of the txtwrap'
19
+ )
20
+
21
+ parser.add_argument(
22
+ '-f', '--fill',
23
+ type=str,
24
+ default=' ',
25
+ metavar='<str (1 character)>',
26
+ help='Fill character (default: " ")'
27
+ )
28
+
29
+ parser.add_argument(
30
+ '-w', '--width',
31
+ type=int,
32
+ default=None,
33
+ metavar='<int>',
34
+ help='Width of the text wrapping (default: current width terminal or 70)'
35
+ )
36
+
37
+ parser.add_argument(
38
+ '-m', '--method',
39
+ type=str,
40
+ choices={'word', 'mono', 'shorten'},
41
+ default='word',
42
+ metavar='{word|mono|shorten}',
43
+ help='Method to be applied to the text (default: "word")'
44
+ )
45
+
46
+ parser.add_argument(
47
+ '-a', '--alignment',
48
+ type=str,
49
+ choices={'left', 'center', 'right', 'fill'},
50
+ default='left',
51
+ metavar='{left|center|right|fill}',
52
+ help='Alignment of the text (default: "left")'
53
+ )
54
+
55
+ parser.add_argument(
56
+ '-n', '--neglect-empty',
57
+ action='store_false',
58
+ help='Neglect empty lines in the text'
59
+ )
60
+
61
+ parser.add_argument(
62
+ '-s', '--start',
63
+ type=int,
64
+ default=0,
65
+ metavar='<int>',
66
+ help='start index of the text to be shorten (default: 0)'
67
+ )
68
+
69
+ parser.add_argument(
70
+ '-p', '--placeholder',
71
+ type=str,
72
+ default='...',
73
+ metavar='<str>',
74
+ help='Placeholder to be used when shortening the text (default: "...")'
75
+ )
76
+
77
+ parser.add_argument(
78
+ '-r', '--no-strip',
79
+ action='store_false',
80
+ help='Do not strip the space in the text'
81
+ )
82
+
83
+ args = parser.parse_args()
84
+
85
+ if args.method == 'shorten':
86
+ from os import get_terminal_size
87
+
88
+ if args.width is None:
89
+ try:
90
+ args.width = get_terminal_size().columns
91
+ except:
92
+ args.width = 70
93
+
94
+ print(
95
+ shorten(
96
+ text=args.text,
97
+ width=args.width,
98
+ start=args.start,
99
+ placeholder=args.placeholder,
100
+ strip_space=args.no_strip
101
+ )
102
+ )
103
+ else:
104
+ printwrap(
105
+ args.text,
106
+ fill=args.fill,
107
+ width=args.width,
108
+ method=args.method,
109
+ alignment=args.alignment,
110
+ preserve_empty=args.neglect_empty
111
+ )
@@ -1,7 +1,9 @@
1
- from typing import Callable, List, Literal, Tuple, Union
1
+ from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union
2
+ from os import get_terminal_size
2
3
  from re import compile
3
4
 
4
5
  hyphenated_regex = compile(r'(?<=-)(?=(?!-).)')
6
+ version = '1.1.1'
5
7
 
6
8
  LOREM_IPSUM_W = 'Lorem ipsum odor amet, consectetuer adipiscing elit.'
7
9
  LOREM_IPSUM_S = ('Lorem ipsum odor amet, consectetuer adipiscing elit. In malesuada eros natoque '
@@ -197,9 +199,12 @@ def align(
197
199
  sizefunc: Callable[[str], Tuple[Union[int, float], Union[int, float]]] = lambda s : (len(s), 1),
198
200
  method: Literal['mono', 'word'] = 'word',
199
201
  alignment: Literal['left', 'center', 'right', 'fill'] = 'left',
200
- preserve_empty: bool = True
202
+ preserve_empty: bool = True,
203
+ use_min_width: bool = True,
204
+ return_details: bool = False
201
205
 
202
- ) -> List[Tuple[Union[int, float], Union[int, float], str]]:
206
+ ) -> List[Union[Tuple[Union[int, float], Union[int, float], str],
207
+ Dict[Literal['aligned', 'wrapped', 'size'], Any]]]:
203
208
 
204
209
  """
205
210
  Wraps and aligns text within a specified width and yields the position and content of each line.
@@ -223,10 +228,19 @@ def align(
223
228
  or 'fill'.
224
229
  Defaults to 'left'.
225
230
  preserve_empty (bool, optional): Whether to preserve empty lines. Defaults to True.
231
+ use_min_width (bool, optional): Whether to use the manimum width of the wrapped text.
232
+ Defaults to True.
233
+ return_details (bool, optional): Whether to return the aligned text, wrapped text, and
234
+ the size.
235
+ Defaults to False.
226
236
 
227
237
  Returns:
228
- list[tuple[int | float, int | float, str]]: A list of tuples containing the position and
229
- content of each line.
238
+ list[tuple[int | float, int | float, str] |
239
+ dict[Literal['aligned', 'wrapped', 'size'], Any]]: A list of tuples containing the
240
+ position and content of each line.
241
+ If return_details, a dictionary
242
+ containing the wrapped text, and
243
+ the size is returned.
230
244
  """
231
245
 
232
246
  assert isinstance(linegap, (int, float)), "linegap must be an integer or float"
@@ -234,47 +248,228 @@ def align(
234
248
 
235
249
  assert linegap >= 0, "linegap must be equal to or greater than 0"
236
250
 
237
- wrapped = []
251
+ wrapped = wrap(text, width, lambda s : sizefunc(s)[0], method, preserve_empty)
252
+ size_wrapped = {i: sizefunc(line) for i, line in enumerate(wrapped)}
253
+ aligned_positions = []
238
254
  offset_y = 0
239
255
 
240
- for line in wrap(text, width, lambda s : sizefunc(s)[0], method, preserve_empty):
256
+ if use_min_width:
257
+ max_width = max(size[0] for size in size_wrapped.values())
258
+ use_width = max_width
259
+ else:
260
+ use_width = width
261
+
262
+ if alignment == 'left':
263
+ for i, line in enumerate(wrapped):
264
+ height_line = size_wrapped[i][1]
265
+ aligned_positions.append((0, offset_y, line))
266
+ offset_y += height_line + linegap
267
+
268
+ elif alignment == 'center':
269
+ for i, line in enumerate(wrapped):
270
+ width_line, height_line = size_wrapped[i]
271
+ aligned_positions.append(((use_width - width_line) / 2, offset_y, line))
272
+ offset_y += height_line + linegap
273
+
274
+ elif alignment == 'right':
275
+ for i, line in enumerate(wrapped):
276
+ width_line, height_line = size_wrapped[i]
277
+ aligned_positions.append((use_width - width_line, offset_y, line))
278
+ offset_y += height_line + linegap
279
+
280
+ elif alignment == 'fill':
281
+ no_spaces = True
282
+ for i, line in enumerate(wrapped):
283
+ height_line = size_wrapped[i][1]
284
+ words = line.split()
285
+ total_words = len(words)
286
+ word_widths = {i: sizefunc(w)[0] for i, w in enumerate(words)}
287
+ extra_space = width - sum(word_widths.values())
288
+ offset_x = 0
241
289
 
242
- width_line, height_line = sizefunc(line)
290
+ if total_words > 1:
291
+ space_between_words = extra_space / (total_words - 1)
292
+ no_spaces = False
293
+ else:
294
+ space_between_words = extra_space
243
295
 
244
- if alignment == 'left':
245
- wrapped.append((0, offset_y, line))
296
+ for i, w in enumerate(words):
297
+ aligned_positions.append((offset_x, offset_y, w))
298
+ offset_x += word_widths[i] + space_between_words
246
299
 
247
- elif alignment == 'center':
248
- wrapped.append(((width - width_line) / 2, offset_y, line))
300
+ offset_y += height_line + linegap
249
301
 
250
- elif alignment == 'right':
251
- wrapped.append((width - width_line, offset_y, line))
302
+ else:
303
+ raise ValueError(f"{alignment=} is invalid, must be 'left', 'center', 'right', or 'fill'")
304
+
305
+ if return_details:
306
+ if use_min_width and alignment == 'fill':
307
+ if no_spaces:
308
+ size_width = max_width
309
+ elif text:
310
+ size_width = width
311
+ else:
312
+ size_width = 0
313
+ else:
314
+ size_width = use_width
252
315
 
253
- elif alignment == 'fill':
254
- offset_x = 0
316
+ return {
317
+ 'aligned': aligned_positions,
318
+ 'wrapped': wrapped,
319
+ 'size': (size_width, offset_y - linegap)
320
+ }
321
+
322
+ return aligned_positions
323
+
324
+ def fillstr(
325
+
326
+ text: str,
327
+ width: Union[int, float] = 70,
328
+ fill: str = ' ',
329
+ lenfunc: Callable[[str], Union[int, float]] = len,
330
+ method: Literal['mono', 'word'] = 'word',
331
+ alignment: Union[Callable[[str], str], Literal['left', 'center', 'right', 'fill']] = 'left',
332
+ preserve_empty: bool = True
333
+
334
+ ) -> str:
335
+
336
+ """
337
+ String formats a given text to fit within a specified width, using various alignment methods.
338
+
339
+ Parameters:
340
+ text (str): The text to be formatted.
341
+ width (Union[int, float], optional): The width of the formatted text. Defaults to 70.
342
+ fill (str, optional): The character used to fill the space. Must be a single character.
343
+ Defaults to ' '.
344
+ lenfunc (Callable[[str], Union[int, float]], optional): A function to calculate the
345
+ length of a string. Defaults to len.
346
+ method (Literal['mono', 'word'], optional): The method to use for wrapping.
347
+ 'mono' for character-based wrapping, 'word'
348
+ for word-based wrapping. Defaults to 'word'.
349
+ alignment (Union[Callable[[str], str],
350
+ Literal['left', 'center', 'right', 'fill']], optional): The alignment of the
351
+ text. 'left', 'center',
352
+ 'right', or 'fill'.
353
+ Defaults to 'left'.
354
+ preserve_empty (bool, optional): Whether to preserve empty lines. Defaults to True.
355
+
356
+ Returns:
357
+ str: The formatted text.
358
+ """
359
+
360
+ assert isinstance(fill, str), "fill must be a string"
361
+ assert len(fill) == 1, "fill must be a single character"
362
+
363
+ wrapped = wrap(text, width, lenfunc, method, preserve_empty)
364
+ justified_lines = ''
365
+
366
+ if callable(alignment):
367
+ return '\n'.join(alignment(line) for line in wrapped)
368
+
369
+ elif alignment == 'left':
370
+ for line in wrapped:
371
+ justified_lines += line + fill * (width - lenfunc(line)) + '\n'
372
+
373
+ elif alignment == 'center':
374
+ for line in wrapped:
375
+ extra_space = width - lenfunc(line)
376
+ left_space = extra_space // 2
377
+ justified_lines += fill * left_space + line + fill * (extra_space - left_space) + '\n'
378
+
379
+ elif alignment == 'right':
380
+ for line in wrapped:
381
+ justified_lines += fill * (width - lenfunc(line)) + line + '\n'
382
+
383
+ elif alignment == 'fill':
384
+ for line in wrapped:
255
385
  words = line.split()
256
386
  total_words = len(words)
257
- widths = {i: sizefunc(w)[0] for i, w in enumerate(words)}
258
- total_words_width = sum(widths.values())
387
+ total_words_width = sum(lenfunc(w) for w in words)
259
388
  extra_space = width - total_words_width
260
389
 
261
390
  if total_words > 1:
262
- space_between_words = extra_space / (total_words - 1)
391
+ space_between_words = extra_space // (total_words - 1)
392
+ extra_padding = extra_space % (total_words - 1)
263
393
  else:
264
394
  space_between_words = extra_space
395
+ extra_padding = 0
265
396
 
266
- for i, w in enumerate(words):
267
- wrapped.append((offset_x, offset_y, w))
268
- offset_x += widths[i] + space_between_words
397
+ justified_line = ''
398
+ for i, word in enumerate(words):
399
+ justified_line += word
400
+ if i < total_words - 1:
401
+ justified_line += fill * (space_between_words + (1 if i < extra_padding else 0))
269
402
 
270
- else:
271
- raise ValueError(
272
- f"{alignment=} is invalid, must be 'left', 'center', 'right', or 'fill'"
273
- )
403
+ justified_lines += justified_line + '\n'
274
404
 
275
- offset_y += height_line + linegap
405
+ else:
406
+ raise ValueError(
407
+ f"{alignment=} is invalid, must be 'left', 'center', 'right', 'fill' or "
408
+ 'a callable function'
409
+ )
410
+
411
+ return justified_lines[:-1]
412
+
413
+ def printwrap(
414
+
415
+ *values: object,
416
+ sep: Optional[str] = ' ',
417
+ end: Optional[str] = '\n',
418
+ fill: str = ' ',
419
+ width: Optional[int] = None,
420
+ lenfunc: Callable[[str], Union[int, float]] = len,
421
+ method: Literal['word', 'mono'] = 'word',
422
+ alignment: Union[Callable[[str], str], Literal['left', 'center', 'right', 'fill']] = 'left',
423
+ file: Optional[object] = None,
424
+ flush: bool = False,
425
+ preserve_empty: bool = True
426
+
427
+ ) -> None:
276
428
 
277
- return wrapped
429
+ """
430
+ Print the given values with word wrapping and alignment.
431
+
432
+ Parameters:
433
+ *values (object): Values to be printed.
434
+ sep (Optional[str]): Separator between values. Default to ' '.
435
+ end (Optional[str]): String appended after the last value. Default to '\\n'.
436
+ fill (str): Fill character for padding. Default to ' '.
437
+ width (Optional[int]): Width of the output. If None, it tries to use the terminal width or
438
+ defaults to 70.
439
+ lenfunc (Callable[[str], Union[int, float]]): Function to calculate the length of a string.
440
+ Default is len.
441
+ method (Literal['word', 'mono']): The method to use for wrapping. 'mono' for character-based
442
+ wrapping, 'word' for word-based wrapping.
443
+ Defaults to 'word'.
444
+ alignment (Union[Callable[[str], str],
445
+ Literal['left', 'center', 'right', 'fill']]): Alignment of the text.
446
+ Default is 'left'.
447
+ file (Optional[object]): A file-like object (stream) to write the output to.
448
+ Default is None, which means sys.stdout.
449
+ flush (bool): Whether to forcibly flush the stream. Default is False.
450
+ preserve_empty (bool, optional): Whether to preserve empty lines. Defaults to True.
451
+ """
452
+
453
+ if width is None:
454
+ try:
455
+ width = get_terminal_size().columns
456
+ except:
457
+ width = 70
458
+
459
+ print(
460
+ fillstr(
461
+ (' ' if sep is None else sep).join(map(str, values)),
462
+ width,
463
+ fill,
464
+ lenfunc,
465
+ method,
466
+ alignment,
467
+ preserve_empty
468
+ ),
469
+ end=end,
470
+ file=file,
471
+ flush=flush
472
+ )
278
473
 
279
474
  def shorten(
280
475
 
@@ -282,7 +477,8 @@ def shorten(
282
477
  width: Union[int, float] = 70,
283
478
  start: int = 0,
284
479
  lenfunc: Callable[[str], Union[int, float]] = len,
285
- placeholder: str = '...'
480
+ placeholder: str = '...',
481
+ strip_space: bool = True
286
482
 
287
483
  ) -> str:
288
484
 
@@ -297,6 +493,7 @@ def shorten(
297
493
  the length of a string. Defaults to len.
298
494
  placeholder (str, optional): The placeholder to append to the shortened text.
299
495
  Defaults to '...'.
496
+ strip_space (bool, optional): Whether to strip extra spaces in the text. Defaults to True.
300
497
 
301
498
  Returns:
302
499
  str: The shortened text with the placeholder appended if necessary.
@@ -311,8 +508,13 @@ def shorten(
311
508
  assert width >= lenfunc(placeholder), "width must be greater than length of the placeholder"
312
509
  assert start >= 0, "start must be equal to or greater than 0"
313
510
 
511
+ if strip_space:
512
+ text = ' '.join(text.split())
513
+
314
514
  if start == 0:
315
515
  current_char = ''
516
+ elif start >= len(text):
517
+ return ''
316
518
  else:
317
519
  current_char = placeholder
318
520
 
@@ -320,6 +522,9 @@ def shorten(
320
522
  if lenfunc(current_char + char + placeholder) <= width:
321
523
  current_char += char
322
524
  else:
323
- return current_char + placeholder
525
+ current_char += placeholder
526
+ if lenfunc(current_char) > width:
527
+ return placeholder
528
+ return current_char
324
529
 
325
530
  return current_char
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.1
2
+ Name: txtwrap
3
+ Version: 1.1.1
4
+ Summary: A simple text wrapping tool.
5
+ Author: azzammuhyala
6
+ License: MIT
7
+ Keywords: wrap,wrapper,wrapping,wrapped,wrapping tool,text wrap,text wrapper,simple wrap,align,aligner,aligning,aligned
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+
15
+ # TxTWrap🔡
16
+ A tool for wrapping a text.🔨
17
+
18
+ > **⚠️All documents are in the each module.⚠️**
19
+
20
+ All constants and functions❕:
21
+ - `LOREM_IPSUM_W`
22
+ - `LOREM_IPSUM_S`
23
+ - `LOREM_IPSUM_P`
24
+ - `mono`
25
+ - `word`
26
+ - `wrap`
27
+ - `align` (Updated!)
28
+ - `fillstr`
29
+ - `printwrap`
30
+ - `shorten`
31
+
32
+ Mod `python -m txtwrap` Commands❗:
33
+ ```shell
34
+ python -m txtwrap --help
35
+ ```
36
+
37
+ Examples❓:
38
+ ## Render a wrap text in PyGame🎮
39
+ ```py
40
+ from typing import Literal, Optional
41
+ from txtwrap import align, LOREM_IPSUM_P
42
+ import pygame
43
+
44
+ def render_wrap(
45
+
46
+ font: pygame.Font,
47
+ text: str,
48
+ width: int,
49
+ antialias: bool,
50
+ color: pygame.Color,
51
+ background: Optional[pygame.Color] = None,
52
+ linegap: int = 0,
53
+ alignment: Literal['left', 'center', 'right', 'fill'] = 'left',
54
+ method: Literal['word', 'mono'] = 'word',
55
+ preserve_empty: bool = True,
56
+ use_min_width: bool = True
57
+
58
+ ) -> pygame.Surface:
59
+
60
+ # Only supports in txtwrap 1.1.1+
61
+ align_info = align(
62
+ text=text,
63
+ width=width,
64
+ linegap=linegap,
65
+ sizefunc=font.size,
66
+ method=method,
67
+ alignment=alignment,
68
+ preserve_empty=preserve_empty,
69
+ use_min_width=use_min_width,
70
+ return_details=True
71
+ )
72
+
73
+ surface = pygame.Surface(align_info['size'], pygame.SRCALPHA)
74
+
75
+ if background is not None:
76
+ surface.fill(background)
77
+
78
+ for x, y, text in align_info['aligned']:
79
+ surface.blit(font.render(text, antialias, color), (x, y))
80
+
81
+ return surface
82
+
83
+ # Example usage:
84
+ pygame.init()
85
+ pygame.display.set_caption("Lorem Ipsum")
86
+
87
+ running = True
88
+ wscrn, hscrn = 600, 600
89
+ screen = pygame.display.set_mode((wscrn, hscrn))
90
+ clock = pygame.time.Clock()
91
+ surface = render_wrap(
92
+ font=pygame.font.Font(None, 20),
93
+ text=LOREM_IPSUM_P,
94
+ width=wscrn,
95
+ antialias=True,
96
+ color='#ffffff',
97
+ background='#303030',
98
+ alignment='fill'
99
+ )
100
+
101
+ wsurf, hsurf = surface.get_size()
102
+ pos = ((wscrn - wsurf) / 2, (hscrn - hsurf) / 2)
103
+
104
+ while running:
105
+ for event in pygame.event.get():
106
+ if event.type == pygame.QUIT:
107
+ running = False
108
+ screen.fill('#000000')
109
+ screen.blit(surface, pos)
110
+ pygame.display.flip()
111
+ clock.tick(60)
112
+ ```
113
+
114
+ ## Print a wrap text to terminal🔡
115
+ ```py
116
+ # Only supports in txtwrap 1.1.0+
117
+ from txtwrap import printwrap, LOREM_IPSUM_W
118
+
119
+ printwrap(LOREM_IPSUM_W, width=20, alignment='left')
120
+ print('=' * 20)
121
+ printwrap(LOREM_IPSUM_W, width=20, alignment='center')
122
+ print('=' * 20)
123
+ printwrap(LOREM_IPSUM_W, width=20, alignment='right')
124
+ print('=' * 20)
125
+ printwrap(LOREM_IPSUM_W, width=20, alignment='fill')
126
+ ```
127
+
128
+ ## Short a long text🔤
129
+ ```py
130
+ from txtwrap import shorten, LOREM_IPSUM_S
131
+
132
+ short_lorem = shorten(LOREM_IPSUM_S, width=20, placeholder='…')
133
+ # Only supports in txtwrap 1.1.0+
134
+ test = shorten(' Helllo, \t\r\n World!! \f', width=20, placeholder='…', strip_space=True)
135
+
136
+ print(short_lorem)
137
+ print(test)
138
+ ```
139
+
140
+ ## Bonus🎁 - Print a colorfull text to terminal🔥
141
+ ```py
142
+ # Run this code in a terminal that supports ansi characters
143
+
144
+ from re import compile
145
+ from random import randint
146
+ from txtwrap import printwrap, LOREM_IPSUM_P
147
+
148
+ # Set the text to be printed here
149
+ text = LOREM_IPSUM_P
150
+
151
+ remove_ansi_regex = compile(r'\x1b\[[0-9;]*[mK]').sub
152
+
153
+ def ralen(s: str) -> int:
154
+ return len(remove_ansi_regex('', s))
155
+
156
+ while True:
157
+ # Only supports in txtwrap 1.1.0+
158
+ printwrap(
159
+ ''.join(f'\x1b[{randint(31, 36)}m{char}' for char in text) + '\x1b[0m',
160
+ end='\x1b[H\x1b[J',
161
+ alignment='fill',
162
+ lenfunc=ralen
163
+ )
164
+ ```
txtwrap-1.0.0/PKG-INFO DELETED
@@ -1,33 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: txtwrap
3
- Version: 1.0.0
4
- Summary: A simple text wrapping tool.
5
- Author: azzammuhyala
6
- License: MIT
7
- Keywords: wrap,wrapper,wrapping,wrapping tool,text wrap,text wrapper,simple wrap,align,aligner,aligning
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.8
10
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
- Classifier: License :: OSI Approved :: MIT License
12
- Requires-Python: >=3.8
13
- Description-Content-Type: text/markdown
14
-
15
- # TxTWrap 🔤
16
- A tool for wrapping a text.🔨
17
-
18
- > **⚠️All documents are in the each module.⚠️**
19
-
20
- All constants and functions❕:
21
- - `LOREM_IPSUM_W`
22
- - `LOREM_IPSUM_S`
23
- - `LOREM_IPSUM_P`
24
- - `mono`
25
- - `word`
26
- - `wrap`
27
- - `align`
28
- - `shorten`
29
-
30
- Mod `python -m txtwrap` Commands❗:
31
- ```shell
32
- python -m txtwrap --help
33
- ```
txtwrap-1.0.0/README.md DELETED
@@ -1,19 +0,0 @@
1
- # TxTWrap 🔤
2
- A tool for wrapping a text.🔨
3
-
4
- > **⚠️All documents are in the each module.⚠️**
5
-
6
- All constants and functions❕:
7
- - `LOREM_IPSUM_W`
8
- - `LOREM_IPSUM_S`
9
- - `LOREM_IPSUM_P`
10
- - `mono`
11
- - `word`
12
- - `wrap`
13
- - `align`
14
- - `shorten`
15
-
16
- Mod `python -m txtwrap` Commands❗:
17
- ```shell
18
- python -m txtwrap --help
19
- ```
@@ -1,105 +0,0 @@
1
- from argparse import ArgumentParser
2
- from os import get_terminal_size
3
- from txtwrap import wrap, shorten
4
-
5
- parser = ArgumentParser(
6
- description='Command-line tool for wrapping, aligning, or shortening text.'
7
- )
8
-
9
- parser.add_argument(
10
- 'text',
11
- type=str,
12
- help='Text to be wrapped, aligned, or shorted'
13
- )
14
-
15
- try:
16
- width = get_terminal_size()[0]
17
- except:
18
- width = 70
19
-
20
- parser.add_argument(
21
- '-w', '--width',
22
- type=int,
23
- default=width,
24
- metavar='<number>',
25
- help='Width of the text wrapping (default: current width terminal or 70)'
26
- )
27
-
28
- parser.add_argument(
29
- '-m', '--method',
30
- type=str,
31
- choices={'word', 'mono', 'shorten'},
32
- default='word',
33
- metavar='{word|mono|shorten}',
34
- help='Method to be applied to the text (default: word)'
35
- )
36
-
37
- parser.add_argument(
38
- '-a', '--alignment',
39
- type=str,
40
- choices={'left', 'center', 'right', 'fill'},
41
- default='left',
42
- metavar='{left|center|right|fill}',
43
- help='Alignment of the text (default: left)'
44
- )
45
-
46
- parser.add_argument(
47
- '-ne', '--neglect-empty',
48
- action='store_false',
49
- help='Neglect empty lines in the text'
50
- )
51
-
52
- parser.add_argument(
53
- '-s', '--start',
54
- type=int,
55
- default=0,
56
- metavar='<number>',
57
- help='start index of the text to be shorten (default: 0)'
58
- )
59
-
60
- parser.add_argument(
61
- '-ph', '--placeholder',
62
- type=str,
63
- default='...',
64
- metavar='<str>',
65
- help='Placeholder to be used when shortening the text (default: ...)'
66
- )
67
-
68
- args = parser.parse_args()
69
-
70
- if args.method == 'shorten':
71
- print(shorten(args.text, args.width, args.start, placeholder=args.placeholder))
72
- else:
73
- wrapped = wrap(args.text, args.width, method=args.method, preserve_empty=args.neglect_empty)
74
-
75
- if args.alignment == 'left':
76
- print('\n'.join(wrapped))
77
- elif args.alignment == 'center':
78
- print('\n'.join(line.center(args.width) for line in wrapped))
79
- elif args.alignment == 'right':
80
- print('\n'.join(line.rjust(args.width) for line in wrapped))
81
- elif args.alignment == 'fill':
82
- justified_lines = ''
83
-
84
- for line in wrapped:
85
- words = line.split()
86
- total_words = len(words)
87
- total_words_width = sum(len(w) for w in words)
88
- extra_space = args.width - total_words_width
89
-
90
- if total_words > 1:
91
- space_between_words = extra_space // (total_words - 1)
92
- extra_padding = extra_space % (total_words - 1)
93
- else:
94
- space_between_words = extra_space
95
- extra_padding = 0
96
-
97
- justified_line = ''
98
- for i, word in enumerate(words):
99
- justified_line += word
100
- if i < total_words - 1:
101
- justified_line += ' ' * (space_between_words + (1 if i < extra_padding else 0))
102
-
103
- justified_lines += justified_line + '\n'
104
-
105
- print(justified_lines, end='')
@@ -1,33 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: txtwrap
3
- Version: 1.0.0
4
- Summary: A simple text wrapping tool.
5
- Author: azzammuhyala
6
- License: MIT
7
- Keywords: wrap,wrapper,wrapping,wrapping tool,text wrap,text wrapper,simple wrap,align,aligner,aligning
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.8
10
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
- Classifier: License :: OSI Approved :: MIT License
12
- Requires-Python: >=3.8
13
- Description-Content-Type: text/markdown
14
-
15
- # TxTWrap 🔤
16
- A tool for wrapping a text.🔨
17
-
18
- > **⚠️All documents are in the each module.⚠️**
19
-
20
- All constants and functions❕:
21
- - `LOREM_IPSUM_W`
22
- - `LOREM_IPSUM_S`
23
- - `LOREM_IPSUM_P`
24
- - `mono`
25
- - `word`
26
- - `wrap`
27
- - `align`
28
- - `shorten`
29
-
30
- Mod `python -m txtwrap` Commands❗:
31
- ```shell
32
- python -m txtwrap --help
33
- ```
File without changes
File without changes