diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-01-22 14:24:50 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-01-22 14:24:50 +0800 |
| commit | 47bf9b75f6dd8c2d3c3f1fb947a16e0e055f49cf (patch) | |
| tree | c767e331e68134e19caeeb03269525be7b4fe6e1 /src/cmd | |
| parent | 53c26d656f975f93319dd432e409c1ea740ce06d (diff) | |
Add renderer system and implement status command
Diffstat (limited to 'src/cmd')
| -rw-r--r-- | src/cmd/cmd_system.rs | 29 | ||||
| -rw-r--r-- | src/cmd/cmds/status.rs | 105 | ||||
| -rw-r--r-- | src/cmd/cmds/template.rs | 2 | ||||
| -rw-r--r-- | src/cmd/errors.rs | 32 | ||||
| -rw-r--r-- | src/cmd/processer.rs | 3 | ||||
| -rw-r--r-- | src/cmd/renderers.rs | 1 | ||||
| -rw-r--r-- | src/cmd/renderers/json_renderer.rs | 44 |
7 files changed, 195 insertions, 21 deletions
diff --git a/src/cmd/cmd_system.rs b/src/cmd/cmd_system.rs index 3edd5cc..229c7f0 100644 --- a/src/cmd/cmd_system.rs +++ b/src/cmd/cmd_system.rs @@ -2,7 +2,7 @@ use serde::Serialize; use crate::{ cmd::{ - errors::{CmdExecuteError, CmdPrepareError, CmdProcessError}, + errors::{CmdExecuteError, CmdPrepareError, CmdProcessError, CmdRenderError}, renderer::{JVRenderResult, JVResultRenderer}, }, r_println, @@ -24,11 +24,30 @@ where /// Get help string for the command fn get_help_str() -> String; + /// Process the command with a specified renderer, performing any necessary post-execution processing + #[rustfmt::skip] + fn process_with_renderer_flag( + args: Vec<String>, + ctx: JVCommandContext, + renderer: String, + ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send + where + Self: Sync, + { + async move { + let renderer_str = renderer.as_str(); + include!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/cmd/renderers/renderer_list.txt" + )) + } + } + /// performing any necessary post-execution processing fn process( args: Vec<String>, ctx: JVCommandContext, - ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send + Sync + ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send where Self: Sync, { @@ -40,7 +59,7 @@ where fn process_with_renderer<R: JVResultRenderer<Output> + Send + Sync>( args: Vec<String>, ctx: JVCommandContext, - ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send + Sync + ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send where Self: Sync, { @@ -77,9 +96,9 @@ where fn prepare( args: Argument, ctx: JVCommandContext, - ) -> impl Future<Output = Result<Input, CmdPrepareError>> + Send + Sync; + ) -> impl Future<Output = Result<Input, CmdPrepareError>> + Send; /// Run the command phase, /// returning an output structure, waiting for rendering - fn exec(args: Input) -> impl Future<Output = Result<Output, CmdExecuteError>> + Send + Sync; + fn exec(input: Input) -> impl Future<Output = Result<Output, CmdExecuteError>> + Send; } diff --git a/src/cmd/cmds/status.rs b/src/cmd/cmds/status.rs index bbc78e8..d73a28a 100644 --- a/src/cmd/cmds/status.rs +++ b/src/cmd/cmds/status.rs @@ -1,10 +1,28 @@ +use std::{ + collections::{HashMap, HashSet}, + path::PathBuf, + time::SystemTime, +}; + use clap::Parser; +use just_enough_vcs::vcs::data::{ + local::workspace_analyzer::{ + CreatedRelativePathBuf, FromRelativePathBuf, LostRelativePathBuf, ModifiedRelativePathBuf, + ToRelativePathBuf, + }, + member::MemberId, + sheet::SheetName, + vault::virtual_file::VirtualFileId, +}; use serde::Serialize; -use crate::cmd::{ - cmd_system::{JVCommand, JVCommandContext}, - errors::{CmdExecuteError, CmdPrepareError, CmdRenderError}, - renderer::{JVRenderResult, JVResultRenderer}, +use crate::{ + cmd::{ + cmd_system::{JVCommand, JVCommandContext}, + errors::{CmdExecuteError, CmdPrepareError, CmdRenderError}, + renderer::{JVRenderResult, JVResultRenderer}, + }, + utils::workspace_reader::LocalWorkspaceReader, }; pub struct JVStatusCommand; @@ -12,23 +30,82 @@ pub struct JVStatusCommand; #[derive(Parser, Debug)] pub struct JVStatusArgument; -pub struct JVStatusInput; - #[derive(Serialize)] -pub struct JVStatusOutput; +pub struct JVStatusResult { + pub current_account: MemberId, + pub current_sheet: SheetName, + pub moved: HashMap<VirtualFileId, (FromRelativePathBuf, ToRelativePathBuf)>, + pub created: HashSet<CreatedRelativePathBuf>, + pub lost: HashSet<LostRelativePathBuf>, + pub erased: HashSet<PathBuf>, + pub modified: HashSet<ModifiedRelativePathBuf>, + pub update_time: SystemTime, + pub now_time: SystemTime, +} + +impl Default for JVStatusResult { + fn default() -> Self { + Self { + current_account: MemberId::default(), + current_sheet: SheetName::default(), + moved: HashMap::default(), + created: HashSet::default(), + lost: HashSet::default(), + erased: HashSet::default(), + modified: HashSet::default(), + update_time: SystemTime::now(), + now_time: SystemTime::now(), + } + } +} -impl JVCommand<JVStatusArgument, JVStatusInput, JVStatusOutput, JVStatusRenderer> +impl JVCommand<JVStatusArgument, JVStatusResult, JVStatusResult, JVStatusRenderer> for JVStatusCommand { async fn prepare( _args: JVStatusArgument, _ctx: JVCommandContext, - ) -> Result<JVStatusInput, CmdPrepareError> { - Ok(JVStatusInput) + ) -> Result<JVStatusResult, CmdPrepareError> { + // Initialize a reader for the local workspace and a default result structure + let mut reader = LocalWorkspaceReader::default(); + let mut input = JVStatusResult::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?; + + // 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 + input.current_account = account; + input.current_sheet = sheet_name; + input.moved = analyzed.moved; + input.created = analyzed.created; + input.lost = analyzed.lost; + input.erased = analyzed.erased; + input.modified = analyzed.modified; + input.update_time = update_time; + input.now_time = now_time; + + Ok(input) } - async fn exec(args: JVStatusInput) -> Result<JVStatusOutput, CmdExecuteError> { - todo!() + async fn exec(input: JVStatusResult) -> Result<JVStatusResult, CmdExecuteError> { + Ok(input) // Analyze command, no needs execute } fn get_help_str() -> String { @@ -38,8 +115,8 @@ impl JVCommand<JVStatusArgument, JVStatusInput, JVStatusOutput, JVStatusRenderer pub struct JVStatusRenderer; -impl JVResultRenderer<JVStatusOutput> for JVStatusRenderer { - async fn render(data: &JVStatusOutput) -> Result<JVRenderResult, CmdRenderError> { +impl JVResultRenderer<JVStatusResult> for JVStatusRenderer { + async fn render(data: &JVStatusResult) -> Result<JVRenderResult, CmdRenderError> { todo!() } } diff --git a/src/cmd/cmds/template.rs b/src/cmd/cmds/template.rs index 8874121..1c56c29 100644 --- a/src/cmd/cmds/template.rs +++ b/src/cmd/cmds/template.rs @@ -27,7 +27,7 @@ impl JVCommand<JVUnknownArgument, JVUnknownInput, JVUnknownOutput, JVStatusRende todo!() } - async fn exec(_args: JVUnknownInput) -> Result<JVUnknownOutput, CmdExecuteError> { + async fn exec(_input: JVUnknownInput) -> Result<JVUnknownOutput, CmdExecuteError> { todo!() } diff --git a/src/cmd/errors.rs b/src/cmd/errors.rs index e1cf835..358d15a 100644 --- a/src/cmd/errors.rs +++ b/src/cmd/errors.rs @@ -1,3 +1,5 @@ +use just_enough_vcs::vcs::data::{member::MemberId, sheet::SheetName}; + #[derive(thiserror::Error, Debug)] pub enum CmdPrepareError { #[error("IO error: {0}")] @@ -5,6 +7,30 @@ pub enum CmdPrepareError { #[error("{0}")] Error(String), + + #[error("LocalWorkspace not found")] + LocalWorkspaceNotFound, + + #[error("LocalConfig not found")] + LocalConfigNotFound, + + #[error("LatestInfo not found")] + LatestInfoNotFound, + + #[error("LatestFileData of {0} not found")] + LatestFileDataNotExist(MemberId), + + #[error("CachedSheet `{0}` not found")] + CachedSheetNotFound(SheetName), + + #[error("LocalSheet `{0}/{1}` not found")] + LocalSheetNotFound(MemberId, SheetName), + + #[error("LocalStatusAnalyzeFailed")] + LocalStatusAnalyzeFailed, + + #[error("No sheet in use")] + NoSheetInUse, } impl CmdPrepareError { @@ -44,6 +70,12 @@ pub enum CmdRenderError { #[error("{0}")] Error(String), + + #[error("Serialize failed, {0}")] + SerializeFailed(String), + + #[error("Renderer `{0}` not found")] + RendererNotFound(String), } impl CmdRenderError { diff --git a/src/cmd/processer.rs b/src/cmd/processer.rs index bc84b7d..f5fc2a6 100644 --- a/src/cmd/processer.rs +++ b/src/cmd/processer.rs @@ -6,6 +6,7 @@ use crate::cmd::renderer::JVRenderResult; pub async fn jv_cmd_process( args: Vec<String>, ctx: JVCommandContext, + renderer_override: String, ) -> Result<JVRenderResult, CmdProcessError> { let nodes = jv_cmd_nodes(); let command = args.join(" "); @@ -25,7 +26,7 @@ pub async fn jv_cmd_process( let matched_prefix = matching_nodes[0]; let prefix_len = matched_prefix.split_whitespace().count(); let trimmed_args: Vec<String> = args.into_iter().skip(prefix_len).collect(); - return jv_cmd_process_node(matched_prefix, trimmed_args, ctx).await; + return jv_cmd_process_node(matched_prefix, trimmed_args, ctx, renderer_override).await; } _ => { // Multiple matching nodes found diff --git a/src/cmd/renderers.rs b/src/cmd/renderers.rs new file mode 100644 index 0000000..91fa88e --- /dev/null +++ b/src/cmd/renderers.rs @@ -0,0 +1 @@ +pub mod json_renderer; diff --git a/src/cmd/renderers/json_renderer.rs b/src/cmd/renderers/json_renderer.rs new file mode 100644 index 0000000..14c1f81 --- /dev/null +++ b/src/cmd/renderers/json_renderer.rs @@ -0,0 +1,44 @@ +use serde::Serialize; +use serde_json; + +use crate::{ + cmd::{ + errors::CmdRenderError, + renderer::{JVRenderResult, JVResultRenderer}, + }, + r_print, +}; + +pub struct JVResultJsonRenderer; + +impl<T> JVResultRenderer<T> for JVResultJsonRenderer +where + T: Serialize + Sync, +{ + async fn render(data: &T) -> Result<JVRenderResult, CmdRenderError> { + 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) + } +} + +pub struct JVResultPrettyJsonRenderer; + +impl<T> JVResultRenderer<T> for JVResultPrettyJsonRenderer +where + T: Serialize + Sync, +{ + async fn render(data: &T) -> Result<JVRenderResult, CmdRenderError> { + 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) + } +} |
