Skip to content

Commit

Permalink
commandpath uses
Browse files Browse the repository at this point in the history
  • Loading branch information
neuecc committed Jun 1, 2024
1 parent 3367c87 commit 3682ad3
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 116 deletions.
1 change: 1 addition & 0 deletions sandbox/CliFrameworkBenchmark/Benchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using CliFx;
using Cocona.Benchmark.External.Commands;
using CommandLine;
using ConsoleAppFramework;
using PowerArgs;
using Spectre.Console.Cli;
using System.ComponentModel.DataAnnotations.Schema;
Expand Down
8 changes: 4 additions & 4 deletions src/ConsoleAppFramework/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public record class Command
{
public required bool IsAsync { get; init; } // Task or Task<int>
public required bool IsVoid { get; init; } // void or int
public string CommandFullName => (CommandPath.Length == 0) ? CommandName : $"{string.Join("/", CommandPath)}/{CommandName}"; // TODO:Join " "
public bool IsRootCommand => CommandFullName == "";
public required string[] CommandPath { get; init; }
public required string CommandName { get; init; }

public bool IsRootCommand => Name == "";
public required string Name { get; init; }

public required CommandParameter[] Parameters { get; init; }
public required string Description { get; init; }
public required MethodKind MethodKind { get; init; }
Expand Down
19 changes: 4 additions & 15 deletions src/ConsoleAppFramework/CommandHelpBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static string BuildRootHelpMessage(Command[] commands)

if (withoutRoot.Length == 0) return sb.ToString();

var helpDefinitions = withoutRoot.OrderBy(x => x.CommandFullName).ToArray();
var helpDefinitions = withoutRoot.OrderBy(x => x.Name).ToArray();

var list = BuildMethodListMessage(helpDefinitions, out _);
sb.Append(list);
Expand All @@ -44,7 +44,7 @@ public static string BuildRootHelpMessage(Command[] commands)

public static string BuildCommandHelpMessage(Command command)
{
return BuildHelpMessageCore(command, showCommandName: command.CommandName != "", showCommand: false);
return BuildHelpMessageCore(command, showCommandName: command.Name != "", showCommand: false);
}

static string BuildHelpMessageCore(Command command, bool showCommandName, bool showCommand)
Expand Down Expand Up @@ -217,13 +217,7 @@ static string BuildMethodListMessage(IEnumerable<Command> commands, out int maxW
var formatted = commands
.Select(x =>
{
var full = x.CommandName;
if (x.CommandPath.Length > 0)
{
full = string.Join(" ", x.CommandPath) + " " + x.CommandName;
}
return (Command: full, x.Description);
return (Command: x.Name, x.Description);
})
.ToArray();
maxWidth = formatted.Max(x => x.Command.Length);
Expand Down Expand Up @@ -309,12 +303,7 @@ static CommandHelpDefinition CreateCommandHelpDefinition(Command descriptor)
parameterDefinitions.Add(new CommandOptionHelpDefinition(options.Distinct().ToArray(), description, paramTypeName, defaultValue, index, isFlag, isParams));
}

var commandName = descriptor.CommandName;
if (descriptor.CommandPath.Length != 0)
{
commandName = string.Join(" ", descriptor.CommandPath) + " " + descriptor.CommandName;
}

var commandName = descriptor.Name;
return new CommandHelpDefinition(
commandName,
parameterDefinitions.ToArray(),
Expand Down
10 changes: 5 additions & 5 deletions src/ConsoleAppFramework/ConsoleAppGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -613,9 +613,9 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex
var command = parser.ParseAndValidateForBuilderDelegateRegistration();
// validation command name duplicate
if (command != null && !names.Add(command.CommandFullName))
if (command != null && !names.Add(command.Name))
{
sourceProductionContext.ReportDiagnostic(DiagnosticDescriptors.DuplicateCommandName, x.Node.ArgumentList.Arguments[0].GetLocation(), command!.CommandFullName);
sourceProductionContext.ReportDiagnostic(DiagnosticDescriptors.DuplicateCommandName, x.Node.ArgumentList.Arguments[0].GetLocation(), command!.Name);
return null;
}
Expand All @@ -629,12 +629,12 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex
var parser = new Parser(sourceProductionContext, x.Node, x.Model, wellKnownTypes, DelegateBuildType.None, globalFilters);
var commands = parser.ParseAndValidateForBuilderClassRegistration();
// validation command name duplicate?
// validation command name duplicate
foreach (var command in commands)
{
if (command != null && !names.Add(command.CommandFullName))
if (command != null && !names.Add(command.Name))
{
sourceProductionContext.ReportDiagnostic(DiagnosticDescriptors.DuplicateCommandName, x.Node.GetLocation(), command!.CommandFullName);
sourceProductionContext.ReportDiagnostic(DiagnosticDescriptors.DuplicateCommandName, x.Node.GetLocation(), command!.Name);
return [null];
}
}
Expand Down
22 changes: 10 additions & 12 deletions src/ConsoleAppFramework/Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy
}

var filterCancellationToken = command.HasFilter ? ", ConsoleAppContext context, CancellationToken cancellationToken" : "";
var rawArgs = !emitForBuilder ? "" : "string[] rawArgs, ";

// method signature
using (sb.BeginBlock($"{accessibility} static {unsafeCode}{returnType} {methodName}(string[] rawArgs, {argsType} args{commandMethodType}{filterCancellationToken})"))
using (sb.BeginBlock($"{accessibility} static {unsafeCode}{returnType} {methodName}({rawArgs}{argsType} args{commandMethodType}{filterCancellationToken})"))
{
sb.AppendLine($"if (TryShowHelpOrVersion(args, {parsableParameterCount}, {commandWithId.Id})) return;");
sb.AppendLine();
Expand All @@ -56,7 +57,8 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy
}
if (hasConsoleAppContext)
{
sb.AppendLine($"var context = new ConsoleAppContext(\"{command.CommandFullName}\", rawArgs, null);");
var rawArgsName = !emitForBuilder ? "args" : "rawArgs";
sb.AppendLine($"var context = new ConsoleAppContext(\"{command.Name}\", {rawArgsName}, null);");
}
for (var i = 0; i < command.Parameters.Length; i++)
{
Expand Down Expand Up @@ -300,7 +302,7 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy
public void EmitBuilder(SourceBuilder sb, CommandWithId[] commandIds, bool emitSync, bool emitAsync)
{
// grouped by path
var commandGroup = commandIds.ToLookup(x => x.Command.CommandPath.Length == 0 ? x.Command.CommandName : x.Command.CommandPath[0]);
var commandGroup = commandIds.ToLookup(x => x.Command.Name.Split(' ')[0]);
var hasRootCommand = commandIds.Any(x => x.Command.IsRootCommand);

using (sb.BeginBlock("partial struct ConsoleAppBuilder"))
Expand All @@ -319,7 +321,7 @@ public void EmitBuilder(SourceBuilder sb, CommandWithId[] commandIds, bool emitS
{
foreach (var item in commandIds.Where(x => x.FieldType != null))
{
using (sb.BeginIndent($"case \"{item.Command.CommandFullName}\":"))
using (sb.BeginIndent($"case \"{item.Command.Name}\":"))
{
sb.AppendLine($"this.command{item.Id} = Unsafe.As<{item.FieldType}>(command);");
sb.AppendLine("break;");
Expand Down Expand Up @@ -441,14 +443,10 @@ void EmitRunBody(ILookup<string, CommandWithId> groupedCommands, int depth, bool
var nextGroup = commands
.ToLookup(x =>
{
var len = x.Command.CommandPath.Length;
if (len > nextDepth)
var path = x.Command.Name.Split(' ');
if (path.Length > nextDepth)
{
return x.Command.CommandPath[nextDepth];
}
if (len == nextDepth)
{
return x.Command.CommandName;
return path[nextDepth];
}
else
{
Expand Down Expand Up @@ -496,7 +494,7 @@ void EmitLeafCommand(CommandWithId? command)
}
else
{
var invokeCode = $"RunWithFilterAsync(\"{command.Command.CommandFullName}\", args, new Command{command.Id}Invoker(args[{depth}..]{commandArgs}).BuildFilter())";
var invokeCode = $"RunWithFilterAsync(\"{command.Command.Name}\", args, new Command{command.Id}Invoker(args[{depth}..]{commandArgs}).BuildFilter())";
if (!isRunAsync)
{
sb.AppendLine($"{invokeCode}.GetAwaiter().GetResult();");
Expand Down
39 changes: 14 additions & 25 deletions src/ConsoleAppFramework/Parser.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Xml.Linq;

namespace ConsoleAppFramework;

Expand All @@ -12,7 +11,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta
var args = node.ArgumentList.Arguments;
if (args.Count == 2) // 0 = args, 1 = lambda
{
var command = ExpressionToCommand(args[1].Expression, [], ""); // rootCommand(path and commandName = "")
var command = ExpressionToCommand(args[1].Expression, ""); // rootCommand(commandName = "")
if (command != null)
{
return ValidateCommand(command);
Expand All @@ -26,7 +25,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta

public Command? ParseAndValidateForBuilderDelegateRegistration() // for ConsoleAppBuilder.Add
{
// Add(string commandName)
// Add(string commandName, Delgate command)
var args = node.ArgumentList.Arguments;
if (args.Count == 2) // 0 = string command, 1 = lambda
{
Expand All @@ -38,15 +37,8 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta
return null;
}

string[] path = [];
var name = (commandName.Expression as LiteralExpressionSyntax)!.Token.ValueText;
var pathAndName = name.Split(['/'], StringSplitOptions.RemoveEmptyEntries);
if (pathAndName.Length > 1)
{
path = pathAndName.AsSpan(0, pathAndName.Length - 1).ToArray();
name = pathAndName[^1];
}
var command = ExpressionToCommand(args[1].Expression, path, name);
var command = ExpressionToCommand(args[1].Expression, name);
if (command != null)
{
return ValidateCommand(command);
Expand All @@ -64,7 +56,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta
var genericType = genericName!.TypeArgumentList.Arguments[0];

// Add<T>(string commandPath)
string[] commandPath = [];
string? commandPath = null;
var args = node.ArgumentList.Arguments;
if (node.ArgumentList.Arguments.Count == 1)
{
Expand All @@ -75,8 +67,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta
return [];
}

var name = (commandName.Expression as LiteralExpressionSyntax)!.Token.ValueText;
commandPath = name.Split(['/'], StringSplitOptions.RemoveEmptyEntries);
commandPath = (commandName.Expression as LiteralExpressionSyntax)!.Token.ValueText;
}

// T
Expand Down Expand Up @@ -160,7 +151,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta
commandName = NameConverter.ToKebabCase(x.Name);
}
var command = ParseFromMethodSymbol(x, false, commandPath, commandName, typeFilters);
var command = ParseFromMethodSymbol(x, false, (commandPath == null) ? commandName : $"{commandPath.Trim()} {commandName}", typeFilters);
if (command == null) return null;
command.CommandMethodInfo = methodInfoBase with { MethodName = x.Name };
Expand All @@ -169,7 +160,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta
.ToArray();
}

Command? ExpressionToCommand(ExpressionSyntax expression, string[] commandPath, string commandName)
Command? ExpressionToCommand(ExpressionSyntax expression, string commandName)
{
var lambda = expression as ParenthesizedLambdaExpressionSyntax;
if (lambda == null)
Expand All @@ -181,27 +172,27 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta
var methodSymbols = model.GetMemberGroup(operand);
if (methodSymbols.Length > 0 && methodSymbols[0] is IMethodSymbol methodSymbol)
{
return ParseFromMethodSymbol(methodSymbol, addressOf: true, commandPath, commandName, []);
return ParseFromMethodSymbol(methodSymbol, addressOf: true, commandName, []);
}
}
else
{
var methodSymbols = model.GetMemberGroup(expression);
if (methodSymbols.Length > 0 && methodSymbols[0] is IMethodSymbol methodSymbol)
{
return ParseFromMethodSymbol(methodSymbol, addressOf: false, commandPath, commandName, []);
return ParseFromMethodSymbol(methodSymbol, addressOf: false, commandName, []);
}
}
}
else
{
return ParseFromLambda(lambda, commandPath, commandName);
return ParseFromLambda(lambda, commandName);
}

return null;
}

Command? ParseFromLambda(ParenthesizedLambdaExpressionSyntax lambda, string[] commandPath, string commandName)
Command? ParseFromLambda(ParenthesizedLambdaExpressionSyntax lambda, string commandName)
{
var isAsync = lambda.AsyncKeyword.IsKind(SyntaxKind.AsyncKeyword);

Expand Down Expand Up @@ -374,8 +365,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta

var cmd = new Command
{
CommandName = commandName,
CommandPath = commandPath,
Name = commandName,
IsAsync = isAsync,
IsVoid = isVoid,
Parameters = parameters,
Expand All @@ -388,7 +378,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta
return cmd;
}

Command? ParseFromMethodSymbol(IMethodSymbol methodSymbol, bool addressOf, string[] commandPath, string commandName, FilterInfo[] typeFilters)
Command? ParseFromMethodSymbol(IMethodSymbol methodSymbol, bool addressOf, string commandName, FilterInfo[] typeFilters)
{
var docComment = methodSymbol.DeclaringSyntaxReferences[0].GetSyntax().GetDocumentationCommentTriviaSyntax();
var summary = "";
Expand Down Expand Up @@ -529,8 +519,7 @@ internal class Parser(SourceProductionContext context, InvocationExpressionSynta

var cmd = new Command
{
CommandName = commandName,
CommandPath = commandPath,
Name = commandName,
IsAsync = isAsync,
IsVoid = isVoid,
Parameters = parameters,
Expand Down
6 changes: 3 additions & 3 deletions tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void ListWithoutRoot()
var app = ConsoleApp.Create();
app.Add("a", (int x, int y) => { });
app.Add("ab", (int x, int y) => { });
app.Add("a/b/c", (int x, int y) => { });
app.Add("a b c", (int x, int y) => { });
app.Run(args);
""";
verifier.Execute(code, args: "--help", expected: """
Expand All @@ -89,7 +89,7 @@ public void ListWithRoot()
app.Add("", (int x, int y) => { });
app.Add("a", (int x, int y) => { });
app.Add("ab", (int x, int y) => { });
app.Add("a/b/c", (int x, int y) => { });
app.Add("a b c", (int x, int y) => { });
app.Run(args);
""";
verifier.Execute(code, args: "--help", expected: """
Expand All @@ -115,7 +115,7 @@ public void SelectLeafHelp()
app.Add("", (int x, int y) => { });
app.Add("a", (int x, int y) => { });
app.Add("ab", (int x, int y) => { });
app.Add("a/b/c", (int x, int y) => { });
app.Add("a b c", (int x, int y) => { });
app.Run(args);
""";
verifier.Execute(code, args: "a b c --help", expected: """
Expand Down
Loading

0 comments on commit 3682ad3

Please sign in to comment.