Files
tsl-devkit/docs/superpowers/specs/2026-07-11-args-parser-startup-errors-design.md
T

4.2 KiB

参数解析与启动错误处理设计

背景

lsp.utils.args_parser 当前同时承担参数解析、全局配置存储、帮助输出和 日志初始化。无效线程数与日志文件打开失败可能触发未捕获异常,帮助文本输出 字面量 \n,而将日志写入 stdout 会破坏 LSP stdio 协议流。

本设计处理审查项 1、2、3、5。解释器路径中的 ~ 展开留到后续任务。

目标

  • stdout 只承载 LSP 协议消息。
  • 参数解析无全局可变状态,可直接单元测试。
  • 所有参数都进行完整校验,错误参数返回明确诊断和退出码 2。
  • 日志初始化或服务器运行失败返回退出码 1,不触发 abort。
  • 帮助文本使用真实换行并准确反映受支持参数。

非目标

  • 不处理解释器路径展开或路径存在性验证。
  • 不保留旧参数兼容层。
  • 不引入第三方命令行解析库。

参数解析接口

删除 ArgsParser 单例、GetConfig() 和内部 config_。模块改为导出无状态 解析接口,结果通过 C++23 std::expected 返回:

enum class ParseAction
{
    kRun,
    kShowHelp,
};

struct ParseResult
{
    ParseAction action = ParseAction::kRun;
    ServerConfig config;
};

std::expected<ParseResult, std::string> ParseArgs(
    int argc,
    char* const argv[]);

void PrintHelp(std::ostream& output, std::string_view program_name);

ServerConfig 只保留运行配置:线程数、日志级别、日志文件和解释器路径。 帮助请求由 ParseAction 表达,不再混入服务器配置。

参数规则

支持以下参数:

  • --help
  • --log=trace|debug|info|warn|error|off
  • --log-file=<path>
  • --threads=<count>
  • --interpreter=<path>

删除 --log-stdout--log-stderr--use-stdio。没有指定日志文件时, 日志始终写入 stderr。

解析遵循以下规则:

  • 未知参数返回错误,不再静默忽略。
  • --threads 使用 std::from_chars 完整解析,只接受 1256
  • --threads 的空值、负数、尾随字符和数值溢出均返回错误。
  • --log 只接受列出的六个级别。
  • --log-file--interpreter 不接受空值。
  • --help 在参数列表中具有最高优先级;只要出现便返回帮助动作,不校验 其他参数,也不初始化日志或服务器。
  • 普通参数重复出现时,以最后一次出现的值为准。

启动与错误处理

日志初始化从参数解析模块移到 lsp.cli.launcher 的私有实现。初始化规则为:

  • log_file 非空时创建文件 logger。
  • 否则创建 stderr logger。
  • 不提供 stdout logger 路径。

Run() 按阶段处理错误:

  1. 调用 ParseArgs();错误写入 stderr,并返回 2。
  2. kShowHelp 将帮助写入 stdout,并返回 0。
  3. 初始化日志;异常写入 stderr,并返回 1。
  4. 构造并运行 LspServer;异常写入 stderr,记录到已初始化的 logger, 并返回 1。
  5. 正常停止后关闭 spdlog,并返回 0。

日志初始化失败时不调用 spdlog 记录该错误,避免在 logger 未就绪时产生二次 异常。

测试设计

新增参数解析单元测试,覆盖:

  • 默认配置与所有有效日志级别。
  • --threads=1--threads=256 两个边界。
  • 空值、零、负数、257、尾随字符和溢出线程数。
  • 空日志文件、空解释器路径和未知参数。
  • 已删除的三个日志输出参数被报告为未知参数。
  • 帮助动作和帮助文本的真实换行。

新增或扩展 CLI 行为测试,覆盖:

  • 无日志文件时日志只进入 stderr,stdout 不出现日志文本。
  • 无法创建日志文件时进程返回 1,并输出可读错误,而非因信号终止。
  • 参数错误返回 2,且不会初始化服务器。

验证命令至少包括目标构建、参数解析测试和 CLI 行为测试。现有 LSP JSON 测试也需要通过,以确认 stdout 协议流未受影响。

完成条件

  • 旧单例和 stdout logger 路径已删除。
  • 所有参数规则均有自动化测试。
  • --help 输出为多行文本。
  • 无效线程数、不可写日志文件均受控退出。
  • LSP stdio 测试通过,stdout 中不混入日志。