From ee09f14bfa950e9fb528321a1a099cbd0a2561d0 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 17 Jun 2025 23:46:02 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=A2=9E=E5=8A=A0cli=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jcnc/snow/compiler/cli/SnowCLI.java | 166 ++++++++---------- 1 file changed, 71 insertions(+), 95 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/cli/SnowCLI.java b/src/main/java/org/jcnc/snow/compiler/cli/SnowCLI.java index 87b50a2..5270dc3 100644 --- a/src/main/java/org/jcnc/snow/compiler/cli/SnowCLI.java +++ b/src/main/java/org/jcnc/snow/compiler/cli/SnowCLI.java @@ -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.RunCommand; -import java.util.*; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; /** - *

- * Snow 语言统一命令行入口(CLI)。 - *
- * 负责命令注册、解析与调度。 - *

- * + * SnowCLI 是项目的命令行入口类,负责解析用户输入、分发子命令并统一处理帮助和错误。 */ -public final class SnowCLI { - - /** 命令注册表,按插入顺序保存命令名到实现的映射。 */ - private final Map registry = new LinkedHashMap<>(); +public class SnowCLI { /** - * 构造 CLI,自动注册所有可用命令。 - * + * 保存所有可用子命令的映射:命令名称 -> 命令实例的提供者 + * 通过 Map.of 初始化,添加新命令时只需在此注册。 */ - public SnowCLI() { - // 1. 自动发现 ServiceLoader 扩展命令 - ServiceLoader.load(CLICommand.class).forEach(this::register); - // 2. 注册核心命令,保证 CLI 可用 - register(new CompileCommand()); - register(new RunCommand()); - } + private static final Map> COMMANDS = Map.of( + "compile", CompileCommand::new, + "run", RunCommand::new + ); /** - * 注册一个命令到 CLI(命令名唯一,若已注册则跳过)。 + * 程序主入口,解析和分发命令。 * - * @param cmd 待注册命令 - */ - 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 [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 --help' for command-specific details. - """); - } - - /** - * CLI 程序主入口。 - * - * @param args 命令行参数 + * @param 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 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 [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 --help' to see command-specific options."); } }