txtwrap 1.0.0__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.
@@ -0,0 +1 @@
1
+ include README.md
txtwrap-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,33 @@
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
+ ```
@@ -0,0 +1,19 @@
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
+ ```
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
txtwrap-1.0.0/setup.py ADDED
@@ -0,0 +1,25 @@
1
+ from setuptools import find_packages, setup
2
+
3
+ with open('README.md', encoding='utf-8') as readme:
4
+ long_description = readme.read()
5
+
6
+ setup(
7
+ name='txtwrap',
8
+ version='1.0.0',
9
+ description='A simple text wrapping tool.',
10
+ long_description=long_description,
11
+ long_description_content_type='text/markdown',
12
+ author='azzammuhyala',
13
+ license='MIT',
14
+ python_requires='>=3.8',
15
+ packages=find_packages(),
16
+ include_package_data=True,
17
+ keywords=['wrap', 'wrapper', 'wrapping', 'wrapping tool', 'text wrap', 'text wrapper',
18
+ 'simple wrap', 'align', 'aligner', 'aligning'],
19
+ classifiers=[
20
+ 'Programming Language :: Python :: 3',
21
+ 'Programming Language :: Python :: 3.8',
22
+ 'Topic :: Software Development :: Libraries :: Python Modules',
23
+ 'License :: OSI Approved :: MIT License',
24
+ ]
25
+ )
@@ -0,0 +1,25 @@
1
+ """
2
+ A simple text wrapping tool
3
+ """
4
+
5
+ # Supports only in Python 3.8+
6
+
7
+ from .txtwrap import (
8
+ LOREM_IPSUM_W, LOREM_IPSUM_S, LOREM_IPSUM_P,
9
+ mono, word, wrap, align,
10
+ shorten
11
+ )
12
+
13
+ __version__ = '1.0.0'
14
+ __license__ = 'MIT'
15
+ __author__ = 'Azzam Muhyala'
16
+ __all__ = [
17
+ 'LOREM_IPSUM_W',
18
+ 'LOREM_IPSUM_S',
19
+ 'LOREM_IPSUM_P',
20
+ 'mono',
21
+ 'word',
22
+ 'wrap',
23
+ 'align',
24
+ 'shorten'
25
+ ]
@@ -0,0 +1,105 @@
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='')
@@ -0,0 +1,325 @@
1
+ from typing import Callable, List, Literal, Tuple, Union
2
+ from re import compile
3
+
4
+ hyphenated_regex = compile(r'(?<=-)(?=(?!-).)')
5
+
6
+ LOREM_IPSUM_W = 'Lorem ipsum odor amet, consectetuer adipiscing elit.'
7
+ LOREM_IPSUM_S = ('Lorem ipsum odor amet, consectetuer adipiscing elit. In malesuada eros natoque '
8
+ 'urna felis diam aptent donec. Cubilia libero morbi fusce tempus, luctus aenean '
9
+ 'augue. Mus senectus rutrum phasellus fusce dictum platea. Eros a integer nec '
10
+ 'fusce erat urna.')
11
+ LOREM_IPSUM_P = ('Lorem ipsum odor amet, consectetuer adipiscing elit. Nulla porta ex condimentum '
12
+ 'velit facilisi; consequat congue. Tristique duis sociosqu aliquam semper sit id. '
13
+ 'Nisi morbi purus, nascetur elit pellentesque venenatis. Velit commodo molestie '
14
+ 'potenti placerat faucibus convallis. Himenaeos dapibus ipsum natoque nam dapibus '
15
+ 'habitasse diam. Viverra ac porttitor cras tempor cras. Pharetra habitant nibh '
16
+ 'dui ipsum scelerisque cras? Efficitur phasellus etiam congue taciti tortor quam. '
17
+ 'Volutpat quam vulputate condimentum hendrerit justo congue iaculis nisl nullam.'
18
+ '\n\nInceptos tempus nostra fringilla arcu; tellus blandit facilisi risus. Platea '
19
+ 'bibendum tristique lectus nunc placerat id aliquam. Eu arcu nisl mattis potenti '
20
+ 'elementum. Dignissim vivamus montes volutpat litora felis fusce ultrices. '
21
+ 'Vulputate magna nascetur bibendum inceptos scelerisque morbi posuere. Consequat '
22
+ 'dolor netus augue augue tristique curabitur habitasse bibendum. Consectetur est '
23
+ 'per eros semper, magnis interdum libero. Arcu adipiscing litora metus fringilla '
24
+ 'varius gravida congue tellus adipiscing. Blandit nulla mauris nullam ante metus '
25
+ 'curae scelerisque.\n\nSem varius sodales ut volutpat imperdiet turpis primis '
26
+ 'nullam. At gravida tincidunt phasellus lacus duis integer eros penatibus. '
27
+ 'Interdum mauris molestie posuere nascetur dignissim himenaeos; magna et quisque. '
28
+ 'Dignissim malesuada etiam donec vehicula aliquet bibendum. Magna dapibus sapien '
29
+ 'semper parturient id dis? Pretium orci ante leo, porta tincidunt molestie. '
30
+ 'Malesuada dictumst commodo consequat interdum nisi fusce cras rhoncus feugiat.'
31
+ '\n\nHimenaeos mattis commodo suspendisse maecenas cras arcu. Habitasse id '
32
+ 'facilisi praesent justo molestie felis luctus suspendisse. Imperdiet ipsum '
33
+ 'praesent nunc mauris mattis curabitur. Et consectetur morbi auctor feugiat enim '
34
+ 'ridiculus arcu. Ultricies magna blandit eget; vivamus sollicitudin nisl proin. '
35
+ 'Sollicitudin sociosqu et finibus elit vestibulum sapien nec odio euismod. Turpis '
36
+ 'eleifend amet quis auctor cursus. Vehicula pharetra sapien praesent amet purus '
37
+ 'ante. Risus blandit cubilia lorem hendrerit penatibus in magnis.\n\nAmet posuere '
38
+ 'nunc; maecenas consequat risus potenti. Volutpat leo lacinia sapien nulla '
39
+ 'sagittis dignissim mauris ultrices aliquet. Nisi pretium interdum luctus donec '
40
+ 'magna suscipit. Dapibus tristique felis natoque malesuada augue? Justo faucibus '
41
+ 'tincidunt congue arcu sem; fusce aliquet proin. Commodo neque nibh; tempus ad '
42
+ 'tortor netus. Mattis ultricies nec maximus porttitor non mauris?')
43
+
44
+ def mono(
45
+
46
+ text: str,
47
+ width: Union[int, float] = 70,
48
+ lenfunc: Callable[[str], Union[int, float]] = len,
49
+
50
+ ) -> List[str]:
51
+
52
+ """
53
+ Wraps the given text into lines of specified width.
54
+
55
+ Parameters:
56
+ text (str): The text to be wrapped.
57
+ width (int | float, optional): The maximum width of each line. Defaults to 70.
58
+ lenfunc (Callable[[str], int | float], optional): A function to calculate
59
+ the length of a string. Defaults to len.
60
+
61
+ Returns:
62
+ list[str]: A list of strings, where each string is a line of the wrapped text.
63
+ """
64
+
65
+ assert isinstance(text, str), "text must be a string"
66
+ assert isinstance(width, (int, float)), "width must be an integer or float"
67
+ assert callable(lenfunc), "lenfunc must be a callable function"
68
+
69
+ assert width > 0, "width must be greater than 0"
70
+
71
+ parts = []
72
+ current_char = ''
73
+
74
+ for char in text:
75
+ if lenfunc(current_char + char) <= width:
76
+ current_char += char
77
+ else:
78
+ parts.append(current_char)
79
+ current_char = char
80
+
81
+ if current_char:
82
+ parts.append(current_char)
83
+
84
+ return parts
85
+
86
+ def word(
87
+
88
+ text: str,
89
+ width: Union[int, float] = 70,
90
+ lenfunc: Callable[[str], Union[int, float]] = len,
91
+
92
+ ) -> List[str]:
93
+
94
+ """
95
+ Wraps the input text into lines of specified width.
96
+
97
+ Parameters:
98
+ text (str): The input text to be wrapped.
99
+ width (int | float, optional): The maximum width of each line. Defaults to 70.
100
+ lenfunc (Callable[[str], int | float], optional): A function to calculate
101
+ the length of a string. Defaults to len.
102
+
103
+ Returns:
104
+ list[str]: A list of strings, where each string is a line of wrapped text.
105
+ """
106
+
107
+ assert isinstance(text, str), "text must be a string"
108
+ assert isinstance(width, (int, float)), "width must be an integer or float"
109
+ assert callable(lenfunc), "lenfunc must be a callable function"
110
+
111
+ assert width > 0, "width must be greater than 0"
112
+
113
+ lines = []
114
+ current_line = ''
115
+
116
+ for word in text.split():
117
+ test_line = current_line + ' ' + word if current_line else word
118
+
119
+ if lenfunc(test_line) <= width:
120
+ current_line = test_line
121
+ else:
122
+ if current_line:
123
+ lines.append(current_line)
124
+
125
+ current_line = ''
126
+
127
+ for part in hyphenated_regex.split(word):
128
+ for wrapped_part in mono(part, width, lenfunc):
129
+ if lenfunc(current_line + wrapped_part) <= width:
130
+ current_line += wrapped_part
131
+ else:
132
+ if current_line:
133
+ lines.append(current_line)
134
+ current_line = wrapped_part
135
+
136
+ if current_line:
137
+ lines.append(current_line)
138
+
139
+ return lines
140
+
141
+ def wrap(
142
+
143
+ text: str,
144
+ width: Union[int, float] = 70,
145
+ lenfunc: Callable[[str], Union[int, float]] = len,
146
+ method: Literal['mono', 'word'] = 'word',
147
+ preserve_empty: bool = True
148
+
149
+ ) -> List[str]:
150
+
151
+ """
152
+ Wraps the given text into lines of specified width.
153
+
154
+ Parameters:
155
+ text (str): The text to be wrapped.
156
+ width (int | float, optional): The maximum width of each line. Defaults to 70.
157
+ lenfunc (Callable[[str], int | float], optional): A function to calculate
158
+ the length of a string. Defaults to len.
159
+ method (Literal['mono', 'word'], optional): The method to use for wrapping.
160
+ 'mono' for character-based wrapping, 'word'
161
+ for word-based wrapping. Defaults to 'word'.
162
+ preserve_empty (bool, optional): Whether to preserve empty lines. Defaults to True.
163
+
164
+ Returns:
165
+ list[str]: A list of wrapped lines.
166
+ """
167
+
168
+ assert isinstance(text, str), "text must be a string"
169
+ assert isinstance(width, (int, float)), "width must be an integer or float"
170
+ assert callable(lenfunc), "lenfunc must be a callable function"
171
+
172
+ assert width > 0, "width must be greater than 0"
173
+
174
+ wrapped_lines = []
175
+
176
+ if method == 'mono':
177
+ wrapfunc = mono
178
+ elif method == 'word':
179
+ wrapfunc = word
180
+ else:
181
+ raise ValueError(f"{method=} is invalid, must be 'mono' or 'word'")
182
+
183
+ for line in text.splitlines():
184
+ wrapped_line = wrapfunc(line, width, lenfunc)
185
+ if wrapped_line:
186
+ wrapped_lines.extend(wrapped_line)
187
+ elif preserve_empty:
188
+ wrapped_lines.append('')
189
+
190
+ return wrapped_lines
191
+
192
+ def align(
193
+
194
+ text: str,
195
+ width: Union[int, float] = 70,
196
+ linegap: Union[int, float] = 0,
197
+ sizefunc: Callable[[str], Tuple[Union[int, float], Union[int, float]]] = lambda s : (len(s), 1),
198
+ method: Literal['mono', 'word'] = 'word',
199
+ alignment: Literal['left', 'center', 'right', 'fill'] = 'left',
200
+ preserve_empty: bool = True
201
+
202
+ ) -> List[Tuple[Union[int, float], Union[int, float], str]]:
203
+
204
+ """
205
+ Wraps and aligns text within a specified width and yields the position and content of each line.
206
+
207
+ Parameters:
208
+ text (str): The text to be wrapped and aligned.
209
+ width (int | float, optional): The maximum width of each line. Defaults to 70.
210
+ linegap (int | float, optional): The vertical gap between lines. Defaults to 0.
211
+ sizefunc (Callable[[str], tuple[int | float, int | float]], optional): A function that
212
+ returns the width and
213
+ height of a given
214
+ string. Defaults to a
215
+ lambda function that
216
+ returns the length of
217
+ the string and 1.
218
+ method (Literal['mono', 'word'], optional): The method to use for wrapping.
219
+ 'mono' for character-based wrapping, 'word'
220
+ for word-based wrapping. Defaults to 'word'.
221
+ alignment (Literal['left', 'center', 'right', 'fill'], optional): The alignment of the text.
222
+ 'left', 'center', 'right',
223
+ or 'fill'.
224
+ Defaults to 'left'.
225
+ preserve_empty (bool, optional): Whether to preserve empty lines. Defaults to True.
226
+
227
+ Returns:
228
+ list[tuple[int | float, int | float, str]]: A list of tuples containing the position and
229
+ content of each line.
230
+ """
231
+
232
+ assert isinstance(linegap, (int, float)), "linegap must be an integer or float"
233
+ assert callable(sizefunc), "sizefunc must be a callable function"
234
+
235
+ assert linegap >= 0, "linegap must be equal to or greater than 0"
236
+
237
+ wrapped = []
238
+ offset_y = 0
239
+
240
+ for line in wrap(text, width, lambda s : sizefunc(s)[0], method, preserve_empty):
241
+
242
+ width_line, height_line = sizefunc(line)
243
+
244
+ if alignment == 'left':
245
+ wrapped.append((0, offset_y, line))
246
+
247
+ elif alignment == 'center':
248
+ wrapped.append(((width - width_line) / 2, offset_y, line))
249
+
250
+ elif alignment == 'right':
251
+ wrapped.append((width - width_line, offset_y, line))
252
+
253
+ elif alignment == 'fill':
254
+ offset_x = 0
255
+ words = line.split()
256
+ total_words = len(words)
257
+ widths = {i: sizefunc(w)[0] for i, w in enumerate(words)}
258
+ total_words_width = sum(widths.values())
259
+ extra_space = width - total_words_width
260
+
261
+ if total_words > 1:
262
+ space_between_words = extra_space / (total_words - 1)
263
+ else:
264
+ space_between_words = extra_space
265
+
266
+ for i, w in enumerate(words):
267
+ wrapped.append((offset_x, offset_y, w))
268
+ offset_x += widths[i] + space_between_words
269
+
270
+ else:
271
+ raise ValueError(
272
+ f"{alignment=} is invalid, must be 'left', 'center', 'right', or 'fill'"
273
+ )
274
+
275
+ offset_y += height_line + linegap
276
+
277
+ return wrapped
278
+
279
+ def shorten(
280
+
281
+ text: str,
282
+ width: Union[int, float] = 70,
283
+ start: int = 0,
284
+ lenfunc: Callable[[str], Union[int, float]] = len,
285
+ placeholder: str = '...'
286
+
287
+ ) -> str:
288
+
289
+ """
290
+ Shortens the given text to fit within the specified width, optionally including a placeholder.
291
+
292
+ Parameters:
293
+ text (str): The text to be shortened.
294
+ width (int | float, optional): The maximum width of the shortened text. Defaults to 70.
295
+ start (int, optional): The starting index of the text to be shortened. Defaults to 0.
296
+ lenfunc (Callable[[str], int | float], optional): A function to calculate
297
+ the length of a string. Defaults to len.
298
+ placeholder (str, optional): The placeholder to append to the shortened text.
299
+ Defaults to '...'.
300
+
301
+ Returns:
302
+ str: The shortened text with the placeholder appended if necessary.
303
+ """
304
+
305
+ assert isinstance(text, str), "text must be a string"
306
+ assert isinstance(width, (int, float)), "width must be an integer or float"
307
+ assert isinstance(start, int), "start must be an integer"
308
+ assert callable(lenfunc), "lenfunc must be a callable function"
309
+ assert isinstance(placeholder, str), "placeholder must be a string"
310
+
311
+ assert width >= lenfunc(placeholder), "width must be greater than length of the placeholder"
312
+ assert start >= 0, "start must be equal to or greater than 0"
313
+
314
+ if start == 0:
315
+ current_char = ''
316
+ else:
317
+ current_char = placeholder
318
+
319
+ for char in text[start:]:
320
+ if lenfunc(current_char + char + placeholder) <= width:
321
+ current_char += char
322
+ else:
323
+ return current_char + placeholder
324
+
325
+ return current_char
@@ -0,0 +1,33 @@
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
+ ```
@@ -0,0 +1,10 @@
1
+ MANIFEST.in
2
+ README.md
3
+ setup.py
4
+ txtwrap/__init__.py
5
+ txtwrap/__main__.py
6
+ txtwrap/txtwrap.py
7
+ txtwrap.egg-info/PKG-INFO
8
+ txtwrap.egg-info/SOURCES.txt
9
+ txtwrap.egg-info/dependency_links.txt
10
+ txtwrap.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ txtwrap