provisorisches run

This commit is contained in:
leart-ramushi 2026-05-26 16:17:50 +02:00
parent d9a46ba701
commit da1d22ec56
4 changed files with 121 additions and 64 deletions

View File

@ -1,12 +1,41 @@
class ExecutionEngine: import subprocess
""" import sys
Platzhalter für die Code-Ausführung [1] from pathlib import Path
"""
def __init__(self):
pass
def execute_code(self):
""" class ExecutionEngine:
Führt Code nicht aus, sondern gibt einen Status aus [1] def run_file(self, filepath: str) -> dict:
""" path = Path(filepath)
return "Code wurde nicht ausgeführt (Platzhalter)"
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}

View File

@ -1,5 +1,6 @@
from pathlib import Path from pathlib import Path
class FileManager: class FileManager:
""" """
Handles file reading and writing Handles file reading and writing

View File

@ -1,89 +1,109 @@
import sys import sys
import os import os
import tkinter as tk
from tkinter import filedialog
from pathlib import Path from pathlib import Path
import streamlit as st import streamlit as st
from streamlit_tree_select import tree_select from streamlit_tree_select import tree_select
# ---------------- PATH FIX ---------------- # ---------------- PATH FIX ----------------
sys.path.append(os.path.dirname(os.path.abspath(__file__))) sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# ---------------- BACKEND ---------------- # ---------------- BACKEND ----------------
from backend.file_manager import FileManager from backend.file_manager import FileManager
from ui.navigation import FileNavigation from ui.navigation import FileNavigation
from ui.chat import ChatInterface from ui.chat import ChatInterface
from ui.editor import CodeEditor from ui.editor import CodeEditor
from ui.output import OutputDisplay
from backend.chat_manager import ChatManager from backend.chat_manager import ChatManager
from backend.execution_engine import ExecutionEngine from backend.execution_engine import ExecutionEngine
# ---------------- PAGE CONFIG ----------------
# ---------------- PAGE ----------------
st.set_page_config( st.set_page_config(
page_title="AI Code Editor", page_title="AI Code Editor",
page_icon="💻", 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 ---------------- # ---------------- SIDEBAR ----------------
def render_sidebar(): def render_sidebar():
st.sidebar.title("File Explorer")
st.sidebar.title("📁 File Explorer") root_folder = st.session_state.get("root_folder")
navigation = FileNavigation()
tree_data = navigation.build_tree(Path.cwd())
with st.sidebar: with st.sidebar:
selection = tree_select( # --- Button on top ---
tree_data, if st.button("📂 Choose Folder", key="pick_folder"):
check_model="leaf", picked = pick_folder()
only_leaf_checkboxes=True if picked:
) st.session_state.root_folder = picked
st.rerun()
if selection and selection.get("checked"): if root_folder:
return selection["checked"][0] 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 return None
# ---------------- MAIN ---------------- # ---------------- MAIN ----------------
def main(): def main():
file_manager = FileManager() file_manager = FileManager()
chat_manager = ChatManager() chat_manager = ChatManager()
execution_engine = ExecutionEngine() execution_engine = ExecutionEngine()
# ---------------- STATE ---------------- # ---------------- STATE ----------------
if "root_folder" not in st.session_state:
st.session_state.root_folder = None
if "selected_file" not in st.session_state: if "selected_file" not in st.session_state:
st.session_state.selected_file = None st.session_state.selected_file = None
if "active_file" not in st.session_state: if "active_file" not in st.session_state:
st.session_state.active_file = None st.session_state.active_file = None
if "editor_content" not in st.session_state: if "editor_content" not in st.session_state:
st.session_state.editor_content = "" st.session_state.editor_content = ""
if "last_applied_content" not in st.session_state: if "last_applied_content" not in st.session_state:
st.session_state.last_applied_content = "" st.session_state.last_applied_content = ""
if "run_result" not in st.session_state:
st.session_state.run_result = None
# ---------------- FILE SELECT ---------------- # ---------------- FILE SELECT ----------------
selected_file = render_sidebar() selected_file = render_sidebar()
if selected_file: if selected_file:
st.session_state.selected_file = selected_file st.session_state.selected_file = selected_file
current_file = st.session_state.selected_file current_file = st.session_state.selected_file
# ---------------- FILE SWITCH ---------------- # ---------------- FILE SWITCH ----------------
if current_file != st.session_state.active_file: if current_file != st.session_state.active_file:
st.session_state.active_file = current_file st.session_state.active_file = current_file
st.session_state.run_result = None # clear output on file switch
if current_file: if current_file:
content = file_manager.read_file(current_file) content = file_manager.read_file(current_file)
st.session_state.editor_content = content st.session_state.editor_content = content
@ -91,55 +111,63 @@ def main():
else: else:
st.session_state.editor_content = "" st.session_state.editor_content = ""
st.sidebar.markdown("---") st.sidebar.markdown("---")
st.sidebar.caption("AI Code Editor") st.sidebar.caption("AI Code Editor")
# ---------------- MAIN UI ---------------- # ---------------- MAIN UI ----------------
if st.session_state.active_file: if st.session_state.active_file:
col1, col2 = st.columns([3, 2]) col1, col2 = st.columns([3, 2])
with col1: with col1:
# --- File name + Run button on same row ---
st.subheader(f"Editing: {Path(st.session_state.active_file).name}") 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() editor = CodeEditor()
# IMPORTANT: only updates AFTER APPLY
new_value = editor.display_code( new_value = editor.display_code(
st.session_state.editor_content, st.session_state.editor_content,
filename=st.session_state.active_file 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 is not None:
if new_value != st.session_state.last_applied_content: if new_value != st.session_state.last_applied_content:
st.session_state.editor_content = new_value st.session_state.editor_content = new_value
st.session_state.last_applied_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( # --- Run execution ---
st.session_state.active_file, if run_clicked:
new_value 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: with col2:
chat = ChatInterface() chat = ChatInterface()
chat.display_chat(chat_manager) chat.display_chat(chat_manager)
output = OutputDisplay() # --- Output panel ---
output.display_execution(execution_engine) 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: else:
st.info("Select a file from the explorer 👈") st.info("Select a file from the explorer")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -28,7 +28,6 @@ class CodeEditor:
language=language, language=language,
theme="chrome", theme="chrome",
key=f"ace_{filename}", key=f"ace_{filename}",
height=500,
font_size=14, font_size=14,
tab_size=4, tab_size=4,
wrap=False, wrap=False,