inscript-lang 2.13.0__tar.gz → 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/PKG-INFO +1 -1
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript.py +63 -1
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/PKG-INFO +1 -1
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/setup.py +1 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib.py +43 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/studio_bridge.py +156 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/README.md +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/analyzer.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/ast_nodes.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/compiler.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/environment.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/errors.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/export_pipeline.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/hot_reload.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_dap.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_fmt.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_studio_api.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_test.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/interpreter.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/lexer.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/parser.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/pygame_backend.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/pyproject.toml +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/repl.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/scene_tree.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/setup.cfg +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_assets.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_extended.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_extended_2.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_game.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_values.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/studio_readiness.py +0 -0
- {inscript_lang-2.13.0 → inscript_lang-3.0.0}/vm.py +0 -0
|
@@ -24,7 +24,7 @@ from errors import (InScriptError, LexerError, ParseError,
|
|
|
24
24
|
SemanticError, InScriptRuntimeError,
|
|
25
25
|
MultiError, InScriptWarning)
|
|
26
26
|
|
|
27
|
-
VERSION = "
|
|
27
|
+
VERSION = "3.0.0"
|
|
28
28
|
|
|
29
29
|
MANIFEST_FILENAME = "inscript.toml"
|
|
30
30
|
LOCK_FILENAME = "inscript.lock"
|
|
@@ -2752,6 +2752,17 @@ Examples:
|
|
|
2752
2752
|
help="v2.12.0: Start Electron bridge JSON-RPC server")
|
|
2753
2753
|
parser.add_argument("--bridge-port", type=int, default=8765,
|
|
2754
2754
|
help="v2.12.0: Port for --studio-bridge (default: 8765)")
|
|
2755
|
+
# v3.0.0: Studio + Visual Scripting
|
|
2756
|
+
parser.add_argument("--studio", action="store_true",
|
|
2757
|
+
help="v3.0.0: Launch InScript Studio web IDE in browser")
|
|
2758
|
+
parser.add_argument("--studio-port", type=int, default=8080,
|
|
2759
|
+
help="v3.0.0: Port for Studio web app (default: 8080)")
|
|
2760
|
+
parser.add_argument("--visual-compile", metavar="FILE",
|
|
2761
|
+
help="v3.0.0: Compile a .vins visual script to .ins source")
|
|
2762
|
+
parser.add_argument("--vins-output", metavar="FILE",
|
|
2763
|
+
help="v3.0.0: Output path for --visual-compile (default: <input>.ins)")
|
|
2764
|
+
parser.add_argument("--vins-template", metavar="NAME",
|
|
2765
|
+
help="v3.0.0: Generate a .vins template for visual scripting")
|
|
2755
2766
|
parser.add_argument("--lsp", action="store_true",
|
|
2756
2767
|
help="Start the Language Server (requires: pip install pygls)")
|
|
2757
2768
|
parser.add_argument("--game", action="store_true",
|
|
@@ -3067,6 +3078,57 @@ Examples:
|
|
|
3067
3078
|
bridge.stop()
|
|
3068
3079
|
return 0
|
|
3069
3080
|
|
|
3081
|
+
# ── v3.0.0 Studio + Visual Scripting ──────────────────────────────────
|
|
3082
|
+
if getattr(args, 'studio', False):
|
|
3083
|
+
import time as _time
|
|
3084
|
+
studio_port = getattr(args, 'studio_port', 8080)
|
|
3085
|
+
bridge_port = getattr(args, 'bridge_port', 8765)
|
|
3086
|
+
proj_dir = getattr(args, 'project_dir', '.') or '.'
|
|
3087
|
+
from studio_app import StudioApp
|
|
3088
|
+
app_s = StudioApp(proj_dir, studio_port=studio_port, bridge_port=bridge_port)
|
|
3089
|
+
app_s.start()
|
|
3090
|
+
url = app_s.url
|
|
3091
|
+
print(f"[InScript Studio] ✅ Running at {url}")
|
|
3092
|
+
print(f"[InScript Studio] Project: {os.path.abspath(proj_dir)}")
|
|
3093
|
+
print(f"[InScript Studio] Ctrl+C to stop")
|
|
3094
|
+
# Open browser
|
|
3095
|
+
try:
|
|
3096
|
+
import webbrowser as _wb
|
|
3097
|
+
_wb.open(url)
|
|
3098
|
+
except Exception:
|
|
3099
|
+
pass
|
|
3100
|
+
try:
|
|
3101
|
+
while True: _time.sleep(1)
|
|
3102
|
+
except KeyboardInterrupt:
|
|
3103
|
+
app_s.stop()
|
|
3104
|
+
print(f"[InScript Studio] Stopped.")
|
|
3105
|
+
return 0
|
|
3106
|
+
|
|
3107
|
+
if getattr(args, 'visual_compile', None) is not None:
|
|
3108
|
+
from visual_script import compile_file
|
|
3109
|
+
vins_path = args.visual_compile
|
|
3110
|
+
out_path = getattr(args, 'vins_output', None)
|
|
3111
|
+
if not os.path.isfile(vins_path):
|
|
3112
|
+
print(f"[visual] File not found: {vins_path}", file=sys.stderr); return 1
|
|
3113
|
+
try:
|
|
3114
|
+
result_path = compile_file(vins_path, out_path)
|
|
3115
|
+
print(f"[visual] Written to: {result_path}")
|
|
3116
|
+
except Exception as _ve:
|
|
3117
|
+
print(f"[visual] Compile error: {_ve}", file=sys.stderr); return 1
|
|
3118
|
+
return 0
|
|
3119
|
+
|
|
3120
|
+
if getattr(args, 'vins_template', None) is not None:
|
|
3121
|
+
import json as _j
|
|
3122
|
+
from visual_script import make_template
|
|
3123
|
+
name = args.vins_template
|
|
3124
|
+
out_path = f"{name}.vins"
|
|
3125
|
+
tmpl = make_template(name)
|
|
3126
|
+
with open(out_path, "w") as f:
|
|
3127
|
+
_j.dump(tmpl, f, indent=2)
|
|
3128
|
+
print(f"[visual] Template written to {out_path}")
|
|
3129
|
+
print(f"[visual] Compile with: inscript --visual-compile {out_path}")
|
|
3130
|
+
return 0
|
|
3131
|
+
|
|
3070
3132
|
# v1.9.1: --no-typecheck is deprecated — emit a warning and honour it
|
|
3071
3133
|
if getattr(args, 'no_typecheck', False):
|
|
3072
3134
|
print(
|
|
@@ -57,6 +57,7 @@ setup(
|
|
|
57
57
|
# ── v2.7.0+ runtime modules ───────────────────────────────────────────
|
|
58
58
|
"scene_tree", "hot_reload", "export_pipeline",
|
|
59
59
|
"studio_bridge", "inscript_studio_api", "studio_readiness",
|
|
60
|
+
"visual_script", "studio_app", "vins_editor",
|
|
60
61
|
],
|
|
61
62
|
package_data = {"": ["examples/*.ins", "lsp/*.py", "*.md"]},
|
|
62
63
|
install_requires = [],
|
|
@@ -1163,3 +1163,46 @@ try:
|
|
|
1163
1163
|
import stdlib_assets # noqa: F401
|
|
1164
1164
|
except Exception as _e4:
|
|
1165
1165
|
import sys; print(f'[stdlib_assets load error] {_e4}', file=sys.stderr)
|
|
1166
|
+
|
|
1167
|
+
# ── Studio IPC (v3.0.0): allows subprocess games to publish scene state ──────
|
|
1168
|
+
try:
|
|
1169
|
+
from studio_bridge import _IPC_STATE_FILE, _ipc_write_scene
|
|
1170
|
+
|
|
1171
|
+
def _studio_publish_scene(scene_manager_or_dict=None):
|
|
1172
|
+
"""
|
|
1173
|
+
Called from .ins: import "studio_ipc" as ipc; ipc.publish_scene()
|
|
1174
|
+
Writes current scene state to the IPC file so Studio can inspect it.
|
|
1175
|
+
"""
|
|
1176
|
+
import json as _j
|
|
1177
|
+
data = {"nodes": [], "count": 0, "source": "ipc"}
|
|
1178
|
+
if scene_manager_or_dict is not None:
|
|
1179
|
+
try:
|
|
1180
|
+
from scene_tree import SceneManager, SceneTree
|
|
1181
|
+
if hasattr(scene_manager_or_dict, 'current'):
|
|
1182
|
+
sm = scene_manager_or_dict
|
|
1183
|
+
if sm.current:
|
|
1184
|
+
nodes = []
|
|
1185
|
+
def _walk(inst, parent=None):
|
|
1186
|
+
nodes.append({
|
|
1187
|
+
"name": inst.name,
|
|
1188
|
+
"blueprint": inst.blueprint.name,
|
|
1189
|
+
"parent": parent,
|
|
1190
|
+
"children": [c.name for c in inst.get_children()],
|
|
1191
|
+
"props": {k: str(v) for k, v in inst._props.items()
|
|
1192
|
+
if not callable(v)},
|
|
1193
|
+
})
|
|
1194
|
+
for child in inst.get_children():
|
|
1195
|
+
_walk(child, inst.name)
|
|
1196
|
+
_walk(sm.current.root)
|
|
1197
|
+
data = {"nodes": nodes, "count": len(nodes), "source": "ipc"}
|
|
1198
|
+
except Exception:
|
|
1199
|
+
pass
|
|
1200
|
+
_ipc_write_scene(data)
|
|
1201
|
+
|
|
1202
|
+
from stdlib import register_module as _rm
|
|
1203
|
+
_rm("studio_ipc", {
|
|
1204
|
+
"publish_scene": _studio_publish_scene,
|
|
1205
|
+
"ipc_file": _IPC_STATE_FILE,
|
|
1206
|
+
})
|
|
1207
|
+
except Exception as _se:
|
|
1208
|
+
pass
|
|
@@ -583,3 +583,159 @@ def _INPUT_MANAGER_INSTANCE():
|
|
|
583
583
|
return _imi
|
|
584
584
|
except ImportError:
|
|
585
585
|
return None
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
589
|
+
# v3.0.0: IPC scene state file (fixes subprocess/inspection disconnect)
|
|
590
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
591
|
+
# When a game runs via start_game, it cannot be introspected directly from
|
|
592
|
+
# the bridge because they are separate processes. The fix: the game process
|
|
593
|
+
# writes its live scene state to a temp JSON file every N frames.
|
|
594
|
+
# The bridge reads that file for get_live_scene / set_node_prop.
|
|
595
|
+
|
|
596
|
+
import tempfile as _tempfile
|
|
597
|
+
|
|
598
|
+
_IPC_STATE_FILE = os.path.join(_tempfile.gettempdir(), "inscript_studio_ipc.json")
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
def _ipc_write_scene(scene_data: dict) -> None:
|
|
602
|
+
"""Called from within the game process to publish scene state."""
|
|
603
|
+
try:
|
|
604
|
+
import json as _j
|
|
605
|
+
tmp = _IPC_STATE_FILE + ".tmp"
|
|
606
|
+
with open(tmp, "w") as f:
|
|
607
|
+
_j.dump(scene_data, f)
|
|
608
|
+
os.replace(tmp, _IPC_STATE_FILE)
|
|
609
|
+
except Exception:
|
|
610
|
+
pass
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def _ipc_read_scene() -> dict:
|
|
614
|
+
"""Called from the bridge to read scene state written by game process."""
|
|
615
|
+
try:
|
|
616
|
+
import json as _j
|
|
617
|
+
with open(_IPC_STATE_FILE) as f:
|
|
618
|
+
return _j.load(f)
|
|
619
|
+
except Exception:
|
|
620
|
+
return {"nodes": [], "count": 0, "source": "ipc"}
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
def _extend_bridge_v300(bridge_cls):
|
|
624
|
+
"""v3.0.0 patches: real build RPC, IPC-aware get_live_scene."""
|
|
625
|
+
|
|
626
|
+
# ── Real build RPC ────────────────────────────────────────────────────────
|
|
627
|
+
def _rpc_build(self, params: dict) -> dict:
|
|
628
|
+
"""
|
|
629
|
+
Actually runs `inscript --build <target> --project-dir <dir>`.
|
|
630
|
+
Non-blocking — spawns subprocess, streams output to _build_output.
|
|
631
|
+
"""
|
|
632
|
+
target = params.get("target", "desktop")
|
|
633
|
+
project_dir = params.get("project_dir", ".")
|
|
634
|
+
|
|
635
|
+
if not hasattr(self, "_build_outputs"):
|
|
636
|
+
self._build_outputs = {}
|
|
637
|
+
if not hasattr(self, "_build_procs"):
|
|
638
|
+
self._build_procs = {}
|
|
639
|
+
|
|
640
|
+
inscript_py = os.path.join(os.path.dirname(__file__), "inscript.py")
|
|
641
|
+
cmd = [sys.executable, inscript_py,
|
|
642
|
+
"--build", target,
|
|
643
|
+
"--project-dir", os.path.abspath(project_dir)]
|
|
644
|
+
|
|
645
|
+
output_lines = []
|
|
646
|
+
self._build_outputs[target] = output_lines
|
|
647
|
+
|
|
648
|
+
def _run():
|
|
649
|
+
try:
|
|
650
|
+
proc = _subprocess.Popen(
|
|
651
|
+
cmd, stdout=_subprocess.PIPE, stderr=_subprocess.STDOUT,
|
|
652
|
+
text=True, bufsize=1
|
|
653
|
+
)
|
|
654
|
+
self._build_procs[target] = proc
|
|
655
|
+
for line in proc.stdout:
|
|
656
|
+
output_lines.append(line.rstrip("\n"))
|
|
657
|
+
proc.wait()
|
|
658
|
+
status = "ok" if proc.returncode == 0 else "error"
|
|
659
|
+
output_lines.append(f"[build:{target}] exit {proc.returncode} — {status}")
|
|
660
|
+
except Exception as e:
|
|
661
|
+
output_lines.append(f"[build:{target}] ERROR: {e}")
|
|
662
|
+
|
|
663
|
+
t = threading.Thread(target=_run, daemon=True)
|
|
664
|
+
t.start()
|
|
665
|
+
return {"started": True, "target": target,
|
|
666
|
+
"project_dir": os.path.abspath(project_dir)}
|
|
667
|
+
|
|
668
|
+
def _rpc_build_status(self, params: dict) -> dict:
|
|
669
|
+
"""Poll build output since a given line index."""
|
|
670
|
+
target = params.get("target", "desktop")
|
|
671
|
+
since = int(params.get("since", 0))
|
|
672
|
+
outputs = getattr(self, "_build_outputs", {})
|
|
673
|
+
lines = outputs.get(target, [])
|
|
674
|
+
proc = getattr(self, "_build_procs", {}).get(target)
|
|
675
|
+
running = proc is not None and proc.poll() is None
|
|
676
|
+
return {
|
|
677
|
+
"target": target,
|
|
678
|
+
"running": running,
|
|
679
|
+
"output": lines[since:],
|
|
680
|
+
"total": len(lines),
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
# ── IPC-aware get_live_scene ──────────────────────────────────────────────
|
|
684
|
+
def _rpc_get_live_scene_v300(self, params: dict) -> dict:
|
|
685
|
+
"""
|
|
686
|
+
v3.0.0: Check both sources:
|
|
687
|
+
1. Bridge's own interpreter (if run() was called)
|
|
688
|
+
2. IPC file (if start_game subprocess is running and wrote state)
|
|
689
|
+
"""
|
|
690
|
+
# Check if we have a live interpreter
|
|
691
|
+
with self._lock:
|
|
692
|
+
if self._interp is not None:
|
|
693
|
+
from scene_tree import NodeInstance
|
|
694
|
+
nodes = []
|
|
695
|
+
for name, val in self._interp._globals._store.items():
|
|
696
|
+
if isinstance(val, NodeInstance):
|
|
697
|
+
nodes.append({
|
|
698
|
+
"name": name,
|
|
699
|
+
"blueprint": val.blueprint.name,
|
|
700
|
+
"parent": val._parent.name if val._parent else None,
|
|
701
|
+
"children": [c.name for c in val.get_children()],
|
|
702
|
+
"props": {k: str(v) for k, v in val._props.items()
|
|
703
|
+
if not callable(v)},
|
|
704
|
+
})
|
|
705
|
+
if nodes:
|
|
706
|
+
return {"nodes": nodes, "count": len(nodes), "source": "interpreter"}
|
|
707
|
+
|
|
708
|
+
# Fall back to IPC file (subprocess game)
|
|
709
|
+
ipc = _ipc_read_scene()
|
|
710
|
+
if ipc.get("nodes"):
|
|
711
|
+
return ipc
|
|
712
|
+
|
|
713
|
+
# Check if game process is running — give a hint
|
|
714
|
+
gp = getattr(self, "_game_process", None)
|
|
715
|
+
if gp and gp.is_running():
|
|
716
|
+
return {"nodes": [], "count": 0,
|
|
717
|
+
"source": "ipc",
|
|
718
|
+
"hint": ("Game is running as subprocess. To enable live scene "
|
|
719
|
+
"inspection, add this to your .ins file: "
|
|
720
|
+
"'import \"studio_ipc\" as ipc' and call 'ipc.publish_scene()'.")}
|
|
721
|
+
return {"nodes": [], "count": 0, "source": "none"}
|
|
722
|
+
|
|
723
|
+
# ── Patch dispatch ────────────────────────────────────────────────────────
|
|
724
|
+
_NEW_V300 = {
|
|
725
|
+
"build": _rpc_build,
|
|
726
|
+
"build_status": _rpc_build_status,
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
_orig_dispatch_v300 = bridge_cls._dispatch
|
|
730
|
+
|
|
731
|
+
def _new_dispatch_v300(self, method, params):
|
|
732
|
+
if method == "get_live_scene":
|
|
733
|
+
return _rpc_get_live_scene_v300(self, params)
|
|
734
|
+
if method in _NEW_V300:
|
|
735
|
+
return _NEW_V300[method](self, params)
|
|
736
|
+
return _orig_dispatch_v300(self, method, params)
|
|
737
|
+
|
|
738
|
+
bridge_cls._dispatch = _new_dispatch_v300
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
_extend_bridge_v300(StudioBridge)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|