mirror of
https://github.com/m4rcel-lol/m5rcode-ubuntu.git
synced 2025-12-06 19:13:57 +05:30
Uploading m5rcode Ubuntu Port to the repo
This commit is contained in:
BIN
commands/__pycache__/cmd_cd.cpython-313.pyc
Normal file
BIN
commands/__pycache__/cmd_cd.cpython-313.pyc
Normal file
Binary file not shown.
BIN
commands/__pycache__/cmd_credits.cpython-313.pyc
Normal file
BIN
commands/__pycache__/cmd_credits.cpython-313.pyc
Normal file
Binary file not shown.
BIN
commands/__pycache__/cmd_exit.cpython-313.pyc
Normal file
BIN
commands/__pycache__/cmd_exit.cpython-313.pyc
Normal file
Binary file not shown.
BIN
commands/__pycache__/cmd_fastfetch.cpython-313.pyc
Normal file
BIN
commands/__pycache__/cmd_fastfetch.cpython-313.pyc
Normal file
Binary file not shown.
BIN
commands/__pycache__/cmd_nano.cpython-313.pyc
Normal file
BIN
commands/__pycache__/cmd_nano.cpython-313.pyc
Normal file
Binary file not shown.
BIN
commands/__pycache__/cmd_new.cpython-313.pyc
Normal file
BIN
commands/__pycache__/cmd_new.cpython-313.pyc
Normal file
Binary file not shown.
BIN
commands/__pycache__/cmd_run.cpython-313.pyc
Normal file
BIN
commands/__pycache__/cmd_run.cpython-313.pyc
Normal file
Binary file not shown.
BIN
commands/__pycache__/cmd_wdir.cpython-313.pyc
Normal file
BIN
commands/__pycache__/cmd_wdir.cpython-313.pyc
Normal file
Binary file not shown.
46
commands/cmd_cd.py
Normal file
46
commands/cmd_cd.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# commands/cmd_cd.py
|
||||
import os
|
||||
from colorama import Fore
|
||||
|
||||
class CdCommand:
|
||||
def __init__(self, files_dir, shell_ref, target_dir):
|
||||
# files_dir = ~/m5rcode/files
|
||||
self.files_dir = files_dir
|
||||
self.project_root = os.path.dirname(files_dir) # ~/m5rcode
|
||||
self.shell = shell_ref[0] # the M5RShell instance
|
||||
self.target = target_dir.strip()
|
||||
|
||||
def run(self):
|
||||
if not self.target or self.target == '.':
|
||||
# Stay in current directory
|
||||
return
|
||||
|
||||
# Compute new absolute path
|
||||
candidate = os.path.abspath(
|
||||
os.path.normpath(
|
||||
os.path.join(self.shell.cwd, self.target)
|
||||
)
|
||||
)
|
||||
|
||||
# If they typed '..' from files_dir, allow up to project_root
|
||||
if self.target == '..':
|
||||
# from files_dir → project_root
|
||||
if self.shell.cwd == self.files_dir:
|
||||
new_path = self.project_root
|
||||
# from any subfolder of files_dir → one level up, but not above project_root
|
||||
else:
|
||||
new_path = os.path.dirname(self.shell.cwd)
|
||||
if not new_path.startswith(self.project_root):
|
||||
new_path = self.project_root
|
||||
else:
|
||||
new_path = candidate
|
||||
|
||||
# Check it stays within project_root
|
||||
if not new_path.startswith(self.project_root):
|
||||
print(Fore.RED + "Access denied: You cannot leave the m5rcode project.")
|
||||
return
|
||||
|
||||
if os.path.isdir(new_path):
|
||||
self.shell.cwd = new_path
|
||||
else:
|
||||
print(Fore.RED + f"No such directory: {self.target}")
|
||||
47
commands/cmd_credits.py
Normal file
47
commands/cmd_credits.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from colorama import Fore, Style
|
||||
from pyfiglet import Figlet
|
||||
|
||||
def strip_ansi(text):
|
||||
import re
|
||||
return re.sub(r'\x1b\[[0-9;]*m', '', text)
|
||||
|
||||
class CreditsCommand:
|
||||
def run(self):
|
||||
box_width = 70
|
||||
inner_width = box_width - 2
|
||||
fig = Figlet(font='slant')
|
||||
credits = [
|
||||
(f"{Style.BRIGHT}{Fore.CYAN}m5rcel{Style.RESET_ALL}", "Lead Developer"),
|
||||
(f"{Style.BRIGHT}{Fore.YELLOW}pythonjs.cfd{Style.RESET_ALL}", "Project Hosting & Deployment"),
|
||||
(f"{Style.BRIGHT}{Fore.MAGENTA}colorama{Style.RESET_ALL}", "Used for terminal styling"),
|
||||
(f"{Style.BRIGHT}{Fore.GREEN}fastfetch inspired{Style.RESET_ALL}", "Design influence"),
|
||||
(f"{Style.BRIGHT}{Fore.RED}openai.com{Style.RESET_ALL}", "Some smart AI help ;)"),
|
||||
]
|
||||
|
||||
# Top border
|
||||
print(Fore.MAGENTA + "╔" + "═" * inner_width + "╗")
|
||||
|
||||
# Figlet "CREDITS" title, trimmed/padded and centered vertically
|
||||
credits_title_lines = fig.renderText("CREDITS").splitlines()
|
||||
for line in credits_title_lines:
|
||||
if line.strip() == '': continue
|
||||
raw = line[:inner_width]
|
||||
pad = (inner_width - len(strip_ansi(raw))) // 2
|
||||
out = " " * pad + raw
|
||||
out = out[:inner_width]
|
||||
out = out + " " * (inner_width - len(strip_ansi(out)))
|
||||
print(Fore.MAGENTA + "║" + Fore.LIGHTMAGENTA_EX + out + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╟" + "─" * inner_width + "╢")
|
||||
|
||||
# Content, each line padded to match box width
|
||||
for name, role in credits:
|
||||
left = f"{name:<25}"
|
||||
dash = f"{Fore.CYAN}━{Style.RESET_ALL}"
|
||||
right = f"{Fore.LIGHTWHITE_EX}{role}{Style.RESET_ALL}"
|
||||
raw_text = f"{left} {dash} {right}"
|
||||
raw_len = len(strip_ansi(raw_text))
|
||||
line = raw_text + " " * (inner_width - raw_len)
|
||||
print(Fore.MAGENTA + "║" + line + Fore.MAGENTA + "║")
|
||||
|
||||
# Bottom border
|
||||
print(Fore.MAGENTA + "╚" + "═" * inner_width + "╝" + Style.RESET_ALL)
|
||||
163
commands/cmd_dir.py
Normal file
163
commands/cmd_dir.py
Normal file
@@ -0,0 +1,163 @@
|
||||
import os
|
||||
from colorama import Fore, Style
|
||||
import re
|
||||
|
||||
def strip_ansi(text):
|
||||
return re.sub(r'\x1b\[[0-9;]*m', '', text)
|
||||
|
||||
class DirCommand:
|
||||
def __init__(self, cwd, target):
|
||||
self.cwd = cwd
|
||||
self.target = target if target else cwd
|
||||
|
||||
def run(self):
|
||||
path = os.path.abspath(os.path.join(self.cwd, self.target))
|
||||
box_min = 60
|
||||
|
||||
if not os.path.exists(path):
|
||||
# Error box
|
||||
width = max(box_min, len(f"No such file or directory: {self.target}") + 10)
|
||||
print(Fore.RED + "╔" + "═" * (width - 2) + "╗")
|
||||
error_msg = f"No such file or directory: {self.target}"
|
||||
print(Fore.RED + "║" + error_msg.center(width - 2) + "║")
|
||||
print(Fore.RED + "╚" + "═" * (width - 2) + "╝" + Style.RESET_ALL)
|
||||
return
|
||||
|
||||
if os.path.isfile(path):
|
||||
# Single file info box
|
||||
file_size = os.path.getsize(path)
|
||||
if file_size > 1024*1024:
|
||||
size_str = f"{file_size/(1024*1024):.1f} MB"
|
||||
elif file_size > 1024:
|
||||
size_str = f"{file_size/1024:.1f} KB"
|
||||
else:
|
||||
size_str = f"{file_size} B"
|
||||
|
||||
width = max(box_min, len(self.target) + 20)
|
||||
print(Fore.MAGENTA + "╔" + "═" * (width - 2) + "╗")
|
||||
title = "File Information"
|
||||
print(Fore.MAGENTA + "║" + Fore.CYAN + Style.BRIGHT + title.center(width - 2) + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╟" + "─" * (width - 2) + "╢")
|
||||
|
||||
name_line = f"Name: {Fore.LIGHTWHITE_EX}{self.target}{Style.RESET_ALL}"
|
||||
size_line = f"Size: {Fore.LIGHTWHITE_EX}{size_str}{Style.RESET_ALL}"
|
||||
type_line = f"Type: {Fore.LIGHTWHITE_EX}File{Style.RESET_ALL}"
|
||||
|
||||
for line in [name_line, size_line, type_line]:
|
||||
pad = " " * (width - 2 - len(strip_ansi(line)))
|
||||
print(Fore.MAGENTA + "║" + line + pad + Fore.MAGENTA + "║")
|
||||
|
||||
print(Fore.MAGENTA + "╚" + "═" * (width - 2) + "╝" + Style.RESET_ALL)
|
||||
return
|
||||
|
||||
# Directory listing
|
||||
try:
|
||||
items = os.listdir(path)
|
||||
if not items:
|
||||
# Empty directory
|
||||
width = box_min
|
||||
print(Fore.MAGENTA + "╔" + "═" * (width - 2) + "╗")
|
||||
title = f"Directory: {os.path.basename(path) or 'Root'}"
|
||||
print(Fore.MAGENTA + "║" + Fore.CYAN + Style.BRIGHT + title.center(width - 2) + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╟" + "─" * (width - 2) + "╢")
|
||||
empty_msg = "Directory is empty"
|
||||
print(Fore.MAGENTA + "║" + Fore.YELLOW + empty_msg.center(width - 2) + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╚" + "═" * (width - 2) + "╝" + Style.RESET_ALL)
|
||||
return
|
||||
|
||||
# Calculate columns for nice layout
|
||||
name_col = 35
|
||||
type_col = 12
|
||||
size_col = 15
|
||||
total_width = name_col + type_col + size_col + 6 # spaces + borders
|
||||
width = max(box_min, total_width)
|
||||
|
||||
# Separate files and directories
|
||||
dirs = []
|
||||
files = []
|
||||
for item in sorted(items):
|
||||
full_path = os.path.join(path, item)
|
||||
if os.path.isdir(full_path):
|
||||
dirs.append(item)
|
||||
else:
|
||||
try:
|
||||
size = os.path.getsize(full_path)
|
||||
if size > 1024*1024:
|
||||
size_str = f"{size/(1024*1024):.1f} MB"
|
||||
elif size > 1024:
|
||||
size_str = f"{size/1024:.1f} KB"
|
||||
else:
|
||||
size_str = f"{size} B"
|
||||
except:
|
||||
size_str = "Unknown"
|
||||
files.append((item, size_str))
|
||||
|
||||
# Header
|
||||
print(Fore.MAGENTA + "╔" + "═" * (width - 2) + "╗")
|
||||
title = f"Directory: {os.path.basename(path) or 'Root'}"
|
||||
print(Fore.MAGENTA + "║" + Fore.CYAN + Style.BRIGHT + title.center(width - 2) + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╟" + "─" * (width - 2) + "╢")
|
||||
|
||||
# Column headers
|
||||
header = (
|
||||
Fore.LIGHTMAGENTA_EX + Style.BRIGHT +
|
||||
f"{'Name':<{name_col}} {'Type':<{type_col}} {'Size':<{size_col}}" +
|
||||
Style.RESET_ALL
|
||||
)
|
||||
pad = " " * (width - 2 - len(strip_ansi(header)))
|
||||
print(Fore.MAGENTA + "║" + header + pad + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╟" + "─" * (width - 2) + "╢")
|
||||
|
||||
# List directories first
|
||||
for dirname in dirs:
|
||||
name = (dirname[:name_col-2] + "..") if len(dirname) > name_col-1 else dirname
|
||||
name_colored = f"{Fore.BLUE + Style.BRIGHT}{name:<{name_col}}{Style.RESET_ALL}"
|
||||
type_colored = f"{Fore.LIGHTCYAN_EX}Directory{Style.RESET_ALL}"
|
||||
size_colored = f"{Style.DIM}-{Style.RESET_ALL}"
|
||||
|
||||
row = f"{name_colored} {type_colored:<{type_col}} {size_colored:<{size_col}}"
|
||||
pad = " " * (width - 2 - len(strip_ansi(row)))
|
||||
print(Fore.MAGENTA + "║" + row + pad + Fore.MAGENTA + "║")
|
||||
|
||||
# List files
|
||||
for filename, file_size in files:
|
||||
name = (filename[:name_col-2] + "..") if len(filename) > name_col-1 else filename
|
||||
name_colored = f"{Fore.LIGHTWHITE_EX}{name:<{name_col}}{Style.RESET_ALL}"
|
||||
|
||||
# File type based on extension
|
||||
if '.' in filename:
|
||||
ext = filename.split('.')[-1].lower()
|
||||
if ext in ['txt', 'md', 'log']:
|
||||
type_color = Fore.GREEN
|
||||
elif ext in ['py', 'js', 'html', 'css', 'php']:
|
||||
type_color = Fore.YELLOW
|
||||
elif ext in ['jpg', 'png', 'gif', 'bmp']:
|
||||
type_color = Fore.MAGENTA
|
||||
elif ext in ['mp3', 'wav', 'mp4', 'avi']:
|
||||
type_color = Fore.CYAN
|
||||
else:
|
||||
type_color = Fore.WHITE
|
||||
file_type = f".{ext} file"
|
||||
else:
|
||||
type_color = Fore.WHITE
|
||||
file_type = "File"
|
||||
|
||||
type_colored = f"{type_color}{file_type:<{type_col}}{Style.RESET_ALL}"
|
||||
size_colored = f"{Style.DIM}{Fore.LIGHTWHITE_EX}{file_size:<{size_col}}{Style.RESET_ALL}"
|
||||
|
||||
row = f"{name_colored} {type_colored} {size_colored}"
|
||||
pad = " " * (width - 2 - len(strip_ansi(row)))
|
||||
print(Fore.MAGENTA + "║" + row + pad + Fore.MAGENTA + "║")
|
||||
|
||||
# Footer with count
|
||||
print(Fore.MAGENTA + "╟" + "─" * (width - 2) + "╢")
|
||||
count_msg = f"{len(dirs)} directories, {len(files)} files"
|
||||
print(Fore.MAGENTA + "║" + Fore.LIGHTBLACK_EX + Style.DIM + count_msg.center(width - 2) + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╚" + "═" * (width - 2) + "╝" + Style.RESET_ALL)
|
||||
|
||||
except PermissionError:
|
||||
width = box_min
|
||||
print(Fore.RED + "╔" + "═" * (width - 2) + "╗")
|
||||
error_msg = "Access denied"
|
||||
print(Fore.RED + "║" + error_msg.center(width - 2) + "║")
|
||||
print(Fore.RED + "╚" + "═" * (width - 2) + "╝" + Style.RESET_ALL)
|
||||
72
commands/cmd_exit.py
Normal file
72
commands/cmd_exit.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from colorama import Fore, Style
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
|
||||
class ExitCommand:
|
||||
def shutdown_animation(self):
|
||||
# Clear screen for clean shutdown
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
|
||||
# Shutdown sequence messages
|
||||
shutdown_msgs = [
|
||||
"Stopping Discord RPC Integration...",
|
||||
"Saving shell session...",
|
||||
"Clearing command history...",
|
||||
"Stopping background processes...",
|
||||
"Unmounting m5rcode directories...",
|
||||
"Finalizing cleanup...",
|
||||
"Thank you for using m5rcode shell!"
|
||||
]
|
||||
|
||||
print(Fore.LIGHTBLACK_EX + "m5rOS Shutdown Sequence" + Style.RESET_ALL)
|
||||
print(Fore.LIGHTBLACK_EX + "=" * 25 + Style.RESET_ALL)
|
||||
|
||||
for i, msg in enumerate(shutdown_msgs):
|
||||
time.sleep(0.3)
|
||||
if i == len(shutdown_msgs) - 1:
|
||||
# Last message in cyan
|
||||
print(Fore.CYAN + Style.BRIGHT + f"[ OK ] {msg}" + Style.RESET_ALL)
|
||||
else:
|
||||
# Regular messages in white/grey
|
||||
color = Fore.WHITE if i % 2 == 0 else Fore.LIGHTBLACK_EX
|
||||
print(color + f"[ OK ] {msg}" + Style.RESET_ALL)
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
# Animated "powering down" effect
|
||||
print()
|
||||
sys.stdout.write(Fore.LIGHTMAGENTA_EX + "Powering down")
|
||||
for _ in range(6):
|
||||
time.sleep(0.2)
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
|
||||
print(Style.RESET_ALL)
|
||||
time.sleep(0.3)
|
||||
|
||||
# Final goodbye box
|
||||
box_width = 50
|
||||
print(Fore.MAGENTA + "╔" + "═" * (box_width - 2) + "╗")
|
||||
|
||||
goodbye_lines = [
|
||||
"m5rcode shell session ended",
|
||||
"",
|
||||
"Thanks for coding with us!",
|
||||
"See you next time! 👋"
|
||||
]
|
||||
|
||||
for line in goodbye_lines:
|
||||
if line == "":
|
||||
print(Fore.MAGENTA + "║" + " " * (box_width - 2) + "║")
|
||||
else:
|
||||
color = Fore.CYAN if "m5rcode" in line else Fore.LIGHTWHITE_EX
|
||||
centered = color + line.center(box_width - 2) + Style.RESET_ALL
|
||||
print(Fore.MAGENTA + "║" + centered + Fore.MAGENTA + "║")
|
||||
|
||||
print(Fore.MAGENTA + "╚" + "═" * (box_width - 2) + "╝" + Style.RESET_ALL)
|
||||
time.sleep(1)
|
||||
|
||||
def run(self):
|
||||
self.shutdown_animation()
|
||||
return True # Signals to shell to exit
|
||||
121
commands/cmd_fastfetch.py
Normal file
121
commands/cmd_fastfetch.py
Normal file
@@ -0,0 +1,121 @@
|
||||
import platform
|
||||
import re
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
from colorama import Fore, Style
|
||||
from pyfiglet import Figlet
|
||||
|
||||
try:
|
||||
import psutil
|
||||
_PSUTIL_AVAILABLE = True
|
||||
except ImportError:
|
||||
_PSUTIL_AVAILABLE = False
|
||||
|
||||
def strip_ansi(text):
|
||||
return re.sub(r'\x1b\[[0-9;]*m', '', text)
|
||||
|
||||
class FastfetchCommand:
|
||||
def _get_uptime(self):
|
||||
if not _PSUTIL_AVAILABLE:
|
||||
return "N/A (psutil not installed)"
|
||||
try:
|
||||
boot_time_timestamp = psutil.boot_time()
|
||||
boot_datetime = datetime.datetime.fromtimestamp(boot_time_timestamp)
|
||||
current_datetime = datetime.datetime.now()
|
||||
uptime_seconds = (current_datetime - boot_datetime).total_seconds()
|
||||
|
||||
days = int(uptime_seconds // (24 * 3600))
|
||||
uptime_seconds %= (24 * 3600)
|
||||
hours = int(uptime_seconds // 3600)
|
||||
uptime_seconds %= 3600
|
||||
minutes = int(uptime_seconds // 60)
|
||||
seconds = int(uptime_seconds % 60)
|
||||
|
||||
uptime_str = []
|
||||
if days > 0:
|
||||
uptime_str.append(f"{days}d")
|
||||
if hours > 0:
|
||||
uptime_str.append(f"{hours}h")
|
||||
if minutes > 0:
|
||||
uptime_str.append(f"{minutes}m")
|
||||
if seconds > 0 or not uptime_str:
|
||||
uptime_str.append(f"{seconds}s")
|
||||
return " ".join(uptime_str)
|
||||
except Exception:
|
||||
return "Error calculating uptime"
|
||||
|
||||
def run(self):
|
||||
m5rcode_version = "1.0.0"
|
||||
try:
|
||||
version_file = Path(__file__).parents[1] / "version.txt"
|
||||
if version_file.exists():
|
||||
m5rcode_version = version_file.read_text().strip()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ASCII "M" logo—27 chars wide
|
||||
ascii_m = [
|
||||
" _____ ",
|
||||
" /\\ \\ ",
|
||||
" /::\\____\\ ",
|
||||
" /::::| | ",
|
||||
" /:::::| | ",
|
||||
" /::::::| | ",
|
||||
" /:::/|::| | ",
|
||||
" /:::/ |::| | ",
|
||||
" /:::/ |::|___|______ ",
|
||||
" /:::/ |::::::::\\ \\ ",
|
||||
" /:::/ |:::::::::\\____\\",
|
||||
" \\::/ / ~~~~~/:::/ / ",
|
||||
" \\/____/ /:::/ / ",
|
||||
" /:::/ / ",
|
||||
" /:::/ / ",
|
||||
" /:::/ / ",
|
||||
" /:::/ / ",
|
||||
" /:::/ / ",
|
||||
" /:::/ / ",
|
||||
" \\::/ / ",
|
||||
" \\/____/ ",
|
||||
" ",
|
||||
]
|
||||
|
||||
uptime_info = self._get_uptime()
|
||||
LABEL_PAD = 17
|
||||
|
||||
info_lines = [
|
||||
f"{Fore.CYAN}{'m5rcode Version:':<{LABEL_PAD}}{Style.RESET_ALL} {Fore.LIGHTWHITE_EX}{m5rcode_version}{Style.RESET_ALL}",
|
||||
f"{Fore.CYAN}{'Python Version:':<{LABEL_PAD}}{Style.RESET_ALL} {Fore.LIGHTWHITE_EX}{platform.python_version()}{Style.RESET_ALL}",
|
||||
f"{Fore.CYAN}{'Platform:':<{LABEL_PAD}}{Style.RESET_ALL} {Fore.LIGHTWHITE_EX}{platform.system()} {platform.release()}{Style.RESET_ALL}",
|
||||
f"{Fore.CYAN}{'Machine:':<{LABEL_PAD}}{Style.RESET_ALL} {Fore.LIGHTWHITE_EX}{platform.machine()}{Style.RESET_ALL}",
|
||||
f"{Fore.CYAN}{'Processor:':<{LABEL_PAD}}{Style.RESET_ALL} {Fore.LIGHTWHITE_EX}{platform.processor()}{Style.RESET_ALL}",
|
||||
f"{Fore.CYAN}{'Uptime:':<{LABEL_PAD}}{Style.RESET_ALL} {Fore.LIGHTWHITE_EX}{uptime_info}{Style.RESET_ALL}",
|
||||
]
|
||||
|
||||
ascii_width = len(strip_ansi(ascii_m[0]))
|
||||
content_width = max(len(strip_ansi(line)) for line in info_lines)
|
||||
sep = " "
|
||||
sep_width = len(sep)
|
||||
total_content_width = ascii_width + sep_width + content_width
|
||||
box_width = max(total_content_width, 48) + 2
|
||||
|
||||
# Pad info lines vertically to align with "M"
|
||||
n_ascii = len(ascii_m)
|
||||
n_info = len(info_lines)
|
||||
info_lines_padded = [""] * ((n_ascii - n_info)//2) + info_lines + [""] * (n_ascii - n_info - (n_ascii - n_info)//2)
|
||||
if len(info_lines_padded) < n_ascii:
|
||||
info_lines_padded += [""] * (n_ascii - len(info_lines_padded))
|
||||
|
||||
# Header
|
||||
print(Fore.MAGENTA + "╔" + "═" * (box_width-2) + "╗")
|
||||
|
||||
title = f"m5rcode Fastfetch"
|
||||
print(Fore.MAGENTA + "║" + Fore.CYAN + title.center(box_width-2) + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╟" + "─" * (box_width-2) + "╢")
|
||||
|
||||
# Body
|
||||
for mline, iline in zip(ascii_m, info_lines_padded):
|
||||
line_content = (mline + sep + iline).rstrip()
|
||||
pad = " " * (box_width - 2 - len(strip_ansi(line_content)))
|
||||
print(Fore.MAGENTA + "║" + line_content + pad + Fore.MAGENTA + "║")
|
||||
|
||||
print(Fore.MAGENTA + "╚" + "═" * (box_width-2) + "╝" + Style.RESET_ALL)
|
||||
15
commands/cmd_nano.py
Normal file
15
commands/cmd_nano.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import os, subprocess
|
||||
from colorama import Fore
|
||||
|
||||
class NanoCommand:
|
||||
def __init__(self, base_dir, filename):
|
||||
if not filename.endswith(".m5r"):
|
||||
filename += ".m5r"
|
||||
self.path = os.path.join(base_dir, filename)
|
||||
|
||||
def run(self):
|
||||
editor = os.getenv("EDITOR", "notepad")
|
||||
if not os.path.exists(self.path):
|
||||
print(Fore.YELLOW + f"Note: {self.path} does not exist, creating it.")
|
||||
open(self.path, "w").close()
|
||||
subprocess.call([editor, self.path])
|
||||
16
commands/cmd_new.py
Normal file
16
commands/cmd_new.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import os
|
||||
from colorama import Fore
|
||||
|
||||
class NewCommand:
|
||||
def __init__(self, base_dir, filename):
|
||||
if not filename.endswith(".m5r"):
|
||||
filename += ".m5r"
|
||||
self.path = os.path.join(base_dir, filename)
|
||||
|
||||
def run(self):
|
||||
if os.path.exists(self.path):
|
||||
print(Fore.RED + f"Error: {self.path} already exists.")
|
||||
return
|
||||
with open(self.path, "w") as f:
|
||||
f.write("// New m5r file\n")
|
||||
print(Fore.GREEN + f"Created: {self.path}")
|
||||
48
commands/cmd_run.py
Normal file
48
commands/cmd_run.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
from colorama import Fore
|
||||
|
||||
class RunCommand:
|
||||
def __init__(self, base_dir, filename):
|
||||
if not filename.endswith(".m5r"):
|
||||
filename += ".m5r"
|
||||
self.base_dir = base_dir
|
||||
self.path = os.path.join(base_dir, filename)
|
||||
|
||||
def run(self):
|
||||
if not os.path.exists(self.path):
|
||||
print(Fore.RED + f"Error: {self.path} not found.")
|
||||
return
|
||||
|
||||
source = open(self.path, encoding="utf-8").read()
|
||||
# Extract only Python segments
|
||||
py_segs = re.findall(r'<\?py(.*?)\?>', source, re.S)
|
||||
if not py_segs:
|
||||
print(Fore.YELLOW + "No Python code found in this .m5r file.")
|
||||
return
|
||||
|
||||
combined = "\n".join(seg.strip() for seg in py_segs)
|
||||
|
||||
# Write to a temporary .py file
|
||||
with tempfile.NamedTemporaryFile("w", delete=False, suffix=".py") as tf:
|
||||
tf.write(combined)
|
||||
tmp_path = tf.name
|
||||
|
||||
# Execute with python, in the project directory
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[ "python", tmp_path ],
|
||||
cwd=self.base_dir,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
if result.stdout:
|
||||
print(result.stdout, end="")
|
||||
if result.stderr:
|
||||
print(Fore.RED + result.stderr, end="")
|
||||
except FileNotFoundError:
|
||||
print(Fore.RED + "Error: 'python' executable not found on PATH.")
|
||||
finally:
|
||||
os.unlink(tmp_path)
|
||||
113
commands/cmd_wdir.py
Normal file
113
commands/cmd_wdir.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from urllib.parse import urljoin
|
||||
from colorama import Fore, Style
|
||||
import re
|
||||
|
||||
def strip_ansi(text):
|
||||
return re.sub(r'\x1b\[[0-9;]*m', '', text)
|
||||
|
||||
class WdirCommand:
|
||||
def __init__(self, url):
|
||||
self.url = url.strip()
|
||||
|
||||
def run(self):
|
||||
box_min = 72
|
||||
if not self.url:
|
||||
print(Fore.RED + "Usage: wdir <url>" + Style.RESET_ALL)
|
||||
return
|
||||
|
||||
# Ensure scheme
|
||||
if not self.url.startswith("http://") and not self.url.startswith("https://"):
|
||||
self.url = "http://" + self.url
|
||||
|
||||
try:
|
||||
print(Fore.CYAN + f"[FETCH] Scanning directory at {self.url}..." + Style.RESET_ALL)
|
||||
resp = requests.get(self.url, timeout=5)
|
||||
resp.raise_for_status()
|
||||
except Exception as e:
|
||||
print(Fore.RED + f"[ERR] Failed to fetch {self.url}: {e}" + Style.RESET_ALL)
|
||||
return
|
||||
|
||||
soup = BeautifulSoup(resp.text, "html.parser")
|
||||
links = soup.find_all("a")
|
||||
|
||||
files = []
|
||||
for link in links:
|
||||
href = link.get("href")
|
||||
if not href:
|
||||
continue
|
||||
if href.startswith("?") or href.startswith("#") or href.startswith("../"):
|
||||
continue
|
||||
is_dir = href.endswith("/")
|
||||
filename = href.rstrip("/").split("/")[-1]
|
||||
if not is_dir and re.search(r"\.(php|html?|asp|aspx|jsp)$", filename, re.I):
|
||||
continue
|
||||
if is_dir:
|
||||
ftype = "Directory"
|
||||
elif "." in filename:
|
||||
ftype = f".{filename.split('.')[-1]} file"
|
||||
else:
|
||||
ftype = "File"
|
||||
row_text = link.parent.get_text(" ", strip=True)
|
||||
size_match = re.search(r"(\d+(?:\.\d+)?\s*(?:KB|MB|GB|B))", row_text, re.I)
|
||||
date_match = re.search(r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2})", row_text)
|
||||
size = size_match.group(1) if size_match else "-"
|
||||
modified = date_match.group(1) if date_match else "-"
|
||||
files.append((filename, ftype, size, modified))
|
||||
|
||||
# Calculate column widths for nice boxed output
|
||||
col_names = ["Name", "Type", "Size", "Modified"]
|
||||
pad = [30, 15, 12, 20]
|
||||
table_width = sum(pad) + len(pad) + 1 # columns + spaces + box
|
||||
width = max(box_min, table_width + 2)
|
||||
|
||||
# If no files, pretty box saying so
|
||||
if not files:
|
||||
print(Fore.MAGENTA + "╔" + "═" * (width - 2) + "╗")
|
||||
out = "No files or directories found (maybe directory listing is disabled)."
|
||||
out = out.center(width - 2)
|
||||
print(Fore.MAGENTA + "║" + Fore.YELLOW + out + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╚" + "═" * (width - 2) + "╝" + Style.RESET_ALL)
|
||||
return
|
||||
|
||||
# Pretty header
|
||||
print(Fore.MAGENTA + "╔" + "═" * (width - 2) + "╗")
|
||||
title = "Web Directory Listing"
|
||||
print(Fore.MAGENTA + "║" + Fore.CYAN + Style.BRIGHT + title.center(width - 2) + Fore.MAGENTA + "║")
|
||||
print(Fore.MAGENTA + "╟" + "─" * (width - 2) + "╢")
|
||||
# Table header
|
||||
header = (
|
||||
Fore.LIGHTMAGENTA_EX
|
||||
+ f"{col_names[0]:<{pad[0]}} {col_names[1]:<{pad[1]}} {col_names[2]:<{pad[2]}} {col_names[3]:<{pad[3]}}"
|
||||
+ Style.RESET_ALL
|
||||
)
|
||||
print(
|
||||
Fore.MAGENTA + "║"
|
||||
+ header
|
||||
+ " " * (width - 2 - len(strip_ansi(header)))
|
||||
+ Fore.MAGENTA + "║"
|
||||
)
|
||||
print(Fore.MAGENTA + "╟" + "─" * (width - 2) + "╢")
|
||||
|
||||
# Table rows
|
||||
for fname, ftype, size, modified in files:
|
||||
if ftype == "Directory":
|
||||
color = Fore.BLUE + Style.BRIGHT
|
||||
elif ftype.endswith("file"):
|
||||
color = Fore.CYAN
|
||||
else:
|
||||
color = Fore.WHITE
|
||||
filecol = f"{color}{fname:<{pad[0]}}{Style.RESET_ALL}"
|
||||
typecol = f"{Style.DIM}{Fore.WHITE}{ftype:<{pad[1]}}{Style.RESET_ALL}"
|
||||
sizecol = f"{Style.DIM}{Fore.LIGHTWHITE_EX}{size:<{pad[2]}}{Style.RESET_ALL}"
|
||||
modcol = f"{Style.DIM}{Fore.LIGHTWHITE_EX}{modified:<{pad[3]}}{Style.RESET_ALL}"
|
||||
row = f"{filecol} {typecol} {sizecol} {modcol}"
|
||||
print(
|
||||
Fore.MAGENTA + "║"
|
||||
+ row
|
||||
+ " " * (width - 2 - len(strip_ansi(row)))
|
||||
+ Fore.MAGENTA + "║"
|
||||
)
|
||||
# Footer
|
||||
print(Fore.MAGENTA + "╚" + "═" * (width - 2) + "╝" + Style.RESET_ALL)
|
||||
Reference in New Issue
Block a user