diff --git a/README.md b/README.md index bf15de8..4fd71ab 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,14 @@ Current installation process doesn't involve any `.mpy` module compilation, so, As of now, T-DeckARD implements the following component modules. +### `deck.runtime` + +A library for establishing runtime compatibility across various Python environments. + +Exported functions: + +- `runcode(code_string)`: compile and execute a Python program expressed as a string. Used by REPL and some applets. + ### `deck.input` A library for single-line and multi-line (ed-like) text input. @@ -240,6 +248,7 @@ The editor mode supports the following subset of POSIX ed commands in the standa - `s/old/new`: replace text in the range (doesn't support regex syntax from POSIX ed) - `f`: set the current filename to write to - `w`: save changes to the current filename +- `x`: interpret the range as Python code and execute it immediately - `q`: quit (`q!` force-quits without prompting for saving changes) ### `app.llmchat` diff --git a/app/ed.py b/app/ed.py index 797c1d8..c389dd5 100644 --- a/app/ed.py +++ b/app/ed.py @@ -5,6 +5,7 @@ from deck.input import input from deck.pager import print_paged +from deck.runtime import runcode class Ed: def __init__(self, filename=None): @@ -191,6 +192,11 @@ class Ed: self.filename = params print(self.filename if self.filename else "No current filename") + elif cmd_char == 'x': # execute current buffer range as Python code + code = '\n'.join(self.buffer[start-1:end]) + print(f'Running lines {start} to {end} as Python code...') + runcode(code) + else: print("Unknown command") diff --git a/code.py b/code.py index c2ded40..9174671 100644 --- a/code.py +++ b/code.py @@ -5,10 +5,8 @@ try: from repl.keys import show_keys except: pass -try: - from codeop import compile_command -except: - pass + +from deck.runtime import runcode if 'tdeckboot.py' in os.listdir('/'): from tdeckboot import * @@ -27,9 +25,9 @@ while True: if __line.lower() == 'exit': break __cmd = __line try: - if compile_command(__cmd): - exec(compile_command(__cmd)) + status, res = runcode(__cmd) + if status != 1: __cmd = "" except Exception as __err: - print("*ERROR* Exception:",str(__err)) + print("*ERROR* Exception:", str(__err)) __cmd = "" diff --git a/deck/runtime.py b/deck/runtime.py new file mode 100644 index 0000000..f433567 --- /dev/null +++ b/deck/runtime.py @@ -0,0 +1,33 @@ +# Runtime compatibility module +# Usage: from deck.runtime import runcode +# Created by Luxferre in 2025, released into public domain + +CMDCOMPILER = False +try: + from codeop import compile_command + CMDCOMPILER = True +except: + pass + +def runcode(code): + """ + Compile and evaluate Python code dynamically. + Returns (statuscode, result) tuple. + Return status codes: + 0 on error, 1 if the command is incomplete, 2 on success + """ + status = 0 # error status + res = None + if CMDCOMPILER: + compiled = compile_command(code) + else: + compiled = compile(code, '', 'exec') + if compiled: + try: + res = exec(compiled) + status = 2 # success status + except Exception as e: + res = str(e) + else: + status = 1 # continuation status + return (status, res)