|
@@ -7,152 +7,90 @@ namespace PixiEditorGen;
|
|
[Generator(LanguageNames.CSharp)]
|
|
[Generator(LanguageNames.CSharp)]
|
|
public class CommandNameListGenerator : IIncrementalGenerator
|
|
public class CommandNameListGenerator : IIncrementalGenerator
|
|
{
|
|
{
|
|
- private const string Command = "PixiEditor.Models.Commands.Attributes.Commands";
|
|
|
|
|
|
+ private const string Commands = "PixiEditor.Models.Commands.Attributes.Commands";
|
|
|
|
|
|
private const string Evaluators = "PixiEditor.Models.Commands.Attributes.Evaluators.Evaluator";
|
|
private const string Evaluators = "PixiEditor.Models.Commands.Attributes.Evaluators.Evaluator";
|
|
|
|
|
|
private const string Groups = "PixiEditor.Models.Commands.Attributes.Commands.Command.GroupAttribute";
|
|
private const string Groups = "PixiEditor.Models.Commands.Attributes.Commands.Command.GroupAttribute";
|
|
-
|
|
|
|
|
|
+
|
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
{
|
|
{
|
|
- var commandList = context.SyntaxProvider.CreateSyntaxProvider(
|
|
|
|
- (x, token) =>
|
|
|
|
- {
|
|
|
|
- return x is MethodDeclarationSyntax method && method.AttributeLists.Count > 0;
|
|
|
|
- }, static (context, cancelToken) =>
|
|
|
|
- {
|
|
|
|
- var method = (MethodDeclarationSyntax)context.Node;
|
|
|
|
-
|
|
|
|
- if (!HasCommandAttribute(method, context, cancelToken, Command))
|
|
|
|
- return (null, null, null);
|
|
|
|
-
|
|
|
|
- var symbol = context.SemanticModel.GetDeclaredSymbol(method, cancelToken);
|
|
|
|
-
|
|
|
|
- if (symbol is IMethodSymbol methodSymbol)
|
|
|
|
- {
|
|
|
|
- if (methodSymbol.ReceiverType == null)
|
|
|
|
- return (null, null, null);
|
|
|
|
-
|
|
|
|
- return (methodSymbol.ReceiverType.ToDisplayString(), methodSymbol.Name, methodSymbol.Parameters.Select(x => x.ToDisplayString()));
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- return (null, null, null);
|
|
|
|
- }
|
|
|
|
- }).Where(x => x.Item1 != null);
|
|
|
|
-
|
|
|
|
- var evaluatorList = context.SyntaxProvider.CreateSyntaxProvider(
|
|
|
|
- (x, token) =>
|
|
|
|
- {
|
|
|
|
- return x is MethodDeclarationSyntax method && method.AttributeLists.Count > 0;
|
|
|
|
- }, static (context, cancelToken) =>
|
|
|
|
- {
|
|
|
|
- var method = (MethodDeclarationSyntax)context.Node;
|
|
|
|
-
|
|
|
|
- if (!HasCommandAttribute(method, context, cancelToken, Evaluators))
|
|
|
|
- return (null, null, null);
|
|
|
|
-
|
|
|
|
- var symbol = context.SemanticModel.GetDeclaredSymbol(method, cancelToken);
|
|
|
|
-
|
|
|
|
- if (symbol is IMethodSymbol methodSymbol)
|
|
|
|
- {
|
|
|
|
- return (methodSymbol.ReceiverType.ToDisplayString(), methodSymbol.Name, methodSymbol.Parameters.Select(x => x.ToDisplayString()));
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- return (null, null, null);
|
|
|
|
- }
|
|
|
|
- }).Where(x => x.Item1 != null);
|
|
|
|
-
|
|
|
|
- var groupList = context.SyntaxProvider.CreateSyntaxProvider(
|
|
|
|
- (x, token) =>
|
|
|
|
- {
|
|
|
|
- return x is TypeDeclarationSyntax type && type.AttributeLists.Count > 0;
|
|
|
|
- }, static (context, cancelToken) =>
|
|
|
|
- {
|
|
|
|
- var method = (TypeDeclarationSyntax)context.Node;
|
|
|
|
-
|
|
|
|
- if (!HasCommandAttribute(method, context, cancelToken, Groups))
|
|
|
|
- return null;
|
|
|
|
-
|
|
|
|
- var symbol = context.SemanticModel.GetDeclaredSymbol(method, cancelToken);
|
|
|
|
-
|
|
|
|
- if (symbol is ITypeSymbol methodSymbol)
|
|
|
|
- {
|
|
|
|
- return methodSymbol.ToDisplayString();
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
- }).Where(x => x != null);
|
|
|
|
|
|
+ var commandList = CreateSyntaxProvider(context, Commands).Where(x => !x.IsNone);
|
|
|
|
+ var evaluatorList = CreateSyntaxProvider(context, Evaluators).Where(x => !x.IsNone);
|
|
|
|
+ var groupList = CreateGroupSyntaxProvider(context).Where(x => x != null);
|
|
|
|
|
|
context.RegisterSourceOutput(commandList.Collect(), static (context, methodNames) =>
|
|
context.RegisterSourceOutput(commandList.Collect(), static (context, methodNames) =>
|
|
{
|
|
{
|
|
var code = new StringBuilder(
|
|
var code = new StringBuilder(
|
|
- @"namespace PixiEditor.Models.Commands;
|
|
|
|
|
|
+ """
|
|
|
|
+ namespace PixiEditor.Models.Commands;
|
|
|
|
|
|
-internal partial class CommandNameList {
|
|
|
|
- partial void AddCommands() {");
|
|
|
|
|
|
+ internal partial class CommandNameList {
|
|
|
|
+ partial void AddCommands() {
|
|
|
|
+ """);
|
|
|
|
|
|
List<string> createdClasses = new List<string>();
|
|
List<string> createdClasses = new List<string>();
|
|
|
|
|
|
foreach (var method in methodNames)
|
|
foreach (var method in methodNames)
|
|
{
|
|
{
|
|
- if (!createdClasses.Contains(method.Item1))
|
|
|
|
|
|
+ if (!createdClasses.Contains(method.OwnerTypeName))
|
|
{
|
|
{
|
|
- code.AppendLine($" Commands.Add(typeof({method.Item1}), new());");
|
|
|
|
- createdClasses.Add(method.Item1);
|
|
|
|
|
|
+ code.AppendLine($" Commands.Add(typeof({method.OwnerTypeName}), new());");
|
|
|
|
+ createdClasses.Add(method.OwnerTypeName);
|
|
}
|
|
}
|
|
|
|
|
|
- var parameters = string.Join(",", method.Item3.Select(x => $"typeof({x})"));
|
|
|
|
-
|
|
|
|
|
|
+ var parameters = string.Join(",", method.ParameterTypeNames);
|
|
|
|
+
|
|
bool hasParameters = parameters.Length > 0;
|
|
bool hasParameters = parameters.Length > 0;
|
|
string paramString = hasParameters ? $"new Type[] {{ {parameters} }}" : "Array.Empty<Type>()";
|
|
string paramString = hasParameters ? $"new Type[] {{ {parameters} }}" : "Array.Empty<Type>()";
|
|
-
|
|
|
|
- code.AppendLine($" Commands[typeof({method.Item1})].Add((\"{method.Item2}\", {paramString}));");
|
|
|
|
|
|
+
|
|
|
|
+ code.AppendLine($" Commands[typeof({method.OwnerTypeName})].Add((\"{method.MethodName}\", {paramString}));");
|
|
}
|
|
}
|
|
|
|
|
|
code.Append(" }\n}");
|
|
code.Append(" }\n}");
|
|
|
|
|
|
context.AddSource("CommandNameList+Commands", code.ToString());
|
|
context.AddSource("CommandNameList+Commands", code.ToString());
|
|
});
|
|
});
|
|
-
|
|
|
|
|
|
+
|
|
context.RegisterSourceOutput(evaluatorList.Collect(), static (context, methodNames) =>
|
|
context.RegisterSourceOutput(evaluatorList.Collect(), static (context, methodNames) =>
|
|
{
|
|
{
|
|
var code = new StringBuilder(
|
|
var code = new StringBuilder(
|
|
- @"namespace PixiEditor.Models.Commands;
|
|
|
|
|
|
+ """
|
|
|
|
+ namespace PixiEditor.Models.Commands;
|
|
|
|
|
|
-internal partial class CommandNameList {
|
|
|
|
- partial void AddEvaluators() {");
|
|
|
|
|
|
+ internal partial class CommandNameList {
|
|
|
|
+ partial void AddEvaluators() {
|
|
|
|
+ """);
|
|
|
|
|
|
List<string> createdClasses = new List<string>();
|
|
List<string> createdClasses = new List<string>();
|
|
|
|
|
|
foreach (var method in methodNames)
|
|
foreach (var method in methodNames)
|
|
{
|
|
{
|
|
- if (!createdClasses.Contains(method.Item1))
|
|
|
|
|
|
+ if (!createdClasses.Contains(method.OwnerTypeName))
|
|
{
|
|
{
|
|
- code.AppendLine($" Evaluators.Add(typeof({method.Item1}), new());");
|
|
|
|
- createdClasses.Add(method.Item1);
|
|
|
|
|
|
+ code.AppendLine($" Evaluators.Add(typeof({method.OwnerTypeName}), new());");
|
|
|
|
+ createdClasses.Add(method.OwnerTypeName);
|
|
}
|
|
}
|
|
|
|
|
|
- if (method.Item3 == null || !method.Item3.Any())
|
|
|
|
|
|
+ if (method.ParameterTypeNames == null || !method.ParameterTypeNames.Any())
|
|
{
|
|
{
|
|
- code.AppendLine($" Evaluators[typeof({method.Item1})].Add((\"{method.Item2}\", Array.Empty<Type>()));");
|
|
|
|
|
|
+ code.AppendLine($" Evaluators[typeof({method.OwnerTypeName})].Add((\"{method.MethodName}\", Array.Empty<Type>()));");
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- var parameters = string.Join(",", method.Item3.Select(x => $"typeof({x})"));
|
|
|
|
|
|
+ var parameters = string.Join(",", method.ParameterTypeNames);
|
|
string paramString = parameters.Length > 0 ? $"new Type[] {{ {parameters} }}" : "Array.Empty<Type>()";
|
|
string paramString = parameters.Length > 0 ? $"new Type[] {{ {parameters} }}" : "Array.Empty<Type>()";
|
|
- code.AppendLine($" Evaluators[typeof({method.Item1})].Add((\"{method.Item2}\", {paramString}));");
|
|
|
|
|
|
+ code.AppendLine($" Evaluators[typeof({method.OwnerTypeName})].Add((\"{method.MethodName}\", {paramString}));");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
code.Append(" }\n}");
|
|
code.Append(" }\n}");
|
|
|
|
|
|
|
|
+ File.WriteAllText(@"C:\Users\phili\Documents\Evals.txt", code.ToString());
|
|
|
|
+
|
|
context.AddSource("CommandNameList+Evaluators", code.ToString());
|
|
context.AddSource("CommandNameList+Evaluators", code.ToString());
|
|
});
|
|
});
|
|
-
|
|
|
|
|
|
+
|
|
context.RegisterSourceOutput(groupList.Collect(), static (context, typeNames) =>
|
|
context.RegisterSourceOutput(groupList.Collect(), static (context, typeNames) =>
|
|
{
|
|
{
|
|
var code = new StringBuilder(
|
|
var code = new StringBuilder(
|
|
@@ -171,7 +109,62 @@ internal partial class CommandNameList {
|
|
context.AddSource("CommandNameList+Groups", code.ToString());
|
|
context.AddSource("CommandNameList+Groups", code.ToString());
|
|
});
|
|
});
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ private IncrementalValuesProvider<Command> CreateSyntaxProvider(IncrementalGeneratorInitializationContext context, string className)
|
|
|
|
+ {
|
|
|
|
+ return context.SyntaxProvider.CreateSyntaxProvider(
|
|
|
|
+ (x, token) =>
|
|
|
|
+ {
|
|
|
|
+ return x is MethodDeclarationSyntax method && method.AttributeLists.Count > 0;
|
|
|
|
+ }, (context, cancelToken) =>
|
|
|
|
+ {
|
|
|
|
+ var method = (MethodDeclarationSyntax)context.Node;
|
|
|
|
+
|
|
|
|
+ if (!HasCommandAttribute(method, context, cancelToken, className))
|
|
|
|
+ return Command.None;
|
|
|
|
+
|
|
|
|
+ var symbol = context.SemanticModel.GetDeclaredSymbol(method, cancelToken);
|
|
|
|
+
|
|
|
|
+ if (symbol is IMethodSymbol methodSymbol)
|
|
|
|
+ {
|
|
|
|
+ if (methodSymbol.ReceiverType == null)
|
|
|
|
+ return Command.None;
|
|
|
|
+
|
|
|
|
+ return new Command(methodSymbol);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ return Command.None;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private IncrementalValuesProvider<string?> CreateGroupSyntaxProvider(IncrementalGeneratorInitializationContext context)
|
|
|
|
+ {
|
|
|
|
+ return context.SyntaxProvider.CreateSyntaxProvider(
|
|
|
|
+ (x, token) =>
|
|
|
|
+ {
|
|
|
|
+ return x is TypeDeclarationSyntax type && type.AttributeLists.Count > 0;
|
|
|
|
+ }, static (context, cancelToken) =>
|
|
|
|
+ {
|
|
|
|
+ var method = (TypeDeclarationSyntax)context.Node;
|
|
|
|
+
|
|
|
|
+ if (!HasCommandAttribute(method, context, cancelToken, Groups))
|
|
|
|
+ return null;
|
|
|
|
+
|
|
|
|
+ var symbol = context.SemanticModel.GetDeclaredSymbol(method, cancelToken);
|
|
|
|
+
|
|
|
|
+ if (symbol is ITypeSymbol methodSymbol)
|
|
|
|
+ {
|
|
|
|
+ return methodSymbol.ToDisplayString();
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
private static bool HasCommandAttribute(MemberDeclarationSyntax declaration, GeneratorSyntaxContext context, CancellationToken token, string commandAttributeStart)
|
|
private static bool HasCommandAttribute(MemberDeclarationSyntax declaration, GeneratorSyntaxContext context, CancellationToken token, string commandAttributeStart)
|
|
{
|
|
{
|
|
foreach (var attrList in declaration.AttributeLists)
|
|
foreach (var attrList in declaration.AttributeLists)
|
|
@@ -191,4 +184,24 @@ internal partial class CommandNameList {
|
|
|
|
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ readonly struct Command
|
|
|
|
+ {
|
|
|
|
+ public string OwnerTypeName { get; }
|
|
|
|
+
|
|
|
|
+ public string MethodName { get; }
|
|
|
|
+
|
|
|
|
+ public string[] ParameterTypeNames { get; }
|
|
|
|
+
|
|
|
|
+ public Command(IMethodSymbol symbol)
|
|
|
|
+ {
|
|
|
|
+ OwnerTypeName = symbol.ContainingType.ToDisplayString();
|
|
|
|
+ MethodName = symbol.Name;
|
|
|
|
+ ParameterTypeNames = symbol.Parameters.Select(x => $"typeof({x.Type.ToDisplayString()})").ToArray();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public bool IsNone => OwnerTypeName == null;
|
|
|
|
+
|
|
|
|
+ public static Command None => default;
|
|
|
|
+ }
|
|
}
|
|
}
|