docs: 增加cli注释
This commit is contained in:
parent
2f473d1e13
commit
ee09f14bfa
@ -3,111 +3,87 @@ package org.jcnc.snow.compiler.cli;
|
|||||||
import org.jcnc.snow.compiler.cli.commands.CompileCommand;
|
import org.jcnc.snow.compiler.cli.commands.CompileCommand;
|
||||||
import org.jcnc.snow.compiler.cli.commands.RunCommand;
|
import org.jcnc.snow.compiler.cli.commands.RunCommand;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* SnowCLI 是项目的命令行入口类,负责解析用户输入、分发子命令并统一处理帮助和错误。
|
||||||
* Snow 语言统一命令行入口(CLI)。
|
|
||||||
* <br>
|
|
||||||
* 负责命令注册、解析与调度。
|
|
||||||
* </p>
|
|
||||||
* <ul>
|
|
||||||
* <li>支持核心命令自动注册(compile/run)。</li>
|
|
||||||
* <li>支持通过 ServiceLoader 自动发现并注册第三方命令。</li>
|
|
||||||
* <li>统一异常处理和 usage 帮助输出。</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
*/
|
||||||
public final class SnowCLI {
|
public class SnowCLI {
|
||||||
|
|
||||||
/** 命令注册表,按插入顺序保存命令名到实现的映射。 */
|
|
||||||
private final Map<String, CLICommand> registry = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造 CLI,自动注册所有可用命令。
|
* 保存所有可用子命令的映射:命令名称 -> 命令实例的提供者
|
||||||
* <ul>
|
* 通过 Map.of 初始化,添加新命令时只需在此注册。
|
||||||
* <li>通过 ServiceLoader 加载所有外部扩展命令。</li>
|
|
||||||
* <li>始终内置注册 compile、run 等核心命令。</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
*/
|
||||||
public SnowCLI() {
|
private static final Map<String, Supplier<CLICommand>> COMMANDS = Map.of(
|
||||||
// 1. 自动发现 ServiceLoader 扩展命令
|
"compile", CompileCommand::new,
|
||||||
ServiceLoader.load(CLICommand.class).forEach(this::register);
|
"run", RunCommand::new
|
||||||
// 2. 注册核心命令,保证 CLI 可用
|
);
|
||||||
register(new CompileCommand());
|
|
||||||
register(new RunCommand());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册一个命令到 CLI(命令名唯一,若已注册则跳过)。
|
* 程序主入口,解析和分发命令。
|
||||||
*
|
*
|
||||||
* @param cmd 待注册命令
|
* @param args 用户在命令行中输入的参数数组
|
||||||
*/
|
|
||||||
private void register(CLICommand cmd) {
|
|
||||||
registry.putIfAbsent(cmd.name(), cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析命令行参数并执行相应命令。
|
|
||||||
*
|
|
||||||
* @param args 命令行参数
|
|
||||||
* @return 进程退出码(0=成功, 1=未知命令, -1=命令异常)
|
|
||||||
*/
|
|
||||||
public int run(String[] args) {
|
|
||||||
// 无参数或 help,打印全局用法
|
|
||||||
if (args.length == 0
|
|
||||||
|| Set.of("help", "-h", "--help").contains(args[0])) {
|
|
||||||
printGlobalUsage();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据命令名查找注册表
|
|
||||||
CLICommand cmd = registry.get(args[0]);
|
|
||||||
if (cmd == null) {
|
|
||||||
System.err.printf("Unknown command: %s%n%n", args[0]);
|
|
||||||
printGlobalUsage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取命令余下参数(不包含命令名)
|
|
||||||
String[] sub = Arrays.copyOfRange(args, 1, args.length);
|
|
||||||
try {
|
|
||||||
return cmd.execute(sub);
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.printf("Error executing command '%s': %s%n",
|
|
||||||
cmd.name(), e.getMessage());
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打印全局帮助信息(所有已注册命令的 usage)。
|
|
||||||
*/
|
|
||||||
private void printGlobalUsage() {
|
|
||||||
System.out.println("""
|
|
||||||
Usage: snow <command> [options]
|
|
||||||
|
|
||||||
Available commands:""");
|
|
||||||
int pad = registry.keySet().stream()
|
|
||||||
.mapToInt(String::length).max().orElse(10) + 2;
|
|
||||||
registry.values().stream()
|
|
||||||
.sorted(Comparator.comparing(CLICommand::name))
|
|
||||||
.forEach(c -> System.out.printf(" %-" + pad + "s%s%n",
|
|
||||||
c.name(), c.description()));
|
|
||||||
|
|
||||||
System.out.println("""
|
|
||||||
|
|
||||||
Use 'snow <command> --help' for command-specific details.
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CLI 程序主入口。
|
|
||||||
*
|
|
||||||
* @param args 命令行参数
|
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
int code = new SnowCLI().run(args);
|
// 如果未给出任何参数,则打印通用帮助并退出
|
||||||
System.exit(code);
|
if (args.length == 0) {
|
||||||
|
printGeneralUsage();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一个参数为子命令名称
|
||||||
|
String cmdName = args[0];
|
||||||
|
Supplier<CLICommand> cmdSupplier = COMMANDS.get(cmdName);
|
||||||
|
// 如果命令不存在,则打印错误和帮助
|
||||||
|
if (cmdSupplier == null) {
|
||||||
|
System.err.println("Unknown command: " + cmdName);
|
||||||
|
printGeneralUsage();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建子命令实例
|
||||||
|
CLICommand cmd = cmdSupplier.get();
|
||||||
|
|
||||||
|
// 提取子命令的剩余参数
|
||||||
|
String[] sub = Arrays.copyOfRange(args, 1, args.length);
|
||||||
|
|
||||||
|
// 支持统一的帮助标志:help, -h, --help
|
||||||
|
if (sub.length > 0 && Set.of("help", "-h", "--help").contains(sub[0])) {
|
||||||
|
// 调用子命令自己的 printUsage
|
||||||
|
cmd.printUsage();
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行子命令并捕获异常
|
||||||
|
try {
|
||||||
|
int exitCode = cmd.execute(sub);
|
||||||
|
System.exit(exitCode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 打印错误信息和堆栈
|
||||||
|
System.err.println("Error: " + e.getMessage());
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印动态生成的通用帮助信息。
|
||||||
|
* 会遍历 COMMANDS,输出所有子命令的名称及描述信息。
|
||||||
|
*/
|
||||||
|
private static void printGeneralUsage() {
|
||||||
|
// 使用方式说明
|
||||||
|
System.out.println("Usage: snow <command> [options]");
|
||||||
|
System.out.println("Commands:");
|
||||||
|
|
||||||
|
// 对每个注册的子命令,获取 description 并格式化输出
|
||||||
|
COMMANDS.forEach((name, supplier) -> {
|
||||||
|
CLICommand c = supplier.get();
|
||||||
|
// %-10s 保证命令名称列宽度为 10
|
||||||
|
System.out.printf(" %-10s %s%n", name, c.description());
|
||||||
|
});
|
||||||
|
// 提示如何查看子命令帮助
|
||||||
|
System.out.println("Use 'snow <command> --help' to see command-specific options.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user