roysh 0.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
roysh/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .shell import main
2
+
3
+ __version__ = "0.1.0"
roysh/shell.py ADDED
@@ -0,0 +1,263 @@
1
+ import sys
2
+ import os
3
+ import subprocess
4
+ import shlex
5
+
6
+ # Handle readline import for different platforms
7
+ try:
8
+ import readline
9
+ except ImportError:
10
+ import pyreadline3 as readline
11
+
12
+ def extract_after_third_slash(command):
13
+ """Extracts the portion of the command after the third slash (/)"""
14
+ parts = command.split("/")
15
+ if len(parts) > 3:
16
+ return "/".join(parts[3:])
17
+ return command
18
+
19
+ def get_executables_from_path():
20
+ """Get list of executable files from PATH directories"""
21
+ executables = []
22
+ extensions = ['.exe', '.bat', '.cmd', ''] if os.name == 'nt' else ['']
23
+ path_sep = ';' if os.name == 'nt' else ':'
24
+
25
+ for directory in os.environ.get("PATH", "").split(path_sep):
26
+ try:
27
+ for file in os.listdir(directory):
28
+ file_path = os.path.join(directory, file)
29
+ # Check if the file has an executable extension on Windows
30
+ if os.name == 'nt':
31
+ file_name, file_ext = os.path.splitext(file.lower())
32
+ if file_ext not in extensions:
33
+ continue
34
+ if os.path.isfile(file_path) and os.access(file_path, os.X_OK):
35
+ # Remove extension for consistency
36
+ base_name = os.path.splitext(file)[0]
37
+ executables.append(base_name)
38
+ except OSError:
39
+ continue
40
+ return executables
41
+
42
+ def get_common_prefix(matches):
43
+ """Find the longest common prefix of all matches"""
44
+ if not matches:
45
+ return ""
46
+ if len(matches) == 1:
47
+ return matches[0]
48
+
49
+ reference = matches[0]
50
+
51
+ for i in range(len(reference)):
52
+ for other in matches[1:]:
53
+ if i >= len(other) or other[i] != reference[i]:
54
+ return reference[:i]
55
+
56
+ return reference
57
+
58
+ def get_matches(text):
59
+ """Get all matching commands for the given text"""
60
+ builtins = ["echo", "exit", "type", "pwd", "cd", "list"]
61
+ all_commands = builtins + get_executables_from_path()
62
+ return sorted(set(cmd for cmd in all_commands if cmd.startswith(text)))
63
+
64
+ def complete(text, state):
65
+ """Autocomplete callback for readline"""
66
+ matches = get_matches(text)
67
+
68
+ if not matches:
69
+ return None
70
+
71
+ if state == 0:
72
+ if len(matches) == 1:
73
+ return matches[0] + " "
74
+ else:
75
+ common = get_common_prefix(matches)
76
+ if common != text:
77
+ return common
78
+ sys.stdout.write('\a')
79
+ sys.stdout.flush()
80
+ print()
81
+ print(" ".join(matches))
82
+ sys.stdout.write("$ " + text)
83
+ sys.stdout.flush()
84
+ return text
85
+
86
+ return None
87
+
88
+ def get_installed_packages():
89
+ """Get list of installed Python packages"""
90
+ try:
91
+ import pkg_resources
92
+ return sorted([f"{dist.key} {dist.version}" for dist in pkg_resources.working_set])
93
+ except Exception:
94
+ return ["Error: Unable to fetch installed packages"]
95
+
96
+ def get_roysh_commands():
97
+ """Get list of roysh commands with descriptions"""
98
+ commands = {
99
+ "echo": "Print text to stdout",
100
+ "exit": "Exit the shell (optional: exit <code>)",
101
+ "type": "Show command type/location",
102
+ "pwd": "Print working directory",
103
+ "cd": "Change directory (defaults to HOME)",
104
+ "list": "List available commands or installed packages",
105
+ }
106
+ return commands
107
+
108
+ def main():
109
+ # Display welcome message
110
+ print("\nRoysh - Shell by Python")
111
+ print("Developed by Nishan Roy")
112
+ print("Type 'exit' to quit\n")
113
+
114
+ # Set up readline with our completer
115
+ readline.parse_and_bind('tab: complete')
116
+ readline.set_completer(complete)
117
+
118
+ # Define the list of built-in commands
119
+ builtins = {"echo", "exit", "type", "pwd", "cd", "list"}
120
+
121
+ while True:
122
+ # Display the shell prompt
123
+ sys.stdout.write("$ ")
124
+ sys.stdout.flush()
125
+ try:
126
+ # Read user input (readline will handle tab completion)
127
+ command = input().strip()
128
+
129
+ # Check for output redirection
130
+ output_file = None
131
+ error_file = None
132
+ append_mode = False
133
+ append_error_mode = False
134
+
135
+ if " 2>> " in command:
136
+ parts = command.split(" 2>> ", 1)
137
+ command = parts[0].strip()
138
+ error_file = parts[1].strip()
139
+ append_error_mode = True
140
+ elif " 2> " in command:
141
+ parts = command.split(" 2> ", 1)
142
+ command = parts[0].strip()
143
+ error_file = parts[1].strip()
144
+ elif " >> " in command or " 1>> " in command:
145
+ parts = command.split(" >> ", 1) if " >> " in command else command.split(" 1>> ", 1)
146
+ command = parts[0].strip()
147
+ output_file = parts[1].strip()
148
+ append_mode = True
149
+ elif " > " in command or " 1> " in command:
150
+ parts = command.split(" > ", 1) if " > " in command else command.split(" 1> ", 1)
151
+ command = parts[0].strip()
152
+ output_file = parts[1].strip()
153
+
154
+ # Parse input to handle quotes
155
+ args = shlex.split(command, posix=True)
156
+ if not args:
157
+ continue
158
+
159
+ # Save original stdout/stderr if we need to redirect
160
+ original_stdout = None
161
+ original_stderr = None
162
+
163
+ try:
164
+ if output_file:
165
+ original_stdout = sys.stdout
166
+ sys.stdout = open(output_file, 'a' if append_mode else 'w')
167
+ if error_file:
168
+ original_stderr = sys.stderr
169
+ sys.stderr = open(error_file, 'a' if append_error_mode else 'w')
170
+
171
+ cmd = args[0]
172
+ # Handle built-in commands
173
+ if cmd == "exit":
174
+ if len(args) > 1 and args[1].isdigit():
175
+ exit_code = int(args[1])
176
+ else:
177
+ exit_code = 0
178
+ sys.exit(exit_code)
179
+ elif cmd == "list":
180
+ if len(args) > 1 and args[1] == "packages":
181
+ packages = get_installed_packages()
182
+ for package in packages:
183
+ print(package)
184
+ else:
185
+ print("\nAvailable Roysh Commands:")
186
+ print("----------------------")
187
+ commands = get_roysh_commands()
188
+ for cmd_name, description in commands.items():
189
+ print(f"{cmd_name:<10} - {description}")
190
+ print("\nUsage:")
191
+ print("list - Show this help")
192
+ print("list packages - Show installed Python packages\n")
193
+ elif cmd == "type":
194
+ if len(args) < 2:
195
+ print("type: missing operand")
196
+ continue
197
+ cmd_to_check = args[1]
198
+ if cmd_to_check in builtins:
199
+ print(f"{cmd_to_check} is a shell builtin")
200
+ else:
201
+ found = False
202
+ for directory in os.environ["PATH"].split(":"):
203
+ command_path = os.path.join(directory, cmd_to_check)
204
+ if os.path.isfile(command_path) and os.access(command_path, os.X_OK):
205
+ print(f"{cmd_to_check} is {command_path}")
206
+ found = True
207
+ break
208
+ if not found:
209
+ print(f"{cmd_to_check}: not found")
210
+ elif cmd == "pwd":
211
+ print(os.getcwd())
212
+ elif cmd == "cd":
213
+ if len(args) < 2:
214
+ target_dir = os.environ.get("HOME", "/")
215
+ else:
216
+ target_dir = args[1]
217
+ if target_dir == "~":
218
+ target_dir = os.environ.get("HOME", "/")
219
+ try:
220
+ os.chdir(target_dir)
221
+ except FileNotFoundError:
222
+ print(f"cd: {target_dir}: No such file or directory")
223
+ except PermissionError:
224
+ print(f"cd: {target_dir}: Permission denied")
225
+ elif cmd == "echo":
226
+ print(" ".join(args[1:]))
227
+ else:
228
+ found = False
229
+ extensions = ['.exe', '.bat', '.cmd', ''] if os.name == 'nt' else ['']
230
+ for directory in os.environ["PATH"].split(os.pathsep):
231
+ for ext in extensions:
232
+ program_path = os.path.join(directory, cmd + ext)
233
+ if os.path.isfile(program_path) and os.access(program_path, os.X_OK):
234
+ found = True
235
+ try:
236
+ result = subprocess.run(
237
+ [program_path] + args[1:],
238
+ capture_output=True,
239
+ text=True,
240
+ )
241
+ if result.stdout:
242
+ print(result.stdout.strip())
243
+ if result.stderr:
244
+ print(result.stderr.strip(), file=sys.stderr)
245
+ except Exception as e:
246
+ print(f"Error running {cmd}: {e}", file=sys.stderr)
247
+ break
248
+ if found:
249
+ break
250
+ if not found:
251
+ print(f"{cmd}: not found")
252
+ finally:
253
+ if output_file and original_stdout:
254
+ sys.stdout.close()
255
+ sys.stdout = original_stdout
256
+ if error_file and original_stderr:
257
+ sys.stderr.close()
258
+ sys.stderr = original_stderr
259
+ except EOFError:
260
+ sys.exit(0)
261
+
262
+ if __name__ == "__main__":
263
+ main()
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.1
2
+ Name: roysh
3
+ Version: 0.1
4
+ Summary: A Python-based shell with tab completion
5
+ Home-page: https://github.com/nishanroy561/RoySH
6
+ Author: Nishan Roy
7
+ Author-email: nishanroy561@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: System :: Shells
14
+ Requires-Python: >=3.6
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: pyreadline3
17
+
18
+ # Roysh - A Python-based Shell
19
+
20
+ Roysh is a simple yet powerful Python-based shell that provides familiar shell functionality with tab completion support.
21
+
22
+ ## Features
23
+
24
+ - Interactive command-line interface
25
+ - Tab completion for commands and file paths
26
+ - Built-in shell commands
27
+ - Command output redirection
28
+ - Path-based command execution
29
+ - Cross-platform support
30
+
31
+ ## Installation
32
+
33
+ Install using pip:
34
+
35
+ ```bash
36
+ pip install roysh
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ Start the shell by running:
42
+
43
+ ```bash
44
+ roysh
45
+ ```
46
+
47
+ ### Built-in Commands
48
+
49
+ | Command | Description |
50
+ |---------|-------------|
51
+ | `echo [text]` | Print text to stdout |
52
+ | `exit [code]` | Exit the shell (optional status code) |
53
+ | `type <command>` | Show command type/location |
54
+ | `pwd` | Print working directory |
55
+ | `cd [path]` | Change directory (defaults to HOME) |
56
+
57
+ ### Output Redirection
58
+
59
+ Roysh supports standard output redirection operators:
60
+
61
+ | Operator | Description |
62
+ |----------|-------------|
63
+ | `>` | Redirect stdout to file (overwrite) |
64
+ | `>>` | Append stdout to file |
65
+ | `2>` | Redirect stderr to file (overwrite) |
66
+ | `2>>` | Append stderr to file |
67
+
68
+ ### Examples
69
+
70
+ ```bash
71
+ # Basic command usage
72
+ $ echo Hello World
73
+ Hello World
74
+
75
+ # Working with directories
76
+ $ pwd
77
+ /home/user
78
+ $ cd /tmp
79
+ $ pwd
80
+ /tmp
81
+
82
+ # Output redirection
83
+ $ echo "log entry" >> log.txt
84
+ $ echo "error message" 2> errors.txt
85
+
86
+ # Command information
87
+ $ type echo
88
+ echo is a shell builtin
89
+ $ type python
90
+ python is /usr/bin/python
91
+ ```
92
+
93
+ ## Contributing
94
+
95
+ Contributions are welcome! Please feel free to submit a Pull Request.
96
+
97
+ ## License
98
+
99
+ This project is licensed under the MIT License - see the LICENSE file for details.
100
+
101
+ ---
102
+ Developed by Nishan Roy
103
+ ```
@@ -0,0 +1,7 @@
1
+ roysh/__init__.py,sha256=8YND5SC_fWqv0C_bZCp0c56HU-wQCUlI1xzBY7fWHq4,49
2
+ roysh/shell.py,sha256=6MxZBS0PJvN5wxxtgb8gLr8RmDrDmtHwZ_y1qqVzYtU,10667
3
+ roysh-0.1.dist-info/METADATA,sha256=JwEVOef1tke0J56Vx7zJwSrmXwxkTdQBLmWJLaZAmGk,2306
4
+ roysh-0.1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
5
+ roysh-0.1.dist-info/entry_points.txt,sha256=ujz21BagQ6boNinTjOmAxCypk9ShJJW6NimV0Ukh9IY,37
6
+ roysh-0.1.dist-info/top_level.txt,sha256=g9yff3iyVU5f3JdBFdMYcIcKLRPL7iMCukSbrGmdA3A,6
7
+ roysh-0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ roysh = roysh:main
@@ -0,0 +1 @@
1
+ roysh