xmyshell 0.1.4__tar.gz → 0.2.0__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.0}/PKG-INFO +19 -1
- {xmyshell-0.1.4 → xmyshell-0.2.0}/README.md +18 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/pyproject.toml +1 -1
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/completer.py +2 -2
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/data/commands.json +1 -1
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/environment.py +8 -1
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/kernel.py +40 -16
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/meta.py +13 -4
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/update.py +3 -4
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/utils.py +5 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0/xmyshell.egg-info}/PKG-INFO +19 -1
- {xmyshell-0.1.4 → xmyshell-0.2.0}/LICENSE +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/setup.cfg +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/__init__.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/__main__.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/init.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/keybindings.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/lexer.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/main.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell/themes.py +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell.egg-info/SOURCES.txt +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell.egg-info/dependency_links.txt +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell.egg-info/entry_points.txt +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/xmyshell.egg-info/requires.txt +0 -0
- {xmyshell-0.1.4 → xmyshell-0.2.0}/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.
|
|
3
|
+
Version: 0.2.0
|
|
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,11 @@ or
|
|
|
112
112
|
❯ update 0.1.3
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
- Alias
|
|
116
|
+
```
|
|
117
|
+
❯ alias ll='ls -lh'
|
|
118
|
+
```
|
|
119
|
+
|
|
115
120
|
- Syntax highlighting via `prompt_toolkit`
|
|
116
121
|
- Powerful auto-completion, history search, and automatic bracket/quote pairing
|
|
117
122
|
- Startup configuration: `~/.xmyshell/config.py` loaded at launch
|
|
@@ -131,6 +136,13 @@ Returns the parent directory of a path.
|
|
|
131
136
|
- `basename(path)`
|
|
132
137
|
Returns the final component of a path.
|
|
133
138
|
|
|
139
|
+
- `cat(file)`
|
|
140
|
+
Shortcut for `open(file).read()`.
|
|
141
|
+
|
|
142
|
+
- `alias(altname, target)`
|
|
143
|
+
Same as the command.
|
|
144
|
+
|
|
145
|
+
|
|
134
146
|
### Reserved global varibles
|
|
135
147
|
- `exit_code`
|
|
136
148
|
The exit code of the last command.
|
|
@@ -138,6 +150,12 @@ The exit code of the last command.
|
|
|
138
150
|
- `exec_duration`
|
|
139
151
|
The duration which last command took.
|
|
140
152
|
|
|
153
|
+
- `HOME_DIR`
|
|
154
|
+
The home directory, similar to `~`.
|
|
155
|
+
|
|
156
|
+
- `PROFILE`
|
|
157
|
+
The path of config file.
|
|
158
|
+
|
|
141
159
|
### Keyboard Shortcuts
|
|
142
160
|
- `↑↓` -> Navigate through command history.
|
|
143
161
|
- `→` -> Apply selected history entry to the prompt.
|
|
@@ -102,6 +102,11 @@ or
|
|
|
102
102
|
❯ update 0.1.3
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
- Alias
|
|
106
|
+
```
|
|
107
|
+
❯ alias ll='ls -lh'
|
|
108
|
+
```
|
|
109
|
+
|
|
105
110
|
- Syntax highlighting via `prompt_toolkit`
|
|
106
111
|
- Powerful auto-completion, history search, and automatic bracket/quote pairing
|
|
107
112
|
- Startup configuration: `~/.xmyshell/config.py` loaded at launch
|
|
@@ -121,6 +126,13 @@ Returns the parent directory of a path.
|
|
|
121
126
|
- `basename(path)`
|
|
122
127
|
Returns the final component of a path.
|
|
123
128
|
|
|
129
|
+
- `cat(file)`
|
|
130
|
+
Shortcut for `open(file).read()`.
|
|
131
|
+
|
|
132
|
+
- `alias(altname, target)`
|
|
133
|
+
Same as the command.
|
|
134
|
+
|
|
135
|
+
|
|
124
136
|
### Reserved global varibles
|
|
125
137
|
- `exit_code`
|
|
126
138
|
The exit code of the last command.
|
|
@@ -128,6 +140,12 @@ The exit code of the last command.
|
|
|
128
140
|
- `exec_duration`
|
|
129
141
|
The duration which last command took.
|
|
130
142
|
|
|
143
|
+
- `HOME_DIR`
|
|
144
|
+
The home directory, similar to `~`.
|
|
145
|
+
|
|
146
|
+
- `PROFILE`
|
|
147
|
+
The path of config file.
|
|
148
|
+
|
|
131
149
|
### Keyboard Shortcuts
|
|
132
150
|
- `↑↓` -> Navigate through command history.
|
|
133
151
|
- `→` -> Apply selected history entry to the prompt.
|
|
@@ -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",
|
|
@@ -342,7 +342,7 @@ class ShellCompleter(Completer):
|
|
|
342
342
|
parts = lstripped.split()
|
|
343
343
|
if len(parts) >= 1:
|
|
344
344
|
cmd = parts[0]
|
|
345
|
-
if cmd in ("print", "pyexec"):
|
|
345
|
+
if cmd in ("print", "pyexec", "alias"):
|
|
346
346
|
param_text = lstripped[len(cmd):].lstrip()
|
|
347
347
|
yield from self._python_completion(param_text)
|
|
348
348
|
return
|
|
@@ -5,11 +5,15 @@ 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
|
|
|
14
|
+
def xmyshell_alias(source: str, target: str) -> None:
|
|
15
|
+
aliases.update({source: target})
|
|
16
|
+
|
|
13
17
|
|
|
14
18
|
_init_namespace: dict[str, Any] = {
|
|
15
19
|
"_xmyshell_magic": XMYSHELL_MAGIC,
|
|
@@ -23,7 +27,10 @@ _init_namespace: dict[str, Any] = {
|
|
|
23
27
|
"getcwd": getcwd,
|
|
24
28
|
"dirname": os.path.dirname,
|
|
25
29
|
"basename": os.path.basename,
|
|
30
|
+
"cat": xmyshell_cat,
|
|
31
|
+
"alias": xmyshell_alias,
|
|
26
32
|
"HOME_DIR": HOME_DIR,
|
|
33
|
+
"PROFILE": f"{HOME_DIR}/.xmyshell/config.py",
|
|
27
34
|
"exit_code": 0,
|
|
28
35
|
"exec_duration": 0,
|
|
29
36
|
"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
|
|
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,20 @@ 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
|
+
alias_source, alias_target = code.split('=', 1)
|
|
132
|
+
alias_source = alias_source.strip()
|
|
133
|
+
aliases[alias_source] = eval(alias_target, namespace, {})
|
|
134
|
+
return 0
|
|
135
|
+
except Exception as e:
|
|
136
|
+
pyerror(f"{type(e).__name__}: {e}")
|
|
137
|
+
return -1
|
|
138
|
+
|
|
119
139
|
case "print":
|
|
120
140
|
expr = cmd_line[len(command):].strip()
|
|
121
141
|
if not expr:
|
|
@@ -139,6 +159,22 @@ def xmyshell_raw_command(cmd_line: str) -> int | None:
|
|
|
139
159
|
[sys.executable, "-m", "xmyshell.update"]
|
|
140
160
|
+ (args[1:] if len(args) > 1 else [])
|
|
141
161
|
)
|
|
162
|
+
return 0
|
|
163
|
+
|
|
164
|
+
case "help":
|
|
165
|
+
print(HELP_MESSAGE)
|
|
166
|
+
return 0
|
|
167
|
+
|
|
168
|
+
case "clear":
|
|
169
|
+
print("\033[2J\033[H", end="")
|
|
170
|
+
return 0
|
|
171
|
+
|
|
172
|
+
case "pwd":
|
|
173
|
+
print(getcwd())
|
|
174
|
+
return 0
|
|
175
|
+
|
|
176
|
+
case "exit":
|
|
177
|
+
sys.exit(0)
|
|
142
178
|
|
|
143
179
|
if command.startswith("import") or command.startswith("from"):
|
|
144
180
|
try:
|
|
@@ -225,6 +261,9 @@ def xmyshell(cmd_line: str) -> int:
|
|
|
225
261
|
if not cmd_line:
|
|
226
262
|
return 0
|
|
227
263
|
|
|
264
|
+
args = cmd_line.split()
|
|
265
|
+
args[0] = aliases.get(args[0], args[0])
|
|
266
|
+
cmd_line = " ".join(args)
|
|
228
267
|
args = cmd_line.split()
|
|
229
268
|
command = args[0]
|
|
230
269
|
|
|
@@ -252,14 +291,6 @@ def xmyshell(cmd_line: str) -> int:
|
|
|
252
291
|
pyerror(f"not a directory: '{target_dir}'")
|
|
253
292
|
return -1
|
|
254
293
|
|
|
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
294
|
case "source":
|
|
264
295
|
if len(args) < 2:
|
|
265
296
|
pyerror("source: missing script")
|
|
@@ -271,13 +302,6 @@ def xmyshell(cmd_line: str) -> int:
|
|
|
271
302
|
pyerror(f"source error: {e}")
|
|
272
303
|
return -1
|
|
273
304
|
|
|
274
|
-
case "pwd":
|
|
275
|
-
print(getcwd())
|
|
276
|
-
return 0
|
|
277
|
-
|
|
278
|
-
case "exit":
|
|
279
|
-
sys.exit(0)
|
|
280
|
-
|
|
281
305
|
if os.name == "nt":
|
|
282
306
|
cmd_line = _fix_first_word(cmd_line)
|
|
283
307
|
if target_var:
|
|
@@ -29,6 +29,7 @@ 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.
|
|
32
33
|
exit Exit XmyShell.
|
|
33
34
|
|
|
34
35
|
Inline Python:
|
|
@@ -44,10 +45,18 @@ IO:
|
|
|
44
45
|
Example: print "\\n".join(str(i) for i in range(100)) |> grep 42
|
|
45
46
|
|
|
46
47
|
Helper Functions:
|
|
47
|
-
getlogin()
|
|
48
|
-
getcwd()
|
|
49
|
-
dirname(p)
|
|
50
|
-
basename(p)
|
|
48
|
+
getlogin() - current username
|
|
49
|
+
getcwd() - current working directory
|
|
50
|
+
dirname(p) - parent directory of path
|
|
51
|
+
basename(p) - final component of path
|
|
52
|
+
cat(file) - Shortcut for open(file).read().
|
|
53
|
+
alias(altname, cmd) - Same as the command.
|
|
54
|
+
|
|
55
|
+
Built-in variables:
|
|
56
|
+
exit_code - The exit code of the last command.
|
|
57
|
+
exec_duration - The duration which last command took.
|
|
58
|
+
HOME_DIR - The home directory, similar to "~".
|
|
59
|
+
PROFILE - The path of config file.
|
|
51
60
|
|
|
52
61
|
Keyboard Shortcuts:
|
|
53
62
|
↑↓ - 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.
|
|
3
|
+
Version: 0.2.0
|
|
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,11 @@ or
|
|
|
112
112
|
❯ update 0.1.3
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
- Alias
|
|
116
|
+
```
|
|
117
|
+
❯ alias ll='ls -lh'
|
|
118
|
+
```
|
|
119
|
+
|
|
115
120
|
- Syntax highlighting via `prompt_toolkit`
|
|
116
121
|
- Powerful auto-completion, history search, and automatic bracket/quote pairing
|
|
117
122
|
- Startup configuration: `~/.xmyshell/config.py` loaded at launch
|
|
@@ -131,6 +136,13 @@ Returns the parent directory of a path.
|
|
|
131
136
|
- `basename(path)`
|
|
132
137
|
Returns the final component of a path.
|
|
133
138
|
|
|
139
|
+
- `cat(file)`
|
|
140
|
+
Shortcut for `open(file).read()`.
|
|
141
|
+
|
|
142
|
+
- `alias(altname, target)`
|
|
143
|
+
Same as the command.
|
|
144
|
+
|
|
145
|
+
|
|
134
146
|
### Reserved global varibles
|
|
135
147
|
- `exit_code`
|
|
136
148
|
The exit code of the last command.
|
|
@@ -138,6 +150,12 @@ The exit code of the last command.
|
|
|
138
150
|
- `exec_duration`
|
|
139
151
|
The duration which last command took.
|
|
140
152
|
|
|
153
|
+
- `HOME_DIR`
|
|
154
|
+
The home directory, similar to `~`.
|
|
155
|
+
|
|
156
|
+
- `PROFILE`
|
|
157
|
+
The path of config file.
|
|
158
|
+
|
|
141
159
|
### Keyboard Shortcuts
|
|
142
160
|
- `↑↓` -> Navigate through command history.
|
|
143
161
|
- `→` -> 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
|