provisorisches run
This commit is contained in:
parent
d9a46ba701
commit
da1d22ec56
@ -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)"
|
||||
|
||||
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}
|
||||
@ -1,5 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class FileManager:
|
||||
"""
|
||||
Handles file reading and writing
|
||||
|
||||
132
src/main.py
132
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()
|
||||
@ -28,7 +28,6 @@ class CodeEditor:
|
||||
language=language,
|
||||
theme="chrome",
|
||||
key=f"ace_{filename}",
|
||||
height=500,
|
||||
font_size=14,
|
||||
tab_size=4,
|
||||
wrap=False,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user