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 where Argument: clap::Parser + Send + Sync, Input: Send + Sync, Output: Serialize + Send + Sync, Renderer: JVResultRenderer + 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, ctx: JVCommandContext, renderer: String, ) -> impl Future> + 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, ctx: JVCommandContext, ) -> impl Future> + Send where Self: Sync, { Self::process_with_renderer::(args, ctx) } /// Process the command output with a custom renderer, /// performing any necessary post-execution processing fn process_with_renderer + Send + Sync>( args: Vec, ctx: JVCommandContext, ) -> impl Future> + 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> + Send; /// Run the command phase, /// returning an output structure, waiting for rendering fn exec(input: Input) -> impl Future> + Send; }