xulbux 1.6.8__py3-none-any.whl → 1.7.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.
Potentially problematic release.
This version of xulbux might be problematic. Click here for more details.
- xulbux/__init__.py +3 -35
- xulbux/_cli_.py +21 -28
- xulbux/_consts_.py +1 -0
- xulbux/xx_code.py +62 -46
- xulbux/xx_color.py +223 -159
- xulbux/xx_console.py +152 -78
- xulbux/xx_data.py +79 -71
- xulbux/xx_env_path.py +6 -9
- xulbux/xx_file.py +22 -26
- xulbux/xx_format_codes.py +55 -33
- xulbux/xx_json.py +107 -51
- xulbux/xx_path.py +74 -24
- xulbux/xx_regex.py +11 -10
- xulbux/xx_string.py +4 -1
- xulbux/xx_system.py +6 -10
- {xulbux-1.6.8.dist-info → xulbux-1.7.0.dist-info}/METADATA +18 -39
- xulbux-1.7.0.dist-info/RECORD +21 -0
- {xulbux-1.6.8.dist-info → xulbux-1.7.0.dist-info}/WHEEL +1 -1
- xulbux-1.6.8.dist-info/RECORD +0 -21
- {xulbux-1.6.8.dist-info → xulbux-1.7.0.dist-info}/entry_points.txt +0 -0
- {xulbux-1.6.8.dist-info → xulbux-1.7.0.dist-info/licenses}/LICENSE +0 -0
- {xulbux-1.6.8.dist-info → xulbux-1.7.0.dist-info}/top_level.txt +0 -0
xulbux/xx_console.py
CHANGED
|
@@ -8,10 +8,10 @@ For more detailed information about formatting codes, see the the `xx_format_cod
|
|
|
8
8
|
from ._consts_ import COLOR, CHARS
|
|
9
9
|
from .xx_format_codes import FormatCodes, _COMPILED
|
|
10
10
|
from .xx_string import String
|
|
11
|
-
from .xx_color import Color,
|
|
11
|
+
from .xx_color import Color, Rgba, Hexa
|
|
12
12
|
|
|
13
13
|
from prompt_toolkit.key_binding.key_bindings import KeyBindings
|
|
14
|
-
from typing import Optional
|
|
14
|
+
from typing import Optional, Any
|
|
15
15
|
import prompt_toolkit as _prompt_toolkit
|
|
16
16
|
import pyperclip as _pyperclip
|
|
17
17
|
import keyboard as _keyboard
|
|
@@ -22,106 +22,142 @@ import sys as _sys
|
|
|
22
22
|
import os as _os
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
# YAPF: disable
|
|
26
25
|
class _ConsoleWidth:
|
|
26
|
+
|
|
27
27
|
def __get__(self, obj, owner=None):
|
|
28
28
|
return _os.get_terminal_size().columns
|
|
29
29
|
|
|
30
|
+
|
|
30
31
|
class _ConsoleHeight:
|
|
32
|
+
|
|
31
33
|
def __get__(self, obj, owner=None):
|
|
32
34
|
return _os.get_terminal_size().lines
|
|
33
35
|
|
|
36
|
+
|
|
34
37
|
class _ConsoleSize:
|
|
38
|
+
|
|
35
39
|
def __get__(self, obj, owner=None):
|
|
36
40
|
size = _os.get_terminal_size()
|
|
37
41
|
return (size.columns, size.lines)
|
|
38
42
|
|
|
43
|
+
|
|
39
44
|
class _ConsoleUser:
|
|
45
|
+
|
|
40
46
|
def __get__(self, obj, owner=None):
|
|
41
47
|
return _os.getenv("USER") or _os.getenv("USERNAME") or _getpass.getuser()
|
|
42
48
|
|
|
49
|
+
|
|
43
50
|
class ArgResult:
|
|
44
51
|
"""Exists: if the argument was found or not\n
|
|
45
52
|
Value: the value from behind the found argument"""
|
|
46
|
-
|
|
53
|
+
|
|
54
|
+
def __init__(self, exists: bool, value: Any):
|
|
47
55
|
self.exists = exists
|
|
48
56
|
self.value = value
|
|
57
|
+
|
|
49
58
|
def __bool__(self):
|
|
50
59
|
return self.exists
|
|
51
60
|
|
|
61
|
+
|
|
52
62
|
class Args:
|
|
53
63
|
"""Stores found command arguments under their aliases with their results."""
|
|
64
|
+
|
|
54
65
|
def __init__(self, **kwargs):
|
|
55
66
|
for key, value in kwargs.items():
|
|
56
67
|
if not key.isidentifier():
|
|
57
68
|
raise TypeError(f"Argument alias '{key}' is invalid. It must be a valid Python variable name.")
|
|
58
69
|
setattr(self, key, ArgResult(**value))
|
|
70
|
+
|
|
59
71
|
def __len__(self):
|
|
60
72
|
return len(vars(self))
|
|
73
|
+
|
|
61
74
|
def __contains__(self, key):
|
|
62
75
|
return hasattr(self, key)
|
|
76
|
+
|
|
63
77
|
def __getitem__(self, key):
|
|
64
78
|
if isinstance(key, int):
|
|
65
79
|
return list(self.__iter__())[key]
|
|
66
80
|
return getattr(self, key)
|
|
81
|
+
|
|
67
82
|
def __iter__(self):
|
|
68
83
|
for key, value in vars(self).items():
|
|
69
84
|
yield (key, {"exists": value.exists, "value": value.value})
|
|
70
|
-
|
|
85
|
+
|
|
86
|
+
def dict(self) -> dict[str, dict[str, Any]]:
|
|
71
87
|
"""Returns the arguments as a dictionary."""
|
|
72
88
|
return {k: {"exists": v.exists, "value": v.value} for k, v in vars(self).items()}
|
|
89
|
+
|
|
73
90
|
def keys(self):
|
|
74
91
|
"""Returns the argument aliases as `dict_keys([...])`."""
|
|
75
92
|
return vars(self).keys()
|
|
93
|
+
|
|
76
94
|
def values(self):
|
|
77
95
|
"""Returns the argument results as `dict_values([...])`."""
|
|
78
96
|
return vars(self).values()
|
|
97
|
+
|
|
79
98
|
def items(self):
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
"""Yields tuples of `(alias, {'exists': bool, 'value': Any})`."""
|
|
100
|
+
for key, value in self.__iter__():
|
|
101
|
+
yield (key, value)
|
|
83
102
|
|
|
84
103
|
|
|
85
104
|
class Console:
|
|
86
105
|
|
|
87
|
-
w: int = _ConsoleWidth()
|
|
106
|
+
w: int = _ConsoleWidth() # type: ignore[assignment]
|
|
88
107
|
"""The width of the console in characters."""
|
|
89
|
-
h: int = _ConsoleHeight()
|
|
108
|
+
h: int = _ConsoleHeight() # type: ignore[assignment]
|
|
90
109
|
"""The height of the console in lines."""
|
|
91
|
-
wh: tuple[int, int] = _ConsoleSize()
|
|
110
|
+
wh: tuple[int, int] = _ConsoleSize() # type: ignore[assignment]
|
|
92
111
|
"""A tuple with the width and height of
|
|
93
112
|
the console in characters and lines."""
|
|
94
|
-
usr: str = _ConsoleUser()
|
|
113
|
+
usr: str = _ConsoleUser() # type: ignore[assignment]
|
|
95
114
|
"""The name of the current user."""
|
|
96
115
|
|
|
97
116
|
@staticmethod
|
|
98
|
-
def get_args(
|
|
117
|
+
def get_args(
|
|
118
|
+
find_args: dict[str, list[str] | tuple[str, ...] | dict[str, list[str] | tuple[str, ...] | Any]],
|
|
119
|
+
allow_spaces: bool = False
|
|
120
|
+
) -> Args:
|
|
99
121
|
"""Will search for the specified arguments in the command line
|
|
100
122
|
arguments and return the results as a special `Args` object.\n
|
|
101
123
|
----------------------------------------------------------------
|
|
102
|
-
The `find_args` dictionary
|
|
124
|
+
The `find_args` dictionary can have the following structures for each alias:
|
|
125
|
+
1. Simple list/tuple of flags (when no default value is needed):
|
|
126
|
+
```python
|
|
127
|
+
"alias_name": ["-f", "--flag"]
|
|
128
|
+
```
|
|
129
|
+
2. Dictionary with 'flags' and optional 'default':
|
|
130
|
+
```python
|
|
131
|
+
"alias_name": {
|
|
132
|
+
"flags": ["-f", "--flag"],
|
|
133
|
+
"default": "some_value" # Optional
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
Example `find_args`:
|
|
103
137
|
```python
|
|
104
138
|
find_args={
|
|
105
|
-
"
|
|
106
|
-
|
|
107
|
-
|
|
139
|
+
"arg1": { # With default
|
|
140
|
+
"flags": ["-a1", "--arg1"],
|
|
141
|
+
"default": "default_val"
|
|
142
|
+
},
|
|
143
|
+
"arg2": ("-a2", "--arg2"), # Without default (original format)
|
|
144
|
+
"arg3": ["-a3"], # Without default (list format)
|
|
145
|
+
"arg4": { # Flag with default True
|
|
146
|
+
"flags": ["-f"],
|
|
147
|
+
"default": True
|
|
148
|
+
}
|
|
108
149
|
}
|
|
109
150
|
```
|
|
110
|
-
|
|
111
|
-
`python script.py -a1 "
|
|
112
|
-
...it would return
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
...which can be accessed like this:\n
|
|
121
|
-
- `Args.<arg_alias>.exists` is `True` if any of the specified
|
|
122
|
-
args were found and `False` if not
|
|
123
|
-
- `Args.<arg_alias>.value` the value from behind the found arg,
|
|
124
|
-
`None` if no value was found\n
|
|
151
|
+
If the script is called via the command line:\n
|
|
152
|
+
`python script.py -a1 "value1" --arg2 -f`\n
|
|
153
|
+
...it would return an `Args` object where:
|
|
154
|
+
- `args.arg1.exists` is `True`, `args.arg1.value` is `"value1"`
|
|
155
|
+
- `args.arg2.exists` is `True`, `args.arg2.value` is `True` (flag present without value)
|
|
156
|
+
- `args.arg3.exists` is `False`, `args.arg3.value` is `None` (not present, no default)
|
|
157
|
+
- `args.arg4.exists` is `True`, `args.arg4.value` is `True` (flag present, overrides default)
|
|
158
|
+
- If an arg defined in `find_args` is *not* present in the command line:
|
|
159
|
+
- `exists` will be `False`
|
|
160
|
+
- `value` will be the specified `default` value, or `None` if no default was specified.\n
|
|
125
161
|
----------------------------------------------------------------
|
|
126
162
|
Normally if `allow_spaces` is false, it will take a space as
|
|
127
163
|
the end of an args value. If it is true, it will take spaces as
|
|
@@ -130,20 +166,40 @@ class Console:
|
|
|
130
166
|
args = _sys.argv[1:]
|
|
131
167
|
args_len = len(args)
|
|
132
168
|
arg_lookup = {}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
169
|
+
results = {}
|
|
170
|
+
for alias, config in find_args.items():
|
|
171
|
+
flags = None
|
|
172
|
+
default_value = None
|
|
173
|
+
if isinstance(config, (list, tuple)):
|
|
174
|
+
flags = config
|
|
175
|
+
elif isinstance(config, dict):
|
|
176
|
+
if "flags" not in config:
|
|
177
|
+
raise ValueError(f"Invalid configuration for alias '{alias}'. Dictionary must contain a 'flags' key.")
|
|
178
|
+
flags = config["flags"]
|
|
179
|
+
default_value = config.get("default")
|
|
180
|
+
if not isinstance(flags, (list, tuple)):
|
|
181
|
+
raise ValueError(f"Invalid 'flags' for alias '{alias}'. Must be a list or tuple.")
|
|
182
|
+
else:
|
|
183
|
+
raise TypeError(f"Invalid configuration type for alias '{alias}'. Must be a list, tuple, or dict.")
|
|
184
|
+
results[alias] = {"exists": False, "value": default_value}
|
|
185
|
+
for flag in flags:
|
|
186
|
+
if flag in arg_lookup:
|
|
187
|
+
raise ValueError(
|
|
188
|
+
f"Duplicate flag '{flag}' found. It's assigned to both '{arg_lookup[flag]}' and '{alias}'."
|
|
189
|
+
)
|
|
190
|
+
arg_lookup[flag] = alias
|
|
137
191
|
i = 0
|
|
138
192
|
while i < args_len:
|
|
139
193
|
arg = args[i]
|
|
140
|
-
|
|
141
|
-
if
|
|
142
|
-
results[
|
|
194
|
+
alias = arg_lookup.get(arg)
|
|
195
|
+
if alias:
|
|
196
|
+
results[alias]["exists"] = True
|
|
197
|
+
value_found_after_flag = False
|
|
143
198
|
if i + 1 < args_len and not args[i + 1].startswith("-"):
|
|
144
199
|
if not allow_spaces:
|
|
145
|
-
results[
|
|
200
|
+
results[alias]["value"] = String.to_type(args[i + 1])
|
|
146
201
|
i += 1
|
|
202
|
+
value_found_after_flag = True
|
|
147
203
|
else:
|
|
148
204
|
value_parts = []
|
|
149
205
|
j = i + 1
|
|
@@ -151,8 +207,11 @@ class Console:
|
|
|
151
207
|
value_parts.append(args[j])
|
|
152
208
|
j += 1
|
|
153
209
|
if value_parts:
|
|
154
|
-
results[
|
|
210
|
+
results[alias]["value"] = String.to_type(" ".join(value_parts))
|
|
155
211
|
i = j - 1
|
|
212
|
+
value_found_after_flag = True
|
|
213
|
+
if not value_found_after_flag:
|
|
214
|
+
results[alias]["value"] = True
|
|
156
215
|
i += 1
|
|
157
216
|
return Args(**results)
|
|
158
217
|
|
|
@@ -190,8 +249,8 @@ class Console:
|
|
|
190
249
|
format_linebreaks: bool = True,
|
|
191
250
|
start: str = "",
|
|
192
251
|
end: str = "\n",
|
|
193
|
-
title_bg_color:
|
|
194
|
-
default_color:
|
|
252
|
+
title_bg_color: Optional[Rgba | Hexa] = None,
|
|
253
|
+
default_color: Optional[Rgba | Hexa] = None,
|
|
195
254
|
_console_tabsize: int = 8,
|
|
196
255
|
) -> None:
|
|
197
256
|
"""Will print a formatted log message:
|
|
@@ -210,10 +269,14 @@ class Console:
|
|
|
210
269
|
title_len, tab_len = len(title) + 4, _console_tabsize - ((len(title) + 4) % _console_tabsize)
|
|
211
270
|
title_color = "_color" if not title_bg_color else Color.text_color_for_on_bg(title_bg_color)
|
|
212
271
|
if format_linebreaks:
|
|
213
|
-
clean_prompt, removals = FormatCodes.remove_formatting(str(prompt), get_removals=True)
|
|
272
|
+
clean_prompt, removals = FormatCodes.remove_formatting(str(prompt), get_removals=True, _ignore_linebreaks=True)
|
|
214
273
|
prompt_lst = (String.split_count(l, Console.w - (title_len + tab_len)) for l in str(clean_prompt).splitlines())
|
|
215
|
-
prompt_lst = (
|
|
216
|
-
|
|
274
|
+
prompt_lst = (
|
|
275
|
+
item for lst in prompt_lst for item in ([""] if lst == [] else (lst if isinstance(lst, list) else [lst]))
|
|
276
|
+
)
|
|
277
|
+
prompt = f"\n{' ' * title_len}\t".join(
|
|
278
|
+
Console.__add_back_removed_parts(list(prompt_lst), removals) # type: ignore[assignment]
|
|
279
|
+
)
|
|
217
280
|
else:
|
|
218
281
|
prompt = str(prompt)
|
|
219
282
|
if title == "":
|
|
@@ -269,8 +332,8 @@ class Console:
|
|
|
269
332
|
format_linebreaks: bool = True,
|
|
270
333
|
start: str = "",
|
|
271
334
|
end: str = "\n",
|
|
272
|
-
title_bg_color:
|
|
273
|
-
default_color:
|
|
335
|
+
title_bg_color: Rgba | Hexa = COLOR.yellow,
|
|
336
|
+
default_color: Rgba | Hexa = COLOR.text,
|
|
274
337
|
pause: bool = False,
|
|
275
338
|
exit: bool = False,
|
|
276
339
|
) -> None:
|
|
@@ -287,8 +350,8 @@ class Console:
|
|
|
287
350
|
format_linebreaks: bool = True,
|
|
288
351
|
start: str = "",
|
|
289
352
|
end: str = "\n",
|
|
290
|
-
title_bg_color:
|
|
291
|
-
default_color:
|
|
353
|
+
title_bg_color: Rgba | Hexa = COLOR.blue,
|
|
354
|
+
default_color: Rgba | Hexa = COLOR.text,
|
|
292
355
|
pause: bool = False,
|
|
293
356
|
exit: bool = False,
|
|
294
357
|
) -> None:
|
|
@@ -303,8 +366,8 @@ class Console:
|
|
|
303
366
|
format_linebreaks: bool = True,
|
|
304
367
|
start: str = "",
|
|
305
368
|
end: str = "\n",
|
|
306
|
-
title_bg_color:
|
|
307
|
-
default_color:
|
|
369
|
+
title_bg_color: Rgba | Hexa = COLOR.teal,
|
|
370
|
+
default_color: Rgba | Hexa = COLOR.text,
|
|
308
371
|
pause: bool = False,
|
|
309
372
|
exit: bool = False,
|
|
310
373
|
) -> None:
|
|
@@ -319,8 +382,8 @@ class Console:
|
|
|
319
382
|
format_linebreaks: bool = True,
|
|
320
383
|
start: str = "",
|
|
321
384
|
end: str = "\n",
|
|
322
|
-
title_bg_color:
|
|
323
|
-
default_color:
|
|
385
|
+
title_bg_color: Rgba | Hexa = COLOR.orange,
|
|
386
|
+
default_color: Rgba | Hexa = COLOR.text,
|
|
324
387
|
pause: bool = False,
|
|
325
388
|
exit: bool = False,
|
|
326
389
|
) -> None:
|
|
@@ -335,8 +398,8 @@ class Console:
|
|
|
335
398
|
format_linebreaks: bool = True,
|
|
336
399
|
start: str = "",
|
|
337
400
|
end: str = "\n",
|
|
338
|
-
title_bg_color:
|
|
339
|
-
default_color:
|
|
401
|
+
title_bg_color: Rgba | Hexa = COLOR.red,
|
|
402
|
+
default_color: Rgba | Hexa = COLOR.text,
|
|
340
403
|
pause: bool = False,
|
|
341
404
|
exit: bool = True,
|
|
342
405
|
reset_ansi=True,
|
|
@@ -352,8 +415,8 @@ class Console:
|
|
|
352
415
|
format_linebreaks: bool = True,
|
|
353
416
|
start: str = "",
|
|
354
417
|
end: str = "\n",
|
|
355
|
-
title_bg_color:
|
|
356
|
-
default_color:
|
|
418
|
+
title_bg_color: Rgba | Hexa = COLOR.magenta,
|
|
419
|
+
default_color: Rgba | Hexa = COLOR.text,
|
|
357
420
|
pause: bool = False,
|
|
358
421
|
exit: bool = True,
|
|
359
422
|
reset_ansi=True,
|
|
@@ -368,8 +431,8 @@ class Console:
|
|
|
368
431
|
*values: object,
|
|
369
432
|
start: str = "",
|
|
370
433
|
end: str = "\n",
|
|
371
|
-
box_bg_color: str |
|
|
372
|
-
default_color:
|
|
434
|
+
box_bg_color: str | Rgba | Hexa = "green",
|
|
435
|
+
default_color: Rgba | Hexa = "#000",
|
|
373
436
|
w_padding: int = 2,
|
|
374
437
|
w_full: bool = False,
|
|
375
438
|
) -> None:
|
|
@@ -384,7 +447,7 @@ class Console:
|
|
|
384
447
|
-----------------------------------------------------------------------------------
|
|
385
448
|
The box content can be formatted with special formatting codes. For more detailed
|
|
386
449
|
information about formatting codes, see `xx_format_codes` module documentation."""
|
|
387
|
-
lines = [line.
|
|
450
|
+
lines = [line.rstrip() for val in values for line in str(val).splitlines()]
|
|
388
451
|
unfmt_lines = [FormatCodes.remove_formatting(line) for line in lines]
|
|
389
452
|
max_line_len = max(len(line) for line in unfmt_lines)
|
|
390
453
|
pad_w_full = (Console.w - (max_line_len + (2 * w_padding))) if w_full else 0
|
|
@@ -407,7 +470,7 @@ class Console:
|
|
|
407
470
|
prompt: object = "Do you want to continue?",
|
|
408
471
|
start="",
|
|
409
472
|
end="\n",
|
|
410
|
-
default_color:
|
|
473
|
+
default_color: Rgba | Hexa = COLOR.cyan,
|
|
411
474
|
default_is_yes: bool = True,
|
|
412
475
|
) -> bool:
|
|
413
476
|
"""Ask a yes/no question.\n
|
|
@@ -429,7 +492,7 @@ class Console:
|
|
|
429
492
|
prompt: object = "",
|
|
430
493
|
start="",
|
|
431
494
|
end="\n",
|
|
432
|
-
default_color:
|
|
495
|
+
default_color: Rgba | Hexa = COLOR.cyan,
|
|
433
496
|
show_keybindings=True,
|
|
434
497
|
input_prefix=" ⤷ ",
|
|
435
498
|
reset_ansi=True,
|
|
@@ -452,7 +515,7 @@ class Console:
|
|
|
452
515
|
def _(event):
|
|
453
516
|
event.app.exit(result=event.app.current_buffer.document.text)
|
|
454
517
|
|
|
455
|
-
FormatCodes.print(start + prompt, default_color=default_color)
|
|
518
|
+
FormatCodes.print(start + str(prompt), default_color=default_color)
|
|
456
519
|
if show_keybindings:
|
|
457
520
|
FormatCodes.print("[dim][[b](CTRL+D)[dim] : end of input][_dim]")
|
|
458
521
|
input_string = _prompt_toolkit.prompt(input_prefix, multiline=True, wrap_lines=True, key_bindings=kb)
|
|
@@ -464,11 +527,11 @@ class Console:
|
|
|
464
527
|
prompt: object = "",
|
|
465
528
|
start="",
|
|
466
529
|
end="\n",
|
|
467
|
-
default_color:
|
|
468
|
-
allowed_chars: str = CHARS.all,
|
|
469
|
-
min_len: int = None,
|
|
470
|
-
max_len: int = None,
|
|
471
|
-
mask_char: str = None,
|
|
530
|
+
default_color: Rgba | Hexa = COLOR.cyan,
|
|
531
|
+
allowed_chars: str = CHARS.all, # type: ignore[assignment]
|
|
532
|
+
min_len: Optional[int] = None,
|
|
533
|
+
max_len: Optional[int] = None,
|
|
534
|
+
mask_char: Optional[str] = None,
|
|
472
535
|
reset_ansi: bool = True,
|
|
473
536
|
) -> Optional[str]:
|
|
474
537
|
"""Acts like a standard Python `input()` with the advantage, that you can specify:
|
|
@@ -479,14 +542,14 @@ class Console:
|
|
|
479
542
|
---------------------------------------------------------------------------------------
|
|
480
543
|
The input can be formatted with special formatting codes. For more detailed
|
|
481
544
|
information about formatting codes, see the `xx_format_codes` module documentation."""
|
|
482
|
-
FormatCodes.print(start + prompt, default_color=default_color, end="")
|
|
545
|
+
FormatCodes.print(start + str(prompt), default_color=default_color, end="")
|
|
483
546
|
result = ""
|
|
484
547
|
select_all = False
|
|
485
548
|
last_line_count = 1
|
|
486
549
|
last_console_width = 0
|
|
487
550
|
|
|
488
551
|
def update_display(console_width: int) -> None:
|
|
489
|
-
nonlocal
|
|
552
|
+
nonlocal last_line_count, last_console_width
|
|
490
553
|
lines = String.split_count(str(prompt) + (mask_char * len(result) if mask_char else result), console_width)
|
|
491
554
|
line_count = len(lines)
|
|
492
555
|
if (line_count > 1 or line_count < last_line_count) and not last_line_count == 1:
|
|
@@ -535,7 +598,8 @@ class Console:
|
|
|
535
598
|
|
|
536
599
|
def handle_character_input():
|
|
537
600
|
nonlocal result
|
|
538
|
-
if (allowed_chars == CHARS.all or event.name in allowed_chars) and
|
|
601
|
+
if event.name is not None and ((allowed_chars == CHARS.all or event.name in allowed_chars) and
|
|
602
|
+
(max_len is None or len(result) < max_len)):
|
|
539
603
|
result += event.name
|
|
540
604
|
update_display(Console.w)
|
|
541
605
|
|
|
@@ -556,7 +620,7 @@ class Console:
|
|
|
556
620
|
return None
|
|
557
621
|
elif event.name == "space":
|
|
558
622
|
handle_character_input()
|
|
559
|
-
elif len(event.name) == 1:
|
|
623
|
+
elif event.name is not None and len(event.name) == 1:
|
|
560
624
|
handle_character_input()
|
|
561
625
|
else:
|
|
562
626
|
select_all = False
|
|
@@ -567,12 +631,22 @@ class Console:
|
|
|
567
631
|
prompt: object = "Password: ",
|
|
568
632
|
start="",
|
|
569
633
|
end="\n",
|
|
570
|
-
default_color:
|
|
634
|
+
default_color: Rgba | Hexa = COLOR.cyan,
|
|
571
635
|
allowed_chars: str = CHARS.standard_ascii,
|
|
572
|
-
min_len: int = None,
|
|
573
|
-
max_len: int = None,
|
|
636
|
+
min_len: Optional[int] = None,
|
|
637
|
+
max_len: Optional[int] = None,
|
|
574
638
|
reset_ansi: bool = True,
|
|
575
|
-
) -> str:
|
|
639
|
+
) -> Optional[str]:
|
|
576
640
|
"""Password input (preset for `Console.restricted_input()`)
|
|
577
641
|
that always masks the entered characters with asterisks."""
|
|
578
|
-
return Console.restricted_input(
|
|
642
|
+
return Console.restricted_input(
|
|
643
|
+
prompt=prompt,
|
|
644
|
+
start=start,
|
|
645
|
+
end=end,
|
|
646
|
+
default_color=default_color,
|
|
647
|
+
allowed_chars=allowed_chars,
|
|
648
|
+
min_len=min_len,
|
|
649
|
+
max_len=max_len,
|
|
650
|
+
mask_char="*",
|
|
651
|
+
reset_ansi=reset_ansi,
|
|
652
|
+
)
|