summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--resources/locales/jvn/cmds/sheetedit/en.yml22
-rw-r--r--resources/locales/jvn/cmds/sheetedit/zh-CN.yml21
-rw-r--r--src/cmds/arg/sheetedit.rs11
-rw-r--r--src/cmds/cmd/sheetedit.rs122
-rw-r--r--src/cmds/in/sheetedit.rs6
5 files changed, 182 insertions, 0 deletions
diff --git a/resources/locales/jvn/cmds/sheetedit/en.yml b/resources/locales/jvn/cmds/sheetedit/en.yml
new file mode 100644
index 0000000..8a439d2
--- /dev/null
+++ b/resources/locales/jvn/cmds/sheetedit/en.yml
@@ -0,0 +1,22 @@
+sheetedit:
+ editor: |
+ # Editing `%{file_dir}`
+
+ # Index format:
+ # Upstream: id/ver
+ # Local: ~id/ver
+
+ # Forward format:
+ # Latest Version: "Mapping" => "ID/VER"
+ # RefSheet Version: "Mapping" => "ID/VER" => "ref"
+ # Specific Version: "Mapping" == "ID/VER"
+ # Or: "Mapping" => "ID/VER" == "VER"
+
+ %{info}
+
+ # TIPS: After editing, save file and exit editor.
+ # It will be automatically written to the original file.
+
+ mapping: Mapping
+ index_source: Index
+ forward: Forward
diff --git a/resources/locales/jvn/cmds/sheetedit/zh-CN.yml b/resources/locales/jvn/cmds/sheetedit/zh-CN.yml
new file mode 100644
index 0000000..6352d36
--- /dev/null
+++ b/resources/locales/jvn/cmds/sheetedit/zh-CN.yml
@@ -0,0 +1,21 @@
+sheetedit:
+ editor: |
+ # 正在编辑 `%{file_dir}`
+
+ # 索引源格式:
+ # 本地命名空间索引:~id/ver
+ # 上游命名空间索引: id/ver
+
+ # 前方格式:
+ # 指向最新版本:"Mapping" => "ID/VER"
+ # 指向参考版本:"Mapping" => "ID/VER" => "ref"
+ # 指向指定版本:"Mapping" == "ID/VER"
+ # 或者:"Mapping" => "ID/VER" == "VER"
+
+ %{info}
+
+ # 完成编辑后,保存文件并退出编辑器,将会自动写入到原始文件
+
+ mapping: 映射地址
+ index_source: 索引源
+ forward: 前方
diff --git a/src/cmds/arg/sheetedit.rs b/src/cmds/arg/sheetedit.rs
new file mode 100644
index 0000000..6232ef7
--- /dev/null
+++ b/src/cmds/arg/sheetedit.rs
@@ -0,0 +1,11 @@
+use std::path::PathBuf;
+
+use clap::Parser;
+
+#[derive(Parser, Debug)]
+pub struct JVSheeteditArgument {
+ pub file: PathBuf,
+
+ #[arg(short, long)]
+ pub editor: Option<String>,
+}
diff --git a/src/cmds/cmd/sheetedit.rs b/src/cmds/cmd/sheetedit.rs
new file mode 100644
index 0000000..3e61642
--- /dev/null
+++ b/src/cmds/cmd/sheetedit.rs
@@ -0,0 +1,122 @@
+use crate::{
+ cmd_output,
+ cmds::{
+ arg::sheetedit::JVSheeteditArgument, collect::single_file::JVSingleFileCollect,
+ r#in::sheetedit::JVSheeteditInput, out::none::JVNoneOutput,
+ },
+ systems::cmd::{
+ cmd_system::JVCommandContext,
+ errors::{CmdExecuteError, CmdPrepareError},
+ },
+};
+use cli_utils::{
+ display::SimpleTable, env::get_default_editor, input::input_with_editor_cutsom, string_vec,
+};
+use cmd_system_macros::exec;
+use just_enough_vcs::system::sheet_system::{mapping::LocalMapping, sheet::SheetData};
+use just_fmt::fmt_path::{PathFormatError, fmt_path};
+use rust_i18n::t;
+use std::{any::TypeId, borrow::Cow, path::PathBuf};
+use tokio::fs::create_dir_all;
+
+pub struct JVSheeteditCommand;
+type Cmd = JVSheeteditCommand;
+type Arg = JVSheeteditArgument;
+type In = JVSheeteditInput;
+type Collect = JVSingleFileCollect;
+
+fn help_str() -> String {
+ todo!()
+}
+
+async fn prepare(args: &Arg, _ctx: &JVCommandContext) -> Result<In, CmdPrepareError> {
+ let file = fmt_path(args.file.clone()).map_err(|e| match e {
+ PathFormatError::InvalidUtf8(e) => CmdPrepareError::Error(e.to_string()),
+ })?;
+ let editor = args.editor.clone().unwrap_or(get_default_editor().await);
+
+ Ok(In { file, editor })
+}
+
+async fn collect(args: &Arg, _ctx: &JVCommandContext) -> Result<Collect, CmdPrepareError> {
+ let data = match tokio::fs::read(&args.file).await {
+ Ok(d) => d,
+ Err(_) => Vec::new(),
+ };
+ Ok(Collect { data })
+}
+
+#[exec]
+async fn exec(
+ input: In,
+ collect: Collect,
+) -> Result<(Box<dyn std::any::Any + Send + 'static>, TypeId), CmdExecuteError> {
+ let sheet = SheetData::try_from(collect.data).unwrap_or(SheetData::empty());
+
+ let mappings = sheet.mappings();
+ let mut mappings_vec = mappings.iter().cloned().collect::<Vec<LocalMapping>>();
+ mappings_vec.sort();
+
+ let template = build_template(&input.file, mappings_vec).to_string();
+
+ let temp_file = input.file.with_added_extension("md");
+ create_dir_all(temp_file.parent().unwrap()).await?;
+
+ let edit_result = input_with_editor_cutsom(template, &temp_file, "#", input.editor).await;
+
+ match edit_result {
+ Ok(t) => {
+ let rebuild_sheet_data = SheetData::try_from(t.as_str())
+ .map_err(|e| CmdExecuteError::Error(e.to_string()))?;
+ tokio::fs::write(&input.file, rebuild_sheet_data.as_bytes()).await?;
+ }
+ Err(e) => return Err(CmdExecuteError::Error(e.to_string())),
+ }
+
+ cmd_output!(JVNoneOutput => JVNoneOutput {})
+}
+
+fn build_template(file: &PathBuf, mappings: Vec<LocalMapping>) -> Cow<'static, str> {
+ let mapping_table = render_pretty_mappings(&mappings);
+ let template = t!(
+ "sheetedit.editor",
+ file_dir = file.display(),
+ info = mapping_table
+ );
+
+ template
+}
+
+fn render_pretty_mappings(mappings: &Vec<LocalMapping>) -> String {
+ let header = string_vec![
+ format!("# {}", t!("sheetedit.mapping")),
+ "",
+ t!("sheetedit.index_source"),
+ "",
+ t!("sheetedit.forward")
+ ];
+
+ let mut simple_table = SimpleTable::new(header);
+
+ for mapping in mappings {
+ let mapping_str = mapping
+ .to_string()
+ .split(" ")
+ .into_iter()
+ .map(|s| s.to_string())
+ .collect::<Vec<String>>();
+ simple_table.push_item(vec![
+ format!(
+ " {} ",
+ mapping_str.get(0).unwrap_or(&String::default())
+ ), // Mapping
+ format!("{} ", mapping_str.get(1).unwrap_or(&String::default())), // => & ==
+ format!("{} ", mapping_str.get(2).unwrap_or(&String::default())), // Index
+ format!("{} ", mapping_str.get(3).unwrap_or(&String::default())), // => & ==
+ format!("{} ", mapping_str.get(4).unwrap_or(&String::default())), // Forward
+ ]);
+ }
+ simple_table.to_string()
+}
+
+crate::command_template!();
diff --git a/src/cmds/in/sheetedit.rs b/src/cmds/in/sheetedit.rs
new file mode 100644
index 0000000..b469580
--- /dev/null
+++ b/src/cmds/in/sheetedit.rs
@@ -0,0 +1,6 @@
+use std::path::PathBuf;
+
+pub struct JVSheeteditInput {
+ pub file: PathBuf,
+ pub editor: String,
+}