Uploading m5rcode Ubuntu Port to the repo

This commit is contained in:
m5rcel { Marcel }
2025-10-09 20:24:27 +02:00
committed by GitHub
commit 342a616ff9
30 changed files with 2363 additions and 0 deletions

185
README.md Normal file
View File

@@ -0,0 +1,185 @@
# m5rcode The Unofficial Polyglot Programming Language
![Polyglot](https://img.shields.io/badge/language-Python%2FJS%2FPHP%2FC%23%2FC++-purple.svg)
![Status](https://img.shields.io/badge/status-experimental-orange.svg)
**m5rcode** is an experimental **polyglot programming language** written with a blend of **Python, JavaScript, PHP, C#, and C++**.
It uses obfuscation and cross-language embedding to allow developers to write multi-language scripts in a single file (`.m5r`).
The project includes a custom **REPL shell** (`m5rshell`) and an **interpreter** for `.m5r` files.
---
## ✨ Features
- **Polyglot Language Core**
- Mix **Python, JavaScript, PHP, CSS, C#, and C++** in a single `.m5r` file.
- Interpreter extracts, executes, and blends code blocks.
- Supports obfuscation for added challenge and uniqueness.
- **m5rshell The REPL Shell**
- Interactive REPL for testing code snippets.
- Commands:
- `new`, `nano`, `run`, `fastfetch`, `credits`, `exit`, `cd`
- Developer-friendly CLI for creating & running `.m5r` scripts.
- **.m5r File Runner (Interpreter)**
- Executes `.m5r` polyglot files directly.
- Efficient, multi-language-aware execution engine.
- Provides fast output even for obfuscated code.
---
## 🔧 Requirements
- Python **3.8+**
---
## 📦 Installation
Clone this repository:
```bash
git clone https://github.com/m4rcel-lol/m5rcode.git
cd m5rcode
```
---
## ⚡ Quick Start
### Run the REPL shell
```bash
python3 m5rshell.py
```
---
## 📝 Example
Heres a `hello.m5r` script that prints **Hello world** in all supported languages:
```m5r
<?py
# M5RCode Python Block: OBFUSCATED - 3D Hello World + Floating Rotating 3D Square
import tkinter as _tk
import math as _m
import time as _t
class _T:
def __init__(self):
self._rt=_tk.Tk()
self._rt.title(''.join([chr(c) for c in [51,68,32,84,101,115,116]])) # 3D Test
self._cv=_tk.Canvas(self._rt,width=420,height=260,bg='#181c22',highlightthickness=0)
self._cv.pack()
self._ang=0
self._t=0
self._run()
self._rt.mainloop()
def _run(self):
self._cv.delete('all')
# Draw "3D" shadowed Hello World text
_s="".join([chr(c) for c in [72,101,108,108,111,32,119,111,114,108,100]])
for _i in range(15,0,-3):
self._cv.create_text(212+_i,90+_i,fill=f"#2a2a5{9-_i//3}",font=('Consolas',42,'bold'),text=_s)
self._cv.create_text(212,90,fill="#ffe257",font=('Consolas',42,'bold'),text=_s)
# Rotating & bouncing 3D square (pseudo-perspective)
_a=self._ang
_Y=130+_m.sin(self._t)*24
_sz=70
_pts=[]
for _dx,_dy in [(-1,-1),(1,-1),(1,1),(-1,1)]:
# 3D cube points, rotate a bit in Y, project to 2D
_x=_dx*_sz*_m.cos(_a)
_y=_dy*_sz*0.67
_z=_dx*_sz*_m.sin(_a)
_X=_x+_z*0.45
_pts.append((212+_X,_Y+_y-_z*0.29))
# Draw top face for 3D effect
self._cv.create_polygon([_pts[i] for i in [0,1,2,3]],fill="#00ffae",outline="#222",width=3)
# Draw floating shadow
self._cv.create_oval(212-45,(_Y+_sz*1.03)+10,212+45,(_Y+_sz*1.24)+20,fill="#000",outline="")
# Draw outline with depth
for _offs in range(1,8):
_offp=[(_x,_y+_offs*2) for _x,_y in _pts]
self._cv.create_polygon(_offp,outline="#161413",fill="",width=1)
# Animate: spin & up-down
self._ang+=0.12
self._t+=0.1
self._rt.after(28,self._run)
_T()
?>
<?js
(function(){
var x=[72,101,108,108,111,32,119,111,114,108,100];
var s='';
for(var i of x){ s+=String.fromCharCode(i); }
console.log(s);
})();
?>
<?php
${a}=array(72,101,108,108,111,32,119,111,114,108,100);
echo implode(array_map('chr',${a})) . "\n";
?>
<?cs
// M5RCode C# Block: OBFUSCATED, illustrative
using System;
class S{
static void Main(){
Console.WriteLine(string.Join("", new int[] {72,101,108,108,111,32,119,111,114,108,100}.Select(c => (char)c)));
}
}
?>
<?cpp
// M5RCode C++ Block: OBFUSCATED, illustrative
#include <iostream>
int main() {
int arr[] = {72,101,108,108,111,32,119,111,114,108,100};
for(int i = 0; i < 11; i++) std::cout << (char)arr[i];
std::cout << std::endl;
return 0;
}
?>
<?css
body { color: #ffe257; background: #1a1c1f; }
?>
```
---
## 📂 Project Structure
```
m5rcode/
├─ m5rshell.py # The REPL shell
├─ m5r_interpreter.py # The .m5r polyglot interpreter
├─ files/ # Sample m5rcode scripts
├─ utils/ # Handling everything
├─ commands # Commands handling
├─ version.txt # Version of m5rcode showing on fastfetch command
├─ requirements.txt # Modules u need to install for m5rcode to work.
└─ README.md
```
---
## 🤝 Contributing
Contributions are welcome!
If you want to add support for more languages, open an issue or PR.
---
## 👥 Credits
- **Creator:** [m5rcel](https://github.com/m4rcel-lol)
- **Contributors:** The m5rcode community
---
## 📜 Where can I install m5rcode from?
You can install m5rcode from it's official website **pythonjs.cfd** hover over and copy paste to your browser.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

46
commands/cmd_cd.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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)

46
files/m5rcel.m5r Normal file
View File

@@ -0,0 +1,46 @@
<?py
import tkinter as tk
from tkinter import messagebox
msg = ''.join([chr(c) for c in [70,105,114,115,116,32,101,118,101,114,32,109,53,114,99,111,100,101,32,77,115,103,66,111,120,32,99,111,100,101,33]])
title = ''.join([chr(c) for c in [109,53,114,99,111,100,101,32,77,115,103,66,111,120]])
root = tk.Tk()
root.withdraw()
messagebox.showinfo(title, msg)
?>
<?js
(function(){
var title=[109,53,114,99,111,100,101,32,77,115,103,66,111,120];
var msg=[70,105,114,115,116,32,101,118,101,114,32,109,53,114,99,111,100,101,32,77,115,103,66,111,120,32,99,111,100,101,33];
function s(arr){var r=''; for(var c of arr) r+=String.fromCharCode(c); return r;}
alert(msg.join(''));
})();
?>
<?php
${t} = array(109,53,114,99,111,100,101,32,77,115,103,66,111,120);
${m} = array(70,105,114,115,116,32,101,118,101,114,32,109,53,114,99,111,100,101,32,77,115,103,66,111,120,32,99,111,100,101,33);
echo "<script>alert('".implode(array_map('chr',${m}))."');</script>";
?>
<?css
/* MsgBox style */
body { background: #111; color: #0f0; font-family: monospace; }
?>
<?cs
string title = string.Join("", new int[] {109,53,114,99,111,100,101,32,77,115,103,66,111,120}.Select(c => (char)c));
string msg = string.Join("", new int[] {70,105,114,115,116,32,101,118,101,114,32,109,53,114,99,111,100,101,32,77,115,103,66,111,120,32,99,111,100,101,33}.Select(c => (char)c));
System.Windows.Forms.MessageBox.Show(msg, title);
?>
<?cpp
#include <windows.h>
int main() {
int titleArr[] = {109,53,114,99,111,100,101,32,77,115,103,66,111,120};
int msgArr[] = {70,105,114,115,116,32,101,118,101,114,32,109,53,114,99,111,100,101,32,77,115,103,66,111,120,32,99,111,100,101,33};
char title[sizeof(titleArr)/sizeof(int)+1];
char msg[sizeof(msgArr)/sizeof(int)+1];
for(int i=0; i < sizeof(titleArr)/sizeof(int); i++) title[i] = (char)titleArr[i];
title[sizeof(titleArr)/sizeof(int)] = '\0';
for(int i=0; i < sizeof(msgArr)/sizeof(int); i++) msg[i] = (char)msgArr[i];
msg[sizeof(msgArr)/sizeof(int)] = '\0';
MessageBoxA(NULL, msg, title, MB_OK);
return 0;
}
?>

288
files/maze.m5r Normal file
View File

@@ -0,0 +1,288 @@
<?py
# -*- coding: utf-8 -*-
import tkinter as _tk, math as _m, random as _r
import math
import random
def _gen_backrooms(_lv):
_sz = min(18 + _lv*4, 60)
_mp = [[1]*_sz for _ in range(_sz)]
def _carve(x, y):
_mp[y][x] = 0
dirs = [(0,2), (0,-2), (2,0), (-2,0)]
_r.shuffle(dirs)
for dx,dy in dirs:
nx,ny=x+dx,y+dy
if 2<=nx<_sz-2 and 2<=ny<_sz-2 and _mp[ny][nx]==1:
_mp[y+dy//2][x+dx//2]=0
_carve(nx,ny)
startx = _sz//2
starty = _sz//2
_carve(startx, starty)
for _ in range(_sz*_sz//7):
_x = _r.randint(2,_sz-3)
_y = _r.randint(2,_sz-3)
if _r.random()<0.45: _mp[_y][_x]=0
_mp[starty][startx]=0
_mp[_sz-3][_sz-3]=0
_mp[_sz-2][_sz-2]=2
return _mp
class _BACKROOMS:
def __init__(self):
self._rt=_tk.Tk()
self._rt.title("BACKROOMS MAZE - M5RCode")
self._W,self._H=1200,820
self._cv=_tk.Canvas(self._rt,bg="#12131a",width=self._W,height=self._H)
self._cv.pack(fill="both",expand=True)
self._game_state="main"
self._fullscreen = False
self._mouse_locked = False
self._reset_game()
self._keys=set()
self._mouse_x_last = None
self._menu_btn_area = None
self._rt.bind("<Configure>",self._resize)
self._rt.bind("<KeyPress>",self._kd)
self._rt.bind("<KeyRelease>",self._ku)
self._cv.bind("<Button-1>", self._mouse_btn) # bind to canvas, not root!
self._rt.bind("<Escape>",self._esc)
self._rt.bind("<F11>", self._toggle_fullscreen)
self._rt.bind("<Motion>", self._mouse_move)
self._tick()
self._rt.mainloop()
def _reset_game(self,level=1):
self._level=level
self._map=_gen_backrooms(level)
self._sz=len(self._map)
self._px,self._py=self._sz//2+0.5,self._sz//2+0.5
self._pa=_m.pi/4
self._levelup_msg=0
def _resize(self,e): self._W,self._H=e.width,e.height
def _mouse_btn(self,e):
if self._game_state=="main":
# only start if inside start button area
if self._menu_btn_area:
x0, y0, x1, y1 = self._menu_btn_area
if x0 <= e.x <= x1 and y0 <= e.y <= y1:
self._game_state="play"
self._lock_mouse()
elif self._game_state=="pause":
self._lock_mouse()
def _lock_mouse(self):
if not self._mouse_locked:
self._mouse_locked=True
self._rt.config(cursor="none")
self._cv.grab_set()
self._mouse_x_last = None
def _unlock_mouse(self,e=None):
self._mouse_locked=False
self._rt.config(cursor="")
self._cv.grab_release()
self._mouse_x_last = None
def _mouse_move(self,e):
if self._mouse_locked and self._game_state=="play":
if self._mouse_x_last is not None:
dx = e.x - self._mouse_x_last
self._pa += dx * 0.0067
self._mouse_x_last = e.x
else:
self._mouse_x_last = None
def _esc(self,e):
if self._game_state=="play" and self._mouse_locked:
self._unlock_mouse()
self._game_state="pause"
elif self._game_state=="pause":
self._game_state="main"
elif self._game_state=="main":
self._rt.destroy()
def _toggle_fullscreen(self,e=None):
self._fullscreen = not self._fullscreen
self._rt.attributes("-fullscreen", self._fullscreen)
def _brighten(self, col, factor):
if col.startswith('#') and len(col)==7:
r,g,b=int(col[1:3],16),int(col[3:5],16),int(col[5:7],16)
r,g,b=min(255,int(r*factor)),min(255,int(g*factor)),min(255,int(b*factor))
return f'#{r:02x}{g:02x}{b:02x}'
return col
def _darken(self, col, factor):
if col.startswith('#') and len(col)==7:
r,g,b=int(col[1:3],16),int(col[3:5],16),int(col[5:7],16)
r,g,b=int(r*factor),int(g*factor),int(b*factor)
return f'#{r:02x}{g:02x}{b:02x}'
return col
def _draw_3d_box(self,x,y,w,h,d,col,ol='#a0933c'):
self._cv.create_rectangle(x,y,x+w,y+h,fill=col,outline=ol,width=2)
pts_top=[(x,y),(x+d,y-d),(x+w+d,y-d),(x+w,y)]
self._cv.create_polygon(pts_top,fill=self._brighten(col,1.22),outline=ol,width=1)
pts_r=[(x+w,y),(x+w+d,y-d),(x+w+d,y+h-d),(x+w,y+h)]
self._cv.create_polygon(pts_r,fill=self._darken(col,0.75),outline=ol,width=1)
def _draw_hud(self):
y = self._H-80
self._draw_3d_box(0,y,self._W,80,6,"#fef2a0","#d8c944")
self._cv.create_text(120,y+25,text=f"LEVEL: {self._level}",font=("Consolas",24,"bold"),fill="#665100")
self._cv.create_text(self._W//2,y+25,text="FIND THE BLUE EXIT!",font=("Consolas",20,"bold"),fill="#3e79ff")
self._cv.create_text(self._W-150,y+25,text=f"SIZE: {self._sz}x{self._sz}",font=("Consolas",16,"bold"),fill="#d8b144")
def _raycast(self,a):
x,y = self._px,self._py
dx,dy = _m.cos(a)*.05,_m.sin(a)*.05
for d in range(1,400):
x+=dx; y+=dy
mx,my=int(x),int(y)
if mx<0 or my<0 or mx>=self._sz or my>=self._sz:
return d/20,1,'#c7bc54'
cell = self._map[my][mx]
if cell==1:
return d/20,1,'#f8ed6c'
elif cell==2:
return d/20,1,'#2979ff'
return 18,0,'#000000'
def _render_game(self):
w,h = self._W,self._H
self._cv.delete('all')
for i in range(h//2):
b=235-i//7;sh=f"#{b:02x}{b:02x}{(b//2)+85:02x}"
self._cv.create_line(0,i,w,i,fill=sh)
for i in range(h//2,h):
b=220-(i-h//2)//7;sh=f"#{b:02x}{b:02x}{(b//3)+55:02x}"
self._cv.create_line(0,i,w,i,fill=sh)
rays=270
for i in range(rays):
a=self._pa-_m.pi/2.3 + (_m.pi/1.15*i)/(rays-1)
d,wall,wall_color=self._raycast(a)
d = max(.08, d*_m.cos(a-self._pa))
hwall=int(h*0.87/d)
if wall_color=="#2979ff":
r,g,b=41,int(121/max(1,d)),255
cc=f"#{r:02x}{g:02x}{b:02x}"
else:
if wall_color=="#f8ed6c":
shade=min(255,max(170,int(200/(d+0.8))))
cc=f"#{shade:02x}{shade:02x}{int(shade*0.88):02x}"
else:
cc=wall_color
x=int(i*w/rays)
self._cv.create_rectangle(x,h//2-hwall//2-10,x+int(w/rays+1),h//2+hwall//2,fill=cc,outline="")
self._draw_hud()
cx,cy=w-80,80
self._cv.create_oval(cx-30,cy-30,cx+30,cy+30,fill="#aaa924",outline="#ffffff",width=2)
arrow_x = cx + 20*_m.cos(self._pa)
arrow_y = cy + 20*_m.sin(self._pa)
self._cv.create_line(cx,cy,arrow_x,arrow_y,fill="#2979ff",width=3)
self._cv.create_text(cx,cy+45,text="N",font=("Consolas",12,"bold"),fill="#665100")
if self._game_state=="pause":
self._draw_3d_box(w//2-150,h//2-70,300,69,10,"#23232a","#343434")
self._cv.create_text(w//2,h//2-37,text="PAUSED",font=("Consolas",28,"bold"),fill="#ffee44")
self._cv.create_text(w//2,h//2+7,text="ESC to resume",font=("Consolas",13,"bold"),fill="#2979ff")
if self._levelup_msg>0:
self._draw_3d_box(w//2-180,h//2-60,360,50,12,"#2979ff","#ffffff")
self._cv.create_text(w//2,h//2-35,text=f"LEVEL {self._level-1} ESCAPED!",font=("Consolas",18,"bold"),fill="#665100")
self._levelup_msg-=1
def _tick(self):
if self._game_state=="play":
self._step()
self._render_game()
elif self._game_state=="main":
self._render_menu()
elif self._game_state=="pause":
self._render_game()
self._rt.after(28,self._tick)
def _render_menu(self):
w,h=self._W,self._H
self._cv.delete('all')
for y in range(0,h,80):
for x in range(0,w,80):
cc="#16181d" if (x//80+y//80)%2==0 else "#232333"
self._cv.create_rectangle(x,y,x+80,y+80,fill=cc,width=0)
self._draw_3d_box(w//2-200,h//3-100,400,80,25,"#232333","#111833")
self._cv.create_text(w//2,h//3-60,text="BACKROOMS MAZE",fill="#d8d8ef",font=("Consolas",36,"bold"))
self._draw_3d_box(w//2-180,h//3,360,50,15,"#282848","#45455a")
self._cv.create_text(w//2,h//3+25,text="2.5D LIMINAL ADVENTURE",fill="#bcbcd2",font=("Consolas",21,"bold"))
# Start button area, properly recorded for click test
btn_x0,btn_y0=w//2-120,h//2+80
btn_x1,btn_y1=w//2+120,h//2+135
self._menu_btn_area = (btn_x0,btn_y0,btn_x1,btn_y1)
self._draw_3d_box(btn_x0,btn_y0,240,55,12,"#1199cc","#ffffff")
self._cv.create_text(w//2,h//2+107,text="START",fill="#ffffff",font=("Consolas",18,"bold"))
self._cv.create_text(w//2,h-78,text="Navigate the yellow maze. Find the BLUE EXIT!",font=("Consolas",16),fill="#2979ff")
self._cv.create_text(w//2,h-50,text="WASD: Move | Mouse: Look | Click: Lock Camera | F11: Fullscreen",font=("Consolas",14),fill="#bcbcd2")
def _move_smooth(self,dx,dy):
def is_blocked(x,y):
mx,my=int(x),int(y)
return mx<0 or my<0 or mx>=self._sz or my>=self._sz or self._map[my][mx]==1
nx,ny = self._px+dx, self._py+dy
if not is_blocked(nx,ny): self._px,self._py=nx,ny
else:
if not is_blocked(self._px,ny): self._py=ny
elif not is_blocked(nx,self._py): self._px=nx
def _step(self):
spd,dx,dy=0.12,0,0
if 'w' in self._keys: dx+=_m.cos(self._pa)*spd; dy+=_m.sin(self._pa)*spd
if 's' in self._keys: dx-=_m.cos(self._pa)*spd*.8; dy-=_m.sin(self._pa)*spd*.8
if 'a' in self._keys: dx+=_m.cos(self._pa-_m.pi/2)*spd*.7; dy+=_m.sin(self._pa-_m.pi/2)*spd*.7
if 'd' in self._keys: dx+=_m.cos(self._pa+_m.pi/2)*spd*.7; dy+=_m.sin(self._pa+_m.pi/2)*spd*.7
self._move_smooth(dx,dy)
mx,my=int(self._px),int(self._py)
for check_x in range(max(0, mx-1), min(self._sz, mx+2)):
for check_y in range(max(0, my-1), min(self._sz, my+2)):
if self._map[check_y][check_x] == 2:
distance = math.sqrt((self._px - (check_x+0.5))**2 + (self._py - (check_y+0.5))**2)
if distance < 1.2:
self._reset_game(self._level + 1)
self._levelup_msg = 80
return
def _kd(self,e):
if self._game_state=="play" and self._mouse_locked:
self._keys.add(e.keysym.lower())
if e.keysym.lower()=='left':
self._pa-=_m.pi/20
if e.keysym.lower()=='right':
self._pa+=_m.pi/20
if e.keysym.lower()=="f11":
self._toggle_fullscreen()
def _ku(self,e):
self._keys.discard(e.keysym.lower())
_BACKROOMS()
?>
<?js
console.log("BACKROOMS MAZE 2.5D M5RCode");
?>
<?php
echo "BACKROOMS MAZE 2.5D M5RCode\n";
?>
<?cs
using System;
class _M{
static void Main(){ Console.WriteLine("BACKROOMS MAZE 2.5D M5RCode"); }
}
?>
<?cpp
#include <iostream>
int main(){ std::cout<<"BACKROOMS MAZE 2.5D M5RCode"<<std::endl; return 0;}
?>
<?css
body{background:#16181d;color:#d8d8ef;font-family:'Courier New',monospace;overflow:hidden;}
canvas{cursor:crosshair;image-rendering:pixelated;}
.maze-wall{filter:contrast(1.1);}
.maze-exit{filter:brightness(1.4) saturate(1.7);}
?>

195
files/snake.m5r Normal file
View File

@@ -0,0 +1,195 @@
<?py
# M5RCode Python Block: OBFUSCATED - 3D Snake Game (Tkinter)
import tkinter as _tk
import random as _r
import collections as _c
_bW=14
_bH=14
_cS=26
_iSL=4
_gTI=110
def _iso(_x,_y):
_sx=(_x-_y)*_cS*0.52+_bW*_cS/2
_sy=((_x+_y)*0.37)*_cS*0.52+54
return _sx,_sy
def _cube(_cv,_x,_y,_col,_head=False):
_ox,_oy=_iso(_x,_y)
_T=[(_ox,_oy),(_ox+_cS*0.5,_oy-_cS*0.33),(_ox+_cS,_oy),(_ox+_cS*0.5,_oy+_cS*0.35)]
_L=[(_ox,_oy),(_ox+_cS*0.5,_oy+_cS*0.35),(_ox+_cS*0.5,_oy+_cS*0.98),(_ox,_oy+_cS*0.63)]
_R=[(_ox+_cS,_oy),(_ox+_cS*0.5,_oy+_cS*0.35),(_ox+_cS*0.5,_oy+_cS*0.98),(_ox+_cS,_oy+_cS*0.63)]
_cv.create_polygon(_T,fill=_col if not _head else "#ffe257",outline="#1c2127",width=2)
_cv.create_polygon(_L,fill="#20c750",outline="#1c2127",width=1)
_cv.create_polygon(_R,fill="#147d2d",outline="#1c2127",width=1)
if _head:
_cv.create_oval(_ox+_cS*0.32,_oy+_cS*0.09,_ox+_cS*0.59,_oy+_cS*0.28,fill="#2a2d35",outline="#fff",width=1)
def _food3d(_cv,_x,_y):
_ox,_oy=_iso(_x,_y)
_r=_cS//2
_cv.create_oval(_ox+_cS*0.26-_r/2,_oy+_cS*0.16-_r/2,_ox+_cS*0.26+_r/2,_oy+_cS*0.16+_r/2,
fill="#ff0039",outline="#7d2034",width=2)
_cv.create_oval(_ox+_cS*0.28-_r/6,_oy+_cS*0.13-_r/6,_ox+_cS*0.28+_r/6,_oy+_cS*0.13+_r/6,
fill="#fff",outline="#fff",width=0)
class _SG:
def __init__(self,_m):
self._m=_m
self._m.title(''.join([chr(_c) for _c in [77,53,82,67,111,100,101,32,51,68,32,83,110,97,107,101]]))
self._m.resizable(False,False)
self._gF=_tk.Frame(self._m,bg='#22223b',padx=20,pady=15,highlightbackground="#363857",highlightthickness=2,bd=0,relief='flat')
self._gF.pack(expand=True,fill='both')
self._tL=_tk.Label(self._gF,text='M5RCode 3D Snake',font=('Inter',22,'bold'),fg='#4CAF50',bg='#22223b')
self._tL.pack(pady=(0,8))
self._s=0
self._sL=_tk.Label(self._gF,text=f"Score: {self._s}",font=('Inter',16,'bold'),fg='#f39c12',bg='#22223b')
self._sL.pack(pady=(0,8))
self._c=_tk.Canvas(self._gF,width=_bW*_cS+56,height=_bH*_cS+88,bg='#151526',
highlightbackground="#23243c",highlightthickness=5,bd=0,relief='flat')
self._c.pack()
self._sn=_c.deque()
self._f=None
self._d='Right'
self._gO=False
self._gR=False
for _k in ['<Left>','<Right>','<Up>','<Down>','w','a','s','d']:
self._m.bind(_k,self._cD)
self._sB=_tk.Button(self._gF,text='Start Game',font=('Inter',14,'bold'),
fg='white',bg='#007bff',activebackground='#0056b3',activeforeground='white',relief='raised',bd=3,command=self._s_g)
self._sB.pack(pady=10)
self._r_g()
def _r_g(self):
self._sn.clear()
for _i in range(_iSL): self._sn.appendleft((_iSL-1-_i,0))
self._d='Right'
self._s=0
self._gO=False
self._sL.config(text=f"Score: {self._s}")
self._c.delete('all')
self._p_f()
self._d_e()
self._sB.config(text='Start Game',command=self._s_g)
self._gR=False
def _s_g(self):
if not self._gR:
self._gR=True
self._sB.config(text='Restart Game',command=self._r_g)
self._g_l()
def _p_f(self):
while 1:
_x=_r.randint(0,_bW-1)
_y=_r.randint(0,_bH-1)
if (_x,_y) not in self._sn:
self._f=(_x,_y)
break
def _d_e(self):
self._c.delete('all')
for _x in range(_bW):
for _y in range(_bH):
_cube(self._c,_x,_y,"#232b39")
if self._f: _food3d(self._c,*self._f)
for _i,(_x,_y) in enumerate(self._sn):
_cube(self._c,_x,_y,"#00ff00",_head=(_i==0))
def _cD(self,_e):
if self._gO: return
_k=_e.keysym
if _k=='Left' and self._d!='Right':self._d='Left'
elif _k=='Right' and self._d!='Left':self._d='Right'
elif _k=='Up' and self._d!='Down':self._d='Up'
elif _k=='Down' and self._d!='Up':self._d='Down'
elif _k=='a' and self._d!='Right':self._d='Left'
elif _k=='d' and self._d!='Left':self._d='Right'
elif _k=='w' and self._d!='Down':self._d='Up'
elif _k=='s' and self._d!='Up':self._d='Down'
def _g_l(self):
if self._gO or not self._gR: return
_hX,_hY=self._sn[0]
if self._d=='Up':_nH=(_hX,_hY-1)
elif self._d=='Down':_nH=(_hX,_hY+1)
elif self._d=='Left':_nH=(_hX-1,_hY)
else:_nH=(_hX+1,_hY)
if (_nH[0]<0 or _nH[0]>=_bW or _nH[1]<0 or _nH[1]>=_bH) or _nH in self._sn:
self._e_g(); return
self._sn.appendleft(_nH)
if _nH==self._f:
self._s+=1
self._sL.config(text=f"Score: {self._s}")
self._p_f()
else: self._sn.pop()
self._d_e()
self._m.after(_gTI,self._g_l)
def _e_g(self):
self._gO=True
self._gR=False
self._c.create_text(self._c.winfo_width()/2,self._c.winfo_height()/2,
text="GAME OVER!",font=('Inter',28,'bold'),fill='red')
print(f"<?py> Game Over! Final Score: {self._s}")
if __name__=='__main__':
_rt=_tk.Tk()
_gm=_SG(_rt)
_rt.mainloop()
?>
<?js
# M5RCode JavaScript Block: OBFUSCATED
(function(){
var _a=''.concat([51,68,32,83,110,97,107,101,32,74,83,32,66,108,111,99,107]); // "3D Snake JS Block"
var _b=''.concat([60,63,106,115,62]);
console.log(_b+_a);
})();
?>
<?php
# M5RCode PHP Block: OBFUSCATED
${_a}=array();
function _b(${_c},${_d}){
global ${_a};
${_a}[]=[''.join([chr(_e) for _e in [116,105,109,101,115,116,97,109,112]])=>microtime(true),
''.join([chr(_e) for _e in [101,118,101,110,116]])=>${_c},
''.join([chr(_e) for _e in [100,97,116,97]])=>${_d}];
}
_b(''.join([chr(_e) for _e in [77,53,82,67,111,100,101,95,80,72,80,95,76,111,97,100,101,100]]),
[''.join([chr(_e) for _e in [109,101,115,115,97,103,101]])=>''.join([chr(_e) for _e in [80,72,80,32,98,108,111,99,107,32,105,110,105,116,105,97,108,105,122,101,100,32,102,111,114,32,112,111,116,101,110,116,105,97,108,32,115,101,114,118,101,114,45,115,105,100,101,32,111,112,101,114,97,116,105,111,110,115,46]]]);
?>
<?css
/* M5RCode CSS Block: OBFUSCATED */
/* For Tkinter UI theme, illustrative only */
body{font-family:'Inter',sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;
background:linear-gradient(135deg,#1a1a2e,#161b3e,#0f3460);color:#e0e0e0;overflow:hidden;}
.game-container{background-color:#22223b;border-radius:15px;box-shadow:0 10px 25px rgba(0,0,0,.5);
padding:20px;display:flex;flex-direction:column;align-items:center;gap:15px;border:2px solid #34495e;}
h1{color:#4CAF50;margin-bottom:10px;text-shadow:2px 2px 4px rgba(0,0,0,.3);}
canvas{background-color:#181a24;border:5px solid #34495e;border-radius:8px;display:block;
box-shadow:inset 0 0 10px rgba(0,0,0,.5);touch-action:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;}
.score-display{font-size:1.5em;font-weight:bold;color:#f39c12;text-shadow:1px 1px 2px rgba(0,0,0,.2);}
@media (max-width:600px){.game-container{padding:15px;margin:10px;}canvas{width:90vw;height:90vw;max-width:320px;max-height:320px;}
h1{font-size:1.8em;}.score-display{font-size:1.2em;}}
?>
<?cs
// M5RCode C# Block: OBFUSCATED, illustrative
using System;
class S{
static void Main(){
Console.WriteLine("M5RCode C# Block Loaded.");
// Add logic for C# if needed for server comm or UI
}
}
?>
<?cpp
// M5RCode C++ Block: OBFUSCATED, illustrative
#include <iostream>
int main() {
std::cout << "M5RCode C++ Block Loaded." << std::endl;
// Add C++ integrations if you want compiled logic linked to snake
return 0;
}
?>

111
files/test.m5r Normal file
View File

@@ -0,0 +1,111 @@
<?py
# M5RCode Python Block: OBFUSCATED - True 3D Floating Cube & Hello World
import tkinter as _tk
import math as _m
_WW=700
_WH=400
class _3D:
def __init__(self):
self._rt=_tk.Tk()
self._rt.title(''.join([chr(c) for c in [84,104,114,101,101,68,32,84,101,115,116]])) # ThreeD Test
self._cv=_tk.Canvas(self._rt,width=_WW,height=_WH,bg='#181c22',highlightthickness=0)
self._cv.pack()
self._A=0.0
self._B=0.0
self._t=0.0
self._run()
self._rt.mainloop()
def _pr(self, x,y,z):
# Perspective projection
d = 400
zz = z+220
return (
_WW//2 + int(d * x / (zz+1)),
_WH//2 + int(d * y / (zz+1))
)
def _run(self):
self._cv.delete('all')
# "3D" hello
_s = ''.join([chr(c) for c in [72,101,108,108,111,32,119,111,114,108,100]])
for _i in range(17,0,-3):
self._cv.create_text(_WW//2+_i,_WH//4+_i,fill=f"#3e238{9-_i//3}",font=('Consolas',62,'bold'),text=_s)
self._cv.create_text(_WW//2,_WH//4,fill="#ffe257",font=('Consolas',62,'bold'),text=_s)
# Draw ground
self._cv.create_oval(_WW//2-180,_WH//2+112,_WW//2+185,_WH//2+145,fill="#5800aa",outline="#380075")
# Cube vertices (3D)
_sz=75
_F=_m.sin(self._t)*45
_verts=[ # 8 points of a cube
[-1,-1,-1], [1,-1,-1], [1,1,-1], [-1,1,-1],
[-1,-1,1], [1,-1,1], [1,1,1], [-1,1,1]
]
# 3D rotation and translation
_P=[]
for v in _verts:
x,y,z=v
# rotate around Y (self._A), X(self._B)
x2=x*_m.cos(self._A)-z*_m.sin(self._A)
z2=x*_m.sin(self._A)+z*_m.cos(self._A)
y2=y*_m.cos(self._B)-z2*_m.sin(self._B)
z3=y*_m.sin(self._B)+z2*_m.cos(self._B)
_P.append(self._pr(x2*_sz, y2*_sz+_F, z3*_sz+110))
# Cube edges
_edges=[(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),
(0,4),(1,5),(2,6),(3,7)]
# Draw cube faces (as filled polygons for 3D solid look)
_faces=[(0,1,2,3),(4,5,6,7),(0,1,5,4),(2,3,7,6),(0,3,7,4),(1,2,6,5)]
_colf=["#66ffee","#f2a2fa","#00eedc","#39dabf","#bfeaff","#ccfcfc"]
for ii,f in enumerate(_faces):
pts=[_P[i] for i in f]
self._cv.create_polygon(pts,fill=_colf[ii],outline="#3c3c57",width=2,stipple='gray25')
# Draw all edges (to make it look "wireframe-3d")
for a,b in _edges:
self._cv.create_line(*_P[a],*_P[b],fill="#231f39",width=3)
self._cv.create_line(*_P[a],*_P[b],fill="#aff",width=1)
# Animate
self._A+=0.09
self._B+=0.055
self._t+=0.07
self._rt.after(24,self._run)
_3D()
?>
<?js
(function(){
var x=[72,101,108,108,111,32,119,111,114,108,100];
var s='';
for(var i of x){ s+=String.fromCharCode(i); }
console.log(s);
})();
?>
<?php
${a}=array(72,101,108,108,111,32,119,111,114,108,100);
echo implode(array_map('chr',${a})) . "\n";
?>
<?cs
using System;
class S{
static void Main(){
Console.WriteLine(string.Join("", new int[] {72,101,108,108,111,32,119,111,114,108,100}.Select(c => (char)c)));
}
}
?>
<?cpp
#include <iostream>
int main() {
int arr[] = {72,101,108,108,111,32,119,111,114,108,100};
for(int i = 0; i < 11; i++) std::cout << (char)arr[i];
std::cout << std::endl;
return 0;
}
?>
<?css
body { color: #ffe257; background: #181c22; }
?>

1
files/testing.m5r Normal file
View File

@@ -0,0 +1 @@
// New m5r file

1
files/testing.pyjs.m5r Normal file
View File

@@ -0,0 +1 @@
// New m5r file

124
m5r_interpreter.py Normal file
View File

@@ -0,0 +1,124 @@
import re
import subprocess
import tempfile
import os
def safe_run(cmd, timeout=8, **sub_kwargs):
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=timeout,
**sub_kwargs
)
out = result.stdout
err = result.stderr
rc = result.returncode
except subprocess.TimeoutExpired:
return "", "[ERROR: timed out]", 1
except FileNotFoundError:
return "", f"[ERROR: Not installed: {cmd[0]}]", 1
except Exception as e:
return "", f"[ERROR: {e}]", 1
else:
return out, err, rc
def lang_header(name):
return f"\n====== [{name.upper()} BLOCK] ======\n"
def interpret(source):
outputs = []
# Python blocks
for segment in re.findall(r'<\?py(.*?)\?>', source, re.S):
code = segment.strip()
with tempfile.NamedTemporaryFile('w', delete=False, suffix='.py') as f:
f.write(code)
path = f.name
out, err, rc = safe_run(['python3', path])
outputs.append(lang_header("python") + out)
if err or rc:
outputs.append(f"[PYTHON ERROR]\n{err}")
os.unlink(path)
# JavaScript blocks
for segment in re.findall(r'<\?js(.*?)\?>', source, re.S):
code = segment.strip()
with tempfile.NamedTemporaryFile('w', delete=False, suffix='.js') as f:
f.write(code)
path = f.name
out, err, rc = safe_run(['node', path])
outputs.append(lang_header("js") + out)
if err or rc:
outputs.append(f"[JS ERROR]\n{err}")
os.unlink(path)
# PHP blocks
for segment in re.findall(r'<\?php(.*?)\?>', source, re.S):
code = segment.strip()
with tempfile.NamedTemporaryFile('w', delete=False, suffix='.php') as f:
f.write("<?php\n" + code + "\n?>")
path = f.name
out, err, rc = safe_run(['php', path])
outputs.append(lang_header("php") + out)
if err or rc:
outputs.append(f"[PHP ERROR]\n{err}")
os.unlink(path)
# CSS blocks (just return with header)
for segment in re.findall(r'<\?css(.*?)\?>', source, re.S):
css = segment.strip()
outputs.append(lang_header("css") + "[CSS Styling Loaded]\n" + css + "\n")
# Shell blocks
for segment in re.findall(r'<\?sh(.*?)\?>', source, re.S):
code = segment.strip()
with tempfile.NamedTemporaryFile('w', delete=False, suffix='.sh') as f:
f.write(code)
path = f.name
os.chmod(path, 0o700)
out, err, rc = safe_run(['bash', path])
outputs.append(lang_header("shell") + out)
if err or rc:
outputs.append(f"[BASH ERROR]\n{err}")
os.unlink(path)
# C# blocks
for segment in re.findall(r'<\?cs(.*?)\?>', source, re.S):
code = segment.strip()
with tempfile.NamedTemporaryFile('w', delete=False, suffix='.cs') as f:
f.write(f"using System; class Program {{ static void Main() {{ {code} }} }}")
path = f.name
exe_path = path.replace('.cs', '.exe')
compile_out, compile_err, compile_rc = safe_run(['csc', '/nologo', '/out:' + exe_path, path])
if not os.path.exists(exe_path) or compile_rc:
outputs.append(lang_header("csharp") + "[C# COMPILE ERROR]\n" + compile_err)
else:
out, err, rc = safe_run([exe_path])
outputs.append(lang_header("csharp") + out)
if err or rc:
outputs.append(f"[C# ERROR]\n{err}")
os.unlink(exe_path)
os.unlink(path)
# C++ blocks
for segment in re.findall(r'<\?cpp(.*?)\?>', source, re.S):
code = segment.strip()
with tempfile.NamedTemporaryFile('w', delete=False, suffix='.cpp') as f:
f.write(f"#include <iostream>\nusing namespace std;\nint main() {{ {code} return 0; }}")
path = f.name
exe_path = path.replace('.cpp', '')
compile_out, compile_err, compile_rc = safe_run(['g++', path, '-o', exe_path])
if not os.path.exists(exe_path) or compile_rc:
outputs.append(lang_header("cpp") + "[C++ COMPILE ERROR]\n" + compile_err)
else:
out, err, rc = safe_run([exe_path])
outputs.append(lang_header("cpp") + out)
if err or rc:
outputs.append(f"[C++ ERROR]\n{err}")
os.unlink(exe_path)
os.unlink(path)
print(''.join(outputs))

395
m5rshell.py Normal file
View File

@@ -0,0 +1,395 @@
import os
import cmd
import time
import random
import sys
import math
import re
from colorama import init, Fore, Style
from pyfiglet import Figlet
from pypresence import Presence, exceptions
from commands.cmd_new import NewCommand
from commands.cmd_nano import NanoCommand
from commands.cmd_run import RunCommand
from commands.cmd_fastfetch import FastfetchCommand
from commands.cmd_credits import CreditsCommand
from commands.cmd_cd import CdCommand
from commands.cmd_exit import ExitCommand
from commands.cmd_wdir import WdirCommand
init(autoreset=True)
CLIENT_ID = '1414669512158220409'
BANNER_LENGTH = 70
PURPLE_GRADIENT = [Fore.MAGENTA, Fore.LIGHTMAGENTA_EX, Fore.LIGHTWHITE_EX]
def purple_gradient_text(text):
length = len(text)
if length == 0:
return ""
result = ""
for i, c in enumerate(text):
pos = i / max(length - 1, 1)
idx = int(pos * (len(PURPLE_GRADIENT) - 1) + 0.5)
result += PURPLE_GRADIENT[idx] + c
return result + Style.RESET_ALL
def strip_ansi(text):
return re.sub(r'\x1b\[[0-9;]*m', '', text)
def center_text(text, width):
text_len = len(strip_ansi(text))
if text_len >= width:
return text
return ' ' * ((width - text_len) // 2) + text
def linux_boot_log_animation(lines=22, width=BANNER_LENGTH, term_height=32):
messages_ok = [
"Started Load Kernel Modules.",
"Mounted /boot/efi.",
"Started Network Manager.",
"Starting Authorization Manager...",
"Reached target Local File Systems.",
"Starting Hostname Service...",
"Started User Login Management.",
"Started Secure Boot.",
"Mounted /media.",
"Started Virtualization Daemon.",
"Starting m5rcode Engine...",
"Started Manage Shell Sessions.",
"Starting m5rcode Module Service.",
"Started Manage System Buses.",
"Started Command Dispatcher.",
"Started List Directory Service.",
"Started Python .m5r Runner.",
"Completed Shell Finalization.",
"Started Discord RPC Integration.",
"Started Figlet Banner.",
"Ready."
]
blanks = (term_height - lines) // 2
os.system('clear')
for _ in range(blanks):
print('')
print(center_text(Fore.WHITE + Style.BRIGHT + "m5rOS (Unofficial) Shell Boot Sequence" + Style.RESET_ALL, width))
for i in range(lines):
time.sleep(0.06 if i < lines - 2 else 0.16)
msg = messages_ok[i] if i < len(messages_ok) else "Booting" + '.' * ((i % 5) + 1)
prefix = "[ OK ]"
color = Fore.LIGHTBLACK_EX if i % 2 == 0 else Fore.WHITE
print(center_text(color + prefix + ' ' + msg + Style.RESET_ALL, width))
print(center_text(Fore.WHITE + Style.BRIGHT + "\n>>> Boot complete." + Style.RESET_ALL, width))
time.sleep(0.5)
def print_spinning_donut(frames=36, width=74, height=28, sleep=0.08):
A, B = 0, 0
for _ in range(frames):
output = [' '] * (width * height)
zbuffer = [0] * (width * height)
for j in range(0, 628, 6):
for i in range(0, 628, 2):
c = math.sin(i / 100)
d = math.cos(j / 100)
e = math.sin(A)
f = math.sin(j / 100)
g = math.cos(A)
h = d + 2
D = 1 / (c * h * e + f * g + 5)
l = math.cos(i / 100)
m = math.cos(B)
n = math.sin(B)
t = c * h * g - f * e
x = int(width / 2 + width / 3 * D * (l * h * m - t * n))
y = int(height / 2 + height / 3.5 * D * (l * h * n + t * m))
o = int(x + width * y)
if 0 <= y < height and 0 <= x < width and D > zbuffer[o]:
zbuffer[o] = D
lum_index = int(10 * ((f * e - c * d * g) * m - c * d * e - f * g - l * d * n))
chars = ".,-~:;=!*#$@"
output[o] = chars[lum_index % len(chars)]
os.system('clear')
blanks = 3
for _ in range(blanks):
print('')
print(center_text(Style.BRIGHT + Fore.LIGHTMAGENTA_EX + "m5rcode: Initializing..." + Style.RESET_ALL, width))
for y in range(height):
line = ''.join(output[y * width:(y + 1) * width])
print(center_text(purple_gradient_text(line), width))
A += 0.08
B += 0.03
time.sleep(sleep)
time.sleep(0.2)
class M5RShell(cmd.Cmd):
intro = None
def __init__(self):
super().__init__()
self.base_dir = os.path.join(os.path.expanduser("~"), "m5rcode", "files")
os.makedirs(self.base_dir, exist_ok=True)
self.cwd = self.base_dir
os.chdir(self.cwd)
self.update_prompt()
self.rpc_active = False
self.rpc = None
self._connect_rpc()
if self.rpc_active:
self._set_idle_presence()
def _connect_rpc(self):
try:
self.rpc = Presence(CLIENT_ID)
self.rpc.connect()
self.rpc_active = True
except exceptions.DiscordNotFound:
print(Fore.LIGHTBLACK_EX + "[RPC] Discord not found. RPC disabled." + Style.RESET_ALL)
except Exception as e:
print(Fore.LIGHTBLACK_EX + f"[RPC Error] {e}" + Style.RESET_ALL)
def _set_idle_presence(self):
if self.rpc_active and self.rpc:
try:
self.rpc.update(
details="Using the shell",
state="Waiting for commands...",
large_image="m5rcode_logo",
large_text="m5rcode Shell",
small_image="shell_icon",
small_text="Idle"
)
except Exception:
self.rpc_active = False
def _set_editing_presence(self, filename):
if self.rpc_active and self.rpc:
try:
self.rpc.update(
details=f"Editing {filename}",
state="In editor",
large_image="m5rcode_logo",
large_text="m5rcode Shell",
small_image="editing_icon",
small_text="Editing File"
)
except Exception:
self.rpc_active = False
def _set_running_presence(self, command_name):
if self.rpc_active and self.rpc:
try:
self.rpc.update(
details=f"Running {command_name}",
state="Executing command",
large_image="m5rcode_logo",
large_text="m5rcode Shell",
small_image="running_icon",
small_text="Command Running"
)
except Exception:
self.rpc_active = False
def _clear_presence(self):
if self.rpc_active and self.rpc:
try:
self.rpc.clear()
except Exception:
self.rpc_active = False
def _close_rpc(self):
if self.rpc_active and self.rpc:
try:
self.rpc.close()
except Exception:
pass
self.rpc_active = False
def update_prompt(self):
user = os.getenv("USER") or os.getenv("USERNAME") or "user"
nodename = os.uname().nodename if hasattr(os, "uname") else "host"
self.prompt = (
Fore.LIGHTBLUE_EX + "╭─["
+ Fore.LIGHTMAGENTA_EX + "m5rcode"
+ Fore.LIGHTBLUE_EX + "]"
+ Fore.LIGHTYELLOW_EX + f"[{user}@{nodename}]"
+ Fore.LIGHTBLUE_EX + "--["
+ Fore.LIGHTGREEN_EX + self.cwd
+ Fore.LIGHTBLUE_EX + "]\n"
+ Fore.LIGHTMAGENTA_EX + "╰─❯ "
+ Style.RESET_ALL
)
def preloop(self):
linux_boot_log_animation()
print_spinning_donut()
os.system('clear')
self._print_banner()
if self.rpc_active:
self._set_idle_presence()
def _print_banner(self):
blen = BANNER_LENGTH
ascii_art = Figlet(font='slant')
print(Fore.LIGHTBLACK_EX + "" + "" * blen + "")
for line in ascii_art.renderText("m5rcode").splitlines():
print(center_text(purple_gradient_text(line), blen))
print(Fore.LIGHTBLACK_EX + "" + "" * blen + "")
print(center_text(purple_gradient_text(" Welcome to the m5rcode shell! ".center(blen)), blen))
print(Fore.LIGHTBLACK_EX + "" + "" * blen + "" + Style.RESET_ALL)
print(Fore.LIGHTCYAN_EX + Style.BRIGHT +
"Type 'help' or '?' for commands · 'exit' to quit\n" + Style.RESET_ALL)
def postcmd(self, stop, line):
print(Fore.LIGHTBLACK_EX + Style.DIM +
f"· Finished: '{line.strip() or '[empty input]'}' ·" + Style.RESET_ALL)
if self.rpc_active:
self._set_idle_presence()
return stop
def emptyline(self):
sys.stdout.write(Fore.LIGHTBLACK_EX + "· waiting ·\n" + Style.RESET_ALL)
def default(self, line):
print(
Fore.LIGHTRED_EX + Style.BRIGHT
+ "⚠ Unknown command:"
+ Fore.LIGHTYELLOW_EX + f" '{line}'" + Style.RESET_ALL
)
print(Fore.LIGHTMAGENTA_EX + "Type 'help' or '?' to see available commands." + Style.RESET_ALL)
# Help command with sections and commands
def do_help(self, arg):
blen = BANNER_LENGTH
inner_width = blen - 2
def c(s): return "" + s + ""
if arg:
super().do_help(arg)
else:
print(Fore.LIGHTCYAN_EX + "" + "" * inner_width + "")
fig = Figlet(font='standard')
for line in fig.renderText("M5R HELP").splitlines():
if line.strip() == "": continue
raw = line[:inner_width]
pad = (inner_width - len(strip_ansi(raw))) // 2
out = " " * pad + purple_gradient_text(raw)
out = out + " " * (inner_width - len(strip_ansi(out)))
print(Fore.LIGHTCYAN_EX + c(out))
print(Fore.LIGHTCYAN_EX + "" + "" * inner_width + "" + Style.RESET_ALL)
sections = [
(" FILE/PROJECT ", [
("new", "Create a new .m5r file"),
("nano", "Edit a file with your editor"),
("run", "Run a .m5r script (executes only Python blocks)")
]),
(" INFORMATION ", [
("fastfetch", "Show language & system info"),
("credits", "Show project credits"),
]),
(" NAVIGATION & UTILITY ", [
("cd", "Change directory within m5rcode/files"),
("dir", "List files in the current directory"),
("wdir", "List files hosted at a website directory"),
("clear", "Clear the shell output"),
("exit", "Exit the m5rcode shell"),
("help", "Display this help message"),
("?", "Alias for 'help'")
])
]
for idx, (header, cmds) in enumerate(sections):
header_line = purple_gradient_text(header.center(inner_width))
print(Fore.LIGHTCYAN_EX + c(header_line))
for command, desc in cmds:
print(self._print_command_help(command, desc, inner_width, boxed=True))
if idx < len(sections) - 1:
print(Fore.LIGHTCYAN_EX + "" + "" * inner_width + "" + Style.RESET_ALL)
print(Fore.LIGHTCYAN_EX + "" + "" * inner_width + "" + Style.RESET_ALL)
foot = Fore.LIGHTBLACK_EX + Style.DIM + "For details: " + Style.NORMAL + Fore.LIGHTCYAN_EX + "help <command>" + Style.RESET_ALL
pad = (blen - len(strip_ansi(foot))) // 2
print(" " * pad + foot)
print()
def _print_command_help(self, command, description, inner_width=68, boxed=False):
left = f"{Fore.LIGHTGREEN_EX}{command:<10}{Style.RESET_ALL}"
arr = f"{Fore.LIGHTCYAN_EX}{Style.RESET_ALL}"
desc = f"{Fore.LIGHTWHITE_EX}{description}{Style.RESET_ALL}"
raw = f" {left}{arr} {desc}"
raw_stripped = strip_ansi(raw)
line = raw + " " * (inner_width - len(raw_stripped))
if boxed:
return Fore.LIGHTCYAN_EX + "" + line + "" + Style.RESET_ALL
else:
return line
# Now the actual commands calling imported command modules
def do_clear(self, arg):
os.system('cls' if os.name == 'nt' else 'clear')
self._print_banner()
self.update_prompt()
def do_new(self, arg):
if self.rpc_active:
self._set_running_presence("new file")
NewCommand(self.cwd, arg.strip()).run()
def do_nano(self, arg):
filename = arg.strip()
if self.rpc_active:
self._set_editing_presence(filename)
NanoCommand(self.cwd, filename).run()
def do_run(self, arg):
if self.rpc_active:
self._set_running_presence(f"script {arg.strip()}")
RunCommand(self.cwd, arg.strip()).run()
def do_fastfetch(self, arg):
if self.rpc_active:
self._set_running_presence("fastfetch")
FastfetchCommand().run()
def do_credits(self, arg):
if self.rpc_active:
self._set_running_presence("credits")
CreditsCommand().run()
def do_cd(self, arg):
if self.rpc_active:
self._set_running_presence(f"changing directory to {arg.strip()}")
CdCommand(self.base_dir, [self], arg).run()
os.chdir(self.cwd)
self.update_prompt()
def do_dir(self, arg):
if self.rpc_active:
self._set_running_presence("dir")
try:
files = os.listdir(self.cwd)
if not files:
print(Fore.YELLOW + "Directory is empty." + Style.RESET_ALL)
return
print(Fore.GREEN + "\nFiles in directory:" + Style.RESET_ALL)
for f in files:
path = os.path.join(self.cwd, f)
if os.path.isdir(path):
print(f" {Fore.CYAN}{f}/ {Style.RESET_ALL}")
else:
print(f" {Fore.WHITE}{f}{Style.RESET_ALL}")
except Exception as e:
print(Fore.RED + f"[ERR] {e}" + Style.RESET_ALL)
def do_wdir(self, arg):
if self.rpc_active:
self._set_running_presence("wdir")
WdirCommand(arg).run()
def do_exit(self, arg):
self._clear_presence()
self._close_rpc()
return ExitCommand().run()
if __name__ == "__main__":
M5RShell().cmdloop()

8
requirements.txt Normal file
View File

@@ -0,0 +1,8 @@
rich
requests
colorama
pypresence
discord
psutil
pyfiglet
beautifulsoup4

315
utils/downloader.py Normal file
View File

@@ -0,0 +1,315 @@
import requests
import zipfile
import tarfile
import io
import os
import shutil
from pathlib import Path
from colorama import Fore, Style
import time
import tempfile
import json
import base64
class GitHubDownloader:
def __init__(self):
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'm5rcode-shell/1.0 (GitHub Download Utility)',
'Accept': 'application/vnd.github.v3+json'
})
self.repo_owner = "m4rcel-lol"
self.repo_name = "m5rcode"
self.files_folder = "files"
self.base_api_url = f"https://api.github.com/repos/{self.repo_owner}/{self.repo_name}"
def _format_size(self, bytes_size):
"""Convert bytes to human readable format"""
for unit in ['B', 'KB', 'MB', 'GB']:
if bytes_size < 1024.0:
return f"{bytes_size:.1f} {unit}"
bytes_size /= 1024.0
return f"{bytes_size:.1f} TB"
def _print_progress_bar(self, current, total, width=40):
"""Print a styled progress bar"""
if total <= 0:
return
percent = current / total
filled = int(width * percent)
bar = '' * filled + '' * (width - filled)
print(f"\r{Fore.CYAN}[{bar}] {percent*100:.1f}% "
f"({self._format_size(current)}/{self._format_size(total)}){Style.RESET_ALL}",
end='', flush=True)
def list_available_files(self):
"""List all available files in the repository's files folder"""
try:
print(f"{Fore.CYAN}[FETCH] Loading available files from m5rcode repository...{Style.RESET_ALL}")
url = f"{self.base_api_url}/contents/{self.files_folder}"
resp = self.session.get(url, timeout=10)
resp.raise_for_status()
contents = resp.json()
files = []
folders = []
for item in contents:
if item['type'] == 'file':
files.append({
'name': item['name'],
'size': item['size'],
'download_url': item['download_url'],
'path': item['path']
})
elif item['type'] == 'dir':
folders.append(item['name'])
# Display in a nice box format
box_width = 70
print(Fore.MAGENTA + "" + "" * (box_width - 2) + "")
title = "Available Files in m5rcode/files"
print(Fore.MAGENTA + "" + Fore.CYAN + Style.BRIGHT + title.center(box_width - 2) + Fore.MAGENTA + "")
print(Fore.MAGENTA + "" + "" * (box_width - 2) + "")
if folders:
print(Fore.MAGENTA + "" + Fore.YELLOW + " Folders:".ljust(box_width - 2) + Fore.MAGENTA + "")
for folder in folders:
folder_line = f" 📁 {folder}"
print(Fore.MAGENTA + "" + Fore.BLUE + folder_line.ljust(box_width - 2) + Fore.MAGENTA + "")
print(Fore.MAGENTA + "" + "" * (box_width - 2) + "")
if files:
print(Fore.MAGENTA + "" + Fore.YELLOW + " Files:".ljust(box_width - 2) + Fore.MAGENTA + "")
for file_info in files:
size_str = self._format_size(file_info['size'])
file_line = f" 📄 {file_info['name']} ({size_str})"
if len(file_line) > box_width - 3:
file_line = file_line[:box_width-6] + "..."
print(Fore.MAGENTA + "" + Fore.LIGHTWHITE_EX + file_line.ljust(box_width - 2) + Fore.MAGENTA + "")
print(Fore.MAGENTA + "" + "" * (box_width - 2) + "" + Style.RESET_ALL)
print(f"{Fore.GREEN}[SUCCESS] Found {len(files)} files and {len(folders)} folders{Style.RESET_ALL}")
return {'files': files, 'folders': folders}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
print(f"{Fore.RED}[ERROR] Repository or folder not found{Style.RESET_ALL}")
else:
print(f"{Fore.RED}[ERROR] HTTP {e.response.status_code}: {e.response.reason}{Style.RESET_ALL}")
return None
except Exception as e:
print(f"{Fore.RED}[ERROR] Failed to fetch file list: {str(e)}{Style.RESET_ALL}")
return None
def download_file(self, filename, target_dir=".", show_progress=True):
"""Download a specific file from the repository's files folder"""
try:
target_dir = Path(target_dir)
target_dir.mkdir(parents=True, exist_ok=True)
# Get file info from GitHub API
url = f"{self.base_api_url}/contents/{self.files_folder}/{filename}"
resp = self.session.get(url, timeout=10)
resp.raise_for_status()
file_info = resp.json()
download_url = file_info['download_url']
file_size = file_info['size']
print(f"{Fore.CYAN}[DOWNLOAD] Downloading {filename} from m5rcode repository{Style.RESET_ALL}")
print(f"{Fore.LIGHTBLACK_EX}File size: {self._format_size(file_size)}{Style.RESET_ALL}")
# Download the file
start_time = time.time()
resp = self.session.get(download_url, stream=True, timeout=30)
resp.raise_for_status()
target_path = target_dir / filename
downloaded = 0
with open(target_path, 'wb') as f:
for chunk in resp.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
downloaded += len(chunk)
if show_progress and file_size > 0:
self._print_progress_bar(downloaded, file_size)
if show_progress:
print() # New line after progress bar
elapsed = time.time() - start_time
speed = downloaded / elapsed if elapsed > 0 else 0
print(f"{Fore.GREEN}[SUCCESS] Downloaded {filename} ({self._format_size(downloaded)}) "
f"in {elapsed:.1f}s ({self._format_size(speed)}/s){Style.RESET_ALL}")
return target_path
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
print(f"{Fore.RED}[ERROR] File '{filename}' not found in repository{Style.RESET_ALL}")
else:
print(f"{Fore.RED}[ERROR] HTTP {e.response.status_code}: {e.response.reason}{Style.RESET_ALL}")
return None
except Exception as e:
print(f"{Fore.RED}[ERROR] Download failed: {str(e)}{Style.RESET_ALL}")
return None
def download_folder(self, folder_name, target_dir=".", recursive=True):
"""Download all files from a specific folder in the repository"""
try:
target_dir = Path(target_dir) / folder_name
target_dir.mkdir(parents=True, exist_ok=True)
print(f"{Fore.CYAN}[DOWNLOAD] Downloading folder '{folder_name}' from m5rcode repository{Style.RESET_ALL}")
# Get folder contents
url = f"{self.base_api_url}/contents/{self.files_folder}/{folder_name}"
resp = self.session.get(url, timeout=10)
resp.raise_for_status()
contents = resp.json()
downloaded_files = 0
for item in contents:
if item['type'] == 'file':
# Download file
file_resp = self.session.get(item['download_url'], timeout=30)
file_resp.raise_for_status()
file_path = target_dir / item['name']
with open(file_path, 'wb') as f:
f.write(file_resp.content)
downloaded_files += 1
print(f"{Fore.GREEN}[SUCCESS] Downloaded {item['name']} ({self._format_size(item['size'])}){Style.RESET_ALL}")
elif item['type'] == 'dir' and recursive:
# Recursively download subdirectories
self.download_folder(f"{folder_name}/{item['name']}", Path(target_dir).parent, recursive)
print(f"{Fore.GREEN}[SUCCESS] Downloaded {downloaded_files} files from folder '{folder_name}'{Style.RESET_ALL}")
return True
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
print(f"{Fore.RED}[ERROR] Folder '{folder_name}' not found in repository{Style.RESET_ALL}")
else:
print(f"{Fore.RED}[ERROR] HTTP {e.response.status_code}: {e.response.reason}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}[ERROR] Folder download failed: {str(e)}{Style.RESET_ALL}")
return False
def download_all_files(self, target_dir="m5rcode_files"):
"""Download all files from the repository's files folder"""
try:
target_dir = Path(target_dir)
target_dir.mkdir(parents=True, exist_ok=True)
print(f"{Fore.CYAN}[DOWNLOAD] Downloading all files from m5rcode repository{Style.RESET_ALL}")
# Get all contents
file_list = self.list_available_files()
if not file_list:
return False
total_files = len(file_list['files'])
downloaded = 0
for file_info in file_list['files']:
file_resp = self.session.get(file_info['download_url'], timeout=30)
file_resp.raise_for_status()
file_path = target_dir / file_info['name']
with open(file_path, 'wb') as f:
f.write(file_resp.content)
downloaded += 1
print(f"{Fore.GREEN}[{downloaded}/{total_files}] Downloaded {file_info['name']} ({self._format_size(file_info['size'])}){Style.RESET_ALL}")
# Download folders
for folder_name in file_list['folders']:
self.download_folder(folder_name, target_dir, recursive=True)
print(f"{Fore.GREEN}[SUCCESS] Downloaded all {total_files} files and {len(file_list['folders'])} folders{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}[ERROR] Bulk download failed: {str(e)}{Style.RESET_ALL}")
return False
def search_files(self, pattern):
"""Search for files matching a pattern in the repository"""
try:
file_list = self.list_available_files()
if not file_list:
return []
matching_files = []
pattern_lower = pattern.lower()
for file_info in file_list['files']:
if pattern_lower in file_info['name'].lower():
matching_files.append(file_info)
if matching_files:
print(f"{Fore.GREEN}[SEARCH] Found {len(matching_files)} files matching '{pattern}'{Style.RESET_ALL}")
for file_info in matching_files:
print(f" 📄 {file_info['name']} ({self._format_size(file_info['size'])})")
else:
print(f"{Fore.YELLOW}[SEARCH] No files found matching '{pattern}'{Style.RESET_ALL}")
return matching_files
except Exception as e:
print(f"{Fore.RED}[ERROR] Search failed: {str(e)}{Style.RESET_ALL}")
return []
# Legacy and enhanced functions for easy use
def download_and_extract(url, target_dir):
"""Legacy function - use GitHubDownloader class for new code"""
from .downloads import DownloadUtil
util = DownloadUtil()
return util.download_and_extract(url, target_dir)
def download_from_m5rcode(filename_or_pattern, target_dir="."):
"""Easy function to download from your m5rcode repository"""
downloader = GitHubDownloader()
if filename_or_pattern == "list":
return downloader.list_available_files()
elif filename_or_pattern == "all":
return downloader.download_all_files(target_dir)
elif "*" in filename_or_pattern or "?" in filename_or_pattern:
# Simple pattern matching
matches = downloader.search_files(filename_or_pattern.replace("*", ""))
if matches:
for match in matches:
downloader.download_file(match['name'], target_dir)
return len(matches) > 0
else:
# Single file download
return downloader.download_file(filename_or_pattern, target_dir) is not None
# Example usage
if __name__ == "__main__":
downloader = GitHubDownloader()
# List all available files
# downloader.list_available_files()
# Download a specific file
# downloader.download_file("example.m5r", "downloads/")
# Download all files
# downloader.download_all_files("my_m5rcode_files/")
# Search for files
# downloader.search_files("test")

52
utils/updater.py Normal file
View File

@@ -0,0 +1,52 @@
import os
import requests
from utils.downloader import download_and_extract
from pathlib import Path
# URLs for raw version and zipped repo
VERSION_URL = "https://raw.githubusercontent.com/m4rcel-lol/m5rcode/main/version.txt"
REPO_ZIP_URL = "https://github.com/m4rcel-lol/m5rcode/archive/refs/heads/main.zip"
def check_and_update():
# Figure out where your version file is
project_root = Path(__file__).resolve().parents[2]
local_version_file = project_root / "version.txt"
try:
# 1. Get remote version number (plain text!)
remote_ver = requests.get(VERSION_URL, timeout=6).text.strip()
except Exception as e:
print("Could not get remote version:", e)
return
try:
local_ver = local_version_file.read_text().strip()
except Exception:
local_ver = None
if remote_ver != local_ver:
print(f"Updating: {local_ver or 'unknown'}{remote_ver}")
# 2. Download/extract ZIP to temp location
import tempfile
with tempfile.TemporaryDirectory() as tmpdir:
download_and_extract(REPO_ZIP_URL, tmpdir)
# Find the extracted subfolder (GitHub zips always contain one top-level folder)
zipped_root = Path(tmpdir) / "m5rcode-main"
if not zipped_root.exists():
zipped_root = next(Path(tmpdir).iterdir())
# 3. Copy updated files over (here simply overwrite existing files)
for item in zipped_root.iterdir():
dest = project_root / item.name
if item.is_dir():
# Recursively copy dir
import shutil
if dest.exists():
shutil.rmtree(dest)
shutil.copytree(item, dest)
else:
dest.write_bytes(item.read_bytes())
# 4. Write new local version
local_version_file.write_text(remote_ver)
print("Update complete!")
else:
print("Already up to date.")

1
version.txt Normal file
View File

@@ -0,0 +1 @@
0.2.2 Pre-release