Source code for simvx.editor.script_ops
"""Script management operations mixin for EditorState."""
from __future__ import annotations
import logging
from pathlib import Path
from typing import TYPE_CHECKING
from simvx.core import Node, ScriptManager
if TYPE_CHECKING:
from .state import EditorState
log = logging.getLogger(__name__)
[docs]
class ScriptOps:
"""Mixin providing script attach/detach/create/save operations.
Methods in this class are designed to be mixed into EditorState, which
provides the workspace, signals, and delegating properties they depend on.
"""
if TYPE_CHECKING:
self: EditorState # type: ignore[assignment]
def _save_script_file(self, node: Node, text: str):
"""Write text to the node's file-backed script path."""
if not node.script:
return
p = Path(node.script)
if not p.is_absolute() and self.project_path:
p = self.project_path / p
try:
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(text)
except Exception as e:
log.error("Failed to save script %s: %s", p, e)
[docs]
def set_script_text(self, text: str):
"""Set the code viewport text and sync it to the selected node's script."""
if self._viewport_code is not None:
self._viewport_code.text = text
node = self.selection.primary
if node is None and self.edited_scene:
node = self.edited_scene.root
if node is not None:
if node.script:
self._save_script_file(node, text)
else:
node._script_inline = text
self.modified = True
[docs]
def attach_script(self, node: Node, path: str):
"""Attach a file-based script to *node*."""
node.script = path
self.modified = True
self.script_changed.emit()
[docs]
def detach_script(self, node: Node):
"""Detach the file-based script from *node*."""
if node.script:
ScriptManager.unload(node)
node.script = None
self.modified = True
self.script_changed.emit()
[docs]
def create_script(self, node: Node, template_name: str, class_name: str, rel_path: str) -> str | None:
"""Create a new script file from a template and attach it to *node*."""
from .templates import generate_script
base = self.project_path or Path(".")
abs_path = base / rel_path
try:
generate_script(template_name, class_name, output_path=str(abs_path))
except Exception as e:
log.error("Failed to create script: %s", e)
return None
self.attach_script(node, rel_path)
return str(abs_path)