xmyshell 0.2.15__tar.gz → 0.2.17__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.
- {xmyshell-0.2.15/xmyshell.egg-info → xmyshell-0.2.17}/PKG-INFO +1 -1
- {xmyshell-0.2.15 → xmyshell-0.2.17}/pyproject.toml +1 -1
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/kernel.py +0 -18
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/main.py +0 -2
- {xmyshell-0.2.15 → xmyshell-0.2.17/xmyshell.egg-info}/PKG-INFO +1 -1
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell.egg-info/SOURCES.txt +0 -1
- xmyshell-0.2.15/xmyshell/lexer.py +0 -259
- {xmyshell-0.2.15 → xmyshell-0.2.17}/LICENSE +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/README.md +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/setup.cfg +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/__init__.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/__main__.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/completer.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/data/commands.json +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/environment.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/init.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/injection.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/keybindings.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/meta.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/stubs/__init__.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/stubs/__init__.pyi +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/stubs/py.typed +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/themes.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/update.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell/utils.py +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell.egg-info/dependency_links.txt +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell.egg-info/entry_points.txt +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell.egg-info/requires.txt +0 -0
- {xmyshell-0.2.15 → xmyshell-0.2.17}/xmyshell.egg-info/top_level.txt +0 -0
|
@@ -232,22 +232,6 @@ def xmyshell_raw_command(cmd_line: str) -> int | None:
|
|
|
232
232
|
pyerror(f"{type(e).__name__}: {e}")
|
|
233
233
|
return -1
|
|
234
234
|
|
|
235
|
-
def _fix_first_word(cmd_line: str) -> str:
|
|
236
|
-
# strip is unnecessary
|
|
237
|
-
if cmd_line.startswith('"'):
|
|
238
|
-
end = cmd_line.find('"', 1)
|
|
239
|
-
if end == -1:
|
|
240
|
-
return cmd_line
|
|
241
|
-
first = cmd_line[:end + 1]
|
|
242
|
-
rest = cmd_line[end + 1:]
|
|
243
|
-
else:
|
|
244
|
-
parts = cmd_line.split(None, 1)
|
|
245
|
-
first = parts[0]
|
|
246
|
-
rest = (" " + parts[1]) if len(parts) > 1 else ""
|
|
247
|
-
|
|
248
|
-
fixed = first.replace("/", "\\")
|
|
249
|
-
return fixed + rest
|
|
250
|
-
|
|
251
235
|
|
|
252
236
|
def xmyshell(cmd_line: str) -> int:
|
|
253
237
|
cmd_line = cmd_line.strip()
|
|
@@ -361,8 +345,6 @@ def xmyshell(cmd_line: str) -> int:
|
|
|
361
345
|
pyerror(f"source error: {e}")
|
|
362
346
|
return -1
|
|
363
347
|
|
|
364
|
-
if os.name == "nt":
|
|
365
|
-
cmd_line = _fix_first_word(cmd_line)
|
|
366
348
|
if target_var:
|
|
367
349
|
result = _run(
|
|
368
350
|
cmd_line, env=os.environ, capture_output=True, text=True
|
|
@@ -19,7 +19,6 @@ from .keybindings import (
|
|
|
19
19
|
)
|
|
20
20
|
from .init import xmyshell_init
|
|
21
21
|
from .kernel import pyeval, xmyshell
|
|
22
|
-
from .lexer import XmyShellLexer
|
|
23
22
|
from .injection import inject
|
|
24
23
|
|
|
25
24
|
def xmyshell_main() -> None:
|
|
@@ -35,7 +34,6 @@ def xmyshell_main() -> None:
|
|
|
35
34
|
complete_in_thread=True,
|
|
36
35
|
complete_while_typing=True,
|
|
37
36
|
key_bindings=bindings,
|
|
38
|
-
lexer=XmyShellLexer(),
|
|
39
37
|
)
|
|
40
38
|
session.default_buffer.on_cursor_position_changed += on_cursor_position_changed
|
|
41
39
|
session.default_buffer.on_text_changed += on_text_changed
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import keyword
|
|
3
|
-
import inspect
|
|
4
|
-
from collections.abc import Callable
|
|
5
|
-
from prompt_toolkit.lexers import Lexer
|
|
6
|
-
from prompt_toolkit.formatted_text import FormattedText
|
|
7
|
-
from .environment import namespace
|
|
8
|
-
|
|
9
|
-
def _is_number_literal(s: str) -> bool:
|
|
10
|
-
try:
|
|
11
|
-
import ast # lazy
|
|
12
|
-
result = ast.literal_eval(s)
|
|
13
|
-
return isinstance(result, (int, float, complex))
|
|
14
|
-
except (ValueError, SyntaxError):
|
|
15
|
-
return False
|
|
16
|
-
|
|
17
|
-
def _shell_split_keep_sep(text: str) -> list[str]:
|
|
18
|
-
parts: list[str] = []
|
|
19
|
-
quote: str | None = None
|
|
20
|
-
i = 0
|
|
21
|
-
n = len(text)
|
|
22
|
-
seg_start = 0
|
|
23
|
-
|
|
24
|
-
def flush(end: int) -> None:
|
|
25
|
-
nonlocal seg_start
|
|
26
|
-
if end > seg_start:
|
|
27
|
-
parts.append(text[seg_start:end])
|
|
28
|
-
seg_start = end
|
|
29
|
-
|
|
30
|
-
while i < n:
|
|
31
|
-
ch = text[i]
|
|
32
|
-
if quote is None:
|
|
33
|
-
if ch in " \t":
|
|
34
|
-
flush(i)
|
|
35
|
-
j = i
|
|
36
|
-
while j < n and text[j] in " \t":
|
|
37
|
-
j += 1
|
|
38
|
-
parts.append(text[i:j])
|
|
39
|
-
seg_start = j
|
|
40
|
-
i = j
|
|
41
|
-
continue
|
|
42
|
-
elif ch == "\\" and i + 1 < n:
|
|
43
|
-
i += 2
|
|
44
|
-
continue
|
|
45
|
-
elif ch in ("'", '"'):
|
|
46
|
-
quote = ch
|
|
47
|
-
else:
|
|
48
|
-
if ch == quote:
|
|
49
|
-
quote = None
|
|
50
|
-
elif ch == "\\" and quote == '"' and i + 1 < n:
|
|
51
|
-
i += 2
|
|
52
|
-
continue
|
|
53
|
-
i += 1
|
|
54
|
-
flush(n)
|
|
55
|
-
return parts
|
|
56
|
-
|
|
57
|
-
def _split_with_braces_and_pipes(line: str) -> list[str]:
|
|
58
|
-
parts = []
|
|
59
|
-
outer_buf = []
|
|
60
|
-
inner_buf = []
|
|
61
|
-
depth = 0
|
|
62
|
-
i = 0
|
|
63
|
-
n = len(line)
|
|
64
|
-
|
|
65
|
-
while i < n:
|
|
66
|
-
ch = line[i]
|
|
67
|
-
|
|
68
|
-
if i + 1 < n and ((ch == '{' and line[i+1] == '{') or (ch == '}' and line[i+1] == '}')):
|
|
69
|
-
seq = line[i:i+2]
|
|
70
|
-
if depth == 0:
|
|
71
|
-
outer_buf.extend(seq)
|
|
72
|
-
else:
|
|
73
|
-
inner_buf.extend(seq)
|
|
74
|
-
i += 2
|
|
75
|
-
continue
|
|
76
|
-
|
|
77
|
-
if ch == '{':
|
|
78
|
-
if depth == 0:
|
|
79
|
-
if outer_buf:
|
|
80
|
-
parts.append(''.join(outer_buf))
|
|
81
|
-
outer_buf = []
|
|
82
|
-
parts.append('{')
|
|
83
|
-
depth = 1
|
|
84
|
-
inner_buf = []
|
|
85
|
-
else:
|
|
86
|
-
inner_buf.append(ch)
|
|
87
|
-
depth += 1
|
|
88
|
-
i += 1
|
|
89
|
-
|
|
90
|
-
elif ch == '}':
|
|
91
|
-
if depth == 0:
|
|
92
|
-
outer_buf.append(ch)
|
|
93
|
-
else:
|
|
94
|
-
depth -= 1
|
|
95
|
-
if depth == 0:
|
|
96
|
-
parts.append(''.join(inner_buf))
|
|
97
|
-
parts.append('}')
|
|
98
|
-
inner_buf = []
|
|
99
|
-
else:
|
|
100
|
-
inner_buf.append(ch)
|
|
101
|
-
i += 1
|
|
102
|
-
|
|
103
|
-
elif ch == '|':
|
|
104
|
-
if depth == 0:
|
|
105
|
-
if outer_buf:
|
|
106
|
-
parts.append(''.join(outer_buf))
|
|
107
|
-
outer_buf = []
|
|
108
|
-
parts.append('|')
|
|
109
|
-
else:
|
|
110
|
-
inner_buf.append(ch)
|
|
111
|
-
i += 1
|
|
112
|
-
|
|
113
|
-
else:
|
|
114
|
-
if depth == 0:
|
|
115
|
-
outer_buf.append(ch)
|
|
116
|
-
else:
|
|
117
|
-
inner_buf.append(ch)
|
|
118
|
-
i += 1
|
|
119
|
-
|
|
120
|
-
if outer_buf:
|
|
121
|
-
parts.append(''.join(outer_buf))
|
|
122
|
-
|
|
123
|
-
if depth > 0 and inner_buf:
|
|
124
|
-
parts.append(''.join(inner_buf))
|
|
125
|
-
|
|
126
|
-
return parts
|
|
127
|
-
|
|
128
|
-
def _lex_cmd(cmd: str, first_word: bool = True) -> list[tuple[str, str]]:
|
|
129
|
-
parts: list[str] = _shell_split_keep_sep(cmd)
|
|
130
|
-
result: list[tuple[str, str]] = []
|
|
131
|
-
for part in parts:
|
|
132
|
-
if part == "":
|
|
133
|
-
continue
|
|
134
|
-
if part.isspace():
|
|
135
|
-
result.append(("", part))
|
|
136
|
-
continue
|
|
137
|
-
if first_word:
|
|
138
|
-
result.append(("ansigreen bold", part))
|
|
139
|
-
first_word = False
|
|
140
|
-
continue
|
|
141
|
-
if part.startswith("-"):
|
|
142
|
-
result.append(("ansibrightblue", part))
|
|
143
|
-
continue
|
|
144
|
-
# if part in keyword.kwlist:
|
|
145
|
-
# result.append(("ansibrightmagenta bold", part))
|
|
146
|
-
# continue
|
|
147
|
-
if _is_number_literal(part):
|
|
148
|
-
result.append(("ansibrightblue", part))
|
|
149
|
-
continue
|
|
150
|
-
result.append(("", part))
|
|
151
|
-
return result
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
STYLE_KEYWORD = "ansibrightmagenta bold"
|
|
155
|
-
STYLE_NUMBER = "ansiblue"
|
|
156
|
-
STYLE_VARIABLE = "ansibrightcyan"
|
|
157
|
-
STYLE_FUNCTION = "ansibrightblue"
|
|
158
|
-
STYLE_CLASS = "ansibrightred"
|
|
159
|
-
|
|
160
|
-
TOKEN_PATTERN = re.compile(r'[a-zA-Z_]\w*|\d+\.?\d*')
|
|
161
|
-
|
|
162
|
-
def _lex_python(text: str) -> list[tuple[str, str]]:
|
|
163
|
-
result = []
|
|
164
|
-
pos = 0
|
|
165
|
-
|
|
166
|
-
for match in TOKEN_PATTERN.finditer(text):
|
|
167
|
-
start, end = match.span()
|
|
168
|
-
if start > pos:
|
|
169
|
-
result.append(("", text[pos:start]))
|
|
170
|
-
|
|
171
|
-
token = match.group()
|
|
172
|
-
|
|
173
|
-
if token.isdigit() or (token.replace('.', '').isdigit() and token.count('.') <= 1):
|
|
174
|
-
result.append((STYLE_NUMBER, token))
|
|
175
|
-
elif keyword.iskeyword(token):
|
|
176
|
-
result.append((STYLE_KEYWORD, token))
|
|
177
|
-
else:
|
|
178
|
-
if token in namespace:
|
|
179
|
-
obj = namespace[token]
|
|
180
|
-
if inspect.isclass(obj):
|
|
181
|
-
style = STYLE_CLASS
|
|
182
|
-
elif callable(obj):
|
|
183
|
-
style = STYLE_FUNCTION
|
|
184
|
-
else:
|
|
185
|
-
style = STYLE_VARIABLE
|
|
186
|
-
else:
|
|
187
|
-
style = STYLE_VARIABLE
|
|
188
|
-
result.append((style, token))
|
|
189
|
-
|
|
190
|
-
pos = end
|
|
191
|
-
|
|
192
|
-
if pos < len(text):
|
|
193
|
-
result.append(("", text[pos:]))
|
|
194
|
-
|
|
195
|
-
return result
|
|
196
|
-
|
|
197
|
-
def _lex_sh(line: str) -> list[tuple[str, str]]:
|
|
198
|
-
result: list[tuple[str, str]] = []
|
|
199
|
-
parts: list[str] = _split_with_braces_and_pipes(line)
|
|
200
|
-
in_expr: bool = False
|
|
201
|
-
first_word: bool = True
|
|
202
|
-
for part in parts:
|
|
203
|
-
if part.startswith("|"):
|
|
204
|
-
first_word = True
|
|
205
|
-
result.append(("ansicyan", part))
|
|
206
|
-
elif part == "{":
|
|
207
|
-
result.append(("ansimagenta", "{"))
|
|
208
|
-
in_expr = True
|
|
209
|
-
first_word = False
|
|
210
|
-
elif part == "}":
|
|
211
|
-
result.append(("ansimagenta", "}"))
|
|
212
|
-
in_expr = False
|
|
213
|
-
elif in_expr:
|
|
214
|
-
result.extend(_lex_python(part))
|
|
215
|
-
else:
|
|
216
|
-
result.extend(_lex_cmd(part, first_word))
|
|
217
|
-
return result
|
|
218
|
-
|
|
219
|
-
def _lex_line(line: str) -> list[tuple[str, str]]:
|
|
220
|
-
|
|
221
|
-
result: list[tuple[str, str]] = []
|
|
222
|
-
|
|
223
|
-
target_var = None
|
|
224
|
-
if "=>" in line:
|
|
225
|
-
line, target_var = line.split("=>", 1)
|
|
226
|
-
|
|
227
|
-
leading_spaces = line[:len(line) - len(line.lstrip())]
|
|
228
|
-
_splited = line.lstrip().split(None, 1)
|
|
229
|
-
_cmd = _splited[0] if _splited else ""
|
|
230
|
-
if _cmd in ["pyexec", "print"]:
|
|
231
|
-
sh_cmd = None
|
|
232
|
-
if "|>" in line:
|
|
233
|
-
line, sh_cmd = line.split("|>", 1)
|
|
234
|
-
result.append(("", leading_spaces))
|
|
235
|
-
result.append(("ansigreen bold", _cmd))
|
|
236
|
-
result.extend(_lex_python(line[len(leading_spaces) + len(_cmd):]))
|
|
237
|
-
if sh_cmd is not None:
|
|
238
|
-
result.append(("ansiblue", "|>"))
|
|
239
|
-
result.extend(_lex_sh(sh_cmd))
|
|
240
|
-
else:
|
|
241
|
-
result.extend(_lex_sh(line))
|
|
242
|
-
|
|
243
|
-
if target_var is not None:
|
|
244
|
-
result.append(("ansiblue", "=>"))
|
|
245
|
-
result.append(("ansibrightcyan", target_var))
|
|
246
|
-
|
|
247
|
-
return result
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
class XmyShellLexer(Lexer):
|
|
251
|
-
def lex_document(self, document) -> Callable[[int], FormattedText]:
|
|
252
|
-
def _lex(line_number: int) -> FormattedText:
|
|
253
|
-
lines = document.text.splitlines()
|
|
254
|
-
if line_number >= len(lines):
|
|
255
|
-
return FormattedText([("", "")])
|
|
256
|
-
line = lines[line_number]
|
|
257
|
-
return FormattedText(_lex_line(line))
|
|
258
|
-
|
|
259
|
-
return _lex
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|