hspylib-clitt 0.9.32__py3-none-any.whl → 0.9.34__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 hspylib-clitt might be problematic. Click here for more details.

@@ -24,69 +24,62 @@ class InputValidator(Validator):
24
24
 
25
25
  class PatternType(Enumeration):
26
26
  # fmt: off
27
- CUSTOM = r'.*' # It will be set later
28
- ANYTHING = r'.{%min%,%max%}'
29
- LETTERS = r'^[a-zA-Z]{%min%,%max%}$'
30
- WORDS = r'^[a-zA-Z0-9 _]{%min%,%max%}$'
31
- NUMBERS = r'^[0-9\.\,]{%min%,%max%}$'
32
- MASKED = CUSTOM # It will be set later
27
+ CUSTOM = r'.' # It will be set later
28
+ ANYTHING = r'.'
29
+ LETTERS = r'[a-zA-Z]'
30
+ WORDS = r'[a-zA-Z0-9 _]'
31
+ NUMBERS = r'[0-9\.\,]'
32
+ BINARY = r'[01]'
33
+ MASKED = r'.'
33
34
  # fmt: on
34
35
 
35
36
  @classmethod
36
- def custom(cls, pattern: str, min_length: int = 1, max_length: int = 50) -> "InputValidator":
37
+ def custom(cls, pattern: str) -> "InputValidator":
37
38
  """Return a custom validator that allows customize the input rules.
38
39
  :param pattern: the custom validator pattern.
39
- :param min_length: the minimum length required.
40
- :param max_length: the maximum length allowed.
41
40
  """
42
41
  pattern_type = cls.PatternType.CUSTOM
43
- validator = InputValidator(min_length, max_length, pattern_type=pattern_type)
42
+ validator = InputValidator(pattern_type=pattern_type)
44
43
  validator.pattern = pattern
45
44
  return validator
46
45
 
47
46
  @classmethod
48
- def letters(cls, min_length: int = 1, max_length: int = 50) -> "InputValidator":
47
+ def letters(cls) -> "InputValidator":
49
48
  """Return a validator that allows only letters.
50
- :param min_length: the minimum length required.
51
- :param max_length: the maximum length allowed.
52
49
  """
53
- return InputValidator(min_length, max_length, cls.PatternType.LETTERS)
50
+ return InputValidator(cls.PatternType.LETTERS)
54
51
 
55
52
  @classmethod
56
- def numbers(cls, min_length: int = 1, max_length: int = 50) -> "InputValidator":
53
+ def numbers(cls) -> "InputValidator":
57
54
  """Return a validator that allows only numbers.
58
- :param min_length: the minimum length required.
59
- :param max_length: the maximum length allowed.
60
55
  """
61
- return InputValidator(min_length, max_length, cls.PatternType.NUMBERS)
56
+ return InputValidator(cls.PatternType.NUMBERS)
62
57
 
63
58
  @classmethod
64
- def words(cls, min_length: int = 1, max_length: int = 50) -> "InputValidator":
59
+ def words(cls) -> "InputValidator":
65
60
  """Return a validator that allows only words (space, numbers or letters).
66
- :param min_length: the minimum length required.
67
- :param max_length: the maximum length allowed.
68
61
  """
69
- return InputValidator(min_length, max_length, cls.PatternType.WORDS)
62
+ return InputValidator(cls.PatternType.WORDS)
70
63
 
71
64
  @classmethod
72
- def anything(cls, min_length: int = 1, max_length: int = 50) -> "InputValidator":
65
+ def anything(cls) -> "InputValidator":
73
66
  """Return a validator that allows any input value.
74
- :param min_length: the minimum length required.
75
- :param max_length: the maximum length allowed.
76
67
  """
77
- return InputValidator(min_length, max_length, cls.PatternType.ANYTHING)
68
+ return InputValidator(cls.PatternType.ANYTHING)
78
69
 
79
70
  @classmethod
80
- def masked(cls, min_length: int = 1, max_length: int = 50) -> "InputValidator":
81
- """Return a validator that allows masked input values.
82
- :param min_length: the minimum length required.
83
- :param max_length: the maximum length allowed.
71
+ def binary(cls) -> "InputValidator":
72
+ """Return a validator that allows only zero or ones.
84
73
  """
85
- return InputValidator(min_length, max_length, cls.PatternType.MASKED)
74
+ return InputValidator(cls.PatternType.BINARY)
86
75
 
87
- def __init__(self, min_length: int = 1, max_length: int = 50, pattern_type: PatternType = PatternType.ANYTHING):
88
- self._min_length = min_length
89
- self._max_length = max_length
76
+ @classmethod
77
+ def masked(cls) -> "InputValidator":
78
+ """Return a validator that allows masked inputs.
79
+ """
80
+ return InputValidator(cls.PatternType.MASKED)
81
+
82
+ def __init__(self, pattern_type: PatternType = PatternType.ANYTHING):
90
83
  self._pattern_type = pattern_type
91
84
  self._pattern = pattern_type.value
92
85
 
@@ -105,16 +98,12 @@ class InputValidator(Validator):
105
98
 
106
99
  def validate(self, value: str) -> bool:
107
100
  """Validate the value against the validator pattern."""
108
- unmasked_value = re.split("[|,;]", value)[0]
101
+ unmasked_value = re.split("[|,;]", value)[0] if value else ""
109
102
  return bool(re.match(self.pattern, unmasked_value))
110
103
 
111
104
  @property
112
105
  def pattern(self) -> str:
113
- return (
114
- str(self._pattern)
115
- .replace("%min%", str(self._min_length or 1))
116
- .replace("%max%", str(self._max_length or 30))
117
- )
106
+ return str(self._pattern)
118
107
 
119
108
  @pattern.setter
120
109
  def pattern(self, pattern: str) -> None:
@@ -13,9 +13,11 @@
13
13
  Copyright 2023, HsPyLib team
14
14
  """
15
15
  import time
16
+ from functools import reduce
16
17
  from typing import List
17
18
 
18
19
  import pyperclip
20
+ from hspylib.core.exception.exceptions import InvalidStateError
19
21
  from hspylib.core.namespace import Namespace
20
22
  from hspylib.modules.cli.keyboard import Keyboard
21
23
  from hspylib.modules.cli.vt100.vt_utils import get_cursor_position, set_enable_echo, set_show_cursor
@@ -71,17 +73,16 @@ class MenuInput(TUIComponent):
71
73
  self.writeln(f"{self.prefs.title_color.placeholder}{self.title}%EOL%%NC%")
72
74
 
73
75
  for idx, field in enumerate(self.fields):
74
- field_size = field.width
76
+ field_length = field.length
75
77
  if self.tab_index == idx:
76
78
  mi_print(
77
79
  self.screen, f" {field.label}", self.prefs.sel_bg_color.placeholder, self.max_label_length + 2)
78
80
  self.cur_field = field
79
81
  else:
80
82
  mi_print(self.screen, f" {field.label}", field_len=self.max_label_length + 2)
81
-
82
- self._buffer_positions(idx, field_size)
83
+ self._buffer_positions(idx, field_length)
83
84
  self._render_field(field)
84
- self._render_details(field, field_size)
85
+ self._render_details(field, field_length)
85
86
 
86
87
  self.draw_navbar(self.navbar())
87
88
  self._re_render = False
@@ -114,7 +115,7 @@ class MenuInput(TUIComponent):
114
115
  case Keyboard.VK_CTRL_P:
115
116
  self._handle_ctrl_p()
116
117
  case Keyboard.VK_ENTER:
117
- self._handle_enter()
118
+ return self._handle_enter()
118
119
  case _ as key if key.isalnum() or key.ispunct() or key == Keyboard.VK_SPACE:
119
120
  if not self.cur_field.can_write():
120
121
  self._display_error("This field is read only !")
@@ -125,19 +126,16 @@ class MenuInput(TUIComponent):
125
126
 
126
127
  return keypress
127
128
 
128
- def _handle_enter(self) -> None:
129
+ def _handle_enter(self) -> Optional[Keyboard]:
129
130
  """Handle 'enter' press. Validate & Save form and exit."""
130
-
131
- # Fixme: Commented because at this point we need to validate the entire form since inputs are already valid
132
- # TODO: Find a way to validate the form itself, maybe add a form validator.
133
- # invalid = next((field for field in self.fields if not field.validate_input(field.value)), None)
134
- invalid = None
131
+ invalid = next((field for field in self.fields if not field.validate_field()), None)
135
132
  if invalid:
136
133
  idx = self.fields.index(invalid)
137
134
  pos = self.positions[idx]
138
135
  self.cur_row = pos[0]
139
136
  self.tab_index = idx
140
137
  self._display_error("Form field is not valid: " + str(invalid))
138
+ return None
141
139
  else:
142
140
  for idx, field in enumerate(self.fields):
143
141
  match field.itype:
@@ -148,6 +146,7 @@ class MenuInput(TUIComponent):
148
146
  case InputType.SELECT:
149
147
  _, field.value = get_selected(field.value)
150
148
  self._done = True
149
+ return Keyboard.VK_ENTER
151
150
 
152
151
  def _handle_input(self, keypress: Keyboard) -> None:
153
152
  """Handle a form input.
@@ -157,24 +156,28 @@ class MenuInput(TUIComponent):
157
156
  match self.cur_field.itype:
158
157
  case InputType.CHECKBOX:
159
158
  if keypress == Keyboard.VK_SPACE:
160
- self.cur_field.value = 1 if not self.cur_field.value else 0
159
+ self.cur_field.value = not self.cur_field.value
161
160
  case InputType.SELECT:
162
161
  if keypress == Keyboard.VK_SPACE:
163
162
  if self.cur_field.value:
164
- self.cur_field.value = toggle_selected(str(self.cur_field.value))
163
+ self.cur_field.value = toggle_selected(str(self.cur_field.value or ''))
165
164
  case InputType.MASKED:
166
- value, mask = unpack_masked(str(self.cur_field.value))
167
- if len(value) < self.cur_field.max_length:
168
- try:
169
- self.cur_field.value = append_masked(value, mask, keypress.value)
170
- except InvalidInputError as err:
171
- self._display_error(f"{str(err)}")
165
+ value, mask = unpack_masked(str(self.cur_field.value or ''))
166
+ try:
167
+ self.cur_field.value = append_masked(value, mask, keypress.value)
168
+ except InvalidInputError as err:
169
+ self._display_error(str(err))
172
170
  case _:
173
- if len(str(self.cur_field.value)) < self.cur_field.max_length:
171
+ if len(str(self.cur_field.value or '')) < self.cur_field.max_length:
174
172
  if self.cur_field.validate_input(keypress.value):
175
- self.cur_field.value = str(self.cur_field.value) + str(keypress.value)
173
+ self.cur_field.value = (
174
+ str(self.cur_field.value) if self.cur_field.value else ''
175
+ ) + str(keypress.value)
176
176
  else:
177
- self._display_error(f"This field only accept {self.cur_field.input_validator} !")
177
+ self._display_error(
178
+ f"Input '{keypress.value}' is invalid. "
179
+ f"This field takes only {self.cur_field.input_validator}!"
180
+ )
178
181
 
179
182
  def _handle_backspace(self) -> None:
180
183
  """Handle 'backspace' press. Delete previous input."""
@@ -200,48 +203,33 @@ class MenuInput(TUIComponent):
200
203
  """Set the cursor at the right position according to the ATB index."""
201
204
  pos = self.positions[self.tab_index]
202
205
  self.screen.cursor.move_to(
203
- pos[0], pos[1] + self._get_field_len())
204
-
205
- def _get_field_len(self) -> int:
206
- """Get the field real length, depending on the field type."""
207
- value = self.cur_field.value
208
- match self.cur_field.itype:
209
- case InputType.CHECKBOX:
210
- value = '1'
211
- case InputType.SELECT:
212
- _, value = get_selected(str(self.cur_field.value))
213
- case InputType.MASKED:
214
- value, mask = unpack_masked(str(self.cur_field.value))
215
- idx = len(value)
216
- while idx < len(mask) and mask[idx] not in MASK_SYMBOLS:
217
- idx += 1
218
- return idx
219
-
220
- return len(str(value))
206
+ pos[0], pos[1] + self.cur_field.length)
221
207
 
222
208
  def _render_field(self, field: FormField) -> None:
223
209
  """Render the specified form field.
224
210
  :param field: the form field to render.
225
211
  """
226
- if field.itype == InputType.TEXT:
227
- mi_print(self.screen, field.value, field_len=self.max_value_length)
228
- elif field.itype == InputType.PASSWORD:
229
- mi_print(self.screen, "*" * field.width, field_len=self.max_value_length)
230
- elif field.itype == InputType.CHECKBOX:
231
- mi_print(
232
- self.screen,
233
- " ",
234
- str(FormIcons.CHECK_SQUARE) if field.value else str(FormIcons.UNCHECK_SQUARE),
235
- field_len=self.max_value_length - 1
236
- )
237
- elif field.itype == InputType.SELECT:
238
- if field.value:
239
- mat = re.search(rf".*({VALUE_SEPARATORS})?<(.+)>({VALUE_SEPARATORS})?.*", field.value)
240
- sel_value = mat.group(2) if mat else re.split(VALUE_SEPARATORS, field.value)[0]
241
- mi_print(self.screen, f"{sel_value}", field_len=self.max_value_length)
242
- elif field.itype == InputType.MASKED:
243
- value, mask = unpack_masked(str(field.value))
244
- mi_print(self.screen, over_masked(value, mask), field_len=self.max_value_length)
212
+ match field.itype:
213
+ case InputType.TEXT:
214
+ mi_print(self.screen, str(field.value or ''), field_len=self.max_value_length)
215
+ case InputType.PASSWORD:
216
+ mi_print(self.screen, "*" * field.length, field_len=self.max_value_length)
217
+ case InputType.CHECKBOX:
218
+ mi_print(
219
+ self.screen, " ",
220
+ FormIcons.CHECK_SQUARE.unicode if field.value else FormIcons.UNCHECK_SQUARE.unicode,
221
+ field_len=self.max_value_length - 1
222
+ )
223
+ case InputType.SELECT:
224
+ if field.value:
225
+ mat = re.search(rf".*({VALUE_SEPARATORS})?<(.+)>({VALUE_SEPARATORS})?.*", str(field.value))
226
+ sel_value = mat.group(2) if mat else re.split(VALUE_SEPARATORS, str(field.value))[0]
227
+ mi_print(self.screen, f"{sel_value}", field_len=self.max_value_length)
228
+ case InputType.MASKED:
229
+ value, mask = unpack_masked(str(field.value))
230
+ mi_print(self.screen, over_masked(value, mask), field_len=self.max_value_length)
231
+ case _:
232
+ raise InvalidStateError(f"Invalid form field type: {field.itype}")
245
233
 
246
234
  def _render_details(self, field: FormField, field_details: int) -> None:
247
235
  """Render details about total/remaining field characters.
@@ -255,8 +243,12 @@ class MenuInput(TUIComponent):
255
243
  count = len(re.split(VALUE_SEPARATORS, field.value))
256
244
  self.writeln(fmt.format(field.icon, idx + 1 if idx >= 0 else 1, count))
257
245
  elif field.itype == InputType.MASKED:
258
- value, _ = unpack_masked(str(field.value))
259
- self.writeln(fmt.format(field.icon, len(value), field.max_length))
246
+ value, mask = unpack_masked(str(field.value or ''))
247
+ self.writeln(fmt.format(
248
+ field.icon,
249
+ reduce(lambda n, m: n + m, list(map(lambda s: mask[:len(value)].count(s), MASK_SYMBOLS))),
250
+ reduce(lambda n, m: n + m, list(map(lambda s: mask.count(s), MASK_SYMBOLS)))
251
+ ))
260
252
  else:
261
253
  self.writeln(fmt.format(field.icon, field_details, field.max_length))
262
254
 
@@ -282,9 +274,10 @@ class MenuInput(TUIComponent):
282
274
  self.cursor.move_to(self.cur_row, err_pos)
283
275
  mi_print_err(self.screen, f"{FormIcons.ERROR_CIRCLE} {err_msg}")
284
276
  # This calculation gives a good delay amount based on the size of the message.
285
- time.sleep(max(1.5, int(len(err_msg) / 25)))
277
+ time.sleep(max(1.8, int(len(err_msg) / 24)))
286
278
  set_enable_echo()
287
- set_show_cursor()
288
279
  # Erase the message after the timeout
289
280
  self.cursor.move_to(self.cur_row, err_pos)
290
281
  self.cursor.erase(TUIScreen.CursorDirection.RIGHT)
282
+ set_show_cursor()
283
+ self._re_render = True
@@ -16,13 +16,14 @@ import re
16
16
  from typing import Any, Optional, Tuple
17
17
 
18
18
  from hspylib.core.exception.exceptions import InvalidInputError
19
- from hspylib.core.preconditions import check_argument
20
19
 
21
20
  from clitt.core.tui.tui_screen import TUIScreen
22
21
 
23
22
  MASK_SYMBOLS = ["#", "@", "%", "*"]
24
23
 
25
- VALUE_SEPARATORS = "[|,;]"
24
+ VALUE_SEPARATORS = r"[|,;]"
25
+
26
+ VALUE_SELECTORS = r"[<>]"
26
27
 
27
28
 
28
29
  def detail_len(field: Any) -> int:
@@ -57,7 +58,6 @@ def mi_print_err(screen: TUIScreen, text: str) -> None:
57
58
  """Special menu input print error message.
58
59
  :param screen: the component's screen.
59
60
  :param text: the text to be printed.
60
- :param end: string appended after the last value, default an empty string.
61
61
  """
62
62
  screen.cursor.write(f"%RED%{text}%NC%")
63
63
 
@@ -74,7 +74,7 @@ def toggle_selected(tokenized_values: str) -> str:
74
74
  else:
75
75
  values[0] = f"<{values[0]}>"
76
76
  return "|".join(values)
77
- unselected = list(map(lambda x: x.replace("<", "").replace(">", ""), values))
77
+ unselected = list(map(lambda x: re.sub(VALUE_SELECTORS, '', x), values))
78
78
  # fmt: off
79
79
  return '|'.join([
80
80
  f'<{val}>'
@@ -91,7 +91,7 @@ def get_selected(tokenized_values: str) -> Optional[Tuple[int, str]]:
91
91
  values = re.split(VALUE_SEPARATORS, tokenized_values)
92
92
  # fmt: off
93
93
  sel_item = next((
94
- val.replace('<', '').replace('>', '')
94
+ re.sub(VALUE_SELECTORS, '', val)
95
95
  for val in values if val.startswith('<') and val.endswith('>')
96
96
  ), values[0])
97
97
  # fmt: on
@@ -110,8 +110,7 @@ def unpack_masked(value: str) -> Tuple[str, str]:
110
110
  """
111
111
  if value:
112
112
  parts = re.split(VALUE_SEPARATORS, value)
113
- check_argument(len(parts) == 2, "Invalid masked value: {}", value)
114
- return parts[0], parts[1]
113
+ return parts[0], parts[1] if len(parts) == 2 else ''
115
114
 
116
115
  return '', ''
117
116
 
@@ -126,43 +125,49 @@ def append_masked(
126
125
  :param keypress_value: the value to append (it can be a part of the mask itself).
127
126
  """
128
127
  idx = len(value)
129
- if keypress_value == mask[idx]:
130
- return f"{value}{keypress_value}|{mask}"
131
128
  masked_value = value
132
- while idx < len(mask) and mask[idx] not in MASK_SYMBOLS:
133
- masked_value += mask[idx]
134
- idx += 1
135
- if mask and idx < len(mask):
136
- mask_regex = mask[idx] \
137
- .replace("#", "[0-9]") \
138
- .replace("@", "[a-zA-Z]") \
139
- .replace("%", "[a-zA-Z0-9]") \
140
- .replace("*", ".")
141
- if re.search(mask_regex, keypress_value):
142
- masked_value += keypress_value
143
- else:
144
- raise InvalidInputError(f"Value {keypress_value} is not a valid value against mask: {mask}")
129
+ if idx < len(mask):
130
+ if keypress_value == mask[idx]:
131
+ return f"{value}{keypress_value}|{mask}"
132
+ while idx < len(mask) and mask[idx] not in MASK_SYMBOLS:
133
+ masked_value += mask[idx]
134
+ idx += 1
135
+ if mask and idx < len(mask):
136
+ mask_re = mask_regex(mask, idx)
137
+ if re.search(mask_re, keypress_value):
138
+ masked_value += keypress_value
139
+ else:
140
+ raise InvalidInputError(f"Value '{keypress_value}' is invalid. Expecting: {mask_re}")
145
141
 
146
142
  return f"{masked_value}|{mask}"
147
143
 
148
144
 
149
145
  def over_masked(
150
146
  value: str,
151
- mask: str,
152
- placeholder: str = "_") -> str:
147
+ mask: str) -> str:
153
148
  """
154
149
  Return the value to be printed by a 'masked' input field. A placeholder value will be used for unfilled values.
155
150
  :param value: the masked field current value.
156
151
  :param mask: the masked field's mask.
157
- :param placeholder: the placeholder character. It's going to be printed if current value is None.
158
152
  """
159
153
  if value:
160
154
  over_masked_val = ""
161
155
  for idx, element in enumerate(mask):
162
- if element in MASK_SYMBOLS: # Digit, Letter or alphanumeric masks.
163
- over_masked_val += value[idx] if idx < len(value) else placeholder
156
+ if element in MASK_SYMBOLS:
157
+ over_masked_val += value[idx] if idx < len(value) else mask[idx]
164
158
  else:
165
159
  over_masked_val += element
166
160
  return over_masked_val
167
161
 
168
- return re.sub(f"[{''.join(MASK_SYMBOLS)}]", "_", mask)
162
+ return mask
163
+
164
+
165
+ def mask_regex(
166
+ mask: str,
167
+ idx: int) -> str:
168
+ """Return a regex matching the index of the mask."""
169
+ return mask[idx] \
170
+ .replace("#", "[0-9]") \
171
+ .replace("@", "[a-zA-Z]") \
172
+ .replace("%", "[a-zA-Z0-9]") \
173
+ .replace("*", ".")
@@ -1,6 +1,6 @@
1
1
  # _*_ coding: utf-8 _*_
2
2
  #
3
- # hspylib-clitt v0.9.32
3
+ # hspylib-clitt v0.9.34
4
4
  #
5
5
  # Package: main.clitt.core.tui.mselect
6
6
  """Package initialization."""
@@ -9,4 +9,4 @@ __all__ = [
9
9
  'menu_select',
10
10
  'mselect'
11
11
  ]
12
- __version__ = '0.9.32'
12
+ __version__ = '0.9.34'
@@ -1,6 +1,6 @@
1
1
  # _*_ coding: utf-8 _*_
2
2
  #
3
- # hspylib-clitt v0.9.32
3
+ # hspylib-clitt v0.9.34
4
4
  #
5
5
  # Package: main.clitt.core.tui.table
6
6
  """Package initialization."""
@@ -8,4 +8,4 @@
8
8
  __all__ = [
9
9
  'table_renderer'
10
10
  ]
11
- __version__ = '0.9.32'
11
+ __version__ = '0.9.34'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hspylib-clitt
3
- Version: 0.9.32
3
+ Version: 0.9.34
4
4
  Summary: HsPyLib - CLI Terminal Tools
5
5
  Home-page: https://github.com/yorevs/hspylib
6
6
  Author: Hugo Saporetti Junior
@@ -31,7 +31,7 @@ Requires-Dist: hspylib
31
31
  ## Create professional CLI applications
32
32
 
33
33
  [![License](https://badgen.net/badge/license/MIT/gray)](LICENSE.md)
34
- [![Release](https://badgen.net/badge/release/v0.9.32/gray)](CHANGELOG.md#unreleased)
34
+ [![Release](https://badgen.net/badge/release/v0.9.34/gray)](CHANGELOG.md#unreleased)
35
35
  [![PyPi](https://badgen.net/badge/icon/python?icon=pypi&label)](https://pypi.org/project/hspylib-cfman)
36
36
  [![GitHub](https://badgen.net/badge/icon/github?icon=github&label)](https://github.com/yorevs/hspylib)
37
37
  [![Gitter](https://badgen.net/badge/icon/gitter?icon=gitter&label)](https://gitter.im/hspylib/community)
@@ -1,13 +1,13 @@
1
- clitt/.version,sha256=KVVptIBoyFyHLc9uQcKTe5XCMdqIrZ5mcilxRcHfC_c,7
1
+ clitt/.version,sha256=GiSux3LKPB7ZJg2Z6q_kl-eS_lJ4cPlTKGImSFNQN4U,7
2
2
  clitt/__classpath__.py,sha256=j7k_kckSu-7r0RB630enzF3JH_1z2J7RByxp2ZZNdmg,717
3
- clitt/__init__.py,sha256=AooF_S5c6wSRGYTZoe7ycicg2U6lL5rH1jnj0NiReyI,164
3
+ clitt/__init__.py,sha256=QEvjCmII4t28WjOdWVBsqDthnsqgF4g4KnguSDc40Hs,164
4
4
  clitt/__main__.py,sha256=leYCCcxf0CrO9zBiI4MVRL-s02rt25Ib6uROSYlNca4,6973
5
5
  clitt/welcome.txt,sha256=x4oQU6m_9g75x4d7tLriPkFR6I_4MLhlHRzqwBIC-lA,452
6
- clitt/addons/__init__.py,sha256=Zi0Mkg2uuMAXC940ioncwryS8I3cyvzoPRN8RM7BlkM,186
7
- clitt/addons/appman/__init__.py,sha256=pTCGzXZ3T4EoLIZltxJk1qX2eC0J8H6EiCdgRuaOtv8,202
6
+ clitt/addons/__init__.py,sha256=eWlL32sZ8cfQ2m1kP24W8NfzC0fxmrvAuuMrmrzZyLg,186
7
+ clitt/addons/appman/__init__.py,sha256=4gIHR-LpwYezD8JPidvgN9Waxs8Al56-Mr29Iz8lPKQ,202
8
8
  clitt/addons/appman/appman.py,sha256=-fwijYySTWoyoAwzWFycIdScBkStH7VLFr-4bFuGXw8,13150
9
9
  clitt/addons/appman/appman_enums.py,sha256=FMfSIBptbCDBxWsqUmF_xIsRBFNITqqxeXr2iOIdcLM,873
10
- clitt/addons/appman/templates/__init__.py,sha256=yRQvMiZWECYrsVr_-k8GE6mRWFar_EEpMgqBsWimiqY,169
10
+ clitt/addons/appman/templates/__init__.py,sha256=V7r3LmKDVG1u_-qyYpq53ZMYm55cekkSOT_BlraZeHg,169
11
11
  clitt/addons/appman/templates/build.gradle.tpl,sha256=VQKs4r41xPr7P14PtQPt3alYCmNuXaGraaXbKB_FKkM,1817
12
12
  clitt/addons/appman/templates/classpath.py.tpl,sha256=R60uLvVxeJ7nJCXCvav_9LAnDe5VOfJqWO-T1QAlwAc,397
13
13
  clitt/addons/appman/templates/dependencies.hspd.tpl,sha256=bbVNU6XBm5QT28lvH7Bp_4nlXvoD-LwX5kGQ-CPhOEA,764
@@ -20,28 +20,28 @@ clitt/addons/appman/templates/run.sh.tpl,sha256=2xpuHjZP9-7j14dAA2CqPm4G2xtnuenf
20
20
  clitt/addons/appman/templates/test_main.py.tpl,sha256=x_xuKy2O2b1bs6tuzOUqF5shnx-2-EfFRc7sBV4Fndc,1239
21
21
  clitt/addons/appman/templates/usage.txt.tpl,sha256=R0e48HCeD7PDbWnX6HGIjz6gr_hBdp-zK6V42U1Aexw,217
22
22
  clitt/addons/appman/templates/widget.py.tpl,sha256=JmlO5rh2ETCF5ldiB9MStfjB4oB4JLI8UUnNP5SAAcM,1668
23
- clitt/addons/setman/__init__.py,sha256=zYoZ_ShPaTy1s8b2gM0TmY1Y__zhZaHM-sNsBidf6iE,270
23
+ clitt/addons/setman/__init__.py,sha256=pGI-w38LyS17ZdFDn_BkCCpcfN5rp200a5C5dVzsVus,270
24
24
  clitt/addons/setman/setman.py,sha256=70CC1dnuNxeumo7fESQfIViIeKBr-ee2ST6JcL1N_Ow,8129
25
25
  clitt/addons/setman/setman_config.py,sha256=X39iFkd4HLqMgQ0dpbtngASe05HrtCdxIbKwgQWImIs,1012
26
26
  clitt/addons/setman/setman_entry.py,sha256=eZqOgNzRK6mtFc_eoyQw8Y-sq8z87QK95RpoYpcqtLo,3394
27
27
  clitt/addons/setman/setman_enums.py,sha256=fZ0uXTzBh7fx1xUqV02BkFmVKSUUIJbr2HmVLbcrhqk,1281
28
28
  clitt/addons/setman/setman_repository.py,sha256=yxL9raNA3FVcvWdFtbIQMrKYmrjgPbu4TcqViJGE3lY,2547
29
29
  clitt/addons/setman/setman_service.py,sha256=1Yw27DFmlaiCedaGjg1TLxDyOfNFjlrbfE91uChzLL8,2244
30
- clitt/addons/widman/__init__.py,sha256=vRUitxFgBlrH_yDesFkYK9QtM0OH4LwB3VGdoFIBvjM,213
30
+ clitt/addons/widman/__init__.py,sha256=kS21YpLV4Jpn-L3q1pu1rfoyKkCUaJLprq_mpOsbOWc,213
31
31
  clitt/addons/widman/widget.py,sha256=mIEB3Fs4ypaUMhh85meg2vMhKJVjW8Tyxkp_XqHIHtA,1920
32
32
  clitt/addons/widman/widget_entry.py,sha256=8Shj4_esh6KN69usTrCcUsfGVas81Xz0QabsY_zV9o0,1350
33
33
  clitt/addons/widman/widman.py,sha256=kfv3CcDSjUZglurPXa4Bv1jYELtEkbixOjpVL8yRf3M,5260
34
- clitt/addons/widman/widgets/__init__.py,sha256=wHsMZHZVfhQBSDJ7LU-IcmpkvrIUq1b_pVfunWhwU5s,244
34
+ clitt/addons/widman/widgets/__init__.py,sha256=EYww5RDRZaLGDuB_pOSGkwfIjnaceX0HQdonKtEmga4,244
35
35
  clitt/addons/widman/widgets/widget_free.py,sha256=5imXWD4F984KqwcWuI-ZuBaF1gtNha0TAmmaiIZ-MVg,3997
36
36
  clitt/addons/widman/widgets/widget_punch.py,sha256=YQ27qC15gyt1jn-R4oNumVLVbMzbs3s7I0yLPqpR8xY,10535
37
37
  clitt/addons/widman/widgets/widget_send_msg.py,sha256=MMBOGTBc6c3jgLgZBzbQIiQsSs5jl-8ohqy7evMSNQU,11056
38
38
  clitt/addons/widman/widgets/widget_time_calc.py,sha256=JQOHRf5OFDL73Y-GJEWtdN5_s2vKR-9mX0yoisxNQRg,5100
39
- clitt/core/__init__.py,sha256=X8XtQKjTk01um_7BQHUQlcmddxfdjbrwsoUAqiYYEyU,167
40
- clitt/core/icons/__init__.py,sha256=s9Oh7ENh4ZPFWRkqc3jl87S5XVJEK4nkdT73PjYxnN0,183
41
- clitt/core/icons/emojis/__init__.py,sha256=EF-SfGpdkImgtNbVNU7ZAetHOlpLXAjp2OVQNL5TQj4,190
39
+ clitt/core/__init__.py,sha256=twL6xekgpsy_Vmp5Wl5VvugMlr_vBbo0Tcl9x_rJV4M,167
40
+ clitt/core/icons/__init__.py,sha256=wklMn68feTajNTbQodPrfU56oGGYGUftp2sw756kT1s,183
41
+ clitt/core/icons/emojis/__init__.py,sha256=NPdTQoJn7sYMXGqWkBr_mpuwZGKON3alp2C-DBP_xQg,190
42
42
  clitt/core/icons/emojis/emojis.py,sha256=LbwpjJonRlNVPa6eMEDTreQz1fmFfFK4dOk6X-4XHrI,1109
43
43
  clitt/core/icons/emojis/face_smiling.py,sha256=qho6t7W3za6-H9bW51_0RoYKah_f0_DCJ0EiCiwvQwI,1269
44
- clitt/core/icons/font_awesome/__init__.py,sha256=KB_xPxQZN7WSvtAx9LJbOwt1CctY7alP2XypK-mIht0,288
44
+ clitt/core/icons/font_awesome/__init__.py,sha256=NPp7cJgEkla2IK3Bzd0V5Z77D-PzFp19DBJE4agLrO0,288
45
45
  clitt/core/icons/font_awesome/app_icons.py,sha256=cMPlXVWOn5YnLmlk20nwhFgA16Ug2jFiHZPYlwwH724,1662
46
46
  clitt/core/icons/font_awesome/awesome.py,sha256=oEOi0DWj0yvJbmg18fXE5hgSrMmCckTYC0cbgw1cyQQ,1831
47
47
  clitt/core/icons/font_awesome/control_icons.py,sha256=OuAnvXRIusxDRVnPHxltTn4V6tF_uc2gfoqoQWB7Bks,1075
@@ -49,41 +49,42 @@ clitt/core/icons/font_awesome/dashboard_icons.py,sha256=MGXLJ-I_xXalOaLeWHkaZe5Z
49
49
  clitt/core/icons/font_awesome/form_icons.py,sha256=mDF_0nFJ9VYO2ZoXWSTETm7qEd03dcIgeCUpFnH0sLI,2314
50
50
  clitt/core/icons/font_awesome/nav_icons.py,sha256=A3GqJuwD-RKybY67THimI1oqcNlDSEaA_Hdy8LSzfqo,1105
51
51
  clitt/core/icons/font_awesome/widget_icons.py,sha256=Oho4jPezyMSw-tKWSjpdK3dv-FK2GC_62liNeThhhAs,1024
52
- clitt/core/tui/__init__.py,sha256=gLYdJ1C7BfPkpRtB4IbBPCPZ_pVj2aJA9b7Xvfqm1t0,311
52
+ clitt/core/tui/__init__.py,sha256=u5pdP4mRJuBtwBIeM3UGVUZgcIYzxFNzBe_35lJnuDw,311
53
53
  clitt/core/tui/tui_application.py,sha256=kBYc_IUrVrZ6v7MZ6A8QJ9hONDpXwqO9TqJa_XBsM8E,1611
54
54
  clitt/core/tui/tui_component.py,sha256=3GXfU7AO9oi7VnM8MAClieZUyTU9s9vkrv0Pwce_0hM,4733
55
55
  clitt/core/tui/tui_preferences.py,sha256=C3cXqwBykE8Sw3Brn-s4nBxr5gDgSslS7bD1g67rtBw,4731
56
56
  clitt/core/tui/tui_screen.py,sha256=I043SGE7d2OQZDwjLsuvyUO7ucwYHmtyfx54FL52ejE,8374
57
- clitt/core/tui/mchoose/__init__.py,sha256=Kn2JkqgJO_Vda0LasWxqfbtH5Cf1z8ikcRM0nceHGC0,189
57
+ clitt/core/tui/mchoose/__init__.py,sha256=6dXoUnpOlyYyfoJRIXmJ508vCnRJu49zSHaozD8F4nM,189
58
58
  clitt/core/tui/mchoose/mchoose.py,sha256=SsflRDJUAB2opK1BeZXBba6zFYuqe1prflaePX21Xfk,1197
59
59
  clitt/core/tui/mchoose/menu_choose.py,sha256=kvEvuADZDk_lRqC7jH_cWtJGiNZjdh_765x27cu8ySo,7016
60
- clitt/core/tui/mdashboard/__init__.py,sha256=kdx1JWiZqk4ChyDDnM3H2ZzX4LIUorbT9Nn1i2ywWa0,243
60
+ clitt/core/tui/mdashboard/__init__.py,sha256=irSTrEeG6efAutKKGlKeRFHWWD0ubDZDR4JuBW7gLVU,243
61
61
  clitt/core/tui/mdashboard/dashboard_builder.py,sha256=wWcT1UyQnOrvalV920XtmBUg5lRVbhA8hMrmxRcLrtY,1658
62
62
  clitt/core/tui/mdashboard/dashboard_item.py,sha256=4MK6bxROWo1ZK9FlMoSm38z0qe5HoxqH0W5tt3iUT5M,886
63
63
  clitt/core/tui/mdashboard/mdashboard.py,sha256=sUOAsrHxCIz3gjJAJOcm6ZD3Xh1uU_I5qx-6pOiJ6KU,903
64
64
  clitt/core/tui/mdashboard/menu_dashboard.py,sha256=UyzbdhSeWV_NylryVJcjcHqW5vwFScUcaTpdCXllvXs,5547
65
- clitt/core/tui/menu/__init__.py,sha256=ba61AHCBqykFtMpqs3h_FdNdZV6PEmYUjBtaPVZzwFQ,272
65
+ clitt/core/tui/menu/__init__.py,sha256=6X1nGM4mWttgTDKgVcJJqQXNgbRiaXvf0eOSAotPttE,272
66
66
  clitt/core/tui/menu/tui_menu.py,sha256=wWgHr0D_jzj3l6XPwWoIfy1kCXn-zYwZn2ctqB9lTrk,3599
67
67
  clitt/core/tui/menu/tui_menu_action.py,sha256=KqhG_YkEMWF37uoI7Q_bCr3jHLIeTbDr_-uROuhAvB0,1590
68
68
  clitt/core/tui/menu/tui_menu_factory.py,sha256=rL33KX5yD2ppvVRAEFIAme5ka7GrBQecVr63aUf2hf0,4459
69
69
  clitt/core/tui/menu/tui_menu_item.py,sha256=NZjlYl6nVwB0wo0fJ4OFnIo98eowLwLWHGMnSD-yTto,7482
70
70
  clitt/core/tui/menu/tui_menu_ui.py,sha256=GK9suH6eeG4rqV_TahZ9PDDIHYpu7yETHWjzKsh_Xdo,3271
71
71
  clitt/core/tui/menu/tui_menu_view.py,sha256=oJwdmwfbMoJ2mh_mc-IQZ4qERuz5v4hZtsHjaW34fvM,1943
72
- clitt/core/tui/minput/__init__.py,sha256=o_aSpcQl_TpGdDEUFkHoMizdR-v_OZYkyAtDghNOW4k,298
72
+ clitt/core/tui/minput/__init__.py,sha256=TCQd9t46b_aQqLleIKPg2bHA6457iNpR2q_3yfKzLi4,318
73
73
  clitt/core/tui/minput/access_type.py,sha256=Dss6okfXHCoUI3_OOu2nKsgpy2NeStIwhdDvTR2z-2w,636
74
- clitt/core/tui/minput/form_builder.py,sha256=r3CKLxZBSzab_O-uu7ja3eq1wPbSP-f1Ra9eGSo2q4s,6438
75
- clitt/core/tui/minput/form_field.py,sha256=fXUCw0oWJLO66-fAT2rHB1K-D8-jXKJ3WK8Uk-fB2Gg,3448
74
+ clitt/core/tui/minput/field_builder.py,sha256=lw-JguTb8glG7NIiyoCb6UigzlOgk7k81l5x0uyWuhI,4311
75
+ clitt/core/tui/minput/form_builder.py,sha256=HjwJVtrizUNgpNWA7NkpzM0ZRweFUJBHvuB5L33LD2k,2866
76
+ clitt/core/tui/minput/form_field.py,sha256=3xYglKDAQj-YFyRGvUWgl9fiF4jJjA7tN4sgYfg6vzQ,5776
76
77
  clitt/core/tui/minput/input_type.py,sha256=O6-jk_QSjjRGeHsGVzIDZSCLg739f2xtnVV_ElcHYpA,722
77
- clitt/core/tui/minput/input_validator.py,sha256=jyDnm_OGuH_o7TDtTV13i3APqX4j-OSumvLqMdWTNmA,4624
78
- clitt/core/tui/minput/menu_input.py,sha256=VgpL9f57MsfVCuFrD-pGOpCZU-RO9jadnGEg7Oxi_G4,12722
78
+ clitt/core/tui/minput/input_validator.py,sha256=z6CNtWFx90wDeYgLilIdPeZC23aub804fCBd_95wKAA,3438
79
+ clitt/core/tui/minput/menu_input.py,sha256=usLRCnjheA7dfoinEZIflsRiwIo0yV6XHrsGqmgCL-w,12535
79
80
  clitt/core/tui/minput/minput.py,sha256=no3J-eIhlalvvEDmfjMLX2Gi197PKqSY28tur6oePBk,1545
80
- clitt/core/tui/minput/minput_utils.py,sha256=kD8lCP5etTbqW_3ig3ryt8cU9KUPLGtCdK2rH9Dmiww,5568
81
- clitt/core/tui/mselect/__init__.py,sha256=hwFfDwPOMNNudZWNrxChMjIdAq585WZ-QhRcsCrmWZg,189
81
+ clitt/core/tui/minput/minput_utils.py,sha256=raA0KE7NaFesR4W1MNeevaDEep0O0XBRYguDtsf2Pbo,5374
82
+ clitt/core/tui/mselect/__init__.py,sha256=ZmwlV0J1fKnTnxbQ__Mkud2C_pK2LFtd_Fuh-1arW8g,189
82
83
  clitt/core/tui/mselect/menu_select.py,sha256=059o7lN81dAO5su7iO2tzIjRpmoerRekGXzFlWNGw5w,6176
83
84
  clitt/core/tui/mselect/mselect.py,sha256=2vuIHjbjBQq0XtIUKxX5ku7hPv3iLBwgEX4Sa82cOc8,1059
84
- clitt/core/tui/table/__init__.py,sha256=KdKkGgJUyeqfWCHLAVwCU37jdF3MU80zPpUpcr9ANtk,176
85
+ clitt/core/tui/table/__init__.py,sha256=PqbtbZNr2NdkmlY1iK_uGE9p-zYrFPqQZ9kfeY0yPiY,176
85
86
  clitt/core/tui/table/table_renderer.py,sha256=qOkcmG7LWYzI8-qTkAVTNogSIr-S7lND41c7hvV3suw,8270
86
- hspylib_clitt-0.9.32.dist-info/METADATA,sha256=2TdAbFzVTl43UsnCb8FZTeWw2npz1_g8uxg5987QmlM,1728
87
- hspylib_clitt-0.9.32.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
88
- hspylib_clitt-0.9.32.dist-info/top_level.txt,sha256=vrnpkFU7dZ-vH7x5xdcY1vJSuboTqPBUcc3jD6SJkAo,6
89
- hspylib_clitt-0.9.32.dist-info/RECORD,,
87
+ hspylib_clitt-0.9.34.dist-info/METADATA,sha256=D7b2w0lR9ZIBGUT5ZW3PWOmWzkiPdWp8aP1Ushaaf-s,1728
88
+ hspylib_clitt-0.9.34.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
89
+ hspylib_clitt-0.9.34.dist-info/top_level.txt,sha256=vrnpkFU7dZ-vH7x5xdcY1vJSuboTqPBUcc3jD6SJkAo,6
90
+ hspylib_clitt-0.9.34.dist-info/RECORD,,