diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-03-14 18:33:20 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-03-14 18:33:20 +0800 |
| commit | 17e7b28f162b3ed75683948144237ee17f81f7a5 (patch) | |
| tree | 9af1e089b517ba73f601b2ec9eacffbf0f6d2485 | |
| parent | 707a1f7c747a08e2ce77df88edc1e72eae9cbebc (diff) | |
Add converter module and update documentation
27 files changed, 693 insertions, 40 deletions
diff --git a/.cargo/registry.toml b/.cargo/registry.toml index 702ab20..d019c45 100644 --- a/.cargo/registry.toml +++ b/.cargo/registry.toml @@ -54,6 +54,9 @@ path = "src/cmds/cmd.rs" [collect.collects] path = "src/cmds/collect.rs" +[collect.converters] +path = "src/cmds/converter.rs" + [collect.inputs] path = "src/cmds/in.rs" @@ -29,6 +29,7 @@ _*.rs /src/cmds/arg.rs /src/cmds/cmd.rs /src/cmds/collect.rs +/src/cmds/converter.rs /src/cmds/in.rs /src/cmds/out.rs /src/cmds/renderer.rs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56e1f2d..6e5db99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,12 +1,12 @@ # Contribution Guide -Welcome to contributing to the JustEnoughVCS command-line tool! This guide is designed to help you quickly get started with the development process and understand the project's code standards. Please read the following content to ensure your contributions can be accepted smoothly. +Thank you for contributing to the JustEnoughVCS command-line tool! This guide is designed to help you quickly get started with the development process and understand the project's code standards. -## Local Development +## Process -### Environment Setup +### Deployment 1. Clone the core library ([VersionControl](https://github.com/JustEnoughVCS/VersionControl)) and your forked command-line library, arranging them in the following directory structure: ``` @@ -14,11 +14,12 @@ Welcome to contributing to the JustEnoughVCS command-line tool! This guide is de │ Cargo.lock │ Cargo.toml └─ VersionControl - Cargo.lock - Cargo.toml + Cargo.lock + Cargo.toml ``` -2. In the core library directory, execute `setup.sh` (Linux/macOS) or `setup.ps1` (Windows) based on your operating system. +2. Switch the core library to the `dev` branch. +3. In the core library directory, execute `setup.sh` (Linux/macOS) or `setup.ps1` (Windows) based on your operating system. ```bash cd VersionControl @@ -29,14 +30,10 @@ cd VersionControl -### Development Workflow +### Development -1. Create a new feature branch from the `dev` branch, using the naming format `feat/xxxx`. -2. It is recommended to add the original repository as a remote upstream to pull updates regularly: -```bash -git remote add upstream https://github.com/JustEnoughVCS/CommandLine -git pull upstream dev -``` +1. Create a new feature branch from the `dev` branch, using the naming format `feat/xxxx`, `fix/xxxx`, or `doc/xxxx`. +2. Write your code, fixes, or documentation. @@ -48,9 +45,9 @@ Use `scripts/dev/dev_deploy.sh` (or `.ps1`) for test builds. The build artifacts ``` # ... - + . C:\...\JustEnoughVCS\CommandLine\.temp\deploy\jv_cli.ps1 - + # ... ``` <center>C:\Users\YourName\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1</center> @@ -76,7 +73,7 @@ source ~/.../JustEnoughVCS/CommandLine/.temp/deploy/jv_cli.sh -### Submitting and Merging +### Submission - Before pushing code, be sure to execute `scripts/dev/deploy.sh` for a formal local deployment to check for potential issues. - When creating a Pull Request (PR), please set the target branch to the command-line repository's `dev`. **PRs submitted to the `main` or `deploy/` branches will not be processed.** @@ -85,11 +82,11 @@ source ~/.../JustEnoughVCS/CommandLine/.temp/deploy/jv_cli.sh ### Important Notes - **Rust Version**: It is recommended to use `rustc 1.92.0 (ded5c06cf 2025-12-08) (stable)`. - **File Size**: **Strictly prohibit** committing binary files larger than 1MB to the repository. If necessary, please discuss it first in an [Issue](https://github.com/JustEnoughVCS/CommandLine/issues). -- **Core Library Modifications**: If you need to modify the core library, please refer to the `CONTRIBUTE.md` document in the [VersionControl](https://github.com/JustEnoughVCS/VersionControl) repository. +- **Core Library Modifications**: If you need to modify the core library, please refer to the `CONTRIBUTING.md` document in the [VersionControl](https://github.com/JustEnoughVCS/VersionControl) repository. -## Development Standards +## Standards ### Code Structure @@ -101,22 +98,25 @@ A complete command consists of the following components, organized by module: | **Argument Definition** | `src/cmds/arg/` | Defines command-line inputs using `clap`. | | **Input Data** | `src/cmds/in/` | User input data during command execution. | | **Collected Data** | `src/cmds/collect/` | Data collected locally during command execution. | +| **Converter** | `src/cmds/converter/` | Converter between core library types and command-line types. | | **Output Data** | `src/cmds/out/` | The command's output data. | | **Renderer** | `src/cmds/renderer/` | The default presentation method for data. | +| **Override Renderer** | `src/cmds/override/renderer/` | Customizable data presentation methods. | ### Naming Conventions -- **File Naming**: Follow the format of `src/cmds/cmd/status.rs`, i.e., use the command name as the filename. +- **File Naming**: Refer to the implementation of `src/cmds/cmd/sheetdump.rs`, i.e., use the command name as the filename. - **Multi-level Subcommands**: In the `cmds` directory, use the `sub_subsub.rs` format for filenames (e.g., `sheet_drop.rs`). - **Struct Naming**: - - Command Struct: `JV{Subcommand}{Subsubcommand}Command` (e.g., `JVSheetDropCommand`). + - Command Struct: `JV{Subcmd}{Subsubcmd}Command` (e.g., `JVSheetDropCommand`). - Other component structs follow the same pattern: - `JV{XXX}Argument` - `JV{XXX}Input` - `JV{XXX}Output` - `JV{XXX}Collect` + - `JV{XXX}Converter` - `JV{XXX}Renderer` diff --git a/CONTRIBUTING_zh_CN.md b/CONTRIBUTING_zh_CN.md index 377b25b..276f959 100644 --- a/CONTRIBUTING_zh_CN.md +++ b/CONTRIBUTING_zh_CN.md @@ -1,12 +1,12 @@ # 贡献指南 -欢迎您愿意为 JustEnoughVCS 命令行工具贡献代码!本指南旨在帮助您快速上手开发流程,并了解项目的代码规范。请先阅读以下内容,以确保您的贡献能够顺利被接受。 +非常感谢您为 `JustEnoughVCS` 命令行工具贡献代码!本指南旨在帮助您快速上手开发流程,并了解项目的代码规范。 -## 本地开发流程 +## 流程 -### 环境准备 +### 部署 1. 克隆核心库([VersionControl](https://github.com/JustEnoughVCS/VersionControl))以及您分叉的命令行库,按照如下文件格式放置 ``` @@ -18,6 +18,7 @@ Cargo.toml ``` +2. 将核心库切换到 `dev` 分支 2. 在核心库目录下,根据您的操作系统执行 `setup.sh` (Linux/macOS) 或 `setup.ps1` (Windows)。 @@ -30,18 +31,14 @@ cd VersionControl -### 开发流程 +### 开发 -1. 从 `dev` 分支创建新的功能分支,命名格式为 `feat/xxxx`。 -2. 建议将原始仓库添加为远程上游仓库,以便定期拉取更新: - ```bash - git remote add upstream https://github.com/JustEnoughVCS/CommandLine - git pull upstream dev - ``` +1. 从 `dev` 分支创建新的功能分支,命名格式为 `feat/xxxx`、`fix/xxxx`、`doc/xxxx` +1. 编写您的代码、修复、或文档。 -### 构建与测试 +### 构建&测试 使用 `scripts/dev/dev_deploy.sh` (或 `.ps1`) 进行测试构建。构建产物位于 `.temp/deploy/` 目录。 @@ -77,7 +74,7 @@ sources ~/.../JustEnoughVCS/CommandLine/.temp/deploy/jv_cli.sh -### 提交与合并 +### 提交 - 在推送代码前,请务必执行 `scripts/dev/deploy.sh` 进行一次正式的本地部署,以检查潜在问题 - 创建 Pull Request (PR) 时,请将目标分支设置为命令行仓库的 `dev`。**提交至 `main` 或 `deploy/` 分支的 PR 将不予处理** @@ -86,11 +83,11 @@ sources ~/.../JustEnoughVCS/CommandLine/.temp/deploy/jv_cli.sh ### 注意事项 - **Rust 版本**: 推荐使用 `rustc 1.92.0 (ded5c06cf 2025-12-08) (stable)` - **文件大小**: **严禁** 向仓库提交超过 1MB 的二进制文件,如有必要,请先在 [Issue](https://github.com/JustEnoughVCS/CommandLine/issues) 中讨论 -- **核心库修改**: 如需修改核心库,请参考 [VersionControl](https://github.com/JustEnoughVCS/VersionControl) 仓库中的 `CONTRIBUTE.md` 文档 +- **核心库修改**: 如需修改核心库,请参考 [VersionControl](https://github.com/JustEnoughVCS/VersionControl) 仓库中的 `CONTRIBUTING.md` 文档 -## 开发规范 +## 规范 ### 代码结构 @@ -102,22 +99,25 @@ sources ~/.../JustEnoughVCS/CommandLine/.temp/deploy/jv_cli.sh | **参数定义** | `src/cmds/arg/` | 使用 `clap` 定义命令行输入。 | | **输入数据** | `src/cmds/in/` | 命令运行阶段的用户输入数据。 | | **收集数据** | `src/cmds/collect/` | 命令运行阶段从本地收集的数据。 | +| **转换器** | `src/cmds/converter/` | 核心库类型和命令行类型的转换器。 | | **输出数据** | `src/cmds/out/` | 命令的输出数据。 | | **渲染器** | `src/cmds/renderer/` | 数据的默认呈现方式。 | +| **覆盖渲染器** | `src/cmds/override/renderer/` | 可自定义的数据呈现方式。 | ### 命名规范 -- **文件命名**: 请遵循 `src/cmds/cmd/status.rs` 的格式,即使用命令名称作为文件名 +- **文件命名**: 请参考 `src/cmds/cmd/sheetdump.rs` 的实现,使用命令名称作为文件名 - **多级子命令**: 在 `cmds` 目录下,使用 `sub_subsub.rs` 格式命名文件(例如:`sheet_drop.rs`) - **结构体命名**: - - 命令结构体: `JV{Subcommand}{Subsubcommand}Command` (例如:`JVSheetDropCommand`) + - 命令结构体: `JV{Subcmd}{Subsubcmd}Command` (例如:`JVSheetDropCommand`) - 其他组件结构体遵循相同模式: - `JV{XXX}Argument` - `JV{XXX}Input` - `JV{XXX}Output` - `JV{XXX}Collect` + - `JV{XXX}Converter` - `JV{XXX}Renderer` @@ -15,3 +15,24 @@ <img src="https://img.shields.io/badge/Status-Development%20in%20Progress-yellow?style=for-the-badge"> <img src="https://img.shields.io/badge/Release-Not%20Available-lightgrey?style=for-the-badge"> </p> + +> [!WARNING] +> The command line and the core repository are currently under refactoring. +> Please go to the `main` branch to get the stable version. +> +> Note: The new command line `jvn` and `jv` / `jvv` are **completely incompatible**. +> They run on **entirely different** core implementations. + +# Intro +`JVCS CLI` provides the command-line tool `jvn`, which binds all the functionalities of the core library: +- Local workspace management +- Upstream vault management +- Raw data editing + +# Deploy +> [!WARNING] +> Currently in the refactoring phase, please refer to the `Deployment` section in the [Contribution Guide](./CONTRIBUTING.md). + +# License +Consistent with the [core library](https://github.com/JustEnoughVCS/CommandLine), +this repository adopts the dual license of [MIT](./LICENSE-MIT) and [APACHE](./LICENSE-APACHE). diff --git a/README_zh_CN.md b/README_zh_CN.md index 1d93bf8..d783625 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -15,3 +15,24 @@ <img src="https://img.shields.io/badge/Status-Development%20in%20Progress-yellow?style=for-the-badge"> <img src="https://img.shields.io/badge/Release-Not%20Available-lightgrey?style=for-the-badge"> </p> + +> [!WARNING] +> 当前命令行和核心仓库都处于重构阶段 +> 请前往 `main` 分支获取稳定的版本 +> +> 注意:新版本命令行 `jvn` 和 `jv` / `jvv` **完全不兼容** +> 他们运行在 **完全不同的** 核心实现上 + +# 介绍 +`JVCS CLI` 提供命令行工具 `jvn`,它绑定了核心库的所有功能: +- 本地工作区管理 +- 上游仓库管理 +- 原始数据编辑 + +# 部署 +> [!WARNING] +> 目前正在重构阶段,请查阅 [贡献指南](./CONTRIBUTING_zh_CN.md) 中的 `部署` 章节 + +# 开源协议 +和 [核心库](https://github.com/JustEnoughVCS/CommandLine) 一致 +本仓库采用 [MIT](./LICENSE-MIT) 和 [APACHE](./LICENSE-APACHE) 双协议 diff --git a/resources/helpdoc/Welcome_To_JVCS.en.md b/resources/helpdoc/commands.en.md index 3a7cf06..3a7cf06 100644 --- a/resources/helpdoc/Welcome_To_JVCS.en.md +++ b/resources/helpdoc/commands.en.md diff --git a/resources/helpdoc/Welcome_To_JVCS.zh-CN.md b/resources/helpdoc/commands.zh-CN.md index fc734cf..fc734cf 100644 --- a/resources/helpdoc/Welcome_To_JVCS.zh-CN.md +++ b/resources/helpdoc/commands.zh-CN.md diff --git a/resources/helpdoc/commands/helpdoc.en.md b/resources/helpdoc/commands/helpdoc.en.md new file mode 100644 index 0000000..05fe5e8 --- /dev/null +++ b/resources/helpdoc/commands/helpdoc.en.md @@ -0,0 +1,5 @@ +> Open Help View + +## Usage +jvn helpdoc <DOC_NAME> # Open a specific article +jvn helpdoc list # List all articles diff --git a/resources/helpdoc/commands/helpdoc.zh-CN.md b/resources/helpdoc/commands/helpdoc.zh-CN.md new file mode 100644 index 0000000..70871a1 --- /dev/null +++ b/resources/helpdoc/commands/helpdoc.zh-CN.md @@ -0,0 +1,5 @@ +> 打开帮助视图 + +## 使用 +jvn helpdoc <文章> # 打开指定文章 +jvn helpdoc list # 列出所有文章 diff --git a/resources/helpdoc/commands/sheetedit.zh-CN.md b/resources/helpdoc/commands/sheetedit.zh-CN.md index d45224b..f897bc9 100644 --- a/resources/helpdoc/commands/sheetedit.zh-CN.md +++ b/resources/helpdoc/commands/sheetedit.zh-CN.md @@ -4,7 +4,7 @@ jvn sheetedit <文件> ## 注意 -它读取按照以下优先级寻找命令行编辑器程序: +它按照以下优先级寻找命令行编辑器程序: 1. JV\_TEXT\_EDITOR 2. EDITOR 3. 若都不存在,使用 `jvii` 回退 diff --git a/resources/helpdoc/commands/workspace.en.md b/resources/helpdoc/commands/workspace.en.md new file mode 100644 index 0000000..000943d --- /dev/null +++ b/resources/helpdoc/commands/workspace.en.md @@ -0,0 +1,14 @@ +> Workspace Management Commands + +## Usage +jvn workspace <SUBCOMMAND> <PARAM: ?> + +## Subcommands + +### Initialize +Initialize a workspace in the _current directory_ +jvn workspace init + +### Create +Initialize a workspace in a _specified directory_ +jvn workspace create <directory> diff --git a/resources/helpdoc/commands/workspace.zh-CN.md b/resources/helpdoc/commands/workspace.zh-CN.md new file mode 100644 index 0000000..3d877fe --- /dev/null +++ b/resources/helpdoc/commands/workspace.zh-CN.md @@ -0,0 +1,14 @@ +> 工作区管理命令 + +## 使用 +jvn workspace <子命令> <参数: ?> + +## 子命令 + +### 初始化工作区 +在_当前目录_初始化一个工作区 +jvn workspace init + +### 创建工作区 +在_指定目录_初始化一个工作区 +jvn workspace create <目录> diff --git a/resources/helpdoc/commands/workspace/create.en.md b/resources/helpdoc/commands/workspace/create.en.md new file mode 100644 index 0000000..bbc201b --- /dev/null +++ b/resources/helpdoc/commands/workspace/create.en.md @@ -0,0 +1,4 @@ +> Initialize a workspace in the _specified directory_ + +## Usage +jvn workspace create <directory> diff --git a/resources/helpdoc/commands/workspace/create.zh-CN.md b/resources/helpdoc/commands/workspace/create.zh-CN.md new file mode 100644 index 0000000..d48c100 --- /dev/null +++ b/resources/helpdoc/commands/workspace/create.zh-CN.md @@ -0,0 +1,4 @@ +> 在_指定目录_初始化一个工作区 + +## 使用 +jvn workspace create <目录> diff --git a/resources/helpdoc/commands/workspace/init.en.md b/resources/helpdoc/commands/workspace/init.en.md new file mode 100644 index 0000000..75476dc --- /dev/null +++ b/resources/helpdoc/commands/workspace/init.en.md @@ -0,0 +1,4 @@ +> Initialize a workspace in the _current directory_ + +## Usage +jvn workspace init diff --git a/resources/helpdoc/commands/workspace/init.zh-CN.md b/resources/helpdoc/commands/workspace/init.zh-CN.md new file mode 100644 index 0000000..101c9cf --- /dev/null +++ b/resources/helpdoc/commands/workspace/init.zh-CN.md @@ -0,0 +1,4 @@ +> 在_当前目录_初始化一个工作区 + +## 使用 +jvn workspace init diff --git a/resources/locales/jvn/en.yml b/resources/locales/jvn/en.yml index 7df57fd..ef3b273 100644 --- a/resources/locales/jvn/en.yml +++ b/resources/locales/jvn/en.yml @@ -320,6 +320,7 @@ logger: verbose: setup_progress: Progress bar initialized setup_verbose: Starting `Verbose` mode + disable_helpdoc: Helpdoc Viewer disabled setup_i18n: Setting language to `%{lang}` setup_renderer: Setting renderer to `%{renderer}` no_error_logs: Disabling error output diff --git a/resources/locales/jvn/helpdoc_viewer/en.yml b/resources/locales/jvn/helpdoc_viewer/en.yml index 78acae4..501e946 100644 --- a/resources/locales/jvn/helpdoc_viewer/en.yml +++ b/resources/locales/jvn/helpdoc_viewer/en.yml @@ -4,3 +4,7 @@ helpdoc_viewer: _List_ | ↑↓: Page | ←→/Space: Switch view | Q: Quit content_area_hint: | _Read_ | ↑↓: Page | ←→/Space: Switch view | Q: Quit + + verbose: + no_helpdoc_output: will directly render the output document `%{doc}` + helpdoc_output: will use the help document viewer to view the document `%{doc}` diff --git a/resources/locales/jvn/helpdoc_viewer/zh-CN.yml b/resources/locales/jvn/helpdoc_viewer/zh-CN.yml index 1c169c9..a502483 100644 --- a/resources/locales/jvn/helpdoc_viewer/zh-CN.yml +++ b/resources/locales/jvn/helpdoc_viewer/zh-CN.yml @@ -4,3 +4,7 @@ helpdoc_viewer: _列表_ | ↑↓: 翻页 | ←→/Space: 切换视图 | Q: 退出 content_area_hint: | _阅读_ | ↑↓: 浏览 | ←→/Space: 切换视图 | Q: 退出 + + verbose: + no_helpdoc_output: 将直接渲染输出文章 `%{doc}` + helpdoc_output: 将使用帮助文档查看器查看文章 `%{doc}` diff --git a/resources/locales/jvn/zh-CN.yml b/resources/locales/jvn/zh-CN.yml index ff1b67a..ca8a52e 100644 --- a/resources/locales/jvn/zh-CN.yml +++ b/resources/locales/jvn/zh-CN.yml @@ -318,6 +318,7 @@ logger: verbose: setup_progress: 已初始化进度条 setup_verbose: 启动 `Verbose` 模式 + disable_helpdoc: 帮助文档查看器已禁用 setup_i18n: 设置语言为 `%{lang}` setup_renderer: 设置渲染器为 `%{renderer}` no_error_logs: 禁用错误输出 diff --git a/src/bin/jvn.rs b/src/bin/jvn.rs index 965d0ec..c2ae5ec 100644 --- a/src/bin/jvn.rs +++ b/src/bin/jvn.rs @@ -11,7 +11,10 @@ use just_enough_vcs_cli::{ processer::jv_cmd_process, }, debug::verbose_logger::init_verbose_logger, - helpdoc::{DEFAULT_HELPDOC, helpdoc_viewer}, + helpdoc::{ + DEFAULT_HELPDOC, + helpdoc_viewer::{self}, + }, }, }; use just_progress::{ diff --git a/src/cmds.rs b/src/cmds.rs index 92e587f..d3c7a27 100644 --- a/src/cmds.rs +++ b/src/cmds.rs @@ -1,6 +1,7 @@ pub mod arg; pub mod cmd; pub mod collect; +pub mod converter; pub mod r#in; pub mod out; pub mod r#override; diff --git a/src/cmds/README.md b/src/cmds/README.md new file mode 100644 index 0000000..491163f --- /dev/null +++ b/src/cmds/README.md @@ -0,0 +1,266 @@ +# Command Dev Guide + +This doc explains how to develop new commands for JVCS CLI. The command system is modular, with distinct components. + +## Directory Structure + +``` +src/cmds/ +├── arg/ # CLI arg definitions +├── cmd/ # Command impl +├── collect/ # Resource collection +├── converter/ # Data converters +├── in/ # Input data structs +├── out/ # Output data structs +├── override/ # Renderer overrides +└── renderer/ # Renderer impls +``` + +## Command Components + +### 1. Argument +- Impl `clap::Parser` trait +- Naming: `JV{CommandName}Argument` +- Location: `src/cmds/arg/{command_name}.rs` + +Example: sum command args +```rust +// src/cmds/arg/sum.rs +use clap::Parser; + +#[derive(Parser, Debug)] +pub struct JVSumArgument { + /// Numbers to add + pub numbers: Vec<i32>, + + /// Don't output result + #[arg(long)] + pub no_output: bool, +} +``` + +### 2. Input +- Lifetime-free struct +- Naming: `JV{CommandName}Input` +- Location: `src/cmds/in/{command_name}.rs` +- Created from `Argument` in `prepare` phase + +Example: sum command input +```rust +// src/cmds/in/sum.rs +pub struct JVSumInput { + pub numbers: Vec<i32>, + pub should_output: bool, +} +``` + +### 3. Collect +- Lifetime-free struct +- Naming: `JV{CommandName}Collect` +- Location: `src/cmds/collect/{command_name}.rs` +- Collects local resources needed for cmd execution + +Example: sum command collect +```rust +// src/cmds/collect/sum.rs +pub struct JVSumCollect { + pub count: usize, +} +``` + +### 4. Output +- Impl `serde::Serialize` trait +- Naming: `JV{CommandName}Output` +- Location: `src/cmds/out/{command_name}.rs` + +Example: sum command output +```rust +// src/cmds/out/sum.rs +use serde::Serialize; + +#[derive(Serialize)] +pub struct JVSumOutput { + pub result: i32, +} +``` + +## Command Execution Phases + +### 1. prepare phase +- Convert `Argument` to stable `Input` +- Detect input format errors early +- Format input (e.g., flag inversion) + +Example: sum command prepare +```rust +async fn prepare(args: &JVSumArgument, ctx: &JVCommandContext) -> Result<JVSumInput, CmdPrepareError> { + trace!("Preparing sum cmd, arg count: {}", 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 phase +- Read resources based on `Argument` info +- Fail early on resource load errors +- Pass collected info to `exec` phase + +Example: sum command collect +```rust +async fn collect(args: &JVSumArgument, ctx: &JVCommandContext) -> Result<JVSumCollect, CmdPrepareError> { + trace!("Collecting sum cmd resources"); + + Ok(JVSumCollect { + count: args.numbers.len(), + }) +} +``` + +### 3. exec phase +- Bind info from `prepare` & `collect` to core API +- Organize result as `Output` +- **Must use** `cmd_output!(JVSomeOutput => output)` syntax + +Example: sum command exec +```rust +#[exec] +async fn exec( + input: JVSumInput, + collect: JVSumCollect, +) -> Result<(Box<dyn std::any::Any + Send + 'static>, TypeId), CmdExecuteError> { + trace!("Exec sum cmd, processing {} numbers", collect.count); + + // Calculate sum + let result = input.numbers.iter().sum(); + debug!("Result: {}", result); + + // Decide output type based on should_output + if input.should_output { + cmd_output!(JVSumOutput => JVSumOutput { result }) + } else { + // Use JVNoneOutput for no result + cmd_output!(JVNoneOutput => JVNoneOutput) + } +} +``` + +## Renderer + +Each `Output` needs a renderer to format data for user display. + +### Renderer Requirements +- Impl async `render` function +- Input: corresponding `Output` value +- Output: `Result<JVRenderResult, CmdRenderError>` +- **Must use** `#[result_renderer(JV{CommandName}Renderer)]` macro + +Example: sum command renderer +```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!("Rendering sum cmd result"); + + let mut r = JVRenderResult::default(); + r_println!(r, "Result: {}", data.result); + Ok(r) +} +``` + +## Dev Workflow + +1. **Plan Command Structure** + - Determine cmd name & args + - Design input/output data structs + +2. **Create Component Files** + - Create `.rs` files in respective dirs + - Impl Argument, Input, Collect, Output structs + +3. **Implement Command Logic** + - Create cmd impl file in `cmd/` dir + - Use cmd template (view via `cargo doc --no-deps`) + - Impl `prepare`, `collect`, `exec` functions + +4. **Implement Renderer** + - Create renderer file in `renderer/` dir + - Use `#[result_renderer]` macro + +5. **Test Command** + - Use `cargo build` to check compile errors + - Run cmd to test functionality + +## Naming Conventions + +| Component Type | Naming Convention | Example | +|---------|---------|------| +| Command | `JV{CommandName}Command` | `JVSumCommand` | +| Argument | `JV{CommandName}Argument` | `JVSumArgument` | +| Input | `JV{CommandName}Input` | `JVSumInput` | +| Collect | `JV{CommandName}Collect` | `JVSumCollect` | +| Output | `JV{CommandName}Output` | `JVSumOutput` | +| Renderer | `JV{CommandName}Renderer` | `JVSumRenderer` | + +## Logging + +Use `log` for debugging during cmd dev: + +- `trace!("msg")` - Most detailed debug info +- `debug!("msg")` - Debug info +- `info!("msg")` - General info +- `warn!("msg")` - Warning +- `error!("msg")` - Error + +## Best Practices + +1. **Error Handling** + - Validate input in `prepare` phase + - Check resource availability in `collect` phase + +2. **Input Formatting** + - Standardize user input in `prepare` phase + - Ensure `Input` struct is clean & stable + +3. **Resource Management** + - Get all needed resources in `collect` phase + - Avoid filesystem ops in `exec` phase + +4. **Output Design** + - Output struct should have enough info for renderer + - Consider needs of different output formats + +## Example Commands + +Check existing cmd impls for inspiration: +- `helpdoc` cmd: `src/cmds/cmd/helpdoc.rs` +- `sheetdump` cmd: `src/cmds/cmd/sheetdump.rs` +- `workspace` cmd: `src/cmds/cmd/workspace.rs` + +## Debug & Test + +1. **Generate Docs for Template** + ```bash + cargo doc --no-deps + ``` + Docs are in `.temp/target/doc/`, see `macro.command_template.html` for full template. + +2. **Run Command Test** + ```bash + # Build & deploy + ./scripts/dev/dev_deploy.sh + # or Windows + .\scripts\dev\dev_deploy.ps1 + + jvn sum 1 2 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 diff --git a/src/cmds/cmd/helpdoc.rs b/src/cmds/cmd/helpdoc.rs index bebd08c..98e0309 100644 --- a/src/cmds/cmd/helpdoc.rs +++ b/src/cmds/cmd/helpdoc.rs @@ -22,7 +22,7 @@ type In = JVHelpdocInput; type Collect = JVEmptyCollect; async fn help_str() -> String { - helpdoc_viewer::display(DEFAULT_HELPDOC).await; + helpdoc_viewer::display("commands/helpdoc").await; String::new() } diff --git a/src/systems/helpdoc.rs b/src/systems/helpdoc.rs index c36130d..f863158 100644 --- a/src/systems/helpdoc.rs +++ b/src/systems/helpdoc.rs @@ -1,6 +1,8 @@ +use cli_utils::display::markdown::Markdown; + pub mod helpdoc_viewer; -pub const DEFAULT_HELPDOC: &str = "Welcome_To_JVCS"; +pub const DEFAULT_HELPDOC: &str = "commands"; helpdoc_system_macros::generate_helpdoc_mapping!(); helpdoc_system_macros::generate_helpdoc_list!(); @@ -18,3 +20,8 @@ pub fn get_helpdoc<'a>(doc_name: &'a str, lang: &'a str) -> &'a str { pub fn get_helpdoc_list<'a>() -> Vec<&'a str> { get_docs_list() } + +pub fn print_help_doc(doc_name: &str, lang: &str) { + let doc = get_helpdoc(doc_name, lang); + println!("{}", doc.markdown()); +} |
