ttyengine 0.1.0__py3-none-any.whl

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.
ttyengine/errors.py ADDED
@@ -0,0 +1,181 @@
1
+ import os, re, sys, traceback
2
+
3
+ from . import ansi
4
+
5
+ HOLD_ENV = 'TTYENGINE_HOLD'
6
+ HOLD_PROMPT = 'Press Enter to close...'
7
+ EXIT_CODE = 1
8
+
9
+ def highlight_traceback(tb_str: str) -> str:
10
+ if not ansi.color_enabled():
11
+ return tb_str
12
+ RESET, BOLD, RED, GREEN, YELLOW, CYAN, MAGENTA = (
13
+ ansi.RESET, ansi.BOLD, ansi.sgr(91), ansi.sgr(92), ansi.sgr(93), ansi.sgr(96), ansi.sgr(95)
14
+ )
15
+ lines = []
16
+ for line in tb_str.splitlines(True):
17
+ if line.startswith("Traceback"):
18
+ lines.append(f"{BOLD}{RED}{line}{RESET}")
19
+ elif line.strip().startswith("File "):
20
+ m = re.match(r'^(\s*File )("[^"]+")(, line )(\d+)(, in )(.*)$', line)
21
+ if m:
22
+ lines.append(
23
+ f"{m.group(1)}{GREEN}{m.group(2)}{RESET}"
24
+ f"{m.group(3)}{YELLOW}{m.group(4)}{RESET}"
25
+ f"{m.group(5)}{CYAN}{m.group(6)}{RESET}\n"
26
+ )
27
+ else:
28
+ lines.append(line)
29
+ elif ":" in line and not line.startswith(" "):
30
+ parts = line.split(":", 1)
31
+ lines.append(f"{BOLD}{RED}{parts[0]}:{RESET}{BOLD}{parts[1]}{RESET}")
32
+ else:
33
+ line_hl = re.sub(r'("[^"]*"|\'[^\']*\')', rf'{GREEN}\1{RESET}', line)
34
+ kw = r'\b(def|class|return|if|elif|else|while|for|in|import|from|as|try|except|finally|raise|with|pass|break|continue|and|or|not|is|None|True|False)\b'
35
+ line_hl = re.sub(kw, rf'{MAGENTA}\1{RESET}', line_hl)
36
+ lines.append(line_hl)
37
+ return "".join(lines)
38
+
39
+
40
+ def _stream(stream=None):
41
+ if stream is not None:
42
+ return stream
43
+ for candidate in (sys.stderr, sys.stdout, sys.__stderr__, sys.__stdout__):
44
+ if candidate is not None:
45
+ return candidate
46
+ return None
47
+
48
+
49
+ def _is_tty(stream):
50
+ try:
51
+ return bool(stream and stream.isatty())
52
+ except Exception:
53
+ return False
54
+
55
+
56
+ def owns_console():
57
+ if sys.platform != 'win32':
58
+ return False
59
+ try:
60
+ import ctypes
61
+ pids = (ctypes.c_uint * 4)()
62
+ count = ctypes.windll.kernel32.GetConsoleProcessList(pids, 4)
63
+ return 0 < count <= 2
64
+ except Exception:
65
+ return False
66
+
67
+
68
+ def should_hold(hold=None):
69
+ if hold is None:
70
+ hold = os.environ.get(HOLD_ENV, 'auto')
71
+ if isinstance(hold, str):
72
+ mode = hold.strip().lower()
73
+ if mode in ('1', 'true', 'yes', 'on', 'always'):
74
+ return True
75
+ if mode in ('0', 'false', 'no', 'off', 'never'):
76
+ return False
77
+ return owns_console()
78
+ return bool(hold)
79
+
80
+
81
+ def hold_console(prompt=HOLD_PROMPT, stream=None):
82
+ stream = _stream(stream)
83
+ try:
84
+ if stream is not None and prompt:
85
+ stream.write(prompt)
86
+ stream.flush()
87
+ input()
88
+ except (Exception, KeyboardInterrupt):
89
+ pass
90
+
91
+
92
+ def format_error(exc=None, color=None, skip=0):
93
+ if exc is None:
94
+ exc = sys.exc_info()[1]
95
+ if exc is None:
96
+ return ''
97
+ tb = exc.__traceback__
98
+ for _ in range(skip):
99
+ if tb is not None and tb.tb_next is not None:
100
+ tb = tb.tb_next
101
+ text = ''.join(traceback.format_exception(type(exc), exc, tb))
102
+ if color is None:
103
+ color = ansi.color_enabled()
104
+ return highlight_traceback(text) if color else text
105
+
106
+
107
+ def report(exc=None, clear=True, stream=None, out=None, flush=None, skip=0):
108
+ stream = _stream(stream)
109
+ if out is None:
110
+ if stream is None:
111
+ return False
112
+ out, flush = stream.write, stream.flush
113
+ tty = _is_tty(stream)
114
+ try:
115
+ if clear and tty:
116
+ out(ansi.wrap_all(ansi.CLEAR_ALL))
117
+ text = format_error(exc, color=tty and ansi.color_enabled(), skip=skip) + '\n'
118
+ out(ansi.wrap_all(text) if tty else text)
119
+ if flush:
120
+ flush()
121
+ return True
122
+ except Exception:
123
+ return False
124
+
125
+
126
+ def trace(exception, lexer=None, clear=True, out=None, flush=None):
127
+ if not report(exception, clear=clear, out=out, flush=flush):
128
+ raise exception
129
+
130
+
131
+ def attempt(func, catch=None, lexer=None, fatal=True, clear=True, reset=True, out=None, flush=None,
132
+ hold=None, code=EXIT_CODE, stream=None):
133
+ try:
134
+ return func()
135
+ except Exception as e:
136
+ target = _stream(stream)
137
+ tty = _is_tty(target)
138
+ if out is None and target is not None:
139
+ out, flush = target.write, target.flush
140
+ if reset and fatal and tty and out:
141
+ try:
142
+ out(ansi.wrap(ansi.FULL_RESET))
143
+ except Exception:
144
+ pass
145
+ catch_exc = None
146
+ if callable(catch):
147
+ try:
148
+ catch()
149
+ except Exception as ce:
150
+ catch_exc = ce
151
+ if not report(e, clear=clear, stream=target, out=out, flush=flush, skip=1):
152
+ raise
153
+ if catch_exc is not None:
154
+ report(catch_exc, clear=False, stream=target, out=out, flush=flush)
155
+ if not fatal:
156
+ return None
157
+ if should_hold(hold):
158
+ hold_console(stream=target)
159
+ sys.exit(code)
160
+
161
+
162
+ def install(hold=None, code=EXIT_CODE, stream=None):
163
+ previous = sys.excepthook
164
+
165
+ def hook(exc_type, exc, tb):
166
+ if issubclass(exc_type, KeyboardInterrupt):
167
+ return previous(exc_type, exc, tb)
168
+ target = _stream(stream)
169
+ text = ''.join(traceback.format_exception(exc_type, exc, tb))
170
+ tty = _is_tty(target)
171
+ try:
172
+ if target is not None:
173
+ target.write(highlight_traceback(text) if tty and ansi.color_enabled() else text)
174
+ target.flush()
175
+ except Exception:
176
+ return previous(exc_type, exc, tb)
177
+ if should_hold(hold):
178
+ hold_console(stream=target)
179
+
180
+ sys.excepthook = hook
181
+ return previous
@@ -0,0 +1,27 @@
1
+ PyFiglet: An implementation of figlet written in Python
2
+
3
+ The MIT License (MIT)
4
+
5
+ Copyright © 2007-2018
6
+ Christopher Jones <cjones@insub.org>
7
+ Stefano Rivera <stefano@rivera.za.net>
8
+ Peter Waller <p@pwaller.net>
9
+ And various contributors (see git history).
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
12
+ this software and associated documentation files (the “Software”), to deal in
13
+ the Software without restriction, including without limitation the rights to
14
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
15
+ of the Software, and to permit persons to whom the Software is furnished to do
16
+ so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
+ DEALINGS IN THE SOFTWARE.
ttyengine/figlet.py ADDED
@@ -0,0 +1,430 @@
1
+ import io, os, re, zipfile
2
+
3
+ DEFAULT_FONT = 'standard'
4
+
5
+ _HERE = os.path.dirname(os.path.abspath(__file__))
6
+ _BUNDLE = os.path.join(_HERE, 'fonts.zip')
7
+ _LOCATIONS = ('./', os.path.join(_HERE, 'fonts'))
8
+ _MAGIC = re.compile(r'^[tf]lf2.')
9
+ _END = re.compile(r'(.)\s*$')
10
+
11
+
12
+ class FigletError(Exception):
13
+ def __init__(self, error):
14
+ self.error = error
15
+
16
+ def __str__(self):
17
+ return str(self.error)
18
+
19
+
20
+ class CharNotPrinted(FigletError):
21
+ pass
22
+
23
+
24
+ class FontNotFound(FigletError):
25
+ pass
26
+
27
+
28
+ class FontError(FigletError):
29
+ pass
30
+
31
+
32
+ def _bundled(filename):
33
+ try:
34
+ with zipfile.ZipFile(_BUNDLE) as bundle:
35
+ return bundle.read(filename)
36
+ except (KeyError, OSError, zipfile.BadZipFile):
37
+ return None
38
+
39
+
40
+ def _locate(font):
41
+ for extension in ('tlf', 'flf'):
42
+ filename = '%s.%s' % (font, extension)
43
+ data = _bundled(filename)
44
+ if data is not None:
45
+ return data
46
+ for location in _LOCATIONS:
47
+ path = os.path.join(location, filename)
48
+ if os.path.isfile(path):
49
+ with open(path, 'rb') as handle:
50
+ return handle.read()
51
+ return None
52
+
53
+
54
+ def _unpack(data):
55
+ if data and zipfile.is_zipfile(io.BytesIO(data)):
56
+ with zipfile.ZipFile(io.BytesIO(data)) as inner:
57
+ return inner.read(inner.namelist()[0])
58
+ return data
59
+
60
+
61
+ def _valid(data):
62
+ header = _unpack(data).split(b'\n', 1)[0].decode('utf-8', 'replace')
63
+ return bool(_MAGIC.search(header))
64
+
65
+
66
+ def available():
67
+ found = set()
68
+ try:
69
+ with zipfile.ZipFile(_BUNDLE) as bundle:
70
+ for name in bundle.namelist():
71
+ if name.endswith(('.flf', '.tlf')) and _valid(bundle.read(name)):
72
+ found.add(name.split('.', 2)[0])
73
+ except (OSError, zipfile.BadZipFile):
74
+ pass
75
+ for location in _LOCATIONS:
76
+ if os.path.isdir(location):
77
+ for name in os.listdir(location):
78
+ path = os.path.join(location, name)
79
+ if name.endswith(('.flf', '.tlf')) and os.path.isfile(path):
80
+ with open(path, 'rb') as handle:
81
+ if _valid(handle.read()):
82
+ found.add(name.split('.', 2)[0])
83
+ return sorted(found)
84
+
85
+
86
+ class FigletFont:
87
+ def __init__(self, font=DEFAULT_FONT):
88
+ self.font = font
89
+ self.comment = ''
90
+ self.chars = {}
91
+ self.width = {}
92
+ data = _unpack(_locate(font))
93
+ if not data:
94
+ raise FontNotFound(font)
95
+ self.data = data.decode('utf-8', 'replace')
96
+ self.loadFont()
97
+
98
+ def loadFont(self):
99
+ try:
100
+ data = re.sub(r'[\u0085

]', ' ', self.data)
101
+ data = data.splitlines()
102
+ header = data.pop(0)
103
+ if _MAGIC.search(header) is None:
104
+ raise FontError('%s is not a valid figlet font' % self.font)
105
+ header = _MAGIC.sub('', header).split()
106
+ if len(header) < 6:
107
+ raise FontError('malformed header for %s' % self.font)
108
+ hardBlank = header[0]
109
+ height, baseLine, maxLength, oldLayout, commentLines = map(int, header[1:6])
110
+ printDirection = fullLayout = None
111
+ if len(header) > 6:
112
+ printDirection = int(header[6])
113
+ if len(header) > 7:
114
+ fullLayout = int(header[7])
115
+ if fullLayout is None:
116
+ if oldLayout == 0:
117
+ fullLayout = 64
118
+ elif oldLayout < 0:
119
+ fullLayout = 0
120
+ else:
121
+ fullLayout = (oldLayout & 31) | 128
122
+ self.height = height
123
+ self.hardBlank = hardBlank
124
+ self.printDirection = printDirection
125
+ self.smushMode = fullLayout
126
+ for _ in range(commentLines):
127
+ self.comment += data.pop(0)
128
+
129
+ def character(data):
130
+ end = None
131
+ width = 0
132
+ rows = []
133
+ for _ in range(height):
134
+ line = data.pop(0)
135
+ if end is None:
136
+ end = _END.search(line).group(1)
137
+ end = re.compile(re.escape(end) + r'{1,2}\s*$')
138
+ line = end.sub('', line)
139
+ if len(line) > width:
140
+ width = len(line)
141
+ rows.append(line)
142
+ return width, rows
143
+
144
+ for i in range(32, 127):
145
+ width, letter = character(data)
146
+ if i == 32 or ''.join(letter) != '':
147
+ self.chars[i] = letter
148
+ self.width[i] = width
149
+ if data:
150
+ for i in 'ÄÖÜäöüß':
151
+ width, letter = character(data)
152
+ if ''.join(letter) != '':
153
+ self.chars[ord(i)] = letter
154
+ self.width[ord(i)] = width
155
+ while data:
156
+ line = data.pop(0).strip()
157
+ i = line.split(' ', 1)[0]
158
+ if i == '':
159
+ continue
160
+ if re.search('^0x', i, re.IGNORECASE) is not None:
161
+ i = int(i, 16)
162
+ width, letter = character(data)
163
+ if ''.join(letter) != '':
164
+ self.chars[i] = letter
165
+ self.width[i] = width
166
+ except Exception as e:
167
+ raise FontError('problem parsing %s font: %s' % (self.font, e))
168
+
169
+ def __str__(self):
170
+ return '<FigletFont object: %s>' % self.font
171
+
172
+
173
+ SM_EQUAL = 1
174
+ SM_LOWLINE = 2
175
+ SM_HIERARCHY = 4
176
+ SM_PAIR = 8
177
+ SM_BIGX = 16
178
+ SM_HARDBLANK = 32
179
+ SM_KERN = 64
180
+ SM_SMUSH = 128
181
+
182
+
183
+ class _Builder:
184
+ def __init__(self, text, font, direction, width, justify):
185
+ self.text = [ord(c) for c in text]
186
+ self.direction = direction
187
+ self.width = width
188
+ self.font = font
189
+ self.justify = justify
190
+ self.iterator = 0
191
+ self.maxSmush = 0
192
+ self.curCharWidth = 0
193
+ self.prevCharWidth = 0
194
+ self.currentTotalWidth = 0
195
+ self.blankMarkers = []
196
+ self.queue = []
197
+ self.buffer = ['' for _ in range(font.height)]
198
+
199
+ def run(self):
200
+ while self.iterator < len(self.text):
201
+ self.addCharToProduct()
202
+ self.iterator += 1
203
+ if self.buffer[0] != '':
204
+ self.queue.append(self.buffer)
205
+ out = ''
206
+ for buffer in self.queue:
207
+ buffer = self.justifyString(buffer)
208
+ out += self.replaceHardblanks(buffer)
209
+ return out
210
+
211
+ def getCharAt(self, i):
212
+ if i < 0 or i >= len(self.text):
213
+ return None
214
+ c = self.text[i]
215
+ if c not in self.font.chars:
216
+ return None
217
+ return self.font.chars[c]
218
+
219
+ def getCurChar(self):
220
+ return self.getCharAt(self.iterator)
221
+
222
+ def getCurWidth(self):
223
+ i = self.iterator
224
+ if i < 0 or i >= len(self.text):
225
+ return None
226
+ c = self.text[i]
227
+ if c not in self.font.chars:
228
+ return None
229
+ return self.font.width[c]
230
+
231
+ def addCharToProduct(self):
232
+ curChar = self.getCurChar()
233
+ if self.text[self.iterator] == ord('\n'):
234
+ self.blankMarkers.append(([row for row in self.buffer], self.iterator))
235
+ self.handleNewLine()
236
+ return
237
+ if curChar is None:
238
+ return
239
+ if self.width < self.getCurWidth():
240
+ raise CharNotPrinted('Width is not enough to print this character')
241
+ self.curCharWidth = self.getCurWidth()
242
+ self.maxSmush = self.smushAmount(self.buffer, curChar)
243
+ self.currentTotalWidth = len(self.buffer[0]) + self.curCharWidth - self.maxSmush
244
+ if self.text[self.iterator] == ord(' '):
245
+ self.blankMarkers.append(([row for row in self.buffer], self.iterator))
246
+ if self.currentTotalWidth >= self.width and self.buffer[0]:
247
+ self.handleNewLine()
248
+ else:
249
+ for row in range(self.font.height):
250
+ self.addCurCharRowToBufferRow(curChar, row)
251
+ self.prevCharWidth = self.curCharWidth
252
+
253
+ def getLeftSmushedChar(self, i, addLeft):
254
+ idx = len(addLeft) - self.maxSmush + i
255
+ if idx >= 0 and idx < len(addLeft):
256
+ left = addLeft[idx]
257
+ else:
258
+ left = ''
259
+ return left, idx
260
+
261
+ def smushRow(self, curChar, row):
262
+ addLeft = self.buffer[row]
263
+ addRight = curChar[row]
264
+ if self.direction == 'right-to-left':
265
+ addLeft, addRight = addRight, addLeft
266
+ for i in range(self.maxSmush):
267
+ left, idx = self.getLeftSmushedChar(i, addLeft)
268
+ right = addRight[i] if i < len(addRight) else ''
269
+ smushed = self.smushChars(left=left, right=right)
270
+ characters = list(addLeft)
271
+ if 0 <= idx <= len(characters):
272
+ characters[idx] = smushed
273
+ addLeft = ''.join(characters)
274
+ return addLeft, addRight
275
+
276
+ def addCurCharRowToBufferRow(self, curChar, row):
277
+ addLeft, addRight = self.smushRow(curChar, row)
278
+ self.buffer[row] = addLeft + addRight[self.maxSmush:]
279
+
280
+ def cutBufferCommon(self):
281
+ self.currentTotalWidth = 0
282
+ self.buffer = ['' for _ in range(self.font.height)]
283
+ self.blankMarkers = []
284
+ self.prevCharWidth = 0
285
+ curChar = self.getCurChar()
286
+ if curChar is None:
287
+ return
288
+ self.maxSmush = self.smushAmount(self.buffer, curChar)
289
+
290
+ def handleNewLine(self):
291
+ if self.blankMarkers:
292
+ saved_buffer, saved_iterator = self.blankMarkers.pop()
293
+ self.queue.append(saved_buffer)
294
+ self.iterator = saved_iterator
295
+ else:
296
+ self.queue.append(self.buffer)
297
+ self.iterator -= 1
298
+ self.cutBufferCommon()
299
+
300
+ def justifyString(self, buffer):
301
+ if self.justify == 'right':
302
+ for row in range(self.font.height):
303
+ buffer[row] = (' ' * (self.width - len(buffer[row]) - 1)) + buffer[row]
304
+ elif self.justify == 'center':
305
+ for row in range(self.font.height):
306
+ buffer[row] = (' ' * int((self.width - len(buffer[row])) / 2)) + buffer[row]
307
+ return buffer
308
+
309
+ def replaceHardblanks(self, buffer):
310
+ return ('\n'.join(buffer) + '\n').replace(self.font.hardBlank, ' ')
311
+
312
+ def smushAmount(self, buffer, curChar):
313
+ if (self.font.smushMode & (SM_SMUSH | SM_KERN)) == 0:
314
+ return 0
315
+ maxSmush = self.curCharWidth
316
+ for row in range(self.font.height):
317
+ lineLeft = buffer[row]
318
+ lineRight = curChar[row]
319
+ if self.direction == 'right-to-left':
320
+ lineLeft, lineRight = lineRight, lineLeft
321
+ linebd = len(lineLeft.rstrip(' ')) - 1
322
+ if linebd < 0:
323
+ linebd = 0
324
+ if linebd < len(lineLeft):
325
+ ch1 = lineLeft[linebd]
326
+ else:
327
+ linebd = 0
328
+ ch1 = ''
329
+ charbd = len(lineRight) - len(lineRight.lstrip(' '))
330
+ if charbd < len(lineRight):
331
+ ch2 = lineRight[charbd]
332
+ else:
333
+ charbd = len(lineRight)
334
+ ch2 = ''
335
+ amt = charbd + len(lineLeft) - 1 - linebd
336
+ if ch1 == '' or ch1 == ' ':
337
+ amt += 1
338
+ elif ch2 != '' and self.smushChars(left=ch1, right=ch2) is not None:
339
+ amt += 1
340
+ if amt < maxSmush:
341
+ maxSmush = amt
342
+ return maxSmush
343
+
344
+ def smushChars(self, left='', right=''):
345
+ if left == ' ':
346
+ return right
347
+ if right == ' ':
348
+ return left
349
+ if (self.prevCharWidth < 2) or (self.curCharWidth < 2):
350
+ return
351
+ mode = self.font.smushMode
352
+ if (mode & SM_SMUSH) == 0:
353
+ return
354
+ if (mode & 63) == 0:
355
+ if left == self.font.hardBlank:
356
+ return right
357
+ if right == self.font.hardBlank:
358
+ return left
359
+ if self.direction == 'right-to-left':
360
+ return left
361
+ return right
362
+ if mode & SM_HARDBLANK:
363
+ if left == self.font.hardBlank and right == self.font.hardBlank:
364
+ return left
365
+ if left == self.font.hardBlank or right == self.font.hardBlank:
366
+ return
367
+ if mode & SM_EQUAL:
368
+ if left == right:
369
+ return left
370
+ smushes = ()
371
+ if mode & SM_LOWLINE:
372
+ smushes += (('_', r'|/\[]{}()<>'),)
373
+ if mode & SM_HIERARCHY:
374
+ smushes += (
375
+ ('|', r'/\[]{}()<>'),
376
+ (r'\/', '[]{}()<>'),
377
+ ('[]', '{}()<>'),
378
+ ('{}', '()<>'),
379
+ ('()', '<>'),
380
+ )
381
+ for a, b in smushes:
382
+ if left in a and right in b:
383
+ return right
384
+ if right in a and left in b:
385
+ return left
386
+ if mode & SM_PAIR:
387
+ for pair in [left + right, right + left]:
388
+ if pair in ['[]', '{}', '()']:
389
+ return '|'
390
+ if mode & SM_BIGX:
391
+ if left == '/' and right == '\\':
392
+ return '|'
393
+ if right == '/' and left == '\\':
394
+ return 'Y'
395
+ if left == '>' and right == '<':
396
+ return 'X'
397
+ return
398
+
399
+
400
+ class Figlet:
401
+ def __init__(self, font=DEFAULT_FONT, direction='auto', justify='auto', width=80):
402
+ self.font = font
403
+ self._direction = direction
404
+ self._justify = justify
405
+ self.width = width
406
+ self.Font = FigletFont(font)
407
+
408
+ @property
409
+ def direction(self):
410
+ if self._direction == 'auto':
411
+ if self.Font.printDirection == 1:
412
+ return 'right-to-left'
413
+ return 'left-to-right'
414
+ return self._direction
415
+
416
+ @property
417
+ def justify(self):
418
+ if self._justify == 'auto':
419
+ return 'left' if self.direction == 'left-to-right' else 'right'
420
+ return self._justify
421
+
422
+ def renderText(self, text):
423
+ return _Builder(text, self.Font, self.direction, self.width, self.justify).run()
424
+
425
+ def getFonts(self):
426
+ return available()
427
+
428
+
429
+ def figlet_format(text, font=DEFAULT_FONT, **kwargs):
430
+ return Figlet(font, **kwargs).renderText(text)
ttyengine/fonts.zip ADDED
Binary file