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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.11
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ nersh = nercone_shell.__main__:main
3
+