From 2abc5acd25756f3ef6a6ad34f8777ffe241e750d Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Tue, 27 Jan 2026 06:16:58 +0800 Subject: Reorganize command modules under a unified cmds directory --- .cargo/registry.toml | 16 +-- .gitignore | 12 +- build.rs | 4 +- src/args/status.rs | 4 - src/cmds.rs | 6 + src/cmds/arg/status.rs | 4 + src/cmds/cmd/status.rs | 159 ++++++++++++++++++++++++ src/cmds/collect/status.rs | 38 ++++++ src/cmds/in/status.rs | 1 + src/cmds/out/status.rs | 47 +++++++ src/cmds/renderer/json.rs | 27 ++++ src/cmds/renderer/json_pretty.rs | 26 ++++ src/cmds/renderer/status.rs | 262 +++++++++++++++++++++++++++++++++++++++ src/cmds/status.rs | 157 ----------------------- src/collects/status.rs | 38 ------ src/inputs/status.rs | 1 - src/lib.rs | 11 -- src/outputs/status.rs | 47 ------- src/renderers/json.rs | 27 ---- src/renderers/json_pretty.rs | 26 ---- src/renderers/status.rs | 262 --------------------------------------- 21 files changed, 586 insertions(+), 589 deletions(-) delete mode 100644 src/args/status.rs create mode 100644 src/cmds.rs create mode 100644 src/cmds/arg/status.rs create mode 100644 src/cmds/cmd/status.rs create mode 100644 src/cmds/collect/status.rs create mode 100644 src/cmds/in/status.rs create mode 100644 src/cmds/out/status.rs create mode 100644 src/cmds/renderer/json.rs create mode 100644 src/cmds/renderer/json_pretty.rs create mode 100644 src/cmds/renderer/status.rs delete mode 100644 src/cmds/status.rs delete mode 100644 src/collects/status.rs delete mode 100644 src/inputs/status.rs delete mode 100644 src/outputs/status.rs delete mode 100644 src/renderers/json.rs delete mode 100644 src/renderers/json_pretty.rs delete mode 100644 src/renderers/status.rs diff --git a/.cargo/registry.toml b/.cargo/registry.toml index 3ebfa17..c1a712d 100644 --- a/.cargo/registry.toml +++ b/.cargo/registry.toml @@ -24,30 +24,30 @@ type = "Renderer" # Json Renderer [renderer.json] name = "json" -type = "crate::renderers::json::JVResultJsonRenderer" +type = "crate::cmds::renderer::json::JVResultJsonRenderer" [renderer.json_pretty] name = "json-pretty" -type = "crate::renderers::json_pretty::JVResultPrettyJsonRenderer" +type = "crate::cmds::renderer::json_pretty::JVResultPrettyJsonRenderer" #################### ### Auto-Collect ### #################### [collect.args] -path = "src/args.rs" +path = "src/cmds/arg.rs" [collect.cmds] -path = "src/cmds.rs" +path = "src/cmds/cmd.rs" [collect.collects] -path = "src/collects.rs" +path = "src/cmds/collect.rs" [collect.inputs] -path = "src/inputs.rs" +path = "src/cmds/in.rs" [collect.outputs] -path = "src/outputs.rs" +path = "src/cmds/out.rs" [collect.renderers] -path = "src/renderers.rs" +path = "src/cmds/renderer.rs" diff --git a/.gitignore b/.gitignore index cf2b5b0..4e45244 100644 --- a/.gitignore +++ b/.gitignore @@ -26,12 +26,12 @@ _*.rs # Generated by the build system -/src/args.rs -/src/cmds.rs -/src/collects.rs -/src/inputs.rs -/src/outputs.rs -/src/renderers.rs +/src/cmds/arg.rs +/src/cmds/cmd.rs +/src/cmds/collect.rs +/src/cmds/in.rs +/src/cmds/out.rs +/src/cmds/renderer.rs # Symbolic links and shortcuts created by scripts /deploy.lnk diff --git a/build.rs b/build.rs index 22842ed..07b5c10 100644 --- a/build.rs +++ b/build.rs @@ -4,7 +4,7 @@ use std::process::Command; use string_proc::pascal_case; -const COMMANDS_PATH: &str = "./src/cmds/"; +const COMMANDS_PATH: &str = "./src/cmds/cmd/"; const COMPILE_INFO_RS_TEMPLATE: &str = "./templates/compile_info.rs.template"; const COMPILE_INFO_RS: &str = "./src/data/compile_info.rs"; @@ -312,7 +312,7 @@ fn generate_cmd_registry_file(repo_root: &PathBuf) -> Result<(), Box + for JVStatusCommand +{ + async fn prepare( + _args: &JVStatusArgument, + _ctx: &JVCommandContext, + ) -> Result { + Ok(JVStatusInput) + } + + async fn collect( + _args: &JVStatusArgument, + _ctx: &JVCommandContext, + ) -> Result { + // Initialize a reader for the local workspace and a default result structure + let mut reader = LocalWorkspaceReader::default(); + let mut collect = JVStatusCollect::default(); + + // Analyze the current status of the local workspace + // (detects changes like created, modified, moved, etc.) + let analyzed = reader.analyze_local_status().await?; + + // Retrieve the current account (member) ID + let account = reader.current_account().await?; + + // Retrieve the name of the current sheet + let sheet_name = reader.sheet_name().await?; + + // Is Host Mode + let is_host_mode = reader.is_host_mode().await?; + + let cached_sheet = reader.cached_sheet(&sheet_name).await?; + let sheet_holder = cached_sheet.holder().cloned().unwrap_or_default(); + let is_ref_sheet = sheet_holder == VAULT_HOST_NAME; + + // Get Latest file data + let latest_file_data = reader.pop_latest_file_data(&account).await?; + + // Get the timestamp of the last update, defaulting to the current time if not available + let update_time = reader + .latest_info() + .await? + .update_instant + .unwrap_or(SystemTime::now()); + + // Record the current system time + let now_time = SystemTime::now(); + + // Populate the result structure with the gathered data + collect.current_account = account; + collect.current_sheet = sheet_name; + collect.is_host_mode = is_host_mode; + collect.in_ref_sheet = is_ref_sheet; + collect.analyzed_result = analyzed; + collect.update_time = update_time; + collect.now_time = now_time; + collect.latest_file_data = latest_file_data; + Ok(collect) + } + + async fn exec( + _input: JVStatusInput, + collect: JVStatusCollect, + ) -> Result { + let mut wrong_modified_items: HashMap = + HashMap::new(); + + let latest_file_data = &collect.latest_file_data; + + // Calculate whether modifications are correc + let modified = &collect.analyzed_result.modified; + for item in modified { + // Get mapping + let Ok(mapping) = collect.local_sheet_data.mapping_data(&item) else { + continue; + }; + + // Check base version + { + let base_version = mapping.version_when_updated().clone(); + let Some(latest_version) = latest_file_data + .file_version(mapping.mapping_vfid()) + .cloned() + else { + continue; + }; + + // Base version dismatch + if base_version != latest_version { + wrong_modified_items.insert( + item.clone(), + JVStatusWrongModifyReason::BaseVersionMismatch { + base_version, + latest_version, + }, + ); + continue; + } + } + + // Check edit right (only check when current is not HOST) + if collect.current_account != VAULT_HOST_NAME { + let holder = latest_file_data.file_holder(mapping.mapping_vfid()); + if holder.is_none() { + wrong_modified_items.insert(item.clone(), JVStatusWrongModifyReason::NoHolder); + continue; + } + + let holder = holder.cloned().unwrap(); + if &collect.current_account != &holder { + wrong_modified_items.insert( + item.clone(), + JVStatusWrongModifyReason::ModifiedButNotHeld { holder: holder }, + ); + } + } + } + + let output = JVStatusOutput { + current_account: collect.current_account, + current_sheet: collect.current_sheet, + is_host_mode: collect.is_host_mode, + in_ref_sheet: collect.in_ref_sheet, + analyzed_result: collect.analyzed_result, + wrong_modified_items: wrong_modified_items, + update_time: collect.update_time, + now_time: collect.now_time, + }; + + Ok(output) + } + + fn get_help_str() -> String { + "".to_string() + } +} diff --git a/src/cmds/collect/status.rs b/src/cmds/collect/status.rs new file mode 100644 index 0000000..b0e8fcd --- /dev/null +++ b/src/cmds/collect/status.rs @@ -0,0 +1,38 @@ +use std::time::SystemTime; + +use just_enough_vcs::vcs::data::{ + local::{ + latest_file_data::LatestFileData, local_sheet::LocalSheetData, + workspace_analyzer::AnalyzeResultPure, + }, + member::MemberId, + sheet::SheetName, +}; + +pub struct JVStatusCollect { + pub current_account: MemberId, + pub current_sheet: SheetName, + pub is_host_mode: bool, + pub in_ref_sheet: bool, + pub analyzed_result: AnalyzeResultPure, + pub latest_file_data: LatestFileData, + pub local_sheet_data: LocalSheetData, + pub update_time: SystemTime, + pub now_time: SystemTime, +} + +impl Default for JVStatusCollect { + fn default() -> Self { + Self { + current_account: MemberId::default(), + current_sheet: SheetName::default(), + is_host_mode: false, + in_ref_sheet: false, + analyzed_result: AnalyzeResultPure::default(), + latest_file_data: LatestFileData::default(), + local_sheet_data: LocalSheetData::default(), + update_time: SystemTime::now(), + now_time: SystemTime::now(), + } + } +} diff --git a/src/cmds/in/status.rs b/src/cmds/in/status.rs new file mode 100644 index 0000000..859ccd2 --- /dev/null +++ b/src/cmds/in/status.rs @@ -0,0 +1 @@ +pub struct JVStatusInput; diff --git a/src/cmds/out/status.rs b/src/cmds/out/status.rs new file mode 100644 index 0000000..2b8d9c6 --- /dev/null +++ b/src/cmds/out/status.rs @@ -0,0 +1,47 @@ +use std::{collections::HashMap, time::SystemTime}; + +use just_enough_vcs::vcs::data::{ + local::workspace_analyzer::{AnalyzeResultPure, ModifiedRelativePathBuf}, + member::MemberId, + sheet::SheetName, +}; +use serde::Serialize; + +#[derive(Serialize)] +pub struct JVStatusOutput { + pub current_account: MemberId, + pub current_sheet: SheetName, + pub is_host_mode: bool, + pub in_ref_sheet: bool, + pub analyzed_result: AnalyzeResultPure, + pub wrong_modified_items: HashMap, + pub update_time: SystemTime, + pub now_time: SystemTime, +} + +#[derive(Serialize)] +pub enum JVStatusWrongModifyReason { + BaseVersionMismatch { + base_version: String, + latest_version: String, + }, + ModifiedButNotHeld { + holder: String, + }, + NoHolder, +} + +impl Default for JVStatusOutput { + fn default() -> Self { + Self { + current_account: MemberId::default(), + current_sheet: SheetName::default(), + is_host_mode: false, + in_ref_sheet: false, + analyzed_result: AnalyzeResultPure::default(), + wrong_modified_items: HashMap::new(), + update_time: SystemTime::now(), + now_time: SystemTime::now(), + } + } +} diff --git a/src/cmds/renderer/json.rs b/src/cmds/renderer/json.rs new file mode 100644 index 0000000..9a3105d --- /dev/null +++ b/src/cmds/renderer/json.rs @@ -0,0 +1,27 @@ +use serde::Serialize; +use serde_json; + +use crate::{ + r_print, + systems::cmd::{ + errors::CmdRenderError, + renderer::{JVRenderResult, JVResultRenderer}, + }, +}; + +pub struct JVResultJsonRenderer; + +impl JVResultRenderer for JVResultJsonRenderer +where + T: Serialize + Sync, +{ + async fn render(data: &T) -> Result { + let mut r = JVRenderResult::default(); + let json_string = serde_json::to_string(data) + .map_err(|e| CmdRenderError::SerializeFailed(e.to_string()))?; + + r_print!(r, "{}", json_string); + + Ok(r) + } +} diff --git a/src/cmds/renderer/json_pretty.rs b/src/cmds/renderer/json_pretty.rs new file mode 100644 index 0000000..a4a3ba5 --- /dev/null +++ b/src/cmds/renderer/json_pretty.rs @@ -0,0 +1,26 @@ +use serde::Serialize; + +use crate::{ + r_print, + systems::cmd::{ + errors::CmdRenderError, + renderer::{JVRenderResult, JVResultRenderer}, + }, +}; + +pub struct JVResultPrettyJsonRenderer; + +impl JVResultRenderer for JVResultPrettyJsonRenderer +where + T: Serialize + Sync, +{ + async fn render(data: &T) -> Result { + let mut r = JVRenderResult::default(); + let json_string = serde_json::to_string_pretty(data) + .map_err(|e| CmdRenderError::SerializeFailed(e.to_string()))?; + + r_print!(r, "{}", json_string); + + Ok(r) + } +} diff --git a/src/cmds/renderer/status.rs b/src/cmds/renderer/status.rs new file mode 100644 index 0000000..965ff87 --- /dev/null +++ b/src/cmds/renderer/status.rs @@ -0,0 +1,262 @@ +use cli_utils::{ + display::{SimpleTable, md}, + env::auto_update_outdate, +}; +use rust_i18n::t; + +use crate::{ + cmds::out::status::{JVStatusOutput, JVStatusWrongModifyReason}, + r_println, + systems::cmd::{ + errors::CmdRenderError, + renderer::{JVRenderResult, JVResultRenderer}, + }, +}; + +pub struct JVStatusRenderer; + +enum Mode { + StructuralChangesMode, + ContentChangesMode, + Clean, +} + +impl JVResultRenderer for JVStatusRenderer { + async fn render(data: &JVStatusOutput) -> Result { + let mut r = JVRenderResult::default(); + + // Render Header + render_header(&mut r, data); + + // Render Info and Mode + render_info_and_mode(&mut r, data); + + // Render Hint + render_hint(&mut r, data); + + Ok(r) + } +} + +fn render_header(r: &mut JVRenderResult, data: &JVStatusOutput) { + let account = &data.current_account; + let sheet = &data.current_sheet; + r_println!( + r, + "{}", + md(t!("status.header", account = account, sheet = sheet)) + ); +} + +fn render_info_and_mode(r: &mut JVRenderResult, data: &JVStatusOutput) { + let mut info_erased = String::default(); + let mut info_moved = String::default(); + let mut info_lost = String::default(); + let mut info_created = String::default(); + let mut info_modified = String::default(); + + // Collect erased items + if !data.analyzed_result.erased.is_empty() { + info_erased.push_str(format!("{}\n", md(t!("status.info_display.erased.header"))).as_str()); + for erased in data.analyzed_result.erased.iter() { + info_erased.push_str( + format!( + "{}\n", + md(t!( + "status.info_display.erased.item", + item = erased.display() + )) + ) + .as_str(), + ); + } + } + + // Collect moved items + if !data.analyzed_result.moved.is_empty() { + let mut table = SimpleTable::new(vec![ + format!("{}", md(t!("status.info_display.moved.header"))), + "".to_string(), + ]); + for (_, (from, to)) in data.analyzed_result.moved.iter() { + table.push_item(vec![ + format!( + "{}", + md(t!("status.info_display.moved.left", left = from.display())) + ), + format!( + "{}", + md(t!("status.info_display.moved.right", right = to.display())) + ), + ]); + } + info_moved.push_str(table.to_string().as_str()); + } + + // Collect lost items + if !data.analyzed_result.lost.is_empty() { + info_lost.push_str(format!("{}\n", md(t!("status.info_display.lost.header"))).as_str()); + for lost in data.analyzed_result.lost.iter() { + info_lost.push_str( + format!( + "{}\n", + md(t!("status.info_display.lost.item", item = lost.display())) + ) + .as_str(), + ); + } + } + + // Collect created items + if !data.analyzed_result.created.is_empty() { + info_created + .push_str(format!("{}\n", md(t!("status.info_display.created.header"))).as_str()); + for created in data.analyzed_result.created.iter() { + info_created.push_str( + format!( + "{}\n", + md(t!( + "status.info_display.created.item", + item = created.display() + )) + ) + .as_str(), + ); + } + } + + // Collect modified items + if !data.analyzed_result.modified.is_empty() { + info_modified + .push_str(format!("{}\n", md(t!("status.info_display.modified.header"))).as_str()); + for modified in data.analyzed_result.modified.iter() { + if let Some(reason) = data.wrong_modified_items.get(modified) { + let reason_str = match reason { + JVStatusWrongModifyReason::BaseVersionMismatch { + base_version, + latest_version, + } => md(t!( + "status.info_display.modified.reason.base_version_mismatch", + base_version = base_version, + latest_version = latest_version + )), + JVStatusWrongModifyReason::ModifiedButNotHeld { holder } => md(t!( + "status.info_display.modified.reason.modified_but_not_held", + holder = holder + )), + JVStatusWrongModifyReason::NoHolder => { + md(t!("status.info_display.modified.reason.no_holder")) + } + }; + info_modified.push_str( + format!( + "{}\n", + md(t!( + "status.info_display.modified.item_wrong", + item = modified.display(), + reason = reason_str + )) + ) + .as_str(), + ); + continue; + } + info_modified.push_str( + format!( + "{}\n", + md(t!( + "status.info_display.modified.item", + item = modified.display() + )) + ) + .as_str(), + ); + } + } + + let structural_info = vec![info_erased, info_moved, info_lost].join("\n"); + let content_info = vec![info_created, info_modified].join("\n"); + + let mode = get_mode(data); + match mode { + Mode::StructuralChangesMode => { + r_println!( + r, + "{}", + md(t!("status.current_mode.structural", info = structural_info)) + ); + } + Mode::ContentChangesMode => { + r_println!( + r, + "{}", + md(t!("status.current_mode.content", info = content_info)) + ); + } + Mode::Clean => r_println!(r, "{}", md(t!("status.current_mode.clean"))), + } +} + +fn render_hint(r: &mut JVRenderResult, data: &JVStatusOutput) { + // Outdate Hint + let update_time = &data.update_time; + let now_time = &data.now_time; + let duration_minutes: i64 = (now_time + .duration_since(*update_time) + .unwrap_or_default() + .as_secs() + / 60) as i64; + let outdate_minutes = auto_update_outdate(); + + // Outdated + if duration_minutes > outdate_minutes { + let hours = duration_minutes / 60; + let minutes = duration_minutes % 60; + let seconds = (now_time + .duration_since(*update_time) + .unwrap_or_default() + .as_secs() + % 60) as i64; + + r_println!( + r, + "{}", + md(t!( + "status.hints.outdate", + h = hours, + m = minutes, + s = seconds + )) + ); + } + + let in_ref_sheet = &data.in_ref_sheet; + let is_host_mode = &data.is_host_mode; + + // Readonly + if *in_ref_sheet && !is_host_mode { + r_println!(r, "{}", md(t!("status.hints.readonly"))); + } + + // Host + if *is_host_mode { + r_println!(r, "{}", md(t!("status.hints.host"))); + } +} + +fn get_mode(data: &JVStatusOutput) -> Mode { + let analyzed = &data.analyzed_result; + + // If there are any lost, moved, or erased items, use structural changes mode + if !analyzed.moved.is_empty() || !analyzed.lost.is_empty() || !analyzed.erased.is_empty() { + Mode::StructuralChangesMode + } + // Otherwise, if there are any created or modified items, use content changes mode + else if !analyzed.created.is_empty() || !analyzed.modified.is_empty() { + Mode::ContentChangesMode + } + // Otherwise, it's clean + else { + Mode::Clean + } +} diff --git a/src/cmds/status.rs b/src/cmds/status.rs deleted file mode 100644 index 6f04408..0000000 --- a/src/cmds/status.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::{collections::HashMap, time::SystemTime}; - -use just_enough_vcs::vcs::{ - constants::VAULT_HOST_NAME, data::local::workspace_analyzer::ModifiedRelativePathBuf, -}; - -use crate::{ - args::status::JVStatusArgument, - collects::status::JVStatusCollect, - inputs::status::JVStatusInput, - outputs::status::{JVStatusOutput, JVStatusWrongModifyReason}, - renderers::status::JVStatusRenderer, - systems::cmd::{ - cmd_system::{JVCommand, JVCommandContext}, - errors::{CmdExecuteError, CmdPrepareError}, - workspace_reader::LocalWorkspaceReader, - }, -}; - -pub struct JVStatusCommand; - -impl JVCommand - for JVStatusCommand -{ - async fn prepare( - _args: &JVStatusArgument, - _ctx: &JVCommandContext, - ) -> Result { - Ok(JVStatusInput) - } - - async fn collect( - _args: &JVStatusArgument, - _ctx: &JVCommandContext, - ) -> Result { - // Initialize a reader for the local workspace and a default result structure - let mut reader = LocalWorkspaceReader::default(); - let mut collect = JVStatusCollect::default(); - - // Analyze the current status of the local workspace - // (detects changes like created, modified, moved, etc.) - let analyzed = reader.analyze_local_status().await?; - - // Retrieve the current account (member) ID - let account = reader.current_account().await?; - - // Retrieve the name of the current sheet - let sheet_name = reader.sheet_name().await?; - - // Is Host Mode - let is_host_mode = reader.is_host_mode().await?; - - let cached_sheet = reader.cached_sheet(&sheet_name).await?; - let sheet_holder = cached_sheet.holder().cloned().unwrap_or_default(); - let is_ref_sheet = sheet_holder == VAULT_HOST_NAME; - - // Get Latest file data - let latest_file_data = reader.pop_latest_file_data(&account).await?; - - // Get the timestamp of the last update, defaulting to the current time if not available - let update_time = reader - .latest_info() - .await? - .update_instant - .unwrap_or(SystemTime::now()); - - // Record the current system time - let now_time = SystemTime::now(); - - // Populate the result structure with the gathered data - collect.current_account = account; - collect.current_sheet = sheet_name; - collect.is_host_mode = is_host_mode; - collect.in_ref_sheet = is_ref_sheet; - collect.analyzed_result = analyzed; - collect.update_time = update_time; - collect.now_time = now_time; - collect.latest_file_data = latest_file_data; - Ok(collect) - } - - async fn exec( - _input: JVStatusInput, - collect: JVStatusCollect, - ) -> Result { - let mut wrong_modified_items: HashMap = - HashMap::new(); - - let latest_file_data = &collect.latest_file_data; - - // Calculate whether modifications are correc - let modified = &collect.analyzed_result.modified; - for item in modified { - // Get mapping - let Ok(mapping) = collect.local_sheet_data.mapping_data(&item) else { - continue; - }; - - // Check base version - { - let base_version = mapping.version_when_updated().clone(); - let Some(latest_version) = latest_file_data - .file_version(mapping.mapping_vfid()) - .cloned() - else { - continue; - }; - - // Base version dismatch - if base_version != latest_version { - wrong_modified_items.insert( - item.clone(), - JVStatusWrongModifyReason::BaseVersionMismatch { - base_version, - latest_version, - }, - ); - continue; - } - } - - // Check edit right (only check when current is not HOST) - if collect.current_account != VAULT_HOST_NAME { - let holder = latest_file_data.file_holder(mapping.mapping_vfid()); - if holder.is_none() { - wrong_modified_items.insert(item.clone(), JVStatusWrongModifyReason::NoHolder); - continue; - } - - let holder = holder.cloned().unwrap(); - if &collect.current_account != &holder { - wrong_modified_items.insert( - item.clone(), - JVStatusWrongModifyReason::ModifiedButNotHeld { holder: holder }, - ); - } - } - } - - let output = JVStatusOutput { - current_account: collect.current_account, - current_sheet: collect.current_sheet, - is_host_mode: collect.is_host_mode, - in_ref_sheet: collect.in_ref_sheet, - analyzed_result: collect.analyzed_result, - wrong_modified_items: wrong_modified_items, - update_time: collect.update_time, - now_time: collect.now_time, - }; - - Ok(output) - } - - fn get_help_str() -> String { - "".to_string() - } -} diff --git a/src/collects/status.rs b/src/collects/status.rs deleted file mode 100644 index b0e8fcd..0000000 --- a/src/collects/status.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::time::SystemTime; - -use just_enough_vcs::vcs::data::{ - local::{ - latest_file_data::LatestFileData, local_sheet::LocalSheetData, - workspace_analyzer::AnalyzeResultPure, - }, - member::MemberId, - sheet::SheetName, -}; - -pub struct JVStatusCollect { - pub current_account: MemberId, - pub current_sheet: SheetName, - pub is_host_mode: bool, - pub in_ref_sheet: bool, - pub analyzed_result: AnalyzeResultPure, - pub latest_file_data: LatestFileData, - pub local_sheet_data: LocalSheetData, - pub update_time: SystemTime, - pub now_time: SystemTime, -} - -impl Default for JVStatusCollect { - fn default() -> Self { - Self { - current_account: MemberId::default(), - current_sheet: SheetName::default(), - is_host_mode: false, - in_ref_sheet: false, - analyzed_result: AnalyzeResultPure::default(), - latest_file_data: LatestFileData::default(), - local_sheet_data: LocalSheetData::default(), - update_time: SystemTime::now(), - now_time: SystemTime::now(), - } - } -} diff --git a/src/inputs/status.rs b/src/inputs/status.rs deleted file mode 100644 index 859ccd2..0000000 --- a/src/inputs/status.rs +++ /dev/null @@ -1 +0,0 @@ -pub struct JVStatusInput; diff --git a/src/lib.rs b/src/lib.rs index d4832f5..74b68f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,16 +11,5 @@ pub mod legacy_json_output; /// Systems pub mod systems; -// --- ASSETS --- - /// Commands pub mod cmds; - -/// Command Data -pub mod args; -pub mod collects; -pub mod inputs; -pub mod outputs; - -/// Result Renderers -pub mod renderers; diff --git a/src/outputs/status.rs b/src/outputs/status.rs deleted file mode 100644 index 2b8d9c6..0000000 --- a/src/outputs/status.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::{collections::HashMap, time::SystemTime}; - -use just_enough_vcs::vcs::data::{ - local::workspace_analyzer::{AnalyzeResultPure, ModifiedRelativePathBuf}, - member::MemberId, - sheet::SheetName, -}; -use serde::Serialize; - -#[derive(Serialize)] -pub struct JVStatusOutput { - pub current_account: MemberId, - pub current_sheet: SheetName, - pub is_host_mode: bool, - pub in_ref_sheet: bool, - pub analyzed_result: AnalyzeResultPure, - pub wrong_modified_items: HashMap, - pub update_time: SystemTime, - pub now_time: SystemTime, -} - -#[derive(Serialize)] -pub enum JVStatusWrongModifyReason { - BaseVersionMismatch { - base_version: String, - latest_version: String, - }, - ModifiedButNotHeld { - holder: String, - }, - NoHolder, -} - -impl Default for JVStatusOutput { - fn default() -> Self { - Self { - current_account: MemberId::default(), - current_sheet: SheetName::default(), - is_host_mode: false, - in_ref_sheet: false, - analyzed_result: AnalyzeResultPure::default(), - wrong_modified_items: HashMap::new(), - update_time: SystemTime::now(), - now_time: SystemTime::now(), - } - } -} diff --git a/src/renderers/json.rs b/src/renderers/json.rs deleted file mode 100644 index 9a3105d..0000000 --- a/src/renderers/json.rs +++ /dev/null @@ -1,27 +0,0 @@ -use serde::Serialize; -use serde_json; - -use crate::{ - r_print, - systems::cmd::{ - errors::CmdRenderError, - renderer::{JVRenderResult, JVResultRenderer}, - }, -}; - -pub struct JVResultJsonRenderer; - -impl JVResultRenderer for JVResultJsonRenderer -where - T: Serialize + Sync, -{ - async fn render(data: &T) -> Result { - let mut r = JVRenderResult::default(); - let json_string = serde_json::to_string(data) - .map_err(|e| CmdRenderError::SerializeFailed(e.to_string()))?; - - r_print!(r, "{}", json_string); - - Ok(r) - } -} diff --git a/src/renderers/json_pretty.rs b/src/renderers/json_pretty.rs deleted file mode 100644 index a4a3ba5..0000000 --- a/src/renderers/json_pretty.rs +++ /dev/null @@ -1,26 +0,0 @@ -use serde::Serialize; - -use crate::{ - r_print, - systems::cmd::{ - errors::CmdRenderError, - renderer::{JVRenderResult, JVResultRenderer}, - }, -}; - -pub struct JVResultPrettyJsonRenderer; - -impl JVResultRenderer for JVResultPrettyJsonRenderer -where - T: Serialize + Sync, -{ - async fn render(data: &T) -> Result { - let mut r = JVRenderResult::default(); - let json_string = serde_json::to_string_pretty(data) - .map_err(|e| CmdRenderError::SerializeFailed(e.to_string()))?; - - r_print!(r, "{}", json_string); - - Ok(r) - } -} diff --git a/src/renderers/status.rs b/src/renderers/status.rs deleted file mode 100644 index 549211e..0000000 --- a/src/renderers/status.rs +++ /dev/null @@ -1,262 +0,0 @@ -use cli_utils::{ - display::{SimpleTable, md}, - env::auto_update_outdate, -}; -use rust_i18n::t; - -use crate::{ - outputs::status::{JVStatusOutput, JVStatusWrongModifyReason}, - r_println, - systems::cmd::{ - errors::CmdRenderError, - renderer::{JVRenderResult, JVResultRenderer}, - }, -}; - -pub struct JVStatusRenderer; - -enum Mode { - StructuralChangesMode, - ContentChangesMode, - Clean, -} - -impl JVResultRenderer for JVStatusRenderer { - async fn render(data: &JVStatusOutput) -> Result { - let mut r = JVRenderResult::default(); - - // Render Header - render_header(&mut r, data); - - // Render Info and Mode - render_info_and_mode(&mut r, data); - - // Render Hint - render_hint(&mut r, data); - - Ok(r) - } -} - -fn render_header(r: &mut JVRenderResult, data: &JVStatusOutput) { - let account = &data.current_account; - let sheet = &data.current_sheet; - r_println!( - r, - "{}", - md(t!("status.header", account = account, sheet = sheet)) - ); -} - -fn render_info_and_mode(r: &mut JVRenderResult, data: &JVStatusOutput) { - let mut info_erased = String::default(); - let mut info_moved = String::default(); - let mut info_lost = String::default(); - let mut info_created = String::default(); - let mut info_modified = String::default(); - - // Collect erased items - if !data.analyzed_result.erased.is_empty() { - info_erased.push_str(format!("{}\n", md(t!("status.info_display.erased.header"))).as_str()); - for erased in data.analyzed_result.erased.iter() { - info_erased.push_str( - format!( - "{}\n", - md(t!( - "status.info_display.erased.item", - item = erased.display() - )) - ) - .as_str(), - ); - } - } - - // Collect moved items - if !data.analyzed_result.moved.is_empty() { - let mut table = SimpleTable::new(vec![ - format!("{}", md(t!("status.info_display.moved.header"))), - "".to_string(), - ]); - for (_, (from, to)) in data.analyzed_result.moved.iter() { - table.push_item(vec![ - format!( - "{}", - md(t!("status.info_display.moved.left", left = from.display())) - ), - format!( - "{}", - md(t!("status.info_display.moved.right", right = to.display())) - ), - ]); - } - info_moved.push_str(table.to_string().as_str()); - } - - // Collect lost items - if !data.analyzed_result.lost.is_empty() { - info_lost.push_str(format!("{}\n", md(t!("status.info_display.lost.header"))).as_str()); - for lost in data.analyzed_result.lost.iter() { - info_lost.push_str( - format!( - "{}\n", - md(t!("status.info_display.lost.item", item = lost.display())) - ) - .as_str(), - ); - } - } - - // Collect created items - if !data.analyzed_result.created.is_empty() { - info_created - .push_str(format!("{}\n", md(t!("status.info_display.created.header"))).as_str()); - for created in data.analyzed_result.created.iter() { - info_created.push_str( - format!( - "{}\n", - md(t!( - "status.info_display.created.item", - item = created.display() - )) - ) - .as_str(), - ); - } - } - - // Collect modified items - if !data.analyzed_result.modified.is_empty() { - info_modified - .push_str(format!("{}\n", md(t!("status.info_display.modified.header"))).as_str()); - for modified in data.analyzed_result.modified.iter() { - if let Some(reason) = data.wrong_modified_items.get(modified) { - let reason_str = match reason { - JVStatusWrongModifyReason::BaseVersionMismatch { - base_version, - latest_version, - } => md(t!( - "status.info_display.modified.reason.base_version_mismatch", - base_version = base_version, - latest_version = latest_version - )), - JVStatusWrongModifyReason::ModifiedButNotHeld { holder } => md(t!( - "status.info_display.modified.reason.modified_but_not_held", - holder = holder - )), - JVStatusWrongModifyReason::NoHolder => { - md(t!("status.info_display.modified.reason.no_holder")) - } - }; - info_modified.push_str( - format!( - "{}\n", - md(t!( - "status.info_display.modified.item_wrong", - item = modified.display(), - reason = reason_str - )) - ) - .as_str(), - ); - continue; - } - info_modified.push_str( - format!( - "{}\n", - md(t!( - "status.info_display.modified.item", - item = modified.display() - )) - ) - .as_str(), - ); - } - } - - let structural_info = vec![info_erased, info_moved, info_lost].join("\n"); - let content_info = vec![info_created, info_modified].join("\n"); - - let mode = get_mode(data); - match mode { - Mode::StructuralChangesMode => { - r_println!( - r, - "{}", - md(t!("status.current_mode.structural", info = structural_info)) - ); - } - Mode::ContentChangesMode => { - r_println!( - r, - "{}", - md(t!("status.current_mode.content", info = content_info)) - ); - } - Mode::Clean => r_println!(r, "{}", md(t!("status.current_mode.clean"))), - } -} - -fn render_hint(r: &mut JVRenderResult, data: &JVStatusOutput) { - // Outdate Hint - let update_time = &data.update_time; - let now_time = &data.now_time; - let duration_minutes: i64 = (now_time - .duration_since(*update_time) - .unwrap_or_default() - .as_secs() - / 60) as i64; - let outdate_minutes = auto_update_outdate(); - - // Outdated - if duration_minutes > outdate_minutes { - let hours = duration_minutes / 60; - let minutes = duration_minutes % 60; - let seconds = (now_time - .duration_since(*update_time) - .unwrap_or_default() - .as_secs() - % 60) as i64; - - r_println!( - r, - "{}", - md(t!( - "status.hints.outdate", - h = hours, - m = minutes, - s = seconds - )) - ); - } - - let in_ref_sheet = &data.in_ref_sheet; - let is_host_mode = &data.is_host_mode; - - // Readonly - if *in_ref_sheet && !is_host_mode { - r_println!(r, "{}", md(t!("status.hints.readonly"))); - } - - // Host - if *is_host_mode { - r_println!(r, "{}", md(t!("status.hints.host"))); - } -} - -fn get_mode(data: &JVStatusOutput) -> Mode { - let analyzed = &data.analyzed_result; - - // If there are any lost, moved, or erased items, use structural changes mode - if !analyzed.moved.is_empty() || !analyzed.lost.is_empty() || !analyzed.erased.is_empty() { - Mode::StructuralChangesMode - } - // Otherwise, if there are any created or modified items, use content changes mode - else if !analyzed.created.is_empty() || !analyzed.modified.is_empty() { - Mode::ContentChangesMode - } - // Otherwise, it's clean - else { - Mode::Clean - } -} -- cgit