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.
Files changed (25) hide show
  1. {xmyshell-0.1.4/xmyshell.egg-info → xmyshell-0.2.1}/PKG-INFO +23 -1
  2. {xmyshell-0.1.4 → xmyshell-0.2.1}/README.md +22 -0
  3. {xmyshell-0.1.4 → xmyshell-0.2.1}/pyproject.toml +1 -1
  4. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/completer.py +12 -3
  5. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/data/commands.json +1 -1
  6. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/environment.py +13 -1
  7. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/kernel.py +50 -19
  8. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/meta.py +15 -4
  9. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/update.py +3 -4
  10. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/utils.py +5 -0
  11. {xmyshell-0.1.4 → xmyshell-0.2.1/xmyshell.egg-info}/PKG-INFO +23 -1
  12. {xmyshell-0.1.4 → xmyshell-0.2.1}/LICENSE +0 -0
  13. {xmyshell-0.1.4 → xmyshell-0.2.1}/setup.cfg +0 -0
  14. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/__init__.py +0 -0
  15. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/__main__.py +0 -0
  16. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/init.py +0 -0
  17. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/keybindings.py +0 -0
  18. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/lexer.py +0 -0
  19. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/main.py +0 -0
  20. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell/themes.py +0 -0
  21. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell.egg-info/SOURCES.txt +0 -0
  22. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell.egg-info/dependency_links.txt +0 -0
  23. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell.egg-info/entry_points.txt +0 -0
  24. {xmyshell-0.1.4 → xmyshell-0.2.1}/xmyshell.egg-info/requires.txt +0 -0
  25. {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.4
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.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "xmyshell"
3
- version = "0.1.4"
3
+ version = "0.2.1"
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"
@@ -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
@@ -1,5 +1,5 @@
1
1
  {
2
- "xmyshell": { "_global": ["--help", "--version"] },
2
+ "xmyshell": { "_global": ["--help", "--version", "--update"] },
3
3
  "git": {
4
4
  "_global": ["--help", "--version"],
5
5
  "add": {
@@ -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
- from .environment import namespace
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
- from .update import xmyshell_update
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() - current username
48
- getcwd() - current working directory
49
- dirname(p) - parent directory of path
50
- basename(p) - final component of path
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
- print("Press <Enter> to continue ...", end="")
22
+ if os.name == "nt":
23
+ print("Press <Enter> to continue ...", end="")
25
24
  sys.exit(returncode)
26
25
 
27
26
  if __name__ == "__main__":
@@ -33,3 +33,8 @@ def getcwd() -> str:
33
33
  return os.getcwd()
34
34
 
35
35
  HOME_DIR = os.path.expanduser("~").replace('\\', '/')
36
+
37
+ def xmyshell_cat(file_path: str) -> str:
38
+ file_path = os.path.expanduser(file_path)
39
+ with open(file_path, "r") as f:
40
+ return f.read()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xmyshell
3
- Version: 0.1.4
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