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.
Files changed (38) hide show
  1. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/PKG-INFO +1 -1
  2. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript.py +63 -1
  3. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/PKG-INFO +1 -1
  4. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/setup.py +1 -0
  5. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib.py +43 -0
  6. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/studio_bridge.py +156 -0
  7. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/README.md +0 -0
  8. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/analyzer.py +0 -0
  9. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/ast_nodes.py +0 -0
  10. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/compiler.py +0 -0
  11. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/environment.py +0 -0
  12. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/errors.py +0 -0
  13. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/export_pipeline.py +0 -0
  14. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/hot_reload.py +0 -0
  15. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_dap.py +0 -0
  16. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_fmt.py +0 -0
  17. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/SOURCES.txt +0 -0
  18. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/dependency_links.txt +0 -0
  19. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/entry_points.txt +0 -0
  20. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/requires.txt +0 -0
  21. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_lang.egg-info/top_level.txt +0 -0
  22. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_studio_api.py +0 -0
  23. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/inscript_test.py +0 -0
  24. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/interpreter.py +0 -0
  25. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/lexer.py +0 -0
  26. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/parser.py +0 -0
  27. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/pygame_backend.py +0 -0
  28. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/pyproject.toml +0 -0
  29. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/repl.py +0 -0
  30. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/scene_tree.py +0 -0
  31. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/setup.cfg +0 -0
  32. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_assets.py +0 -0
  33. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_extended.py +0 -0
  34. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_extended_2.py +0 -0
  35. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_game.py +0 -0
  36. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/stdlib_values.py +0 -0
  37. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/studio_readiness.py +0 -0
  38. {inscript_lang-2.13.0 → inscript_lang-3.0.0}/vm.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inscript-lang
3
- Version: 2.13.0
3
+ Version: 3.0.0
4
4
  Summary: InScript — a game-focused scripting language with 59 game modules and a bytecode VM
5
5
  Author: Shreyasi Sarkar
6
6
  License: MIT
@@ -24,7 +24,7 @@ from errors import (InScriptError, LexerError, ParseError,
24
24
  SemanticError, InScriptRuntimeError,
25
25
  MultiError, InScriptWarning)
26
26
 
27
- VERSION = "2.13.0"
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(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inscript-lang
3
- Version: 2.13.0
3
+ Version: 3.0.0
4
4
  Summary: InScript — a game-focused scripting language with 59 game modules and a bytecode VM
5
5
  Author: Shreyasi Sarkar
6
6
  License: MIT
@@ -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