summaryrefslogtreecommitdiff
path: root/src/cmds/README_zh_CN.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmds/README_zh_CN.md')
-rw-r--r--src/cmds/README_zh_CN.md266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/cmds/README_zh_CN.md b/src/cmds/README_zh_CN.md
new file mode 100644
index 0000000..42823a8
--- /dev/null
+++ b/src/cmds/README_zh_CN.md
@@ -0,0 +1,266 @@
+# 命令开发指南
+
+本文档详细介绍了如何在 JVCS CLI 中开发新的命令。命令系统采用模块化设计,分为多个组件,每个组件有明确的职责。
+
+## 目录结构
+
+```
+src/cmds/
+├── arg/ # 命令行参数定义
+├── cmd/ # 命令实现
+├── collect/ # 资源收集信息
+├── converter/ # 数据转换器
+├── in/ # 输入数据结构
+├── out/ # 输出数据结构
+├── override/ # 渲染器重写
+└── renderer/ # 渲染器实现
+```
+
+## 命令组件
+
+### 1. Argument
+- 实现 `clap::Parser` trait
+- 命名规范:`JV{CommandName}Argument`
+- 位置:`src/cmds/arg/{command_name}.rs`
+
+示例:sum 命令的参数定义
+```rust
+// src/cmds/arg/sum.rs
+use clap::Parser;
+
+#[derive(Parser, Debug)]
+pub struct JVSumArgument {
+ /// 要相加的数字
+ pub numbers: Vec<i32>,
+
+ /// 不输出结果
+ #[arg(long)]
+ pub no_output: bool,
+}
+```
+
+### 2. Input
+- 无生命周期的结构体
+- 命名规范:`JV{CommandName}Input`
+- 位置:`src/cmds/in/{command_name}.rs`
+- 在 `prepare` 阶段由 `Argument` 转换而来
+
+示例:sum 命令的输入结构
+```rust
+// src/cmds/in/sum.rs
+pub struct JVSumInput {
+ pub numbers: Vec<i32>,
+ pub should_output: bool,
+}
+```
+
+### 3. Collect
+- 无生命周期的结构体
+- 命名规范:`JV{CommandName}Collect`
+- 位置:`src/cmds/collect/{command_name}.rs`
+- 用于收集执行命令所需的本地资源信息
+
+示例:sum 命令的资源收集
+```rust
+// src/cmds/collect/sum.rs
+pub struct JVSumCollect {
+ pub count: usize,
+}
+```
+
+### 4. Output
+- 实现 `serde::Serialize` trait
+- 命名规范:`JV{CommandName}Output`
+- 位置:`src/cmds/out/{command_name}.rs`
+
+示例:sum 命令的输出结构
+```rust
+// src/cmds/out/sum.rs
+use serde::Serialize;
+
+#[derive(Serialize)]
+pub struct JVSumOutput {
+ pub result: i32,
+}
+```
+
+## 命令执行阶段
+
+### 1. prepare 阶段
+- 将 `Argument` 转换为稳定的 `Input` 信息
+- 检测输入格式错误并提前失败
+- 对输入进行格式化处理(如标志取反)
+
+示例:sum 命令的 prepare 函数
+```rust
+async fn prepare(args: &JVSumArgument, ctx: &JVCommandContext) -> Result<JVSumInput, CmdPrepareError> {
+ trace!("开始准备 sum 命令,参数数量: {}", args.numbers.len());
+ debug!("no_output: {}, should_output: {}", args.no_output, should_output);
+
+ Ok(JVSumInput {
+ numbers: args.numbers.clone(),
+ should_output = !args.no_output,
+ })
+}
+```
+
+### 2. collect 阶段
+- 根据 `Argument` 的信息读取需要用到的资源
+- 资源加载错误时提前失败
+- 将收集的资源信息传入 `exec` 阶段
+
+示例:sum 命令的 collect 函数
+```rust
+async fn collect(args: &JVSumArgument, ctx: &JVCommandContext) -> Result<JVSumCollect, CmdPrepareError> {
+ trace!("收集 sum 命令资源");
+
+ Ok(JVSumCollect {
+ count: args.numbers.len(),
+ })
+}
+```
+
+### 3. exec 阶段
+- 将 `prepare` 和 `collect` 阶段收集的信息绑定到核心 API
+- 将结果整理为 `Output` 输出
+- **必须使用** `cmd_output!(JVSomeOutput => output)` 语法实现输出
+
+示例:sum 命令的 exec 函数
+```rust
+#[exec]
+async fn exec(
+ input: JVSumInput,
+ collect: JVSumCollect,
+) -> Result<(Box<dyn std::any::Any + Send + 'static>, TypeId), CmdExecuteError> {
+ trace!("执行 sum 命令,处理 {} 个数字", collect.count);
+
+ // 计算总和
+ let result = input.numbers.iter().sum();
+ debug!("计算结果: {}", result);
+
+ // 根据 should_output 决定输出类型
+ if input.should_output {
+ cmd_output!(JVSumOutput => JVSumOutput { result })
+ } else {
+ // 使用 JVNoneOutput 表示不输出结果
+ cmd_output!(JVNoneOutput => JVNoneOutput)
+ }
+}
+```
+
+## 渲染器
+
+每个 `Output` 需要对应一个渲染器,用于将输出数据渲染为用户可读的格式。
+
+### 渲染器实现要求
+- 实现异步的 `render` 函数
+- 输入为对应的 `Output` 值
+- 输出为 `Result<JVRenderResult, CmdRenderError>`
+- **必须使用** `#[result_renderer(JV{CommandName}Renderer)]` 宏
+
+示例:sum 命令的渲染器
+```rust
+// src/cmds/renderer/sum.rs
+use render_system_macros::result_renderer;
+
+use crate::{
+ cmds::out::sum::JVSumOutput,
+ r_println,
+ systems::{cmd::errors::CmdRenderError, render::renderer::JVRenderResult},
+};
+
+#[result_renderer(JVSumRenderer)]
+pub async fn render(data: &JVSumOutput) -> Result<JVRenderResult, CmdRenderError> {
+ trace!("渲染 sum 命令结果");
+
+ let mut r = JVRenderResult::default();
+ r_println!(r, "Result: {}", data.result);
+ Ok(r)
+}
+```
+
+## 开发流程
+
+1. **规划命令结构**
+ - 确定命令名称和参数
+ - 设计输入/输出数据结构
+
+2. **创建组件文件**
+ - 在相应目录创建 `.rs` 文件
+ - 实现 Argument、Input、Collect、Output 结构体
+
+3. **实现命令逻辑**
+ - 在 `cmd/` 目录创建命令实现文件
+ - 使用命令模板(通过 `cargo doc --no-deps` 生成文档查看完整模板)
+ - 实现 `prepare`、`collect`、`exec` 函数
+
+4. **实现渲染器**
+ - 在 `renderer/` 目录创建渲染器文件
+ - 使用 `#[result_renderer]` 宏
+
+5. **测试命令**
+ - 使用 `cargo build` 检查编译错误
+ - 运行命令测试功能
+
+## 命名规范
+
+| 组件类型 | 命名规范 | 示例 |
+|---------|---------|------|
+| 命令 | `JV{CommandName}Command` | `JVSumCommand` |
+| 参数 | `JV{CommandName}Argument` | `JVSumArgument` |
+| 输入 | `JV{CommandName}Input` | `JVSumInput` |
+| 收集 | `JV{CommandName}Collect` | `JVSumCollect` |
+| 输出 | `JV{CommandName}Output` | `JVSumOutput` |
+| 渲染器 | `JV{CommandName}Renderer` | `JVSumRenderer` |
+
+## 日志输出
+
+在命令开发中,可以使用 `log` 进行调试:
+
+- `trace!("消息")` - 最详细的调试信息
+- `debug!("消息")` - 调试信息
+- `info!("消息")` - 一般信息
+- `warn!("消息")` - 警告信息
+- `error!("消息")` - 错误信息
+
+## 最佳实践
+
+1. **错误处理**
+ - 在 `prepare` 阶段验证输入
+ - 在 `collect` 阶段检查资源可用性
+
+2. **输入格式化**
+ - 在 `prepare` 阶段对用户输入进行标准化
+ - 确保 `Input` 结构是干净、稳定的
+
+3. **资源管理**
+ - 在 `collect` 阶段获取所有需要的资源
+ - 避免在 `exec` 阶段进行文件系统操作
+
+4. **输出设计**
+ - 输出结构应包含足够的信息供渲染器使用
+ - 考虑不同输出格式的需求
+
+## 示例命令参考
+
+查看现有命令实现以获取更多灵感:
+- `helpdoc` 命令:`src/cmds/cmd/helpdoc.rs`
+- `sheetdump` 命令:`src/cmds/cmd/sheetdump.rs`
+- `workspace` 命令:`src/cmds/cmd/workspace.rs`
+
+## 调试与测试
+
+1. **生成文档查看模板**
+ ```bash
+ cargo doc --no-deps
+ ```
+ 文档生成在 `.temp/target/doc/` 目录,查看 `macro.command_template.html` 获取完整命令模板。
+
+2. **运行命令测试**
+ ```bash
+ # 构建并部署
+ ./scripts/dev/dev_deploy.sh
+ # 或 Windows
+ .\scripts\dev\dev_deploy.ps1
+
+ jvn sum 1 2