xmyshell 0.2.16__tar.gz → 0.2.18__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.
Files changed (29) hide show
  1. {xmyshell-0.2.16/xmyshell.egg-info → xmyshell-0.2.18}/PKG-INFO +10 -1
  2. {xmyshell-0.2.16 → xmyshell-0.2.18}/README.md +9 -0
  3. {xmyshell-0.2.16 → xmyshell-0.2.18}/pyproject.toml +1 -1
  4. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/environment.py +1 -0
  5. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/kernel.py +1 -1
  6. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/main.py +0 -2
  7. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/meta.py +3 -0
  8. {xmyshell-0.2.16 → xmyshell-0.2.18/xmyshell.egg-info}/PKG-INFO +10 -1
  9. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell.egg-info/SOURCES.txt +0 -1
  10. xmyshell-0.2.16/xmyshell/lexer.py +0 -259
  11. {xmyshell-0.2.16 → xmyshell-0.2.18}/LICENSE +0 -0
  12. {xmyshell-0.2.16 → xmyshell-0.2.18}/setup.cfg +0 -0
  13. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/__init__.py +0 -0
  14. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/__main__.py +0 -0
  15. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/completer.py +0 -0
  16. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/data/commands.json +0 -0
  17. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/init.py +0 -0
  18. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/injection.py +0 -0
  19. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/keybindings.py +0 -0
  20. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/stubs/__init__.py +0 -0
  21. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/stubs/__init__.pyi +0 -0
  22. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/stubs/py.typed +0 -0
  23. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/themes.py +0 -0
  24. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/update.py +0 -0
  25. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell/utils.py +0 -0
  26. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell.egg-info/dependency_links.txt +0 -0
  27. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell.egg-info/entry_points.txt +0 -0
  28. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell.egg-info/requires.txt +0 -0
  29. {xmyshell-0.2.16 → xmyshell-0.2.18}/xmyshell.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xmyshell
3
- Version: 0.2.16
3
+ Version: 0.2.18
4
4
  Summary: XmyShell is a shell-like tool built on top of prompt_toolkit which provides a persistent Python runtime.
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -163,6 +163,15 @@ The exit code of the last command.
163
163
  - `exec_duration`
164
164
  The duration which last command took.
165
165
 
166
+ - `last_error`
167
+ The error raised from last Python operation (if exists).
168
+
169
+ - `last_traceback`
170
+ The traceback of last Python operation (if exists).
171
+
172
+ - `ans`
173
+ The result from last print command.
174
+
166
175
  - `SHOW_WELCOME`
167
176
  Toggle whether to show welcome message when staring.
168
177
 
@@ -153,6 +153,15 @@ The exit code of the last command.
153
153
  - `exec_duration`
154
154
  The duration which last command took.
155
155
 
156
+ - `last_error`
157
+ The error raised from last Python operation (if exists).
158
+
159
+ - `last_traceback`
160
+ The traceback of last Python operation (if exists).
161
+
162
+ - `ans`
163
+ The result from last print command.
164
+
156
165
  - `SHOW_WELCOME`
157
166
  Toggle whether to show welcome message when staring.
158
167
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "xmyshell"
3
- version = "0.2.16"
3
+ version = "0.2.18"
4
4
  description = "XmyShell is a shell-like tool built on top of prompt_toolkit which provides a persistent Python runtime."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -43,6 +43,7 @@ _init_namespace: dict[str, Any] = {
43
43
  "exec_duration": 0,
44
44
  "last_error": None,
45
45
  "last_traceback": None,
46
+ "ans": None,
46
47
  "shell_prompt": "",
47
48
  "shell_rprompt": "",
48
49
  "prompt_placeholder": "",
@@ -189,10 +189,10 @@ def xmyshell_raw_command(cmd_line: str) -> int | None:
189
189
  result = eval(expr, dict(os.environ), namespace)
190
190
  print(result)
191
191
  namespace["last_error"] = None
192
+ namespace["ans"] = result
192
193
  return 0
193
194
  except Exception as e:
194
195
  import traceback
195
-
196
196
  namespace["last_error"] = e
197
197
  namespace["last_traceback"] = traceback.format_exc()
198
198
  pyerror(f"{type(e).__name__}: {e}")
@@ -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
@@ -57,6 +57,9 @@ Helper Functions:
57
57
  Built-in variables:
58
58
  exit_code - The exit code of the last command.
59
59
  exec_duration - The duration which last command took.
60
+ last_error - The error raised from last Python operation (if exists).
61
+ last_traceback - The traceback of last Python operation (if exists).
62
+ ans - The result from last print command.
60
63
  HOME_DIR - The home directory, similar to "~".
61
64
  PROFILE - The path of config file.
62
65
  SHOW_WELCOME - Toggle whether to show welcome message.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xmyshell
3
- Version: 0.2.16
3
+ Version: 0.2.18
4
4
  Summary: XmyShell is a shell-like tool built on top of prompt_toolkit which provides a persistent Python runtime.
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -163,6 +163,15 @@ The exit code of the last command.
163
163
  - `exec_duration`
164
164
  The duration which last command took.
165
165
 
166
+ - `last_error`
167
+ The error raised from last Python operation (if exists).
168
+
169
+ - `last_traceback`
170
+ The traceback of last Python operation (if exists).
171
+
172
+ - `ans`
173
+ The result from last print command.
174
+
166
175
  - `SHOW_WELCOME`
167
176
  Toggle whether to show welcome message when staring.
168
177
 
@@ -9,7 +9,6 @@ xmyshell/init.py
9
9
  xmyshell/injection.py
10
10
  xmyshell/kernel.py
11
11
  xmyshell/keybindings.py
12
- xmyshell/lexer.py
13
12
  xmyshell/main.py
14
13
  xmyshell/meta.py
15
14
  xmyshell/themes.py
@@ -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", "pwd", "help"]:
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