xulbux 1.6.5__py3-none-any.whl → 1.6.7__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/xx_console.py CHANGED
@@ -1,31 +1,18 @@
1
1
  """
2
- Functions for logging and other small actions within the console:
3
- - `Console.get_args()`
4
- - `Console.user()`
5
- - `Console.is_admin()`
6
- - `Console.pause_exit()`
7
- - `Console.cls()`
8
- - `Console.log()`
9
- - `Console.debug()`
10
- - `Console.info()`
11
- - `Console.done()`
12
- - `Console.warn()`
13
- - `Console.fail()`
14
- - `Console.exit()`
15
- - `Console.confirm()`
16
- - `Console.restricted_input()`
17
- - `Console.pwd_input()`\n
18
- ------------------------------------------------------------------------------------------------------
2
+ Functions for logging and other small actions within the console.\n
3
+ ----------------------------------------------------------------------------------------------------------
19
4
  You can also use special formatting codes directly inside the log message to change their appearance.
20
- For more detailed information about formatting codes, see the the `xx_format_codes` description.
5
+ For more detailed information about formatting codes, see the the `xx_format_codes` module documentation.
21
6
  """
22
7
 
23
- from ._consts_ import DEFAULT, CHARS
24
- from .xx_format_codes import FormatCodes
8
+ from ._consts_ import COLOR, CHARS
9
+ from .xx_format_codes import FormatCodes, _COMPILED
25
10
  from .xx_string import String
26
- from .xx_color import *
11
+ from .xx_color import Color, rgba, hexa
27
12
 
28
- from contextlib import suppress
13
+ from prompt_toolkit.key_binding.key_bindings import KeyBindings
14
+ from typing import Optional
15
+ import prompt_toolkit as _prompt_toolkit
29
16
  import pyperclip as _pyperclip
30
17
  import keyboard as _keyboard
31
18
  import getpass as _getpass
@@ -35,10 +22,81 @@ import sys as _sys
35
22
  import os as _os
36
23
 
37
24
 
25
+ # YAPF: disable
26
+ class _ConsoleWidth:
27
+ def __get__(self, obj, owner=None):
28
+ return _os.get_terminal_size().columns
29
+
30
+ class _ConsoleHeight:
31
+ def __get__(self, obj, owner=None):
32
+ return _os.get_terminal_size().lines
33
+
34
+ class _ConsoleSize:
35
+ def __get__(self, obj, owner=None):
36
+ size = _os.get_terminal_size()
37
+ return (size.columns, size.lines)
38
+
39
+ class _ConsoleUser:
40
+ def __get__(self, obj, owner=None):
41
+ return _os.getenv("USER") or _os.getenv("USERNAME") or _getpass.getuser()
42
+
43
+ class ArgResult:
44
+ """Exists: if the argument was found or not\n
45
+ Value: the value from behind the found argument"""
46
+ def __init__(self, exists: bool, value: any):
47
+ self.exists = exists
48
+ self.value = value
49
+
50
+ class Args:
51
+ """Stores arguments under their aliases with their results."""
52
+ def __init__(self, **kwargs):
53
+ for key, value in kwargs.items():
54
+ if not key.isidentifier():
55
+ raise TypeError(f"Argument alias '{key}' is invalid. It must be a valid Python variable name.")
56
+ setattr(self, key, ArgResult(**value))
57
+ # YAPF: enable
58
+
59
+
38
60
  class Console:
39
61
 
62
+ w: int = _ConsoleWidth()
63
+ """The width of the console in characters."""
64
+ h: int = _ConsoleHeight()
65
+ """The height of the console in lines."""
66
+ wh: tuple[int, int] = _ConsoleSize()
67
+ """A tuple with the width and height of
68
+ the console in characters and lines."""
69
+ usr: str = _ConsoleUser()
70
+ """The name of the current user."""
71
+
40
72
  @staticmethod
41
- def get_args(find_args: dict) -> dict[str, dict[str, any]]:
73
+ def get_args(find_args: dict[str, list[str] | tuple[str, ...]]) -> Args:
74
+ """Will search for the specified arguments in the command line
75
+ arguments and return the results as a special `Args` object.\n
76
+ ----------------------------------------------------------------
77
+ The `find_args` dictionary should have the following structure:
78
+ ```python
79
+ find_args={
80
+ "arg1_alias": ["-a1", "--arg1", "--argument-1"],
81
+ "arg2_alias": ("-a2", "--arg2", "--argument-2"),
82
+ ...
83
+ }
84
+ ```
85
+ And if the script is called via the command line:\n
86
+ `python script.py -a1 "argument value" --arg2`\n
87
+ ...it would return the following `Args` object:
88
+ ```python
89
+ Args(
90
+ arg1_alias=ArgResult(exists=True, value="argument value"),
91
+ arg2_alias=ArgResult(exists=True, value=None),
92
+ ...
93
+ )
94
+ ```
95
+ ...which can be accessed like this:\n
96
+ - `Args.<arg_alias>.exists` is `True` if any of the specified
97
+ args were found and `False` if not
98
+ - `Args.<arg_alias>.value` the value from behind the found arg,
99
+ `None` if no value was found"""
42
100
  args = _sys.argv[1:]
43
101
  results = {}
44
102
  for arg_key, arg_group in find_args.items():
@@ -52,19 +110,7 @@ class Console:
52
110
  value = String.to_type(args[arg_index + 1])
53
111
  break
54
112
  results[arg_key] = {"exists": exists, "value": value}
55
- return results
56
-
57
- def w() -> int:
58
- return getattr(_shutil.get_terminal_size(), "columns", 80)
59
-
60
- def h() -> int:
61
- return getattr(_shutil.get_terminal_size(), "lines", 24)
62
-
63
- def wh() -> tuple[int, int]:
64
- return Console.w(), Console.h()
65
-
66
- def user() -> str:
67
- return _os.getenv("USER") or _os.getenv("USERNAME") or _getpass.getuser()
113
+ return Args(**results)
68
114
 
69
115
  @staticmethod
70
116
  def pause_exit(
@@ -84,6 +130,7 @@ class Console:
84
130
  if exit:
85
131
  _sys.exit(exit_code)
86
132
 
133
+ @staticmethod
87
134
  def cls() -> None:
88
135
  """Will clear the console in addition to completely resetting the ANSI formats."""
89
136
  if _shutil.which("cls"):
@@ -94,33 +141,46 @@ class Console:
94
141
 
95
142
  @staticmethod
96
143
  def log(
97
- title: str,
144
+ title: Optional[str] = None,
98
145
  prompt: object = "",
146
+ format_linebreaks: bool = True,
99
147
  start: str = "",
100
148
  end: str = "\n",
101
149
  title_bg_color: hexa | rgba = None,
102
150
  default_color: hexa | rgba = None,
151
+ _console_tabsize: int = 8,
103
152
  ) -> None:
104
153
  """Will print a formatted log message:
105
154
  - `title` -⠀the title of the log message (e.g. `DEBUG`, `WARN`, `FAIL`, etc.)
106
155
  - `prompt` -⠀the log message
156
+ - `format_linebreaks` -⠀whether to format (indent after) the line breaks or not
107
157
  - `start` -⠀something to print before the log is printed
108
158
  - `end` -⠀something to print after the log is printed (e.g. `\\n`)
109
159
  - `title_bg_color` -⠀the background color of the `title`
110
- - `default_color` -⠀the default text color of the `prompt`\n
111
- --------------------------------------------------------------------------------
112
- The log message supports special formatting codes. For more detailed
113
- information about formatting codes, see `xx_format_codes` class description."""
160
+ - `default_color` -⠀the default text color of the `prompt`
161
+ - `_console_tabsize` -⠀the tab size of the console (default is 8)\n
162
+ -----------------------------------------------------------------------------------
163
+ The log message can be formatted with special formatting codes. For more detailed
164
+ information about formatting codes, see `xx_format_codes` module documentation."""
165
+ title = "" if title is None else title.strip().upper()
166
+ title_len, tab_len = len(title) + 4, _console_tabsize - ((len(title) + 4) % _console_tabsize)
114
167
  title_color = "_color" if not title_bg_color else Color.text_color_for_on_bg(title_bg_color)
115
- if title:
168
+ if format_linebreaks:
169
+ prompt_lst = (String.split_count(l, Console.w - (title_len + tab_len)) for l in str(prompt).splitlines())
170
+ prompt_lst = (item for lst in prompt_lst for item in (lst if isinstance(lst, list) else [lst]))
171
+ prompt = f"\n{' ' * title_len}\t".join(prompt_lst)
172
+ else:
173
+ prompt = str(prompt)
174
+ if title == "":
116
175
  FormatCodes.print(
117
- f'{start} [bold][{title_color}]{f"[BG:{title_bg_color}]" if title_bg_color else ""} {title.upper()}: [_]\t{f"[{default_color}]" if default_color else ""}{str(prompt)}[_]',
176
+ f'{start} {f"[{default_color}]" if default_color else ""}{str(prompt)}[_]',
118
177
  default_color=default_color,
119
178
  end=end,
120
179
  )
121
180
  else:
122
181
  FormatCodes.print(
123
- f'{start} {f"[{default_color}]" if default_color else ""}{str(prompt)}[_]',
182
+ f'{start} [bold][{title_color}]{f"[BG:{title_bg_color}]" if title_bg_color else ""} {title} [_]'
183
+ + f'\t{f"[{default_color}]" if default_color else ""}{prompt}[_]',
124
184
  default_color=default_color,
125
185
  end=end,
126
186
  )
@@ -129,94 +189,101 @@ class Console:
129
189
  def debug(
130
190
  prompt: object = "Point in program reached.",
131
191
  active: bool = True,
192
+ format_linebreaks: bool = True,
132
193
  start: str = "",
133
194
  end: str = "\n",
134
- title_bg_color: hexa | rgba = DEFAULT.color["yellow"],
135
- default_color: hexa | rgba = DEFAULT.text_color,
195
+ title_bg_color: hexa | rgba = COLOR.yellow,
196
+ default_color: hexa | rgba = COLOR.text,
136
197
  pause: bool = False,
137
198
  exit: bool = False,
138
199
  ) -> None:
139
200
  """A preset for `log()`: `DEBUG` log message with the options to pause
140
- at the message and exit the program after the message was printed."""
201
+ at the message and exit the program after the message was printed.
202
+ If `active` is false, no debug message will be printed."""
141
203
  if active:
142
- Console.log("DEBUG", prompt, start, end, title_bg_color, default_color)
204
+ Console.log("DEBUG", prompt, format_linebreaks, start, end, title_bg_color, default_color)
143
205
  Console.pause_exit(pause, exit)
144
206
 
145
207
  @staticmethod
146
208
  def info(
147
209
  prompt: object = "Program running.",
210
+ format_linebreaks: bool = True,
148
211
  start: str = "",
149
212
  end: str = "\n",
150
- title_bg_color: hexa | rgba = DEFAULT.color["blue"],
151
- default_color: hexa | rgba = DEFAULT.text_color,
213
+ title_bg_color: hexa | rgba = COLOR.blue,
214
+ default_color: hexa | rgba = COLOR.text,
152
215
  pause: bool = False,
153
216
  exit: bool = False,
154
217
  ) -> None:
155
218
  """A preset for `log()`: `INFO` log message with the options to pause
156
219
  at the message and exit the program after the message was printed."""
157
- Console.log("INFO", prompt, start, end, title_bg_color, default_color)
220
+ Console.log("INFO", prompt, format_linebreaks, start, end, title_bg_color, default_color)
158
221
  Console.pause_exit(pause, exit)
159
222
 
160
223
  @staticmethod
161
224
  def done(
162
225
  prompt: object = "Program finished.",
226
+ format_linebreaks: bool = True,
163
227
  start: str = "",
164
228
  end: str = "\n",
165
- title_bg_color: hexa | rgba = DEFAULT.color["teal"],
166
- default_color: hexa | rgba = DEFAULT.text_color,
229
+ title_bg_color: hexa | rgba = COLOR.teal,
230
+ default_color: hexa | rgba = COLOR.text,
167
231
  pause: bool = False,
168
232
  exit: bool = False,
169
233
  ) -> None:
170
234
  """A preset for `log()`: `DONE` log message with the options to pause
171
235
  at the message and exit the program after the message was printed."""
172
- Console.log("DONE", prompt, start, end, title_bg_color, default_color)
236
+ Console.log("DONE", prompt, format_linebreaks, start, end, title_bg_color, default_color)
173
237
  Console.pause_exit(pause, exit)
174
238
 
175
239
  @staticmethod
176
240
  def warn(
177
241
  prompt: object = "Important message.",
242
+ format_linebreaks: bool = True,
178
243
  start: str = "",
179
244
  end: str = "\n",
180
- title_bg_color: hexa | rgba = DEFAULT.color["orange"],
181
- default_color: hexa | rgba = DEFAULT.text_color,
245
+ title_bg_color: hexa | rgba = COLOR.orange,
246
+ default_color: hexa | rgba = COLOR.text,
182
247
  pause: bool = False,
183
248
  exit: bool = False,
184
249
  ) -> None:
185
250
  """A preset for `log()`: `WARN` log message with the options to pause
186
251
  at the message and exit the program after the message was printed."""
187
- Console.log("WARN", prompt, start, end, title_bg_color, default_color)
252
+ Console.log("WARN", prompt, format_linebreaks, start, end, title_bg_color, default_color)
188
253
  Console.pause_exit(pause, exit)
189
254
 
190
255
  @staticmethod
191
256
  def fail(
192
257
  prompt: object = "Program error.",
258
+ format_linebreaks: bool = True,
193
259
  start: str = "",
194
260
  end: str = "\n",
195
- title_bg_color: hexa | rgba = DEFAULT.color["red"],
196
- default_color: hexa | rgba = DEFAULT.text_color,
261
+ title_bg_color: hexa | rgba = COLOR.red,
262
+ default_color: hexa | rgba = COLOR.text,
197
263
  pause: bool = False,
198
264
  exit: bool = True,
199
265
  reset_ansi=True,
200
266
  ) -> None:
201
267
  """A preset for `log()`: `FAIL` log message with the options to pause
202
268
  at the message and exit the program after the message was printed."""
203
- Console.log("FAIL", prompt, start, end, title_bg_color, default_color)
269
+ Console.log("FAIL", prompt, format_linebreaks, start, end, title_bg_color, default_color)
204
270
  Console.pause_exit(pause, exit, reset_ansi=reset_ansi)
205
271
 
206
272
  @staticmethod
207
273
  def exit(
208
274
  prompt: object = "Program ended.",
275
+ format_linebreaks: bool = True,
209
276
  start: str = "",
210
277
  end: str = "\n",
211
- title_bg_color: hexa | rgba = DEFAULT.color["magenta"],
212
- default_color: hexa | rgba = DEFAULT.text_color,
278
+ title_bg_color: hexa | rgba = COLOR.magenta,
279
+ default_color: hexa | rgba = COLOR.text,
213
280
  pause: bool = False,
214
281
  exit: bool = True,
215
282
  reset_ansi=True,
216
283
  ) -> None:
217
284
  """A preset for `log()`: `EXIT` log message with the options to pause
218
285
  at the message and exit the program after the message was printed."""
219
- Console.log("EXIT", prompt, start, end, title_bg_color, default_color)
286
+ Console.log("EXIT", prompt, format_linebreaks, start, end, title_bg_color, default_color)
220
287
  Console.pause_exit(pause, exit, reset_ansi=reset_ansi)
221
288
 
222
289
  @staticmethod
@@ -226,28 +293,33 @@ class Console:
226
293
  end: str = "\n",
227
294
  box_bg_color: str | hexa | rgba = "green",
228
295
  default_color: hexa | rgba = "#000",
229
- _padding: int = 2,
296
+ w_padding: int = 2,
297
+ w_full: bool = False,
230
298
  ) -> None:
231
299
  """Will print a box, containing a formatted log message:
232
300
  - `*values` -⠀the box content (each value is on a new line)
233
301
  - `start` -⠀something to print before the log box is printed
234
302
  - `end` -⠀something to print after the log box is printed (e.g. `\\n`)
235
- - `box_bg_color` -⠀the box's background color
236
- - `default_color` -⠀the default text color of the `*values`\n
237
- --------------------------------------------------------------------------------
238
- The log message supports special formatting codes. For more detailed
239
- information about formatting codes, see `xx_format_codes` class description."""
240
- lines = [line for val in values for line in val.splitlines()]
303
+ - `box_bg_color` -⠀the background color of the box
304
+ - `default_color` -⠀the default text color of the `*values`
305
+ - `w_padding` -⠀the horizontal padding (in chars) to the box content
306
+ - `w_full` -⠀whether to make the box be the full console width or not\n
307
+ -----------------------------------------------------------------------------------
308
+ The box content can be formatted with special formatting codes. For more detailed
309
+ information about formatting codes, see `xx_format_codes` module documentation."""
310
+ lines = [line.strip() for val in values for line in val.splitlines()]
241
311
  unfmt_lines = [FormatCodes.remove_formatting(line) for line in lines]
242
312
  max_line_len = max(len(line) for line in unfmt_lines)
313
+ pad_w_full = (Console.w - (max_line_len + (2 * w_padding))) if w_full else 0
243
314
  lines = [
244
- f"[bg:{box_bg_color}]{' ' * _padding}{line}{' ' * (_padding + max_line_len - len(unfmt))}[_bg]"
245
- for line, unfmt in zip(lines, unfmt_lines)
315
+ f"[bg:{box_bg_color}]{' ' * w_padding}{line}" + " " *
316
+ ((w_padding + max_line_len - len(unfmt)) + pad_w_full) + "[_bg]" for line, unfmt in zip(lines, unfmt_lines)
246
317
  ]
318
+ pady = " " * (Console.w if w_full else max_line_len + (2 * w_padding))
247
319
  FormatCodes.print(
248
- f"{start}[bg:{box_bg_color}]{(pad := " " * (max_line_len + (2 * _padding)))}[_bg]\n"
249
- + "\n".join(lines)
250
- + f"\n[bg:{box_bg_color}]{pad}[_]",
320
+ f"{start}[bg:{box_bg_color}]{pady}[_bg]\n"
321
+ + _COMPILED["formatting"].sub(lambda m: f"{m.group(0)}[bg:{box_bg_color}]", "\n".join(lines))
322
+ + f"\n[bg:{box_bg_color}]{pady}[_bg]",
251
323
  default_color=default_color,
252
324
  sep="\n",
253
325
  end=end,
@@ -258,13 +330,13 @@ class Console:
258
330
  prompt: object = "Do you want to continue?",
259
331
  start="",
260
332
  end="\n",
261
- default_color: hexa | rgba = DEFAULT.color["cyan"],
333
+ default_color: hexa | rgba = COLOR.cyan,
262
334
  default_is_yes: bool = True,
263
335
  ) -> bool:
264
336
  """Ask a yes/no question.\n
265
- -------------------------------------------------------------------------------
266
- The question can be formatted with special formatting codes. For more detailed
267
- information about formatting codes, see the `xx_format_codes` description."""
337
+ ---------------------------------------------------------------------------------------
338
+ The prompt can be formatted with special formatting codes. For more detailed
339
+ information about formatting codes, see the `xx_format_codes` module documentation."""
268
340
  confirmed = input(
269
341
  FormatCodes.to_ansi(
270
342
  f'{start} {str(prompt)} [_|dim](({"Y" if default_is_yes else "y"}/{"n" if default_is_yes else "N"}): )',
@@ -275,26 +347,61 @@ class Console:
275
347
  Console.log("", end, end="")
276
348
  return confirmed
277
349
 
350
+ @staticmethod
351
+ def multiline_input(
352
+ prompt: object = "",
353
+ start="",
354
+ end="\n",
355
+ default_color: hexa | rgba = COLOR.cyan,
356
+ show_keybindings=True,
357
+ input_prefix=" ⤷ ",
358
+ reset_ansi=True,
359
+ ) -> str:
360
+ """An input where users can input (and paste) text over multiple lines.\n
361
+ -----------------------------------------------------------------------------------
362
+ - `prompt` -⠀the input prompt
363
+ - `start` -⠀something to print before the input
364
+ - `end` -⠀something to print after the input (e.g. `\\n`)
365
+ - `default_color` -⠀the default text color of the `prompt`
366
+ - `show_keybindings` -⠀whether to show the special keybindings or not
367
+ - `input_prefix` -⠀the prefix of the input line
368
+ - `reset_ansi` -⠀whether to reset the ANSI codes after the input or not
369
+ -----------------------------------------------------------------------------------
370
+ The input prompt can be formatted with special formatting codes. For more detailed
371
+ information about formatting codes, see `xx_format_codes` module documentation."""
372
+ kb = KeyBindings()
373
+
374
+ @kb.add("c-d", eager=True) # CTRL+D
375
+ def _(event):
376
+ event.app.exit(result=event.app.current_buffer.document.text)
377
+
378
+ FormatCodes.print(start + prompt, default_color=default_color)
379
+ if show_keybindings:
380
+ FormatCodes.print("[dim][[b](CTRL+D)[dim] : end of input][_dim]")
381
+ input_string = _prompt_toolkit.prompt(input_prefix, multiline=True, wrap_lines=True, key_bindings=kb)
382
+ FormatCodes.print("[_]" if reset_ansi else "", end=end[1:] if end.startswith("\n") else end)
383
+ return input_string
384
+
278
385
  @staticmethod
279
386
  def restricted_input(
280
387
  prompt: object = "",
281
388
  start="",
282
389
  end="\n",
283
- default_color: hexa | rgba = DEFAULT.color["cyan"],
390
+ default_color: hexa | rgba = COLOR.cyan,
284
391
  allowed_chars: str = CHARS.all,
285
392
  min_len: int = None,
286
393
  max_len: int = None,
287
394
  mask_char: str = None,
288
395
  reset_ansi: bool = True,
289
- ) -> str | None:
396
+ ) -> Optional[str]:
290
397
  """Acts like a standard Python `input()` with the advantage, that you can specify:
291
398
  - what text characters the user is allowed to type and
292
399
  - the minimum and/or maximum length of the users input
293
400
  - optional mask character (hide user input, e.g. for passwords)
294
401
  - reset the ANSI formatting codes after the user continues\n
295
- -----------------------------------------------------------------------------------
402
+ ---------------------------------------------------------------------------------------
296
403
  The input can be formatted with special formatting codes. For more detailed
297
- information about formatting codes, see the `xx_format_codes` description."""
404
+ information about formatting codes, see the `xx_format_codes` module documentation."""
298
405
  FormatCodes.print(start + prompt, default_color=default_color, end="")
299
406
  result = ""
300
407
  select_all = False
@@ -303,22 +410,17 @@ class Console:
303
410
 
304
411
  def update_display(console_width: int) -> None:
305
412
  nonlocal select_all, last_line_count, last_console_width
306
- lines = String.split_count(
307
- str(prompt) + (mask_char * len(result) if mask_char else result),
308
- console_width,
309
- )
413
+ lines = String.split_count(str(prompt) + (mask_char * len(result) if mask_char else result), console_width)
310
414
  line_count = len(lines)
311
415
  if (line_count > 1 or line_count < last_line_count) and not last_line_count == 1:
312
416
  if last_console_width > console_width:
313
417
  line_count *= 2
314
- for _ in range(
315
- line_count
316
- if line_count < last_line_count and not line_count > last_line_count
317
- else (line_count - 2 if line_count > last_line_count else line_count - 1)
318
- ):
418
+ for _ in range(line_count if line_count < last_line_count and not line_count > last_line_count else (
419
+ line_count - 2 if line_count > last_line_count else line_count - 1)):
319
420
  _sys.stdout.write("\033[2K\r\033[A")
320
421
  prompt_len = len(str(prompt)) if prompt else 0
321
- prompt_str, input_str = lines[0][:prompt_len], (
422
+ prompt_str = lines[0][:prompt_len]
423
+ input_str = (
322
424
  lines[0][prompt_len:] if len(lines) == 1 else "\n".join([lines[0][prompt_len:]] + lines[1:])
323
425
  ) # SEPARATE THE PROMPT AND THE INPUT
324
426
  _sys.stdout.write(
@@ -338,7 +440,7 @@ class Console:
338
440
  result, select_all = "", False
339
441
  elif result and event.name == "backspace":
340
442
  result = result[:-1]
341
- update_display(Console.w())
443
+ update_display(Console.w)
342
444
 
343
445
  def handle_paste():
344
446
  nonlocal result, select_all
@@ -347,25 +449,18 @@ class Console:
347
449
  filtered_text = "".join(char for char in _pyperclip.paste() if allowed_chars == CHARS.all or char in allowed_chars)
348
450
  if max_len is None or len(result) + len(filtered_text) <= max_len:
349
451
  result += filtered_text
350
- update_display(Console.w())
452
+ update_display(Console.w)
351
453
 
352
454
  def handle_select_all():
353
455
  nonlocal select_all
354
456
  select_all = True
355
- update_display(Console.w())
356
-
357
- def handle_copy():
358
- nonlocal select_all
359
- with suppress(KeyboardInterrupt):
360
- select_all = False
361
- update_display(Console.w())
362
- _pyperclip.copy(result)
457
+ update_display(Console.w)
363
458
 
364
459
  def handle_character_input():
365
460
  nonlocal result
366
461
  if (allowed_chars == CHARS.all or event.name in allowed_chars) and (max_len is None or len(result) < max_len):
367
462
  result += event.name
368
- update_display(Console.w())
463
+ update_display(Console.w)
369
464
 
370
465
  while True:
371
466
  event = _keyboard.read_event()
@@ -378,8 +473,8 @@ class Console:
378
473
  handle_paste()
379
474
  elif event.name == "a" and _keyboard.is_pressed("ctrl"):
380
475
  handle_select_all()
381
- elif event.name == "c" and _keyboard.is_pressed("ctrl") and select_all:
382
- handle_copy()
476
+ elif event.name == "c" and _keyboard.is_pressed("ctrl"):
477
+ raise KeyboardInterrupt
383
478
  elif event.name == "esc":
384
479
  return None
385
480
  elif event.name == "space":
@@ -388,19 +483,19 @@ class Console:
388
483
  handle_character_input()
389
484
  else:
390
485
  select_all = False
391
- update_display(Console.w())
486
+ update_display(Console.w)
392
487
 
393
488
  @staticmethod
394
489
  def pwd_input(
395
490
  prompt: object = "Password: ",
396
491
  start="",
397
492
  end="\n",
398
- default_color: hexa | rgba = DEFAULT.color["cyan"],
493
+ default_color: hexa | rgba = COLOR.cyan,
399
494
  allowed_chars: str = CHARS.standard_ascii,
400
495
  min_len: int = None,
401
496
  max_len: int = None,
402
- _reset_ansi: bool = True,
497
+ reset_ansi: bool = True,
403
498
  ) -> str:
404
499
  """Password input (preset for `Console.restricted_input()`)
405
500
  that always masks the entered characters with asterisks."""
406
- return Console.restricted_input(prompt, start, end, default_color, allowed_chars, min_len, max_len, "*", _reset_ansi)
501
+ return Console.restricted_input(prompt, start, end, default_color, allowed_chars, min_len, max_len, "*", reset_ansi)