summaryrefslogtreecommitdiff
path: root/src/systems/cmd/cmd_system.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-01-23 04:49:34 +0800
committer魏曹先生 <1992414357@qq.com>2026-01-23 04:49:34 +0800
commit626536ce51975b051fea087620bc1eb7f6bc69d3 (patch)
treeb24916b22012d9b8b3b09366bca9911781e6d596 /src/systems/cmd/cmd_system.rs
parentf607f6ac3b98d00370f613e674da7beb4c61ce58 (diff)
Reorganize project structure into systems and assets
Diffstat (limited to 'src/systems/cmd/cmd_system.rs')
-rw-r--r--src/systems/cmd/cmd_system.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/systems/cmd/cmd_system.rs b/src/systems/cmd/cmd_system.rs
new file mode 100644
index 0000000..65f972d
--- /dev/null
+++ b/src/systems/cmd/cmd_system.rs
@@ -0,0 +1,100 @@
+use serde::Serialize;
+
+use crate::{
+ r_println,
+ systems::cmd::{
+ errors::{CmdExecuteError, CmdPrepareError, CmdProcessError, CmdRenderError},
+ renderer::{JVRenderResult, JVResultRenderer},
+ },
+};
+use std::future::Future;
+
+pub struct JVCommandContext {
+ pub help: bool,
+ pub confirmed: bool,
+}
+
+pub trait JVCommand<Argument, Input, Output, Renderer>
+where
+ Argument: clap::Parser + Send + Sync,
+ Input: Send + Sync,
+ Output: Serialize + Send + Sync,
+ Renderer: JVResultRenderer<Output> + Send + Sync,
+{
+ /// Get help string for the command
+ fn get_help_str() -> String;
+
+ /// Process the command with a specified renderer, performing any necessary post-execution processing
+ 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!("_renderers.rs")
+ }
+ }
+
+ /// performing any necessary post-execution processing
+ fn process(
+ args: Vec<String>,
+ ctx: JVCommandContext,
+ ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send
+ where
+ Self: Sync,
+ {
+ Self::process_with_renderer::<Renderer>(args, ctx)
+ }
+
+ /// Process the command output with a custom renderer,
+ /// performing any necessary post-execution processing
+ fn process_with_renderer<R: JVResultRenderer<Output> + Send + Sync>(
+ args: Vec<String>,
+ ctx: JVCommandContext,
+ ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send
+ where
+ Self: Sync,
+ {
+ async move {
+ let mut full_args = vec!["jv".to_string()];
+ full_args.extend(args);
+ let parsed_args = match Argument::try_parse_from(full_args) {
+ Ok(args) => args,
+ Err(_) => return Err(CmdProcessError::ParseError(Self::get_help_str())),
+ };
+ // If the help flag is used, skip execution and directly print help
+ if ctx.help {
+ let mut r = JVRenderResult::default();
+ r_println!(r, "{}", Self::get_help_str());
+ return Ok(r);
+ }
+ let input = match Self::prepare(parsed_args, ctx).await {
+ Ok(input) => input,
+ Err(e) => return Err(CmdProcessError::from(e)),
+ };
+ let output = match Self::exec(input).await {
+ Ok(output) => output,
+ Err(e) => return Err(CmdProcessError::from(e)),
+ };
+ match R::render(&output).await {
+ Ok(r) => Ok(r),
+ Err(e) => Err(CmdProcessError::from(e)),
+ }
+ }
+ }
+
+ /// Prepare to run the command,
+ /// converting Clap input into the command's supported input
+ fn prepare(
+ args: Argument,
+ ctx: JVCommandContext,
+ ) -> impl Future<Output = Result<Input, CmdPrepareError>> + Send;
+
+ /// Run the command phase,
+ /// returning an output structure, waiting for rendering
+ fn exec(input: Input) -> impl Future<Output = Result<Output, CmdExecuteError>> + Send;
+}