nercone-shell 0.1.0__py3-none-any.whl
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.
|
File without changes
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# -- nercone-shell ---------------------------------------------- #
|
|
4
|
+
# __main__.py on nercone-shell #
|
|
5
|
+
# Made by DiamondGotCat, Licensed under MIT License #
|
|
6
|
+
# Copyright (c) 2025 DiamondGotCat #
|
|
7
|
+
# ---------------------------------------------- DiamondGotCat -- #
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
import json
|
|
12
|
+
import glob
|
|
13
|
+
import shutil
|
|
14
|
+
import getpass
|
|
15
|
+
import readline
|
|
16
|
+
import subprocess
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from nercone_modern.color import ModernColor
|
|
19
|
+
from nercone_modern.text import ModernText
|
|
20
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
VERSION: str = version("nercone-shell")
|
|
24
|
+
except PackageNotFoundError:
|
|
25
|
+
VERSION: str = "0.0.0"
|
|
26
|
+
ENVIRONMENT: dict = {}
|
|
27
|
+
NERSH_AUTORUN: str = os.environ.get("NERSH_AUTORUN", None)
|
|
28
|
+
NERSH_PATH = Path(os.environ.get("NERSH_PATH", str(Path(Path("~").expanduser(), ".nercone", "nercone-shell"))))
|
|
29
|
+
NERSH_HISTORY_PATH = Path(os.environ.get("NERSH_HISTORY_PATH", str(Path(NERSH_PATH, "history.txt"))))
|
|
30
|
+
NERSH_CONFIG: dict = {}
|
|
31
|
+
NERSH_CONFIG_PATH = Path(os.environ.get("NERSH_CONFIG_PATH", str(Path(NERSH_PATH, "config.json"))))
|
|
32
|
+
NERSH_CONFIG_DEFAULT: dict = {
|
|
33
|
+
"override_env": {
|
|
34
|
+
"SHELL": f"{shutil.which('nersh')}"
|
|
35
|
+
},
|
|
36
|
+
"history": {
|
|
37
|
+
"path": f"{Path(NERSH_PATH, 'history.txt')}"
|
|
38
|
+
},
|
|
39
|
+
"autoruns": [
|
|
40
|
+
f"{Path(NERSH_PATH, 'autostart.sh')}"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class NershCompleter:
|
|
45
|
+
def __init__(self):
|
|
46
|
+
self.matches = []
|
|
47
|
+
|
|
48
|
+
def complete(self, text, state):
|
|
49
|
+
if state == 0:
|
|
50
|
+
full_line = readline.get_line_buffer()
|
|
51
|
+
line_to_cursor = full_line[:readline.get_begidx()]
|
|
52
|
+
if not line_to_cursor.strip() and ' ' not in text:
|
|
53
|
+
self.matches = self._complete_command(text)
|
|
54
|
+
else:
|
|
55
|
+
self.matches = self._complete_path(text)
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
return self.matches[state]
|
|
59
|
+
except IndexError:
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
def _complete_command(self, text):
|
|
63
|
+
results = set()
|
|
64
|
+
|
|
65
|
+
builtins = ['cd', 'exit']
|
|
66
|
+
for cmd in builtins:
|
|
67
|
+
if cmd.startswith(text):
|
|
68
|
+
results.add(cmd + " ")
|
|
69
|
+
|
|
70
|
+
path_dirs = os.environ.get("PATH", "").split(os.pathsep)
|
|
71
|
+
for p in path_dirs:
|
|
72
|
+
if not os.path.isdir(p):
|
|
73
|
+
continue
|
|
74
|
+
try:
|
|
75
|
+
for filename in os.listdir(p):
|
|
76
|
+
if filename.startswith(text):
|
|
77
|
+
results.add(filename + " ")
|
|
78
|
+
except (PermissionError, OSError):
|
|
79
|
+
continue
|
|
80
|
+
|
|
81
|
+
return sorted(list(results))
|
|
82
|
+
|
|
83
|
+
def _complete_path(self, text):
|
|
84
|
+
expanded_text = os.path.expanduser(text)
|
|
85
|
+
|
|
86
|
+
current_pwd = ENVIRONMENT.get("PWD", os.getcwd())
|
|
87
|
+
|
|
88
|
+
if os.path.isabs(expanded_text):
|
|
89
|
+
search_pattern = expanded_text + "*"
|
|
90
|
+
else:
|
|
91
|
+
search_pattern = os.path.join(current_pwd, expanded_text + "*")
|
|
92
|
+
|
|
93
|
+
glob_matches = glob.glob(search_pattern)
|
|
94
|
+
|
|
95
|
+
results = []
|
|
96
|
+
for match in glob_matches:
|
|
97
|
+
if os.path.isdir(match):
|
|
98
|
+
display_match = match + "/"
|
|
99
|
+
else:
|
|
100
|
+
display_match = match + " "
|
|
101
|
+
|
|
102
|
+
if not os.path.isabs(expanded_text) and not text.startswith("~"):
|
|
103
|
+
rel_path = os.path.relpath(match, current_pwd)
|
|
104
|
+
if os.path.isdir(match):
|
|
105
|
+
rel_path += "/"
|
|
106
|
+
else:
|
|
107
|
+
rel_path += " "
|
|
108
|
+
results.append(rel_path)
|
|
109
|
+
elif text.startswith("~"):
|
|
110
|
+
home = os.path.expanduser("~")
|
|
111
|
+
if match.startswith(home):
|
|
112
|
+
rel_home = "~" + match[len(home):]
|
|
113
|
+
if os.path.isdir(match):
|
|
114
|
+
rel_home += "/"
|
|
115
|
+
else:
|
|
116
|
+
rel_home += " "
|
|
117
|
+
results.append(rel_home)
|
|
118
|
+
else:
|
|
119
|
+
results.append(display_match)
|
|
120
|
+
else:
|
|
121
|
+
results.append(display_match)
|
|
122
|
+
|
|
123
|
+
return sorted(results)
|
|
124
|
+
|
|
125
|
+
def shorten_path(path: str) -> str:
|
|
126
|
+
path = os.path.abspath(path)
|
|
127
|
+
home = os.path.expanduser('~')
|
|
128
|
+
if path.startswith(home):
|
|
129
|
+
rel = os.path.relpath(path, home)
|
|
130
|
+
if rel == ".":
|
|
131
|
+
return "~"
|
|
132
|
+
parts = rel.split("/")
|
|
133
|
+
prefix = "~"
|
|
134
|
+
else:
|
|
135
|
+
parts = path.strip("/").split("/")
|
|
136
|
+
prefix = "/"
|
|
137
|
+
if len(parts) > 1:
|
|
138
|
+
shortened = [p[0] for p in parts[:-1]]
|
|
139
|
+
shortened.append(parts[-1])
|
|
140
|
+
path_str = "/".join(shortened)
|
|
141
|
+
elif parts:
|
|
142
|
+
path_str = parts[0]
|
|
143
|
+
else:
|
|
144
|
+
path_str = ""
|
|
145
|
+
if prefix == "~":
|
|
146
|
+
return f"~/{path_str}"
|
|
147
|
+
elif prefix == "/":
|
|
148
|
+
return f"/{path_str}"
|
|
149
|
+
return path_str
|
|
150
|
+
|
|
151
|
+
def reset():
|
|
152
|
+
global ENVIRONMENT, NERSH_CONFIG
|
|
153
|
+
ENVIRONMENT = {"PWD": f"{Path(Path("~").expanduser())}"}
|
|
154
|
+
NERSH_CONFIG = {}
|
|
155
|
+
reload()
|
|
156
|
+
|
|
157
|
+
def reload():
|
|
158
|
+
global ENVIRONMENT
|
|
159
|
+
load_config()
|
|
160
|
+
ENVIRONMENT |= os.environ
|
|
161
|
+
ENVIRONMENT |= NERSH_CONFIG.get("override_env", {})
|
|
162
|
+
|
|
163
|
+
def load_config(filepath: str | Path = NERSH_CONFIG_PATH) -> dict:
|
|
164
|
+
global NERSH_CONFIG
|
|
165
|
+
NERSH_PATH.mkdir(parents=True, exist_ok=True)
|
|
166
|
+
if not NERSH_CONFIG_PATH.is_file():
|
|
167
|
+
with NERSH_CONFIG_PATH.open("w") as f:
|
|
168
|
+
f.write(json.dumps(NERSH_CONFIG_DEFAULT, indent=4) + "\n")
|
|
169
|
+
with NERSH_CONFIG_PATH.open("r") as f:
|
|
170
|
+
NERSH_CONFIG |= json.loads(f.read())
|
|
171
|
+
for p in NERSH_CONFIG.get("autoruns", []):
|
|
172
|
+
if not Path(p).is_file():
|
|
173
|
+
with Path(p).open("w") as f:
|
|
174
|
+
f.write("\n")
|
|
175
|
+
return NERSH_CONFIG
|
|
176
|
+
|
|
177
|
+
def run_line(command: str) -> int:
|
|
178
|
+
args = command.strip().split(" ")
|
|
179
|
+
if args[0] == "cd":
|
|
180
|
+
target = " ".join(args[1:])
|
|
181
|
+
if not target:
|
|
182
|
+
ENVIRONMENT["PWD"] = f"{Path("~").expanduser()}"
|
|
183
|
+
|
|
184
|
+
target = os.path.expanduser(target)
|
|
185
|
+
target_path = Path(target)
|
|
186
|
+
|
|
187
|
+
if not target_path.is_absolute():
|
|
188
|
+
target_path = Path(ENVIRONMENT["PWD"]) / target_path
|
|
189
|
+
try:
|
|
190
|
+
resolved_path = target_path.resolve()
|
|
191
|
+
if resolved_path.is_dir():
|
|
192
|
+
ENVIRONMENT["PWD"] = str(resolved_path)
|
|
193
|
+
elif resolved_path.exists():
|
|
194
|
+
print(f"Not a directory: {target}")
|
|
195
|
+
else:
|
|
196
|
+
print(f"Not exist: {target}")
|
|
197
|
+
except FileNotFoundError:
|
|
198
|
+
print(f"Not exist: {target}")
|
|
199
|
+
elif args[0] == "exit":
|
|
200
|
+
readline.write_history_file(str(NERSH_HISTORY_PATH))
|
|
201
|
+
try:
|
|
202
|
+
raise SystemExit(int(args[1]))
|
|
203
|
+
except IndexError:
|
|
204
|
+
raise SystemExit(0)
|
|
205
|
+
else:
|
|
206
|
+
process = subprocess.run(command, cwd=ENVIRONMENT.get("PWD", None), env=ENVIRONMENT, shell=True, encoding="utf-8", stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)
|
|
207
|
+
return process.returncode
|
|
208
|
+
|
|
209
|
+
def run_script(script: str):
|
|
210
|
+
for line in script.split('\n'):
|
|
211
|
+
run_line(line)
|
|
212
|
+
|
|
213
|
+
def main() -> int:
|
|
214
|
+
reset()
|
|
215
|
+
completer = NershCompleter()
|
|
216
|
+
readline.set_completer(completer.complete)
|
|
217
|
+
if 'libedit' in readline.__doc__:
|
|
218
|
+
readline.parse_and_bind("bind ^I rl_complete")
|
|
219
|
+
else:
|
|
220
|
+
readline.parse_and_bind("tab: complete")
|
|
221
|
+
readline.set_completer_delims(' \t\n;')
|
|
222
|
+
if NERSH_AUTORUN:
|
|
223
|
+
run_script(NERSH_AUTORUN)
|
|
224
|
+
if NERSH_HISTORY_PATH.is_file():
|
|
225
|
+
readline.read_history_file(NERSH_HISTORY_PATH)
|
|
226
|
+
while True:
|
|
227
|
+
try:
|
|
228
|
+
command = input(f"{ModernColor.GREEN}{getpass.getuser()}{ModernColor.RESET}@{os.uname()[1].rsplit('.', 1)[0]} {ModernColor.GREEN}{shorten_path(ENVIRONMENT.get('PWD', f'{Path('~').expanduser()}'))}{ModernColor.RESET}> ")
|
|
229
|
+
run_line(command)
|
|
230
|
+
except KeyboardInterrupt:
|
|
231
|
+
print()
|
|
232
|
+
continue
|
|
233
|
+
except EOFError:
|
|
234
|
+
print()
|
|
235
|
+
break
|
|
236
|
+
|
|
237
|
+
if __name__ == "__main__":
|
|
238
|
+
main()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: nercone-shell
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Modern shell for Developers
|
|
5
|
+
Author: Nercone
|
|
6
|
+
Author-email: Nercone <nercone@diamondgotcat.net>
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Dist: nercone-modern
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# Nersh (Nercone Shell)
|
|
16
|
+
Modern shell for Developers
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
nercone_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
nercone_shell/__main__.py,sha256=XZMZr52fPFmobbDvx0KFGars2MVQB6MS3a6ZPjmHWZM,7856
|
|
3
|
+
nercone_shell-0.1.0.dist-info/WHEEL,sha256=YUH1mBqsx8Dh2cQG2rlcuRYUhJddG9iClegy4IgnHik,79
|
|
4
|
+
nercone_shell-0.1.0.dist-info/entry_points.txt,sha256=STrGlvrPc2Rr5ktWVfiZ_5Lr7i1GcfOMvsTxL6768sw,55
|
|
5
|
+
nercone_shell-0.1.0.dist-info/METADATA,sha256=svOEvZBQr7afUHxu6Cvek9_AXV7U_j393Vxja_H3aNM,465
|
|
6
|
+
nercone_shell-0.1.0.dist-info/RECORD,,
|