From 74bc8902be593796eb6292151e08374072766e3e Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Wed, 18 Mar 2026 22:50:03 +0800 Subject: Add workspace sheet command with help and localization --- resources/helpdoc/commands/workspace/sheet.en.md | 14 +++ .../helpdoc/commands/workspace/sheet.zh-CN.md | 14 +++ resources/locales/jvn/cmds/workspace/sheet/en.yml | 11 +++ .../locales/jvn/cmds/workspace/sheet/zh-CN.yml | 11 +++ .../locales/jvn/converters/make_sheet_error/en.yml | 4 + .../jvn/converters/make_sheet_error/zh-CN.yml | 4 + .../converters/workspace_operation_error/en.yml | 9 ++ .../converters/workspace_operation_error/zh-CN.yml | 9 ++ src/cmds/arg/workspace_sheet.rs | 22 +++++ src/cmds/cmd/workspace_sheet.rs | 109 +++++++++++++++++++++ src/cmds/collect/workspace.rs | 5 + src/cmds/comp/workspace_sheet.rs | 20 ++++ src/cmds/converter/make_sheet_error.rs | 22 +++++ src/cmds/converter/workspace_operation_error.rs | 59 +++++++---- src/cmds/in/workspace_sheet.rs | 6 ++ 15 files changed, 300 insertions(+), 19 deletions(-) create mode 100644 resources/helpdoc/commands/workspace/sheet.en.md create mode 100644 resources/helpdoc/commands/workspace/sheet.zh-CN.md create mode 100644 resources/locales/jvn/cmds/workspace/sheet/en.yml create mode 100644 resources/locales/jvn/cmds/workspace/sheet/zh-CN.yml create mode 100644 resources/locales/jvn/converters/make_sheet_error/en.yml create mode 100644 resources/locales/jvn/converters/make_sheet_error/zh-CN.yml create mode 100644 resources/locales/jvn/converters/workspace_operation_error/en.yml create mode 100644 resources/locales/jvn/converters/workspace_operation_error/zh-CN.yml create mode 100644 src/cmds/arg/workspace_sheet.rs create mode 100644 src/cmds/cmd/workspace_sheet.rs create mode 100644 src/cmds/collect/workspace.rs create mode 100644 src/cmds/comp/workspace_sheet.rs create mode 100644 src/cmds/converter/make_sheet_error.rs create mode 100644 src/cmds/in/workspace_sheet.rs diff --git a/resources/helpdoc/commands/workspace/sheet.en.md b/resources/helpdoc/commands/workspace/sheet.en.md new file mode 100644 index 0000000..e7fcfff --- /dev/null +++ b/resources/helpdoc/commands/workspace/sheet.en.md @@ -0,0 +1,14 @@ +> Operate on or display the `sheet` in the _current workspace_ + +## Usage +jvn workspace sheet +__ --new # Create a sheet +__ --delete # Delete a sheet +__ --print-path # Print the sheet path +__ --list-all # List all sheets + +## Aliases +__ --n +__ -d +__ -p +__ -A diff --git a/resources/helpdoc/commands/workspace/sheet.zh-CN.md b/resources/helpdoc/commands/workspace/sheet.zh-CN.md new file mode 100644 index 0000000..0e0aa3f --- /dev/null +++ b/resources/helpdoc/commands/workspace/sheet.zh-CN.md @@ -0,0 +1,14 @@ +> 操作或显示_当前工作区_下的 `结构表` + +## 使用 +jvn workspace sheet <参数: ?> +__ --new <结构表名称> # 创建结构表 +__ --delete <结构表名称> # 删除结构表 +__ --print-path <结构表名称> # 打印结构表路径 +__ --list-all # 列出所有结构表 + +## 别名 +__ --n <结构表名称> +__ -d <结构表名称> +__ -p <结构表名称> +__ -A diff --git a/resources/locales/jvn/cmds/workspace/sheet/en.yml b/resources/locales/jvn/cmds/workspace/sheet/en.yml new file mode 100644 index 0000000..0eaec26 --- /dev/null +++ b/resources/locales/jvn/cmds/workspace/sheet/en.yml @@ -0,0 +1,11 @@ +workspace_sheet: + error: + sheet_name_required_for_new: | + Sheet name is required for `--new` + sheet_name_required_for_delete: | + Sheet name is required for `--delete` + sheet_name_required_for_print_path: | + Sheet name is required for `--print-path` + exactly_one_required: | + Exactly one of `--new`, `--delete`, `--list-all`, or `--print-path` is required. + You can use `jvn helpdoc commands/workspace/sheet` to view usage. diff --git a/resources/locales/jvn/cmds/workspace/sheet/zh-CN.yml b/resources/locales/jvn/cmds/workspace/sheet/zh-CN.yml new file mode 100644 index 0000000..3998078 --- /dev/null +++ b/resources/locales/jvn/cmds/workspace/sheet/zh-CN.yml @@ -0,0 +1,11 @@ +workspace_sheet: + error: + sheet_name_required_for_new: | + 对于符号 `--new`,需要显式指定 `结构表` 名称 + sheet_name_required_for_delete: | + 对于符号 `--delete`,需要显式指定 `结构表` 名称 + sheet_name_required_for_print_path: | + 对于符号 `--print-path`,需要显式指定 `结构表` 名称 + exactly_one_required: | + 需要指定 `--new`、`--delete`、`--list-all` 或 `--print-path` 中的任意符号 + 您可以使用 `jvn helpdoc commands/workspace/sheet` 来查看使用方式 diff --git a/resources/locales/jvn/converters/make_sheet_error/en.yml b/resources/locales/jvn/converters/make_sheet_error/en.yml new file mode 100644 index 0000000..0a9b533 --- /dev/null +++ b/resources/locales/jvn/converters/make_sheet_error/en.yml @@ -0,0 +1,4 @@ +make_sheet_error: + sheet_already_exists: "Sheet already exists" + sheet_not_found: "Sheet not found" + other: "Other error: %{error}" diff --git a/resources/locales/jvn/converters/make_sheet_error/zh-CN.yml b/resources/locales/jvn/converters/make_sheet_error/zh-CN.yml new file mode 100644 index 0000000..2157c82 --- /dev/null +++ b/resources/locales/jvn/converters/make_sheet_error/zh-CN.yml @@ -0,0 +1,4 @@ +make_sheet_error: + sheet_already_exists: "无法创建,结构表已存在" + sheet_not_found: "未找到指定结构表" + other: "其他错误:%{error}" diff --git a/resources/locales/jvn/converters/workspace_operation_error/en.yml b/resources/locales/jvn/converters/workspace_operation_error/en.yml new file mode 100644 index 0000000..b445856 --- /dev/null +++ b/resources/locales/jvn/converters/workspace_operation_error/en.yml @@ -0,0 +1,9 @@ +workspace_operation_error: + other: "Other error" + config_not_found: "Config not found" + workspace_not_found: "Workspace not found" + handle_lock: "Handle lock error: %{error}" + data_read: "Data read error: %{error}" + data_write: "Data write error: %{error}" + data_apply: "Data apply error: %{error}" + id_alias_error: "ID alias error: %{error}" diff --git a/resources/locales/jvn/converters/workspace_operation_error/zh-CN.yml b/resources/locales/jvn/converters/workspace_operation_error/zh-CN.yml new file mode 100644 index 0000000..bd1b160 --- /dev/null +++ b/resources/locales/jvn/converters/workspace_operation_error/zh-CN.yml @@ -0,0 +1,9 @@ +workspace_operation_error: + other: "其他错误" + config_not_found: "配置未找到" + workspace_not_found: "工作空间未找到" + handle_lock: "处理锁错误: %{error}" + data_read: "数据读取错误: %{error}" + data_write: "数据写入错误: %{error}" + data_apply: "数据应用错误: %{error}" + id_alias_error: "ID别名错误: %{error}" diff --git a/src/cmds/arg/workspace_sheet.rs b/src/cmds/arg/workspace_sheet.rs new file mode 100644 index 0000000..7cf65e4 --- /dev/null +++ b/src/cmds/arg/workspace_sheet.rs @@ -0,0 +1,22 @@ +// Why not directly design new, delete, print_path as Option? +// Because the former would only allow the following syntax: +// jvn workspace sheet --new sheet +// But by separating name and operation, it can simultaneously support: +// jvn workspace sheet sheet --new + +#[derive(clap::Parser)] +pub struct JVWorkspaceSheetArgument { + pub name: Option, + + #[arg(short = 'n', long = "new")] + pub new: bool, + + #[arg(short = 'd', long = "delete")] + pub delete: bool, + + #[arg(short = 'A', long = "list-all")] + pub list_all: bool, + + #[arg(short = 'p', long = "print-path")] + pub print_path: bool, +} diff --git a/src/cmds/cmd/workspace_sheet.rs b/src/cmds/cmd/workspace_sheet.rs new file mode 100644 index 0000000..a360203 --- /dev/null +++ b/src/cmds/cmd/workspace_sheet.rs @@ -0,0 +1,109 @@ +use crate::{ + cmd_output, + cmds::{ + arg::workspace_sheet::JVWorkspaceSheetArgument, collect::workspace::JVWorkspaceCollect, + converter::make_sheet_error::MakeSheetErrorConverter, + r#in::workspace_sheet::JVWorkspaceSheetInput, out::none::JVNoneOutput, + }, + systems::{ + cmd::{ + cmd_system::{AnyOutput, JVCommandContext}, + errors::{CmdExecuteError, CmdPrepareError}, + }, + helpdoc::helpdoc_viewer, + }, +}; +use cmd_system_macros::exec; +use just_enough_vcs::system::workspace::workspace::manager::WorkspaceManager; +use rust_i18n::t; + +pub struct JVWorkspaceSheetCommand; +type Cmd = JVWorkspaceSheetCommand; +type Arg = JVWorkspaceSheetArgument; +type In = JVWorkspaceSheetInput; +type Collect = JVWorkspaceCollect; + +async fn help_str() -> String { + helpdoc_viewer::display("commands/workspace/sheet").await; + String::new() +} + +async fn prepare(_args: &Arg, _ctx: &JVCommandContext) -> Result { + let input = match (_args.new, _args.delete, _args.list_all, _args.print_path) { + (true, false, false, false) => { + let name = _args.name.as_ref().ok_or_else(|| { + CmdPrepareError::Error( + t!("workspace_sheet.error.sheet_name_required_for_new") + .trim() + .to_string(), + ) + })?; + JVWorkspaceSheetInput::Add(name.clone()) + } + (false, true, false, false) => { + let name = _args.name.as_ref().ok_or_else(|| { + CmdPrepareError::Error( + t!("workspace_sheet.error.sheet_name_required_for_delete") + .trim() + .to_string(), + ) + })?; + JVWorkspaceSheetInput::Delete(name.clone()) + } + (false, false, true, false) => JVWorkspaceSheetInput::ListAll, + (false, false, false, true) => { + let name = _args.name.as_ref().ok_or_else(|| { + CmdPrepareError::Error( + t!("workspace_sheet.error.sheet_name_required_for_print_path") + .trim() + .to_string(), + ) + })?; + JVWorkspaceSheetInput::PrintPath(name.clone()) + } + _ => { + return Err(CmdPrepareError::Error( + t!("workspace_sheet.error.exactly_one_required") + .trim() + .to_string(), + )); + } + }; + Ok(input) +} + +async fn collect(_args: &Arg, _ctx: &JVCommandContext) -> Result { + Ok(JVWorkspaceCollect { + manager: WorkspaceManager::new(), + }) +} + +#[exec] +async fn exec(input: In, collect: Collect) -> Result { + match input { + JVWorkspaceSheetInput::Add(sheet_name) => { + if let Err(e) = collect.manager.make_sheet(sheet_name).await { + return Err(MakeSheetErrorConverter::to_exec_error(e)); + } + } + JVWorkspaceSheetInput::Delete(sheet_name) => { + if let Err(e) = collect.manager.drop_sheet(sheet_name).await { + return Err(MakeSheetErrorConverter::to_exec_error(e)); + } + } + JVWorkspaceSheetInput::ListAll => { + collect + .manager + .list_sheet_names() + .await + .iter() + .for_each(|name| println!("{}", name)); + } + JVWorkspaceSheetInput::PrintPath(sheet_name) => { + println!("{}", collect.manager.get_sheet_path(sheet_name).display()) + } + } + cmd_output!(JVNoneOutput => JVNoneOutput) +} + +crate::command_template!(); diff --git a/src/cmds/collect/workspace.rs b/src/cmds/collect/workspace.rs new file mode 100644 index 0000000..5759a09 --- /dev/null +++ b/src/cmds/collect/workspace.rs @@ -0,0 +1,5 @@ +use just_enough_vcs::system::workspace::workspace::manager::WorkspaceManager; + +pub struct JVWorkspaceCollect { + pub manager: WorkspaceManager, +} diff --git a/src/cmds/comp/workspace_sheet.rs b/src/cmds/comp/workspace_sheet.rs new file mode 100644 index 0000000..3d7e6d5 --- /dev/null +++ b/src/cmds/comp/workspace_sheet.rs @@ -0,0 +1,20 @@ +use crate::systems::comp::context::CompletionContext; +use just_enough_vcs::system::workspace::workspace::manager::WorkspaceManager; + +pub fn comp(ctx: CompletionContext) -> Option> { + if ctx.current_word.starts_with('-') { + return Some(vec![ + "--list-all".to_string(), + "--print-path".to_string(), + "--new".to_string(), + "--delete".to_string(), + ]); + } + + if ctx.previous_word == "--new" || ctx.previous_word == "-n" { + return Some(vec![]); + } + + let rt = tokio::runtime::Runtime::new().unwrap(); + Some(rt.block_on(WorkspaceManager::new().list_sheet_names())) +} diff --git a/src/cmds/converter/make_sheet_error.rs b/src/cmds/converter/make_sheet_error.rs new file mode 100644 index 0000000..8bbc45d --- /dev/null +++ b/src/cmds/converter/make_sheet_error.rs @@ -0,0 +1,22 @@ +use crate::systems::cmd::errors::CmdExecuteError; +use just_enough_vcs::system::workspace::workspace::manager::sheet_state::error::MakeSheetError; +use rust_i18n::t; + +pub struct MakeSheetErrorConverter; + +impl MakeSheetErrorConverter { + pub fn to_exec_error(err: MakeSheetError) -> CmdExecuteError { + match err { + MakeSheetError::SheetAlreadyExists => { + CmdExecuteError::Error(t!("make_sheet_error.sheet_already_exists").to_string()) + } + MakeSheetError::SheetNotFound => { + CmdExecuteError::Error(t!("make_sheet_error.sheet_not_found").to_string()) + } + MakeSheetError::Io(error) => CmdExecuteError::Io(error), + MakeSheetError::Other(error) => CmdExecuteError::Error( + t!("make_sheet_error.other", error = error.to_string()).to_string(), + ), + } + } +} diff --git a/src/cmds/converter/workspace_operation_error.rs b/src/cmds/converter/workspace_operation_error.rs index f2f71d0..3e6252d 100644 --- a/src/cmds/converter/workspace_operation_error.rs +++ b/src/cmds/converter/workspace_operation_error.rs @@ -1,5 +1,6 @@ use crate::systems::cmd::errors::CmdExecuteError; use just_enough_vcs::system::workspace::workspace::error::WorkspaceOperationError; +use rust_i18n::t; pub struct JVWorkspaceOperationErrorConverter; @@ -9,26 +10,46 @@ impl JVWorkspaceOperationErrorConverter { WorkspaceOperationError::Io(error) => CmdExecuteError::Io(error), WorkspaceOperationError::Other(msg) => CmdExecuteError::Error(msg), WorkspaceOperationError::ConfigNotFound => { - CmdExecuteError::Error("Config not found".to_string()) - } - WorkspaceOperationError::WorkspaceNotFound => { - CmdExecuteError::Error("Workspace not found".to_string()) - } - WorkspaceOperationError::HandleLock(handle_lock_error) => { - CmdExecuteError::Error(format!("Handle lock error: {}", handle_lock_error)) - } - WorkspaceOperationError::DataRead(data_read_error) => { - CmdExecuteError::Error(format!("Data read error: {}", data_read_error)) - } - WorkspaceOperationError::DataWrite(data_write_error) => { - CmdExecuteError::Error(format!("Data write error: {}", data_write_error)) - } - WorkspaceOperationError::DataApply(data_apply_error) => { - CmdExecuteError::Error(format!("Data apply error: {}", data_apply_error)) - } - WorkspaceOperationError::IDAliasError(id_alias_error) => { - CmdExecuteError::Error(format!("ID alias error: {}", id_alias_error)) + CmdExecuteError::Error(t!("workspace_operation_error.config_not_found").to_string()) } + WorkspaceOperationError::WorkspaceNotFound => CmdExecuteError::Error( + t!("workspace_operation_error.workspace_not_found").to_string(), + ), + WorkspaceOperationError::HandleLock(handle_lock_error) => CmdExecuteError::Error( + t!( + "workspace_operation_error.handle_lock", + error = handle_lock_error + ) + .to_string(), + ), + WorkspaceOperationError::DataRead(data_read_error) => CmdExecuteError::Error( + t!( + "workspace_operation_error.data_read", + error = data_read_error + ) + .to_string(), + ), + WorkspaceOperationError::DataWrite(data_write_error) => CmdExecuteError::Error( + t!( + "workspace_operation_error.data_write", + error = data_write_error + ) + .to_string(), + ), + WorkspaceOperationError::DataApply(data_apply_error) => CmdExecuteError::Error( + t!( + "workspace_operation_error.data_apply", + error = data_apply_error + ) + .to_string(), + ), + WorkspaceOperationError::IDAliasError(id_alias_error) => CmdExecuteError::Error( + t!( + "workspace_operation_error.id_alias_error", + error = id_alias_error + ) + .to_string(), + ), } } } diff --git a/src/cmds/in/workspace_sheet.rs b/src/cmds/in/workspace_sheet.rs new file mode 100644 index 0000000..78159ac --- /dev/null +++ b/src/cmds/in/workspace_sheet.rs @@ -0,0 +1,6 @@ +pub enum JVWorkspaceSheetInput { + Add(String), + Delete(String), + ListAll, + PrintPath(String), +} -- cgit