Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 28 additions & 20 deletions samples/DotNetCampus.CommandLine.Sample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
using DotNetCampus.Cli;
using DotNetCampus.Cli.Compiler;
using DotNetCampus.Cli.Legacy;
using DotNetCampus.Cli.Properties;

namespace DotNetCampus.Cli;

class Program
var appState = new AppState
{
static async Task Main(string[] args)
AppName = "DotNetCampus.CommandLine.Sample",
};

await CommandLine.Parse(args, CommandLineParsingOptions.Flexible)
.AddHandler<DefaultOptions>(o => o.Run())
.AddHandler<ConvertHandler>()
.AddHandler<EditHandler>()
.AddHandler<TestHandler>()
.AddHandler<BenchmarkHandler>()
.AddHelpHandler(new HelpConfigurations
{
var appState = new AppState
{
AppName = "DotNetCampus.CommandLine.Sample",
};
HelpTextLocalizer = key => LocalizableStrings.ResourceManager.GetString(key) ?? key,
})
.ForState(appState).AddHandler<UrlOpenHandler>()
.ForState()
.RunAsync();


await CommandLine.Parse(args, CommandLineParsingOptions.Flexible)
.AddHandler<DefaultOptions>(o => o.Run())
.AddHandler<ConvertHandler>()
.AddHandler<EditHandler>()
.AddHandler<BenchmarkHandler>()
.AddHelpHandler(new HelpConfigurations
{
HelpTextLocalizer = key => LocalizableStrings.ResourceManager.GetString(key) ?? key,
})
.ForState(appState).AddHandler<UrlOpenHandler>()
.ForState()
.RunAsync();
[Command("test")]
internal record TestHandler : ICommandHandler
{
[Option("test")]
public int? Count { get; init; }

public Task<int> RunAsync()
{
return Task.FromResult(0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ private void GenerateCommandLineAddHandlerCode(TypeDeclarationSourceTextBuilder
.AddTypeConstraints("where T : class, global::DotNetCampus.Cli.ICommandHandler")
.AddRawStatement(GenerateComment(model))
.AddRawStatements($"""
return commandLine.AsRunner().AddHandler<T>(global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.CommandNameGroup, new global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.Metadata());
return commandLine.AsRunner().AddHandler<T>({model.GetGlobalBuilderTypeName()}.CommandNameGroup, new {model.GetGlobalBuilderTypeName()}.Metadata());
"""));
Comment on lines 151 to 155
}

Expand All @@ -166,7 +166,7 @@ private void GenerateCommandLineAddHandlerActionCode(TypeDeclarationSourceTextBu
.AddTypeConstraints("where T : class")
.AddRawStatement(GenerateComment(model))
.AddRawStatements($"""
return commandLine.AsRunner().AddHandler<T>(handler, global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.CommandNameGroup, new global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.Metadata());
return commandLine.AsRunner().AddHandler<T>(handler, {model.GetGlobalBuilderTypeName()}.CommandNameGroup, new {model.GetGlobalBuilderTypeName()}.Metadata());
"""));
}

Expand Down Expand Up @@ -265,7 +265,7 @@ private void GenerateCommandLineAsCode(TypeDeclarationSourceTextBuilder builder,
.AddRawStatement(GenerateComment(model))
.AddRawStatements($$"""""
var context = new global::DotNetCampus.Cli.Compiler.CommandRunningContext { CommandLine = commandLine };
var instance = new global::{{model.CommandObjectType.ContainingNamespace}}.{{model.GetBuilderTypeName()}}().Build(context);
var instance = new {{model.GetGlobalBuilderTypeName()}}().Build(context);
{{(
model.UseFullStackParser
? $"""
Expand Down Expand Up @@ -293,7 +293,7 @@ private void GenerateCommandBuilderAddHandlerCode(TypeDeclarationSourceTextBuild
.AddTypeConstraints("where T : class, global::DotNetCampus.Cli.ICommandHandler")
.AddRawStatement(GenerateComment(model))
.AddRawStatements($"""
return global::DotNetCampus.Cli.CommandRunnerBuilderExtensions.AddHandler<T>(builder, global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.CommandNameGroup, new global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.Metadata());
return global::DotNetCampus.Cli.CommandRunnerBuilderExtensions.AddHandler<T>(builder, {model.GetGlobalBuilderTypeName()}.CommandNameGroup, new {model.GetGlobalBuilderTypeName()}.Metadata());
"""));
}

Expand All @@ -310,7 +310,7 @@ private void GenerateStatedCommandBuilderAddHandlerCode(TypeDeclarationSourceTex
.AddTypeConstraints("where T : class, global::DotNetCampus.Cli.ICommandHandler<TState>")
.AddRawStatement(GenerateComment(model))
.AddRawStatements($"""
return builder.AddHandler<T>(global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.CommandNameGroup, new global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.Metadata());
return builder.AddHandler<T>({model.GetGlobalBuilderTypeName()}.CommandNameGroup, new {model.GetGlobalBuilderTypeName()}.Metadata());
"""));
}

Expand All @@ -327,7 +327,7 @@ private void GenerateCommandBuilderAddHandlerActionCode(TypeDeclarationSourceTex
.AddTypeConstraints("where T : class")
.AddRawStatement(GenerateComment(model))
.AddRawStatements($"""
return global::DotNetCampus.Cli.CommandRunnerBuilderExtensions.AddHandler<T>(builder, handler, global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.CommandNameGroup, new global::{model.CommandObjectType.ContainingNamespace}.{model.GetBuilderTypeName()}.Metadata());
return global::DotNetCampus.Cli.CommandRunnerBuilderExtensions.AddHandler<T>(builder, handler, {model.GetGlobalBuilderTypeName()}.CommandNameGroup, new {model.GetGlobalBuilderTypeName()}.Metadata());
"""));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private void GenerateCommandObjectMetadata(TypeDeclarationSourceTextBuilder buil
{
builder
.AddMethodDeclaration("public object Build(global::DotNetCampus.Cli.Compiler.CommandRunningContext context)", m => m
.AddRawStatement($"return new {model.Namespace}.{model.GetBuilderTypeName()}().Build(context);"))
.AddRawStatement($"return new {model.GetGlobalBuilderTypeName()}().Build(context);"))
.AddMethodDeclaration("public global::DotNetCampus.Cli.Compiler.CommandHelpMetadata? GetHelp()", m => m
.AddRawStatement(GenerateGetHelpReturnStatement(model)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public static IncrementalValuesProvider<CommandObjectGeneratingModel> SelectComm
return null;
}

var @namespace = typeSymbol.ContainingNamespace.ToDisplayString();
var @namespace = typeSymbol.GetNamespaceOrNull();
var commandNames = attribute?.ConstructorArguments.FirstOrDefault().Value?.ToString();
var commandDescription = attribute?.NamedArguments
.FirstOrDefault(kv => kv.Key == "Description").Value.Value?.ToString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ string InvocationInfo

public string GetBuilderTypeName() => CommandObjectGeneratingModel.GetBuilderTypeName(CommandObjectType);

/// <summary>
/// 获取创建器类型带 global:: 前缀的完整名称。支持命令行对象位于全局命名空间的情况(如使用顶级语句时)。
/// </summary>
public string GetGlobalBuilderTypeName() => CommandObjectGeneratingModel.GetGlobalBuilderTypeName(CommandObjectType);

internal static IEqualityComparer<InterceptorGeneratingModel> CommandObjectTypeEqualityComparer { get; } =
new PrivateTypeSymbolEqualityComparer();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DotNetCampus.Cli.Utils;
using DotNetCampus.CommandLine.Utils.CodeAnalysis;
using Microsoft.CodeAnalysis;

namespace DotNetCampus.CommandLine.Generators.Models;
Expand All @@ -10,7 +11,10 @@ internal record CommandObjectGeneratingModel
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters);

public required string Namespace { get; init; }
/// <summary>
/// 命令行对象类型所在的命名空间。如果类型位于全局命名空间(例如顶级语句所在的项目中未声明命名空间的类型),则为 <see langword="null"/>。
/// </summary>
public required string? Namespace { get; init; }

public required INamedTypeSymbol CommandObjectType { get; init; }

Expand Down Expand Up @@ -41,6 +45,25 @@ public static string GetBuilderTypeName(INamedTypeSymbol commandObjectType)
return $"{name}Builder";
}

/// <summary>
/// 获取创建器类型带 global:: 前缀的完整名称。支持命令行对象位于全局命名空间的情况。
/// </summary>
public string GetGlobalBuilderTypeName()
{
return GetGlobalBuilderTypeName(CommandObjectType);
}

/// <summary>
/// 获取创建器类型带 global:: 前缀的完整名称。支持命令行对象位于全局命名空间的情况。
/// </summary>
public static string GetGlobalBuilderTypeName(INamedTypeSymbol commandObjectType)
{
var typeName = GetBuilderTypeName(commandObjectType);
return commandObjectType.GetNamespaceOrNull() is { } @namespace
? $"global::{@namespace}.{typeName}"
: $"global::{typeName}";
}

public int GetCommandLevel() => CommandNames switch
{
null => 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ namespace DotNetCampus.CommandLine.Utils.CodeAnalysis;
/// </summary>
internal static class TypeSymbolExtensions
{
/// <summary>
/// 获取一个符号所在的命名空间。如果此符号位于全局命名空间(例如使用顶级语句时定义的类型),则返回 <see langword="null"/>。
/// </summary>
/// <param name="symbol">要获取命名空间的符号。</param>
/// <returns>命名空间的字符串形式;如果位于全局命名空间,则返回 <see langword="null"/>。</returns>
public static string? GetNamespaceOrNull(this ISymbol symbol) => symbol.ContainingNamespace is { IsGlobalNamespace: false } @namespace
? @namespace.ToDisplayString()
: null;

/// <summary>
/// 判断一个类型是否是指定类型的子类或实现了指定接口。
/// </summary>
Expand Down
Loading