Source code for simvx.editor.script_ops

"""Script management operations mixin for State."""

import logging
from pathlib import Path
from typing import TYPE_CHECKING

from simvx.core import Node, ScriptManager
from simvx.core.script import parse_script_ref

if TYPE_CHECKING:
    from .state import State

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 State, which provides the workspace, signals, and delegating properties they depend on. """ if TYPE_CHECKING: self: State # 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 file_path, _ = parse_script_ref(node.script) p = Path(file_path) 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.""" 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) self.modified = True else: log.warning("set_script_text called on node with no attached script")
[docs] def attach_script(self, node: Node, path: str, class_name: str = ""): """Attach a file-based script to *node*. Args: node: The node to attach the script to. path: File path (relative to project root). class_name: The Node subclass name defined in the script. If provided, ``node.script`` is set to ``"path::ClassName"``. """ if class_name: node.script = f"{path}::{class_name}" else: 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, class_name=class_name) return str(abs_path)