xmyshell 0.1.4__tar.gz → 0.2.1__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.1.4/xmyshell.egg-info → xmyshell-0.2.1}/PKG-INFO +23 -1
- {xmyshell-0.1.4 → xmyshell-0.2.1}/README.md +22 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/pyproject.toml +1 -1
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/completer.py +12 -3
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/data/commands.json +1 -1
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/environment.py +13 -1
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/kernel.py +50 -19
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/meta.py +15 -4
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/update.py +3 -4
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/utils.py +5 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1/xmyshell.egg-info}/PKG-INFO +23 -1
- {xmyshell-0.1.4 → xmyshell-0.2.1}/LICENSE +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/setup.cfg +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/__init__.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/__main__.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/init.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/keybindings.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/lexer.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/main.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/themes.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell.egg-info/SOURCES.txt +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell.egg-info/dependency_links.txt +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell.egg-info/entry_points.txt +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell.egg-info/requires.txt +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.1}/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.1
|
|
3
|
+
Version: 0.2.1
|
|
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
|
|
@@ -112,6 +112,12 @@ or
|
|
|
112
112
|
❯ update 0.1.3
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
- Alias
|
|
116
|
+
```
|
|
117
|
+
❯ alias ll='ls -lh'
|
|
118
|
+
❯ unalias ll
|
|
119
|
+
```
|
|
120
|
+
|
|
115
121
|
- Syntax highlighting via `prompt_toolkit`
|
|
116
122
|
- Powerful auto-completion, history search, and automatic bracket/quote pairing
|
|
117
123
|
- Startup configuration: `~/.xmyshell/config.py` loaded at launch
|
|
@@ -131,6 +137,16 @@ Returns the parent directory of a path.
|
|
|
131
137
|
- `basename(path)`
|
|
132
138
|
Returns the final component of a path.
|
|
133
139
|
|
|
140
|
+
- `cat(file)`
|
|
141
|
+
Shortcut for `open(file).read()`.
|
|
142
|
+
|
|
143
|
+
- `alias(altname, target)`
|
|
144
|
+
Same as the command.
|
|
145
|
+
|
|
146
|
+
- `unalias(altname)`
|
|
147
|
+
Same as the command.
|
|
148
|
+
|
|
149
|
+
|
|
134
150
|
### Reserved global varibles
|
|
135
151
|
- `exit_code`
|
|
136
152
|
The exit code of the last command.
|
|
@@ -138,6 +154,12 @@ The exit code of the last command.
|
|
|
138
154
|
- `exec_duration`
|
|
139
155
|
The duration which last command took.
|
|
140
156
|
|
|
157
|
+
- `HOME_DIR`
|
|
158
|
+
The home directory, similar to `~`.
|
|
159
|
+
|
|
160
|
+
- `PROFILE`
|
|
161
|
+
The path of config file.
|
|
162
|
+
|
|
141
163
|
### Keyboard Shortcuts
|
|
142
164
|
- `↑↓` -> Navigate through command history.
|
|
143
165
|
- `→` -> Apply selected history entry to the prompt.
|
|
@@ -102,6 +102,12 @@ or
|
|
|
102
102
|
❯ update 0.1.3
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
- Alias
|
|
106
|
+
```
|
|
107
|
+
❯ alias ll='ls -lh'
|
|
108
|
+
❯ unalias ll
|
|
109
|
+
```
|
|
110
|
+
|
|
105
111
|
- Syntax highlighting via `prompt_toolkit`
|
|
106
112
|
- Powerful auto-completion, history search, and automatic bracket/quote pairing
|
|
107
113
|
- Startup configuration: `~/.xmyshell/config.py` loaded at launch
|
|
@@ -121,6 +127,16 @@ Returns the parent directory of a path.
|
|
|
121
127
|
- `basename(path)`
|
|
122
128
|
Returns the final component of a path.
|
|
123
129
|
|
|
130
|
+
- `cat(file)`
|
|
131
|
+
Shortcut for `open(file).read()`.
|
|
132
|
+
|
|
133
|
+
- `alias(altname, target)`
|
|
134
|
+
Same as the command.
|
|
135
|
+
|
|
136
|
+
- `unalias(altname)`
|
|
137
|
+
Same as the command.
|
|
138
|
+
|
|
139
|
+
|
|
124
140
|
### Reserved global varibles
|
|
125
141
|
- `exit_code`
|
|
126
142
|
The exit code of the last command.
|
|
@@ -128,6 +144,12 @@ The exit code of the last command.
|
|
|
128
144
|
- `exec_duration`
|
|
129
145
|
The duration which last command took.
|
|
130
146
|
|
|
147
|
+
- `HOME_DIR`
|
|
148
|
+
The home directory, similar to `~`.
|
|
149
|
+
|
|
150
|
+
- `PROFILE`
|
|
151
|
+
The path of config file.
|
|
152
|
+
|
|
131
153
|
### Keyboard Shortcuts
|
|
132
154
|
- `↑↓` -> Navigate through command history.
|
|
133
155
|
- `→` -> Apply selected history entry to the prompt.
|
|
@@ -8,7 +8,7 @@ import pkgutil
|
|
|
8
8
|
from string import whitespace
|
|
9
9
|
from prompt_toolkit.completion import Completer, Completion
|
|
10
10
|
from prompt_toolkit.document import Document
|
|
11
|
-
from .environment import namespace
|
|
11
|
+
from .environment import namespace, aliases
|
|
12
12
|
from .utils import truncate
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@ MAX_DISPLAY_LEN = 24
|
|
|
16
16
|
MAX_META_LEN = 12
|
|
17
17
|
|
|
18
18
|
BUILTINS = ("cd", "cp", "cat", "echo", "exit", "import", "ls", "print", "pyexec", "pwd", "source",
|
|
19
|
-
"clear", "grep", "find", "from", "mkdir", "rm", "reload", "mv", "help")
|
|
19
|
+
"clear", "grep", "find", "from", "mkdir", "rm", "reload", "mv", "help", "alias", "update")
|
|
20
20
|
|
|
21
21
|
COMMON = (
|
|
22
22
|
"python", "python3", "pip", "pip3", "git", "conda", "uv",
|
|
@@ -328,7 +328,16 @@ class ShellCompleter(Completer):
|
|
|
328
328
|
if " " not in lstripped:
|
|
329
329
|
if len(lstripped) < 1:
|
|
330
330
|
return
|
|
331
|
+
for alias in aliases.keys():
|
|
332
|
+
if alias.startswith(lstripped):
|
|
333
|
+
yield Completion(
|
|
334
|
+
alias,
|
|
335
|
+
start_position=-len(lstripped),
|
|
336
|
+
display=truncate(alias, MAX_DISPLAY_LEN),
|
|
337
|
+
display_meta="alias",
|
|
338
|
+
)
|
|
331
339
|
for cmd in self._get_commands():
|
|
340
|
+
if cmd in aliases: return
|
|
332
341
|
if cmd.startswith(lstripped):
|
|
333
342
|
meta = "command" if cmd in BUILTINS else "program"
|
|
334
343
|
yield Completion(
|
|
@@ -342,7 +351,7 @@ class ShellCompleter(Completer):
|
|
|
342
351
|
parts = lstripped.split()
|
|
343
352
|
if len(parts) >= 1:
|
|
344
353
|
cmd = parts[0]
|
|
345
|
-
if cmd in ("print", "pyexec"):
|
|
354
|
+
if cmd in ("print", "pyexec", "alias"):
|
|
346
355
|
param_text = lstripped[len(cmd):].lstrip()
|
|
347
356
|
yield from self._python_completion(param_text)
|
|
348
357
|
return
|
|
@@ -5,12 +5,20 @@ import time
|
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
from typing import Any
|
|
7
7
|
from collections.abc import Mapping
|
|
8
|
-
from .utils import XMYSHELL_MAGIC, getcwd, getlogin, HOME_DIR
|
|
8
|
+
from .utils import XMYSHELL_MAGIC, getcwd, getlogin, HOME_DIR, xmyshell_cat
|
|
9
9
|
|
|
10
10
|
namespace: dict[str, Any] = {}
|
|
11
|
+
aliases: dict[str, str] = {}
|
|
11
12
|
init_environ: dict[str, str] = dict(os.environ)
|
|
12
13
|
|
|
13
14
|
|
|
15
|
+
def xmyshell_alias(altname: str, target: str) -> None:
|
|
16
|
+
aliases.update({altname: target})
|
|
17
|
+
|
|
18
|
+
def xmyshell_unalias(altname: str) -> None:
|
|
19
|
+
aliases.pop(altname)
|
|
20
|
+
|
|
21
|
+
|
|
14
22
|
_init_namespace: dict[str, Any] = {
|
|
15
23
|
"_xmyshell_magic": XMYSHELL_MAGIC,
|
|
16
24
|
"__builtins__": __builtins__,
|
|
@@ -23,7 +31,11 @@ _init_namespace: dict[str, Any] = {
|
|
|
23
31
|
"getcwd": getcwd,
|
|
24
32
|
"dirname": os.path.dirname,
|
|
25
33
|
"basename": os.path.basename,
|
|
34
|
+
"cat": xmyshell_cat,
|
|
35
|
+
"alias": xmyshell_alias,
|
|
36
|
+
"unalias": xmyshell_unalias,
|
|
26
37
|
"HOME_DIR": HOME_DIR,
|
|
38
|
+
"PROFILE": f"{HOME_DIR}/.xmyshell/config.py",
|
|
27
39
|
"exit_code": 0,
|
|
28
40
|
"exec_duration": 0,
|
|
29
41
|
"last_error": None,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
from collections.abc import Generator, Sequence
|
|
1
2
|
import os
|
|
2
3
|
import sys
|
|
3
4
|
import runpy
|
|
4
5
|
import subprocess
|
|
5
|
-
|
|
6
|
+
import shlex
|
|
7
|
+
from .environment import namespace, aliases, xmyshell_alias, xmyshell_unalias
|
|
6
8
|
from .utils import pywarning, pyerror, getcwd
|
|
7
9
|
from .meta import HELP_MESSAGE
|
|
8
10
|
|
|
@@ -52,6 +54,10 @@ def pyeval(cmd_line: str) -> str:
|
|
|
52
54
|
if expr:
|
|
53
55
|
try:
|
|
54
56
|
val = eval(expr, dict(os.environ), namespace)
|
|
57
|
+
if not isinstance(
|
|
58
|
+
val, (str, bytes, bytearray, memoryview)
|
|
59
|
+
) and isinstance(val, (Sequence, Generator)):
|
|
60
|
+
val = shlex.join(str(ele) for ele in val)
|
|
55
61
|
result.append(str(val) if val is not None else '')
|
|
56
62
|
except Exception as e:
|
|
57
63
|
pywarning(f"An error occured when unfolding {expr!r}, using original string instead"
|
|
@@ -116,6 +122,28 @@ def xmyshell_raw_command(cmd_line: str) -> int | None:
|
|
|
116
122
|
pyerror(f"{type(e).__name__}: {e}")
|
|
117
123
|
return -1
|
|
118
124
|
|
|
125
|
+
case "alias":
|
|
126
|
+
code: str = cmd_line[len(command):].strip()
|
|
127
|
+
if not code:
|
|
128
|
+
pyerror("export: missing code")
|
|
129
|
+
return -1
|
|
130
|
+
try:
|
|
131
|
+
altname, alias_target = code.split('=', 1)
|
|
132
|
+
altname = altname.strip()
|
|
133
|
+
xmyshell_alias(altname, eval(alias_target, namespace, {}))
|
|
134
|
+
return 0
|
|
135
|
+
except Exception as e:
|
|
136
|
+
pyerror(f"{type(e).__name__}: {e}")
|
|
137
|
+
return -1
|
|
138
|
+
|
|
139
|
+
case "unalias":
|
|
140
|
+
name: str = cmd_line[len(command):].strip()
|
|
141
|
+
if not name:
|
|
142
|
+
pyerror("export: missing name")
|
|
143
|
+
return -1
|
|
144
|
+
xmyshell_unalias(name)
|
|
145
|
+
return 0
|
|
146
|
+
|
|
119
147
|
case "print":
|
|
120
148
|
expr = cmd_line[len(command):].strip()
|
|
121
149
|
if not expr:
|
|
@@ -134,11 +162,26 @@ def xmyshell_raw_command(cmd_line: str) -> int | None:
|
|
|
134
162
|
return 0
|
|
135
163
|
|
|
136
164
|
case "update":
|
|
137
|
-
|
|
138
|
-
subprocess.run(
|
|
165
|
+
returncode = subprocess.run(
|
|
139
166
|
[sys.executable, "-m", "xmyshell.update"]
|
|
140
167
|
+ (args[1:] if len(args) > 1 else [])
|
|
141
|
-
)
|
|
168
|
+
).returncode
|
|
169
|
+
return returncode
|
|
170
|
+
|
|
171
|
+
case "help":
|
|
172
|
+
print(HELP_MESSAGE)
|
|
173
|
+
return 0
|
|
174
|
+
|
|
175
|
+
case "clear":
|
|
176
|
+
print("\033[2J\033[H", end="")
|
|
177
|
+
return 0
|
|
178
|
+
|
|
179
|
+
case "pwd":
|
|
180
|
+
print(getcwd())
|
|
181
|
+
return 0
|
|
182
|
+
|
|
183
|
+
case "exit":
|
|
184
|
+
sys.exit(0)
|
|
142
185
|
|
|
143
186
|
if command.startswith("import") or command.startswith("from"):
|
|
144
187
|
try:
|
|
@@ -225,6 +268,9 @@ def xmyshell(cmd_line: str) -> int:
|
|
|
225
268
|
if not cmd_line:
|
|
226
269
|
return 0
|
|
227
270
|
|
|
271
|
+
args = cmd_line.split()
|
|
272
|
+
args[0] = aliases.get(args[0], args[0])
|
|
273
|
+
cmd_line = " ".join(args)
|
|
228
274
|
args = cmd_line.split()
|
|
229
275
|
command = args[0]
|
|
230
276
|
|
|
@@ -252,14 +298,6 @@ def xmyshell(cmd_line: str) -> int:
|
|
|
252
298
|
pyerror(f"not a directory: '{target_dir}'")
|
|
253
299
|
return -1
|
|
254
300
|
|
|
255
|
-
case "help":
|
|
256
|
-
print(HELP_MESSAGE)
|
|
257
|
-
return 0
|
|
258
|
-
|
|
259
|
-
case "clear":
|
|
260
|
-
print("\033[2J\033[H", end="")
|
|
261
|
-
return 0
|
|
262
|
-
|
|
263
301
|
case "source":
|
|
264
302
|
if len(args) < 2:
|
|
265
303
|
pyerror("source: missing script")
|
|
@@ -271,13 +309,6 @@ def xmyshell(cmd_line: str) -> int:
|
|
|
271
309
|
pyerror(f"source error: {e}")
|
|
272
310
|
return -1
|
|
273
311
|
|
|
274
|
-
case "pwd":
|
|
275
|
-
print(getcwd())
|
|
276
|
-
return 0
|
|
277
|
-
|
|
278
|
-
case "exit":
|
|
279
|
-
sys.exit(0)
|
|
280
|
-
|
|
281
312
|
if os.name == "nt":
|
|
282
313
|
cmd_line = _fix_first_word(cmd_line)
|
|
283
314
|
if target_var:
|
|
@@ -29,6 +29,8 @@ Built-in Commands:
|
|
|
29
29
|
cd <dir> Change directory (supports {{expr}}).
|
|
30
30
|
pwd Print working directory.
|
|
31
31
|
clear Clear the terminal screen.
|
|
32
|
+
alias altname=<cmd> Create an alias command.
|
|
33
|
+
unalias altname Remove an alias command.
|
|
32
34
|
exit Exit XmyShell.
|
|
33
35
|
|
|
34
36
|
Inline Python:
|
|
@@ -44,10 +46,19 @@ IO:
|
|
|
44
46
|
Example: print "\\n".join(str(i) for i in range(100)) |> grep 42
|
|
45
47
|
|
|
46
48
|
Helper Functions:
|
|
47
|
-
getlogin()
|
|
48
|
-
getcwd()
|
|
49
|
-
dirname(p)
|
|
50
|
-
basename(p)
|
|
49
|
+
getlogin() - current username
|
|
50
|
+
getcwd() - current working directory
|
|
51
|
+
dirname(p) - parent directory of path
|
|
52
|
+
basename(p) - final component of path
|
|
53
|
+
cat(file) - Shortcut for open(file).read().
|
|
54
|
+
alias(altname, cmd) - Same as the command.
|
|
55
|
+
unalias(altname) - Same as the command.
|
|
56
|
+
|
|
57
|
+
Built-in variables:
|
|
58
|
+
exit_code - The exit code of the last command.
|
|
59
|
+
exec_duration - The duration which last command took.
|
|
60
|
+
HOME_DIR - The home directory, similar to "~".
|
|
61
|
+
PROFILE - The path of config file.
|
|
51
62
|
|
|
52
63
|
Keyboard Shortcuts:
|
|
53
64
|
↑↓ - Navigate through command history.
|
|
@@ -6,8 +6,6 @@ import subprocess
|
|
|
6
6
|
def xmyshell_update(version: str | None = None) -> None:
|
|
7
7
|
if os.name == "nt":
|
|
8
8
|
subprocess.run("taskkill /F /IM xmyshell.exe", shell=True)
|
|
9
|
-
else:
|
|
10
|
-
subprocess.run(["pkill", "-f", "-x", "xmyshell"])
|
|
11
9
|
|
|
12
10
|
time.sleep(1)
|
|
13
11
|
|
|
@@ -19,9 +17,10 @@ def xmyshell_update(version: str | None = None) -> None:
|
|
|
19
17
|
"--upgrade",
|
|
20
18
|
"xmyshell" + (f"=={version}" if version else ""),
|
|
21
19
|
]
|
|
22
|
-
print()
|
|
20
|
+
if os.name == "nt": print()
|
|
23
21
|
returncode = subprocess.run(install_args).returncode
|
|
24
|
-
|
|
22
|
+
if os.name == "nt":
|
|
23
|
+
print("Press <Enter> to continue ...", end="")
|
|
25
24
|
sys.exit(returncode)
|
|
26
25
|
|
|
27
26
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xmyshell
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
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
|
|
@@ -112,6 +112,12 @@ or
|
|
|
112
112
|
❯ update 0.1.3
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
- Alias
|
|
116
|
+
```
|
|
117
|
+
❯ alias ll='ls -lh'
|
|
118
|
+
❯ unalias ll
|
|
119
|
+
```
|
|
120
|
+
|
|
115
121
|
- Syntax highlighting via `prompt_toolkit`
|
|
116
122
|
- Powerful auto-completion, history search, and automatic bracket/quote pairing
|
|
117
123
|
- Startup configuration: `~/.xmyshell/config.py` loaded at launch
|
|
@@ -131,6 +137,16 @@ Returns the parent directory of a path.
|
|
|
131
137
|
- `basename(path)`
|
|
132
138
|
Returns the final component of a path.
|
|
133
139
|
|
|
140
|
+
- `cat(file)`
|
|
141
|
+
Shortcut for `open(file).read()`.
|
|
142
|
+
|
|
143
|
+
- `alias(altname, target)`
|
|
144
|
+
Same as the command.
|
|
145
|
+
|
|
146
|
+
- `unalias(altname)`
|
|
147
|
+
Same as the command.
|
|
148
|
+
|
|
149
|
+
|
|
134
150
|
### Reserved global varibles
|
|
135
151
|
- `exit_code`
|
|
136
152
|
The exit code of the last command.
|
|
@@ -138,6 +154,12 @@ The exit code of the last command.
|
|
|
138
154
|
- `exec_duration`
|
|
139
155
|
The duration which last command took.
|
|
140
156
|
|
|
157
|
+
- `HOME_DIR`
|
|
158
|
+
The home directory, similar to `~`.
|
|
159
|
+
|
|
160
|
+
- `PROFILE`
|
|
161
|
+
The path of config file.
|
|
162
|
+
|
|
141
163
|
### Keyboard Shortcuts
|
|
142
164
|
- `↑↓` -> Navigate through command history.
|
|
143
165
|
- `→` -> Apply selected history entry to the prompt.
|
|
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
|