Spectre.Console-实现自己的CLI
Posted 波多尔斯基
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spectre.Console-实现自己的CLI相关的知识,希望对你有一定的参考价值。
引言
最近发现自己喜欢用的 Todo 软件总是差点意思,毕竟每个人的习惯和工作流不太一样,我就想着自己写一个小的Todo 项目,核心的功能是自动记录 Todo 执行过程中消耗的时间(尤其面向程序员),按照自己的想法实现一套 GTD
工作流。
不想写 Winform
,WPF
也写腻了,就想着学学 MAUI
、Avalonia
、Uno Platform
、blazor
之类的。由于前端技术选型纠结,迟迟动不了手,想想还是暂时先不弄了。但为了测试,没有个界面总是不太行,先搞一个 CLI 吧。
更新:由于想让程序持续执行,所以后面还是替换了 CLI 。
Spectre. Console
Spectre.Console(spectreconsole.net) 是一个美化 Console 输出的类库,通过它可以实现丰富多样的 Console 输出。核心的特性有这些:
- 格式化输出文本(支持斜体等)
- 支持对文字着色
- 渲染复杂的组件(表格、结构树、ASCII 图片)
- 显示进度条与状态
- 强类型输入验证
- 对 exception 输出着色
除此以外,它还提供了一个 Spectre.Console.Cli
类库,可以帮助我们实现类似 dotnet
、git
之类的 CLI(Command Line Interface)。
基本用法
这里使用官方的示例:
var app = new CommandApp<FileSizeCommand>();
return app.Run(args);
internal sealed class FileSizeCommand : Command<FileSizeCommand.Settings>
public sealed class Settings : CommandSettings
[Description("Path to search. Defaults to current directory.")]
[CommandArgument(0, "[searchPath]")]
public string? SearchPath get; init;
[CommandOption("-p|--pattern")]
public string? SearchPattern get; init;
[CommandOption("--hidden")]
[DefaultValue(true)]
public bool IncludeHidden get; init;
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
var searchOptions = new EnumerationOptions
AttributesToSkip = settings.IncludeHidden
? FileAttributes.Hidden | FileAttributes.System
: FileAttributes.System
;
var searchPattern = settings.SearchPattern ?? "*.*";
var searchPath = settings.SearchPath ?? Directory.GetCurrentDirectory();
var files = new DirectoryInfo(searchPath)
.GetFiles(searchPattern, searchOptions);
var totalFileSize = files
.Sum(fileInfo => fileInfo.Length);
AnsiConsole.MarkupLine($"Total file size for [green]searchPattern[/] files in [green]searchPath[/]: [blue]totalFileSize:N0[/] bytes");
return 0;
结构非常简单,标有 [CommandOption("xxx")]
会自动将参数归类,通过下列命令进行调用。
app.exe
app.exe c:\\windows
app.exe c:\\windows --pattern *.dll
app.exe c:\\windows --hidden --pattern *.dll
多命令
上面这个示例只支持一个默认的命令,但是一般的 CLI 都有很多支持的命令,需要调整一下实现:
var app = new CommandApp();
app.Configure(config =>
config.AddCommand<AddCommand>("add");
config.AddCommand<CommitCommand>("commit");
config.AddCommand<RebaseCommand>("rebase");
);
层级命令
更复杂一点的,比如 dotnet add package
和 dotnet add reference
这种,add 后面还有 package 这个子命令,上面的方法还得继续拓展,首先定义 add 基类和 package 与 reference 继承类。
public class AddSettings : CommandSettings
[CommandArgument(0, "[PROJECT]")]
public string Project get; set;
public class AddPackageSettings : AddSettings
[CommandArgument(0, "<PACKAGE_NAME>")]
public string PackageName get; set;
[CommandOption("-v|--version <VERSION>")]
public string Version get; set;
public class AddReferenceSettings : AddSettings
[CommandArgument(0, "<PROJECT_REFERENCE>")]
public string ProjectReference get; set;
然后对不同的命令,指定不同处理函数。
public class AddPackageCommand : Command<AddPackageSettings>
public override int Execute(CommandContext context, AddPackageSettings settings)
// Omitted
return 0;
public class AddReferenceCommand : Command<AddReferenceSettings>
public override int Execute(CommandContext context, AddReferenceSettings settings)
// Omitted
return 0;
最后使用 AddBranch 进行组合:
using Spectre.Console.Cli;
namespace MyApp
public static class Program
public static int Main(string[] args)
var app = new CommandApp();
app.Configure(config =>
config.AddBranch<AddSettings>("add", add =>
add.AddCommand<AddPackageCommand>("package");
add.AddCommand<AddReferenceCommand>("reference");
);
);
return app.Run(args);
参考
使用Spectre.Console创建漂亮的控制台应用程序
前言
你是否厌倦了控制台应用程序默认的简陋界面?
这时,你可以试试引用Nuget包Spectre.Console
。
打印使用帮助
首先,我们可以设置控制台应用程序可以执行的命令:
static async Task<int> Main(string[] args)
var app = new CommandApp();
app.Configure(config =>
config.AddCommand<DemoCommand>("demo");
config.AddCommand<AnotherCommand>("another");
);
return await app.RunAsync(args);
然后,为每个命令指定参数:
public class DemoCommandSettings : CommandSettings
[CommandOption("-u|--username")]
[Description("需要显示的名称")]
public string Name get; set;
最后,实现命令:
public class DemoCommand : AsyncCommand<DemoCommandSettings>
public override Task<int> ExecuteAsync(CommandContext context, DemoCommandSettings settings)
Console.WriteLine($@"Hello settings.Name!");
return Task.FromResult(0);
可以看到,Spectre.Console自动生成了帮助信息,指导用户如何使用。
与用户交互
我们还可以运行命令时询问用户,进行一定的交互输入:
var name =settings.Name?? AnsiConsole.Ask<string>("What's your [green]name[/]?");
Console.WriteLine($@"Hello name!");
显示信息
当我们从用户那里收集完信息后,可以让用户检查信息,以确保所有信息输入正确。例如,我们可以以表格格式呈现摘要:
do
name = AnsiConsole.Ask<string>("What's your [green]name[/]?");
var table = new Table();
table.AddColumn("参数");
table.AddColumn(new TableColumn("值").Centered());
table.AddRow("-u", $@"[green]name[/]");
AnsiConsole.Write(table);
while (!AnsiConsole.Confirm("输入是否正确?"));
报告进度
在执行命令时,可以显示进度来告诉用户工作完成的百分比:
await AnsiConsole.Progress()
.StartAsync(async ctx =>
var task1 = ctx.AddTask("执行中......");
while (!ctx.IsFinished)
// 模拟工作耗时
await Task.Delay(100);
task1.Increment(1);
);
结论
正如我在开始时提到的,使用Spectre.Console可以创建出漂亮的控制台应用程序,更多功能请参看官方文档:https://spectreconsole.net/
如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“
以上是关于Spectre.Console-实现自己的CLI的主要内容,如果未能解决你的问题,请参考以下文章
vue-cli3.0结合lib-flexiblepx2rem实现移动端适配,完美解决第三方ui库样式变小问题
vue-cli3使用 DllPlugin 实现预编译,提升构建速度