mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Adds help method to C# scripting. (#2368)
This commit is contained in:
committed by
GitHub
parent
a54283e637
commit
eecb104cc5
@@ -210,6 +210,23 @@ namespace Robust.Client.Console
|
||||
vvm.OpenVV(a);
|
||||
}
|
||||
|
||||
protected override void WriteSyntax(object toString)
|
||||
{
|
||||
var code = toString.ToString();
|
||||
|
||||
if (code == null)
|
||||
return;
|
||||
|
||||
var options = ScriptInstanceShared.GetScriptOptions(_owner._reflectionManager).AddReferences(typeof(Image).Assembly);
|
||||
var script = CSharpScript.Create(code, options, typeof(ScriptGlobals));
|
||||
script.Compile();
|
||||
|
||||
var syntax = new FormattedMessage();
|
||||
ScriptInstanceShared.AddWithSyntaxHighlighting(script, syntax, code, _owner._highlightWorkspace);
|
||||
|
||||
_owner.OutputPanel.AddMessage(syntax);
|
||||
}
|
||||
|
||||
public override void write(object toString)
|
||||
{
|
||||
_owner.OutputPanel.AddText(toString?.ToString() ?? "");
|
||||
|
||||
@@ -155,6 +155,11 @@ namespace Robust.Client.Console
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected override void WriteSyntax(object toString)
|
||||
{
|
||||
// No-op: nothing to write to.
|
||||
}
|
||||
|
||||
public override void write(object toString)
|
||||
{
|
||||
// No-op: nothing to write to.
|
||||
|
||||
@@ -224,9 +224,9 @@ namespace Robust.Server.Scripting
|
||||
instance.RunningScript = false;
|
||||
}
|
||||
|
||||
if (instance.OutputBuffer.Length != 0)
|
||||
if (!instance.OutputBuffer.IsEmpty)
|
||||
{
|
||||
msg.AddText(instance.OutputBuffer.ToString());
|
||||
msg.AddMessage(instance.OutputBuffer);
|
||||
instance.OutputBuffer.Clear();
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ namespace Robust.Server.Scripting
|
||||
{
|
||||
public Workspace HighlightWorkspace { get; } = new AdhocWorkspace();
|
||||
public StringBuilder InputBuffer { get; } = new();
|
||||
public StringBuilder OutputBuffer { get; } = new();
|
||||
public FormattedMessage OutputBuffer { get; } = new();
|
||||
public bool RunningScript { get; set; }
|
||||
|
||||
public ScriptGlobals Globals { get; }
|
||||
@@ -348,6 +348,8 @@ namespace Robust.Server.Scripting
|
||||
|
||||
private sealed class ScriptGlobalsImpl : ScriptGlobals
|
||||
{
|
||||
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
|
||||
|
||||
private readonly ScriptInstance _scriptInstance;
|
||||
|
||||
public ScriptGlobalsImpl(ScriptInstance scriptInstance)
|
||||
@@ -356,11 +358,26 @@ namespace Robust.Server.Scripting
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected override void WriteSyntax(object toString)
|
||||
{
|
||||
if (_scriptInstance.RunningScript && toString?.ToString() is {} code)
|
||||
{
|
||||
var options = ScriptInstanceShared.GetScriptOptions(_reflectionManager);
|
||||
var script = CSharpScript.Create(code, options, typeof(ScriptGlobals));
|
||||
script.Compile();
|
||||
|
||||
var syntax = new FormattedMessage();
|
||||
ScriptInstanceShared.AddWithSyntaxHighlighting(script, syntax, code, _scriptInstance.HighlightWorkspace);
|
||||
|
||||
_scriptInstance.OutputBuffer.AddMessage(syntax);
|
||||
}
|
||||
}
|
||||
|
||||
public override void write(object toString)
|
||||
{
|
||||
if (_scriptInstance.RunningScript)
|
||||
if (_scriptInstance.RunningScript && toString.ToString() is {} value)
|
||||
{
|
||||
_scriptInstance.OutputBuffer.AppendLine(toString?.ToString());
|
||||
_scriptInstance.OutputBuffer.AddText(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Scripting
|
||||
{
|
||||
@@ -15,6 +19,9 @@ namespace Robust.Shared.Scripting
|
||||
[SuppressMessage("ReSharper", "CA1822")]
|
||||
public abstract class ScriptGlobalsShared
|
||||
{
|
||||
private const BindingFlags DefaultHelpFlags =
|
||||
BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
|
||||
[field: Dependency] public IEntityManager ent { get; } = default!;
|
||||
[field: Dependency] public IPrototypeManager prot { get; } = default!;
|
||||
[field: Dependency] public IMapManager map { get; } = default!;
|
||||
@@ -103,6 +110,50 @@ namespace Robust.Shared.Scripting
|
||||
return m!.Invoke(target, args);
|
||||
}
|
||||
|
||||
public void help()
|
||||
{
|
||||
help(GetType(), DefaultHelpFlags &~ BindingFlags.NonPublic, false, false);
|
||||
}
|
||||
|
||||
public void help(Type type, BindingFlags flags = DefaultHelpFlags, bool specialNameMethods = true, bool modifiers = true)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
foreach (var member in type.GetMembers(flags))
|
||||
{
|
||||
switch (member.MemberType)
|
||||
{
|
||||
case MemberTypes.Method:
|
||||
var method = (MethodInfo) member;
|
||||
|
||||
if (!specialNameMethods && method.IsSpecialName)
|
||||
continue; // Let's not print constructors, property methods, etc.
|
||||
|
||||
builder.Append(method.PrintMethodSignature(modifiers));
|
||||
builder.AppendLine(";");
|
||||
break;
|
||||
|
||||
case MemberTypes.Property:
|
||||
builder.AppendLine(((PropertyInfo)member).PrintPropertySignature(modifiers, true));
|
||||
break;
|
||||
|
||||
case MemberTypes.Field:
|
||||
builder.Append(((FieldInfo) member).PrintFieldSignature(modifiers));
|
||||
builder.AppendLine(";");
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
// This is slow, so do it all at once.
|
||||
WriteSyntax(builder.ToString());
|
||||
}
|
||||
|
||||
protected abstract void WriteSyntax(object toString);
|
||||
public abstract void write(object toString);
|
||||
public abstract void show(object obj);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace Robust.Shared.Utility
|
||||
public TagList Tags => new(_tags);
|
||||
private readonly List<Tag> _tags;
|
||||
|
||||
public bool IsEmpty => _tags.Count == 0;
|
||||
|
||||
public FormattedMessage()
|
||||
{
|
||||
_tags = new List<Tag>();
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -68,5 +73,193 @@ namespace Robust.Shared.Utility
|
||||
|
||||
return stringRep!;
|
||||
}
|
||||
|
||||
public static string PrintTypeSignature(this Type type)
|
||||
{
|
||||
if (TypeShortHand.TryGetValue(type, out var value))
|
||||
return value;
|
||||
|
||||
var nullable = false;
|
||||
if (type.IsNullable(out var underlying))
|
||||
{
|
||||
type = underlying;
|
||||
nullable = true;
|
||||
}
|
||||
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
return $"{type.Name.Split('`')[0]}<{string.Join(", ", type.GetGenericArguments().Select(PrintTypeSignature))}>{(nullable ? "?" : string.Empty)}";
|
||||
}
|
||||
|
||||
return type.Name;
|
||||
}
|
||||
|
||||
public static string PrintParameterSignature(this ParameterInfo parameter)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (parameter.IsIn)
|
||||
{
|
||||
builder.Append($"in ");
|
||||
}
|
||||
|
||||
if (parameter.IsOut)
|
||||
{
|
||||
builder.Append($"out ");
|
||||
}
|
||||
else if (parameter.ParameterType.IsByRef)
|
||||
{
|
||||
builder.Append($"ref ");
|
||||
}
|
||||
|
||||
builder.Append(parameter.ParameterType.PrintTypeSignature());
|
||||
|
||||
if (parameter.Name is { } name)
|
||||
{
|
||||
builder.Append($" {name}");
|
||||
}
|
||||
|
||||
if (parameter.HasDefaultValue)
|
||||
{
|
||||
builder.Append($" = {PrintUserFacing(parameter.DefaultValue)}");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static string PrintMethodSignature(this MethodInfo method, bool modifiers = false, bool arguments = true, bool returnType = true, bool name = true)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (modifiers)
|
||||
{
|
||||
// Access modifiers.
|
||||
if (method.IsPublic)
|
||||
builder.Append("public ");
|
||||
|
||||
if (method.IsPrivate)
|
||||
builder.Append("private ");
|
||||
|
||||
if (method.IsFamilyAndAssembly)
|
||||
builder.Append("private protected ");
|
||||
|
||||
if (method.IsFamily)
|
||||
builder.Append("protected ");
|
||||
|
||||
if (method.IsFamilyOrAssembly)
|
||||
builder.Append("protected internal ");
|
||||
|
||||
if (method.IsAssembly)
|
||||
builder.Append("internal ");
|
||||
|
||||
if(method.IsStatic)
|
||||
builder.Append("static ");
|
||||
|
||||
if (method.IsAbstract && method.DeclaringType is {IsAbstract:true, IsInterface:false})
|
||||
builder.Append("abstract ");
|
||||
else if(method.DeclaringType is {IsInterface:false})
|
||||
{
|
||||
if (method.IsFinal)
|
||||
builder.Append("sealed override ");
|
||||
else if (method.IsVirtual)
|
||||
builder.Append(method.Equals(method.GetBaseDefinition()) ? "virtual " : "override ");
|
||||
}
|
||||
}
|
||||
|
||||
if (returnType && !method.IsConstructor)
|
||||
builder.Append($"{method.ReturnType.PrintTypeSignature()} ");
|
||||
|
||||
if(name)
|
||||
builder.Append(method.Name);
|
||||
|
||||
if (!arguments)
|
||||
return builder.ToString();
|
||||
|
||||
if (method.IsGenericMethod)
|
||||
builder.Append($"<{string.Join(", ", method.GetGenericArguments().Select(PrintTypeSignature))}>");
|
||||
|
||||
builder.Append($"({string.Join($", ", method.GetParameters().Select(PrintParameterSignature))})");
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static string PrintPropertySignature(this PropertyInfo property, bool modifiers = false, bool accessors = false)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append($"{property.PropertyType.PrintTypeSignature()} {property.Name}");
|
||||
|
||||
if (accessors)
|
||||
{
|
||||
builder.Append(" { ");
|
||||
|
||||
if (property.CanRead)
|
||||
builder.Append($"{property.GetMethod!.PrintMethodSignature(modifiers, false, false, false)}get; ");
|
||||
|
||||
if (property.CanWrite)
|
||||
builder.Append($"{property.SetMethod!.PrintMethodSignature(modifiers, false, false, false)}set; ");
|
||||
|
||||
builder.Append('}');
|
||||
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static string PrintFieldSignature(this FieldInfo field, bool modifiers = false)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (modifiers)
|
||||
{
|
||||
// Access modifiers. Hmm... Déjà vu.
|
||||
if (field.IsPublic)
|
||||
builder.Append("public ");
|
||||
|
||||
if (field.IsPrivate)
|
||||
builder.Append("private ");
|
||||
|
||||
if (field.IsFamilyAndAssembly)
|
||||
builder.Append("private protected ");
|
||||
|
||||
if (field.IsFamily)
|
||||
builder.Append("protected ");
|
||||
|
||||
if (field.IsFamilyOrAssembly)
|
||||
builder.Append("protected internal ");
|
||||
|
||||
if (field.IsAssembly)
|
||||
builder.Append("internal ");
|
||||
|
||||
if(field.IsStatic)
|
||||
builder.Append("static ");
|
||||
}
|
||||
|
||||
builder.Append($"{field.FieldType.PrintTypeSignature()} {field.Name}");
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static readonly IReadOnlyDictionary<Type, string> TypeShortHand = new Dictionary<Type, string>()
|
||||
{
|
||||
// ReSharper disable BuiltInTypeReferenceStyle
|
||||
{typeof(void), "void"},
|
||||
{typeof(Object), "object"},
|
||||
{typeof(Boolean), "bool"},
|
||||
{typeof(Byte), "byte"},
|
||||
{typeof(Char), "char"},
|
||||
{typeof(Decimal), "decimal"},
|
||||
{typeof(Double), "double"},
|
||||
{typeof(Single), "float"},
|
||||
{typeof(Int32), "int"},
|
||||
{typeof(Int64), "long"},
|
||||
{typeof(SByte), "sbyte"},
|
||||
{typeof(Int16), "short"},
|
||||
{typeof(String), "string"},
|
||||
{typeof(UInt32), "uint"},
|
||||
{typeof(UInt64), "ulong"},
|
||||
{typeof(UInt16), "ushort"},
|
||||
// ReSharper restore BuiltInTypeReferenceStyle
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user