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-实现自己的CLI的更多相关文章
- dotnet core cli 命令
1 dotnet new 2 创建code 程序 dotnet new console using System; namespace cli { class Program { static voi ...
- spark cli
Spark SQL CLI Spark1.1增加了Spark SQL CLI和ThriftServer SparkSQL CLI配置 1.创建并配置hive-site.xml 在运行Spark SQL ...
- 事件冒泡和事件捕获以及解释target和currenttarget的区别
冒泡和捕获的区别是冒泡事件是先触发子元素事件,再触发父元素事件,这个是冒泡.捕获是先触发父元素事件,再触发子元素事件.简单的来说,冒泡的顺序是由内到外,捕获的顺序是由外到内 举例:<!DOCTY ...
- 170多个Ionic Framework学习资源(转载)
在Ionic官网找到的学习资源:http://blog.ionic.io/learning-ionic-in-your-living-room/ 网上的文章比较多,但是很多时候我们很难找到自己需要的. ...
- Yii2 捕获错误日志
在技术开发中,捕获程序框架错误,是非常必要的一件事情,我们公司使用Yii2框架,简单说下Yii2的错误捕获处理 Yii2 web应用 1 配置如下 其中errorHandler就是错误处理配置,执行E ...
- Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio »迁移
Migrations¶ 4 of 4 people found this helpful The Contoso University sample web application demonstra ...
- ionic项目相关的操作命令
更新npmD:\Program Files\npm-3.9.0\npmnode cli.js install npm -gf vs安装 更新node.js windows版直接从官网下载安装包 n ...
- 方法:怎么用ionic命令行调试你的ionic app
官网上有很详细的解说 http://blog.ionic.io/live-reload-all-things-ionic-cli/ 下面说说我自己的调试过程(android版): 首先用命令行进入你 ...
- sparkSQL1.1入门
http://blog.csdn.net/book_mmicky/article/details/39288715 2014年9月11日,Spark1.1.0忽然之间发布.笔者立即下载.编译.部署了S ...
- 基于Casperjs的网页抓取技术【抓取豆瓣信息网络爬虫实战示例】
CasperJS is a navigation scripting & testing utility for the PhantomJS (WebKit) and SlimerJS (Ge ...
随机推荐
- C++ 用户输入验证
在编写程序时,请考虑用户将如何滥用您的程序,尤其是在文本输入方面.对于每个文本输入点,请考虑: 会不会提取失败? 用户可以输入比预期更多的输入吗? 用户可以输入无意义的输入吗 用户可以溢出输入吗? 以 ...
- 人工智能机器学习底层原理剖析,人造神经元,您一定能看懂,通俗解释把AI“黑话”转化为“白话文”
按照固有思维方式,人们总以为人工智能是一个莫测高深的行业,这个行业的人都是高智商人群,无论是写文章还是和人讲话,总是讳莫如深,接着就是蹦出一些"高级"词汇,什么"神经网络 ...
- kafka rebalance你真的了解吗
介绍 今天主要分享一下 kafka 的 rebalance,在 kafka 中,rebalance 是一个十分重要的概念,很多时候引发的一些问题可能都是由于 rebalance 引起的,rebalan ...
- HTTP TCP UDP WEBSOCKET
概念: TCP和UDP:传输层协议:(卡车) HTTP:应用层协议:(货物).HTTP(超文本传输协议)是利用TCP在两台电脑(通常是Web服务器和客户端)之间传输信息的协议.客户端使用Web浏览器发 ...
- Spring(Ioc和Bean的作用域)
Spring Spring为简化开发而生,让程序员只关心核心业务的实现,尽可能的不在关注非业务逻辑代码(事务控制,安全日志等). 1,Spring八大模块 这八大模块组成了Spring 1.1 Spr ...
- 代码Bug太多?给新人Code Review头都大了?快来试试SpotBugs
如果你需要一个自动化的工具帮助你或者你的团队发现代码中的缺陷,在提升代码质量同时减少人工Code Review的成本,那这篇文章非常的适合你.本文围绕SpotBugs与Gradle集成,将相关配置和使 ...
- OpenWRT实现NAT64/DNS64
OpenWRT实现NAT64/DNS64 连接到核心路由器 # 连接到核心路由器 [C:\~]$ ssh root@10.0.0.1 Connecting to 10.0.0.1:22... Conn ...
- Java设计模式 —— 外观模式
13 外观模式 13.1 外观模式概述 Facade Pattern: 为子系统的接口提供一组统一的入口.外观模式定义了一个高层接口,这个接口使得子系统的更加容易使用. 在外观模式中,一个子系统的外部 ...
- Redis为什么能抗住10万并发?揭秘性能优越的背后原因
1. Redis简介 Redis是一个开源的,基于内存的,高性能的键值型数据库.它支持多种数据结构,包含五种基本类型 String(字符串).Hash(哈希).List(列表).Set(集合).Zse ...
- 25-tree shaking(树摇)
const { resolve } = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin') ...