rabidus-test/Assets/Plugins/QFSW/Quantum Console/Source/Scripts/QuantumConsoleCommands.cs

194 lines
9.9 KiB
C#
Raw Permalink Normal View History

2023-08-22 15:41:12 +03:00
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace QFSW.QC
{
public static partial class QuantumConsoleProcessor
{
private const string helpStr = "Welcome to Quantum Console! In order to see specific help about any specific command, " +
"please use the 'man' command. Use 'man man' to see more about the man command. To see a full list of all " +
"commands, use 'all-commands'.\n\n" +
"mono-targets\nVarious commands may show a mono-target in their command signature.\n" +
"This means they are not static commands, and instead requires instance(s) of the class in order to invoke the command." +
"\nEach mono-target works differently as follows:" +
"\n - single: uses the first instance of the type found in the scene" +
"\n - all: uses all instances of the type found in the scene" +
"\n - registry: uses all instances of the type found in the registry" +
"\n - singleton: creates and manages a single instance automatically" +
"\n\nThe registry is a part of the Quantum Registry that allows you to decide which specific instances of the class " +
"should be used when invoking the command. In order to add an object to the registry, either use " +
"QFSW.QC.QuantumRegistry.RegisterObject<T> or the runtime command 'register-object<T>'.";
[Command("help", "Shows a basic help guide for Quantum Console")]
private static string GetHelp()
{
return helpStr;
}
[Command("manual")]
[Command("man")]
private static string ManualHelp()
{
return "To use the man command, simply put the desired command name in front of it. For example, 'man my-command' will generate the manual for 'my-command'";
}
[CommandDescription("Generates a user manual for any given command, including built in ones. To use the man command, simply put the desired command name infront of it. For example, 'man my-command' will generate the manual for 'my-command'")]
[Command("help")]
[Command("manual")]
[Command("man")]
private static string GenerateCommandManual(string commandName)
{
string[] matchingCommands = _commandTable.Keys.Where((string key) => key.Split('(')[0] == commandName).OrderBy((string key) => key).ToArray();
if (matchingCommands.Length == 0) { throw new ArgumentException($"No command with the name {commandName} was found."); }
else
{
Dictionary<string, ParameterInfo> foundParams = new Dictionary<string, ParameterInfo>();
Dictionary<string, Type> foundGenericArguments = new Dictionary<string, Type>();
Dictionary<string, CommandParameterDescriptionAttribute> foundParamDescriptions = new Dictionary<string, CommandParameterDescriptionAttribute>();
List<Type> declaringTypes = new List<Type>(1);
string manual = $"Generated user manual for {commandName}\nAvailable command signatures:";
for (int i = 0; i < matchingCommands.Length; i++)
{
CommandData currentCommand = _commandTable[matchingCommands[i]];
declaringTypes.Add(currentCommand.MethodData.DeclaringType);
manual += $"\n - {currentCommand.CommandSignature}";
if (!currentCommand.IsStatic) { manual += $" (mono-target = {currentCommand.MonoTarget.ToString().ToLower()})"; }
for (int j = 0; j < currentCommand.ParamCount; j++)
{
ParameterInfo param = currentCommand.MethodParamData[j];
if (!foundParams.ContainsKey(param.Name)) { foundParams.Add(param.Name, param); }
if (!foundParamDescriptions.ContainsKey(param.Name))
{
CommandParameterDescriptionAttribute descriptionAttribute = param.GetCustomAttribute<CommandParameterDescriptionAttribute>();
if (descriptionAttribute != null && descriptionAttribute.Valid) { foundParamDescriptions.Add(param.Name, descriptionAttribute); }
}
}
if (currentCommand.IsGeneric)
{
Type[] genericArgs = currentCommand.GenericParamTypes;
for (int j = 0; j < genericArgs.Length; j++)
{
Type arg = genericArgs[j];
if (!foundGenericArguments.ContainsKey(arg.Name)) { foundGenericArguments.Add(arg.Name, arg); }
}
}
}
if (foundParams.Count > 0)
{
manual += "\nParameter info:";
ParameterInfo[] commandParams = foundParams.Values.ToArray();
for (int i = 0; i < commandParams.Length; i++)
{
ParameterInfo currentParam = commandParams[i];
manual += $"\n - {currentParam.Name}: {currentParam.ParameterType.GetDisplayName()}";
}
}
string genericConstraintInformation = "";
if (foundGenericArguments.Count > 0)
{
Type[] genericArgs = foundGenericArguments.Values.ToArray();
for (int i = 0; i < genericArgs.Length; i++)
{
Type arg = genericArgs[i];
Type[] typeConstraints = arg.GetGenericParameterConstraints();
GenericParameterAttributes attributes = arg.GenericParameterAttributes;
List<string> formattedConstraints = new List<string>();
if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint)) { formattedConstraints.Add("struct"); }
if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint)) { formattedConstraints.Add("class"); }
for (int j = 0; j < typeConstraints.Length; j++) { formattedConstraints.Add(typeConstraints[i].GetDisplayName()); }
if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint)) { formattedConstraints.Add("new()"); }
if (formattedConstraints.Count > 0)
{
genericConstraintInformation += $"\n - {arg.Name}: {string.Join(", ", formattedConstraints)}";
}
}
}
if (!string.IsNullOrWhiteSpace(genericConstraintInformation)) { manual += $"\nGeneric constraints:{genericConstraintInformation}"; }
for (int i = 0; i < matchingCommands.Length; i++)
{
CommandData currentCommand = _commandTable[matchingCommands[i]];
if (currentCommand.HasDescription)
{
manual += $"\n\nCommand description:\n{currentCommand.CommandDescription}";
i = matchingCommands.Length;
}
}
if (foundParamDescriptions.Count > 0)
{
manual += "\n\nParameter descriptions:";
ParameterInfo[] commandParams = foundParams.Values.ToArray();
for (int i = 0; i < commandParams.Length; i++)
{
ParameterInfo currentParam = commandParams[i];
if (foundParamDescriptions.ContainsKey(currentParam.Name))
{
manual += $"\n - {currentParam.Name}: {foundParamDescriptions[currentParam.Name].Description}";
}
}
}
declaringTypes = declaringTypes.Distinct().ToList();
manual += "\n\nDeclared in";
if (declaringTypes.Count == 1) { manual += $" {declaringTypes[0].GetDisplayName(true)}"; }
else
{
manual += ":";
foreach (Type type in declaringTypes)
{
manual += $"\n - {type.GetDisplayName(true)}";
}
}
return manual;
}
}
/// <summary>
/// Gets all loaded unique commands. Unique excludes multiple overloads of the same command from appearing.
/// </summary>
/// <returns>All loaded unique commands.</returns>
public static IEnumerable<CommandData> GetUniqueCommands()
{
return GetAllCommands()
.DistinctBy(x => x.CommandName)
.OrderBy(x => x.CommandName);
}
[CommandDescription("Generates a list of all commands currently loaded by the Quantum Console Processor")]
[Command("commands")]
[Command("all-commands")]
private static string GenerateCommandList()
{
string output = "List of all commands loaded by the Quantum Processor. Use 'man' on any command to see more:";
foreach (CommandData command in GetUniqueCommands())
{
output += $"\n - {command.CommandName}";
}
return output;
}
[Command("user-commands", "Generates a list of all commands added by the user")]
private static IEnumerable<string> GenerateUserCommandList()
{
return GetUniqueCommands()
.Where(x => !x.MethodData.DeclaringType.Assembly.FullName.StartsWith("QFSW.QC"))
.Select(x => $" - {x.CommandName}");
}
}
}