From da1d22ec56aede968a251ab0d952d20f4c8ef6a4 Mon Sep 17 00:00:00 2001 From: leart-ramushi <113895250+leart-ramushi@users.noreply.github.com> Date: Tue, 26 May 2026 16:17:50 +0200 Subject: [PATCH] provisorisches run --- src/backend/execution_engine.py | 51 +++++++++--- src/backend/file_manager.py | 1 + src/main.py | 132 +++++++++++++++++++------------- src/ui/editor.py | 1 - 4 files changed, 121 insertions(+), 64 deletions(-) diff --git a/src/backend/execution_engine.py b/src/backend/execution_engine.py index 67cfd1b..9ab6723 100644 --- a/src/backend/execution_engine.py +++ b/src/backend/execution_engine.py @@ -1,12 +1,41 @@ -class ExecutionEngine: - """ - Platzhalter für die Code-Ausführung [1] - """ - def __init__(self): - pass +import subprocess +import sys +from pathlib import Path - def execute_code(self): - """ - Führt Code nicht aus, sondern gibt einen Status aus [1] - """ - return "Code wurde nicht ausgeführt (Platzhalter)" \ No newline at end of file + +class ExecutionEngine: + def run_file(self, filepath: str) -> dict: + path = Path(filepath) + + if not path.exists(): + return {"stdout": "", "stderr": f"File not found: {filepath}", "returncode": -1} + + ext = path.suffix.lower() + if ext == ".py": + cmd = [sys.executable, str(path)] + elif ext == ".js": + cmd = ["node", str(path)] + elif ext == ".sh": + cmd = ["bash", str(path)] + else: + return {"stdout": "", "stderr": f"Unsupported file type: {ext}", "returncode": -1} + + try: + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=30, + cwd=str(path.parent), + ) + return { + "stdout": result.stdout, + "stderr": result.stderr, + "returncode": result.returncode, + } + except subprocess.TimeoutExpired: + return {"stdout": "", "stderr": "Timed out after 30 seconds.", "returncode": -1} + except FileNotFoundError as e: + return {"stdout": "", "stderr": f"Runtime not found: {e}", "returncode": -1} + except Exception as e: + return {"stdout": "", "stderr": f"Error: {e}", "returncode": -1} \ No newline at end of file diff --git a/src/backend/file_manager.py b/src/backend/file_manager.py index 011b975..004a9f9 100644 --- a/src/backend/file_manager.py +++ b/src/backend/file_manager.py @@ -1,5 +1,6 @@ from pathlib import Path + class FileManager: """ Handles file reading and writing diff --git a/src/main.py b/src/main.py index 83744ba..bcdfb63 100644 --- a/src/main.py +++ b/src/main.py @@ -1,89 +1,109 @@ import sys import os +import tkinter as tk +from tkinter import filedialog from pathlib import Path - import streamlit as st from streamlit_tree_select import tree_select - # ---------------- PATH FIX ---------------- sys.path.append(os.path.dirname(os.path.abspath(__file__))) - # ---------------- BACKEND ---------------- from backend.file_manager import FileManager - from ui.navigation import FileNavigation from ui.chat import ChatInterface from ui.editor import CodeEditor -from ui.output import OutputDisplay - from backend.chat_manager import ChatManager from backend.execution_engine import ExecutionEngine - -# ---------------- PAGE ---------------- +# ---------------- PAGE CONFIG ---------------- st.set_page_config( page_title="AI Code Editor", page_icon="💻", - layout="wide" + layout="wide", ) - +# ---------------- FOLDER PICKER ---------------- +def pick_folder(): + root = tk.Tk() + root.withdraw() + root.wm_attributes("-topmost", 1) + folder = filedialog.askdirectory(title="Select project folder") + root.destroy() + return folder if folder else None # ---------------- SIDEBAR ---------------- def render_sidebar(): + st.sidebar.title("File Explorer") - st.sidebar.title("📁 File Explorer") - - navigation = FileNavigation() - tree_data = navigation.build_tree(Path.cwd()) + root_folder = st.session_state.get("root_folder") with st.sidebar: - selection = tree_select( - tree_data, - check_model="leaf", - only_leaf_checkboxes=True - ) + # --- Button on top --- + if st.button("📂 Choose Folder", key="pick_folder"): + picked = pick_folder() + if picked: + st.session_state.root_folder = picked + st.rerun() - if selection and selection.get("checked"): - return selection["checked"][0] + if root_folder: + st.caption(f" {Path(root_folder).name}") + + st.markdown("---") + + # --- Tree below --- + if root_folder: + try: + root_path = Path(root_folder) + if root_path.exists() and root_path.is_dir(): + navigation = FileNavigation() + tree_data = navigation.build_tree(root_path) + selection = tree_select( + tree_data, + check_model="leaf", + only_leaf_checkboxes=True + ) + if selection and selection.get("checked"): + return selection["checked"][0] + else: + st.warning("Folder not found.") + except Exception: + st.error("Could not load folder.") + else: + st.info("No folder selected yet.") return None - # ---------------- MAIN ---------------- def main(): - file_manager = FileManager() chat_manager = ChatManager() execution_engine = ExecutionEngine() # ---------------- STATE ---------------- + if "root_folder" not in st.session_state: + st.session_state.root_folder = None if "selected_file" not in st.session_state: st.session_state.selected_file = None - if "active_file" not in st.session_state: st.session_state.active_file = None - if "editor_content" not in st.session_state: st.session_state.editor_content = "" - if "last_applied_content" not in st.session_state: st.session_state.last_applied_content = "" + if "run_result" not in st.session_state: + st.session_state.run_result = None # ---------------- FILE SELECT ---------------- selected_file = render_sidebar() - if selected_file: st.session_state.selected_file = selected_file current_file = st.session_state.selected_file - # ---------------- FILE SWITCH ---------------- if current_file != st.session_state.active_file: - st.session_state.active_file = current_file - + st.session_state.run_result = None # clear output on file switch if current_file: content = file_manager.read_file(current_file) st.session_state.editor_content = content @@ -91,55 +111,63 @@ def main(): else: st.session_state.editor_content = "" - st.sidebar.markdown("---") st.sidebar.caption("AI Code Editor") - # ---------------- MAIN UI ---------------- if st.session_state.active_file: - col1, col2 = st.columns([3, 2]) with col1: - - st.subheader(f"Editing: {Path(st.session_state.active_file).name}") + # --- File name + Run button on same row --- + title_col, btn_col = st.columns([5, 1]) + with title_col: + st.subheader(f"✏️ {Path(st.session_state.active_file).name}") + with btn_col: + run_clicked = st.button("▶ Run", type="primary", use_container_width=True) editor = CodeEditor() - - # IMPORTANT: only updates AFTER APPLY new_value = editor.display_code( st.session_state.editor_content, filename=st.session_state.active_file ) - - # ---------------- APPLY DETECTION ---------------- - # Apply only triggers when Streamlit reruns with new value if new_value is not None: - if new_value != st.session_state.last_applied_content: - st.session_state.editor_content = new_value st.session_state.last_applied_content = new_value + file_manager.save_file(st.session_state.active_file, new_value) + st.success("Saved ✔") - file_manager.save_file( - st.session_state.active_file, - new_value + # --- Run execution --- + if run_clicked: + with st.spinner("Running…"): + st.session_state.run_result = execution_engine.run_file( + st.session_state.active_file ) - st.success("Saved via Apply ✔") - with col2: - chat = ChatInterface() chat.display_chat(chat_manager) - output = OutputDisplay() - output.display_execution(execution_engine) + # --- Output panel --- + result = st.session_state.run_result + if result is not None: + st.markdown("---") + success = result["returncode"] == 0 + status = "✅ Exited 0" if success else f"❌ Exited {result['returncode']}" + st.caption(f"Output — {status}") + + if result["stdout"]: + st.code(result["stdout"], language="text") + + if result["stderr"]: + st.code(result["stderr"], language="text") + + if not result["stdout"] and not result["stderr"]: + st.caption("No output.") else: - st.info("Select a file from the explorer 👈") - + st.info("Select a file from the explorer") if __name__ == "__main__": main() \ No newline at end of file diff --git a/src/ui/editor.py b/src/ui/editor.py index 026d07a..6798a03 100644 --- a/src/ui/editor.py +++ b/src/ui/editor.py @@ -28,7 +28,6 @@ class CodeEditor: language=language, theme="chrome", key=f"ace_{filename}", - height=500, font_size=14, tab_size=4, wrap=False,