#if CLIENT_SCRIPTING using System; using Microsoft.CodeAnalysis.CSharp.Scripting; using Microsoft.CodeAnalysis.CSharp.Scripting.Hosting; using Microsoft.CodeAnalysis.Scripting; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.IoC; using Robust.Shared.Reflection; using Robust.Shared.Scripting; using Robust.Shared.Timing; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Robust.Client.Console { public sealed class WatchWindow : DefaultWindow { private readonly IReflectionManager _reflectionManager; private readonly IDependencyCollection _dependency; private readonly BoxContainer _watchesVBox; private readonly LineEdit _addWatchEdit; private readonly Button _addWatchButton; public WatchWindow() { _reflectionManager = IoCManager.Resolve(); _dependency = IoCManager.Resolve(); ScriptInstanceShared.InitDummy(); Title = "Watch Window"; var mainVBox = new BoxContainer { Orientation = LayoutOrientation.Vertical, MinSize = new(500, 300), Children = { (_watchesVBox = new BoxContainer { Orientation = LayoutOrientation.Vertical, VerticalExpand = true }), new BoxContainer { Orientation = LayoutOrientation.Horizontal, Children = { (_addWatchEdit = new HistoryLineEdit { HorizontalExpand = true, PlaceHolder = "Add watch (C# interactive)" }), (_addWatchButton = new Button { Text = "Add" }) } } }, }; _addWatchButton.OnPressed += _ => AddWatch(); _addWatchEdit.OnTextEntered += _ => AddWatch(); Contents.AddChild(mainVBox); SetSize = new(300, 300); } private void AddWatch() { var code = _addWatchEdit.Text; if (string.IsNullOrWhiteSpace(code)) { return; } var options = ScriptInstanceShared.GetScriptOptions(_reflectionManager); var script = CSharpScript.Create(code, options, typeof(ScriptGlobalsShared)); ScriptRunner @delegate; try { @delegate = script.CreateDelegate(); } catch (CompilationErrorException compilationError) { _watchesVBox.AddChild(new CompilationErrorControl(string.Join('\n', compilationError.Diagnostics))); return; } var control = new WatchControl(@delegate, _dependency); _watchesVBox.AddChild(control); _addWatchEdit.Clear(); } private sealed class WatchControl : Control { private readonly ScriptRunner _runner; private readonly ScriptGlobalsImpl _globals; private readonly Label _outputLabel; public WatchControl(ScriptRunner runner, IDependencyCollection dependency) { Button delButton; _runner = runner; _globals = new ScriptGlobalsImpl(dependency); AddChild(new BoxContainer { Orientation = LayoutOrientation.Horizontal, Children = { (_outputLabel = new Label { HorizontalExpand = true, ClipText = true }), (delButton = new Button { Text = "Remove" }), } }); delButton.OnPressed += _ => Orphan(); } protected override async void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); object obj; try { obj = await _runner(_globals); } catch (Exception e) { _outputLabel.Text = CSharpObjectFormatter.Instance.FormatException(e); return; } _outputLabel.Text = CSharpObjectFormatter.Instance.FormatObject(obj); } } private sealed class ScriptGlobalsImpl : ScriptGlobalsShared { public ScriptGlobalsImpl(IDependencyCollection dependency) : base(dependency) { } protected override void WriteSyntax(object toString) { // No-op: nothing to write to. } public override void write(object toString) { // No-op: nothing to write to. } public override void show(object obj) { // No-op: nothing to write to. } } private sealed class CompilationErrorControl : Control { public CompilationErrorControl(string message) { Button delButton; AddChild(new BoxContainer { Orientation = LayoutOrientation.Horizontal, Children = { new Label { Text = message, ClipText = true, HorizontalExpand = true }, (delButton = new Button {Text = "Remove"}) } }); delButton.OnPressed += _ => Orphan(); } } } } #endif