Commit 89f4bad14f5c63ffd28c6860f99798733f4f37a1
Commits[COMMIT BEGIN]commit 89f4bad14f5c63ffd28c6860f99798733f4f37a1 Author: 0x4248 <[email protected]> Date: Sun Jan 11 23:42:22 2026 +0000 Orion: added manual, and many improvements Signed-off-by: 0x4248 <[email protected]> diff --git a/lab/orion/commands/echo.py b/lab/orion/commands/echo.py index 2c3874e..7abfd7e 100644 --- a/lab/orion/commands/echo.py +++ b/lab/orion/commands/echo.py @@ -2,6 +2,7 @@ from fastapi import Request from core.registry import registry from core.commands import Command from core import page +import manpages.echo def echo(request: Request, text: str = ""): if not text: diff --git a/lab/orion/commands/system/manual.py b/lab/orion/commands/system/manual.py new file mode 100644 index 0000000..7fbe5f0 --- /dev/null +++ b/lab/orion/commands/system/manual.py @@ -0,0 +1,66 @@ +# Manual command man <name/alias> or ? <name/alias> or help <name/alias> +from fastapi import APIRouter, Request +from fastapi.responses import RedirectResponse +from core.registry import registry +from core.commands import Command +from core import page + +from core.manual import manual_registry +from core.commands import Command + +router = APIRouter() [email protected]("/man/{name}") +def manual_page_api(request: Request, name: str): + return manual_page(request, name) + +def manual_page(request: Request, name: str = ""): + if name == "": + # show forum + return RedirectResponse(url="/forum/man") + man = manual_registry.get(name) + if not man: + return page.message( + request, + "MANUAL", + error=f"No manual page for: {name}" + ) + + return page.static(request, f"MANUAL PAGE FOR: {man.name.upper()}", html=f""" + <h1 style="text-align: center; text-transform: uppercase;">{man.name}</h1> +<pre>{man.text}</pre> + +<a href="javascript:history.back()" style="text-align:center">[ BACK ]</a> + """, buttons=page.with_nav(page.DEFAULT_NAV)) + +registry.register(Command( + name="man", + handler=manual_page, + summary="Show manual page for command", + mode="both", + form_fields=[ + {"name": "name", "type": "text"}, + ], +)) + +### ALIASES ### + +registry.register(Command( + name="?", + handler=manual_page, + summary="Show manual page for command", + mode="both", + form_fields=[ + {"name": "name", "type": "text"}, + ], +)) + + +registry.register(Command( + name="help", + handler=manual_page, + summary="Show manual page for command", + mode="both", + form_fields=[ + {"name": "name", "type": "text"}, + ], +)) diff --git a/lab/orion/core/layout.py b/lab/orion/core/layout.py index 38f8de1..083bb2b 100644 --- a/lab/orion/core/layout.py +++ b/lab/orion/core/layout.py @@ -127,6 +127,21 @@ input[type=submit]:focus , input[type=submit]:hover { SCRIPT = """ <script> document.addEventListener('keydown', function(event) { + if (event.key === 'Escape') { + document.activeElement.blur(); + } + + if (event.key === 'F1') { + const firstInput = document.querySelector('input, textarea'); + if (firstInput) { + const commandName = firstInput.value.trim(); + if (commandName) { + window.location.href = '/man/' + encodeURIComponent(commandName); + } + } + } + + if (event.key === 'F2') { window.location.href = '/command'; } @@ -134,10 +149,10 @@ document.addEventListener('keydown', function(event) { if (event.target.tagName.toLowerCase() === 'input' || event.target.tagName.toLowerCase() === 'textarea') { return; } - if (event.key === 'F4' || event.key === ',' || event.key === 'Escape') { + if (event.key === 'F4' || event.key === ',' || event.key === 'Backspace') { window.history.back(); } - if (event.key === 'F1') { + if (event.key === '.') { const firstInput = document.querySelector('input, textarea'); if (firstInput) { firstInput.focus(); @@ -161,7 +176,10 @@ def layout(request: Request, title: str, buttons: list[tuple[str, str]], header_ header = header_html if header_html is not None else f"<div class='header'><strong>ORION SYSTEM:</strong> {title}<br>{nav}</div>" return f""" <html> - <head>{STYLE}</head> + <head> + <title>ORION SYSTEM: {title}</title> + {STYLE} + </head> <body> {header} <hr/> diff --git a/lab/orion/core/manual.py b/lab/orion/core/manual.py new file mode 100644 index 0000000..6845748 --- /dev/null +++ b/lab/orion/core/manual.py @@ -0,0 +1,34 @@ +from typing import Dict, Optional, List + +# Manual funcions +# Commands can create manual pages by doing manual.register(NAME, TEXT, ALIASES (List, optional)) + +class ManualPage: + def __init__(self, name: str, text: str, aliases: Optional[List[str]] = None): + self.name = name + self.text = text + self.aliases = aliases if aliases is not None else [] +class ManualRegistry: + def __init__(self): + self._manuals: Dict[str, ManualPage] = {} + + def register(self, name: str, text: str, aliases: Optional[List[str]] = None): + if name in self._manuals: + raise ValueError(f"Duplicate manual page: {name}") + manual_page = ManualPage(name, text, aliases) + self._manuals[name] = manual_page + if aliases: + for alias in aliases: + if alias in self._manuals: + raise ValueError(f"Duplicate manual page alias: {alias}") + self._manuals[alias] = manual_page + + def get(self, name: str) -> Optional[ManualPage]: + return self._manuals.get(name) + + def all(self) -> List[ManualPage]: + # Return only unique manual pages (avoid duplicates from aliases) + unique_manuals = {mp.name: mp for mp in self._manuals.values()} + return list(unique_manuals.values()) + +manual_registry = ManualRegistry() diff --git a/lab/orion/main.py b/lab/orion/main.py index 3ed3e08..53d82db 100644 --- a/lab/orion/main.py +++ b/lab/orion/main.py @@ -1,13 +1,14 @@ from fastapi import FastAPI, Request -from fastapi.responses import RedirectResponse +from fastapi.responses import FileResponse, RedirectResponse -from pages import command +from pages import command,about from core import auth from core import page as p import commands.system.open -# import commands.testing.demo + +import commands.system.manual as manual import commands.echo app = FastAPI() @@ -18,7 +19,8 @@ app.middleware("http")(auth.auth_middleware) app.include_router(auth.router) app.include_router(command.router) - +app.include_router(about.router) +app.include_router(manual.router) @app.exception_handler(404) async def not_found(request: Request, exc): @@ -29,6 +31,9 @@ async def not_found(request: Request, exc): "<a href='javascript:history.back()'>[ BACK ]</a>", ) [email protected]("/favicon.ico") +async def favicon(): + return FileResponse("./static/mascot.ico") if __name__ == "__main__": import uvicorn diff --git a/lab/orion/manpages/echo.py b/lab/orion/manpages/echo.py new file mode 100644 index 0000000..8758ada --- /dev/null +++ b/lab/orion/manpages/echo.py @@ -0,0 +1,19 @@ +from core import manual + +manual.manual_registry.register( + name="echo", + text=""" +DESCRIPTION: + Echo back the provided text. + +USAGE: + echo <text> + +EXAMPLE: + $ echo Hello, World! + Hello, World! + +ALIASES: + none +""" +) \ No newline at end of file[COMMIT END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.