wizlib 3.3.3__tar.gz → 3.3.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of wizlib might be problematic. Click here for more details.
- {wizlib-3.3.3 → wizlib-3.3.5}/PKG-INFO +1 -1
- {wizlib-3.3.3 → wizlib-3.3.5}/pyproject.toml +2 -2
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/config_handler.py +8 -1
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/io.py +7 -2
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/ui/shell/__init__.py +6 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/ui/shell/line_editor.py +24 -9
- /wizlib-3.3.3/README.md → /wizlib-3.3.5/PACKAGE.md +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/__init__.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/app.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/class_family.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/command.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/error.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/handler.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/parser.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/stream_handler.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/super_wrapper.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/test_case.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/ui/__init__.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/ui/shell_ui.py +0 -0
- {wizlib-3.3.3 → wizlib-3.3.5}/wizlib/ui_handler.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "wizlib"
|
|
3
|
-
version = "3.3.
|
|
3
|
+
version = "3.3.5"
|
|
4
4
|
description = "Framework for flexible and powerful command-line applications"
|
|
5
5
|
authors = ["Steampunk Wizard <wizlib@steampunkwizard.ca>"]
|
|
6
6
|
license = "MIT"
|
|
7
|
-
readme = "
|
|
7
|
+
readme = "PACKAGE.md"
|
|
8
8
|
|
|
9
9
|
[tool.poetry.dependencies]
|
|
10
10
|
python = ">=3.11,<3.12"
|
|
@@ -27,14 +27,21 @@ class ConfigHandler(Handler):
|
|
|
27
27
|
|
|
28
28
|
name = 'config'
|
|
29
29
|
|
|
30
|
-
def __init__(self, file=None):
|
|
30
|
+
def __init__(self, file=None, yaml=None):
|
|
31
31
|
self.file = file
|
|
32
|
+
self.yaml_dict = yaml
|
|
32
33
|
self.cache = {}
|
|
33
34
|
|
|
34
35
|
@property
|
|
35
36
|
def yaml(self):
|
|
36
37
|
if hasattr(self, '_yaml'):
|
|
37
38
|
return self._yaml
|
|
39
|
+
|
|
40
|
+
# If yaml_dict was provided, use it directly
|
|
41
|
+
if self.yaml_dict is not None:
|
|
42
|
+
self._yaml = self.yaml_dict
|
|
43
|
+
return self._yaml
|
|
44
|
+
|
|
38
45
|
path = None
|
|
39
46
|
if self.file:
|
|
40
47
|
path = Path(self.file)
|
|
@@ -6,6 +6,7 @@ import sys
|
|
|
6
6
|
import readchar
|
|
7
7
|
|
|
8
8
|
from wizlib.parser import WizArgumentError
|
|
9
|
+
from wizlib.ui.shell import ESC
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
ISATTY = all(s.isatty() for s in (sys.stdin, sys.stdout, sys.stderr))
|
|
@@ -19,9 +20,13 @@ def stream():
|
|
|
19
20
|
return '' if ISATTY else sys.stdin.read()
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
def ttyin():
|
|
23
|
+
def ttyin(): # pragma: nocover
|
|
23
24
|
if ISATTY:
|
|
24
|
-
|
|
25
|
+
key = readchar.readkey()
|
|
26
|
+
# Handle specialized escape sequences
|
|
27
|
+
if key == ESC + '[1;':
|
|
28
|
+
key = key + readchar.readkey() + readchar.readkey()
|
|
29
|
+
return key
|
|
25
30
|
else:
|
|
26
31
|
raise WizArgumentError(
|
|
27
32
|
'Command designed for interactive use')
|
|
@@ -38,3 +38,9 @@ class S(StrEnum):
|
|
|
38
38
|
MAGENTA = ESC + '[35m'
|
|
39
39
|
CYAN = ESC + '[36m'
|
|
40
40
|
CLEAR = ESC + '[2J'
|
|
41
|
+
|
|
42
|
+
# Alternative keys that can be configured in a terminal emulator
|
|
43
|
+
CUSTOM_END = ESC + '[1;5C'
|
|
44
|
+
CUSTOM_BEGINNING = ESC + '[1;5D'
|
|
45
|
+
CUSTOM_RIGHTWORD = ESC + '[1;9C'
|
|
46
|
+
CUSTOM_LEFTWORD = ESC + '[1;9D'
|
|
@@ -92,10 +92,7 @@ class ShellLineEditor: # pragma: nocover
|
|
|
92
92
|
if key == S.RETURN:
|
|
93
93
|
break
|
|
94
94
|
if key.isprintable():
|
|
95
|
-
|
|
96
|
-
('\b' * (len(self.buf) - self.pos)) + S.RESET)
|
|
97
|
-
self.buf = self.buf[:self.pos] + key + self.buf[self.pos:]
|
|
98
|
-
self.pos += 1
|
|
95
|
+
self.write_key(key)
|
|
99
96
|
self.fillstate = FillState.USER
|
|
100
97
|
elif (key in [S.BACKSPACE, S.KILL]) and self.has_fill:
|
|
101
98
|
# Backspace clears the fill
|
|
@@ -113,13 +110,13 @@ class ShellLineEditor: # pragma: nocover
|
|
|
113
110
|
elif key == S.RIGHT and self.pos < len(self.buf):
|
|
114
111
|
self.move_right()
|
|
115
112
|
self.fillstate = FillState.USER
|
|
116
|
-
elif key
|
|
113
|
+
elif (key in [S.BEGINNING, S.CUSTOM_BEGINNING]) and self.pos > 0:
|
|
117
114
|
self.move_beginning()
|
|
118
115
|
self.fillstate = FillState.USER
|
|
119
|
-
elif key
|
|
116
|
+
elif (key in [S.END, S.CUSTOM_END]) and self.has_fill:
|
|
120
117
|
self.accept_fill()
|
|
121
118
|
self.fillstate = FillState.USER
|
|
122
|
-
elif key
|
|
119
|
+
elif (key in [S.END, S.CUSTOM_END]) and self.pos < len(self.buf):
|
|
123
120
|
self.move_end_buf()
|
|
124
121
|
self.fillstate = FillState.USER
|
|
125
122
|
elif key == S.TAB and (choices := self.valid_choices):
|
|
@@ -128,13 +125,25 @@ class ShellLineEditor: # pragma: nocover
|
|
|
128
125
|
elif key == S.SHIFT_TAB and self.index > -1:
|
|
129
126
|
self.index = (self.index - 1) % len(self.valid_choices)
|
|
130
127
|
self.fillstate = FillState.TAB
|
|
131
|
-
elif key
|
|
128
|
+
elif (key in [S.LEFT_WORD, S.CUSTOM_LEFTWORD]) and self.pos > 0:
|
|
132
129
|
while (self.pos > 0) and self.is_sep(self.pos - 1):
|
|
133
130
|
self.move_left()
|
|
134
131
|
while (self.pos > 0) and not self.is_sep(self.pos - 1):
|
|
135
132
|
self.move_left()
|
|
136
133
|
self.fillstate = FillState.USER
|
|
137
|
-
elif key
|
|
134
|
+
elif (key in [S.RIGHT_WORD, S.CUSTOM_RIGHTWORD]) and self.has_fill:
|
|
135
|
+
fill = self.fill
|
|
136
|
+
self.fillstate = FillState.USER
|
|
137
|
+
while fill:
|
|
138
|
+
char = fill[0]
|
|
139
|
+
self.write_key(char)
|
|
140
|
+
fill = fill[1:]
|
|
141
|
+
if char in S.SEPARATORS:
|
|
142
|
+
self.fillstate = FillState.TAB
|
|
143
|
+
self.index = self.valid_choices.index(self.buf + fill)
|
|
144
|
+
break
|
|
145
|
+
elif (key in [S.RIGHT_WORD, S.CUSTOM_RIGHTWORD]) and \
|
|
146
|
+
self.pos < len(self.buf):
|
|
138
147
|
while (self.pos < len(self.buf)) and self.is_sep(self.pos):
|
|
139
148
|
self.move_right()
|
|
140
149
|
while (self.pos < len(self.buf)) and not self.is_sep(self.pos):
|
|
@@ -151,6 +160,12 @@ class ShellLineEditor: # pragma: nocover
|
|
|
151
160
|
write(S.RETURN)
|
|
152
161
|
return self.buf
|
|
153
162
|
|
|
163
|
+
def write_key(self, key):
|
|
164
|
+
write(S.BOLD + key + self.buf[self.pos:] +
|
|
165
|
+
('\b' * (len(self.buf) - self.pos)) + S.RESET)
|
|
166
|
+
self.buf = self.buf[:self.pos] + key + self.buf[self.pos:]
|
|
167
|
+
self.pos += 1
|
|
168
|
+
|
|
154
169
|
def is_sep(self, pos):
|
|
155
170
|
return (self.buf[pos] in S.SEPARATORS)
|
|
156
171
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|