docs: 增加cli注释

This commit is contained in:
Luke 2025-06-17 23:46:02 +08:00
parent 2f473d1e13
commit ee09f14bfa

View File

@ -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>始终内置注册 compilerun 等核心命令</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.");
} }
} }