use clap::ArgMatches;
use std::cell::RefCell;
use std::rc::Rc;
use crate::cli::handler::Output as HandlerOutput;
use crate::cli::handler::{CommandContext, RunError, RunErrorKind};
use crate::cli::hooks::Hooks;
use crate::context::{ContextRegistry, RenderContext};
use crate::StructuredOutputProjection;
use crate::Theme;
use serde::Serialize;
pub use standout_dispatch::{
extract_command_path, get_deepest_matches, has_subcommand, insert_default_command,
};
pub enum DispatchOutput {
Text {
formatted: String,
raw: String,
},
Binary(Vec<u8>, String),
Silent,
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn render_handler_output<T: Serialize>(
result: Result<HandlerOutput<T>, String>,
matches: &ArgMatches,
ctx: &CommandContext,
hooks: Option<&Hooks>,
template: &str,
theme: &Theme,
context_registry: &ContextRegistry,
template_engine: &dyn standout_render::template::TemplateEngine,
output_mode: crate::OutputMode,
structured_output_projection: Option<&StructuredOutputProjection>,
) -> Result<DispatchOutput, RunError> {
match result {
Ok(output) => match output {
HandlerOutput::Render(data) => {
let mut json_data = serde_json::to_value(&data).map_err(|e| {
RunError::new(
format!("Failed to serialize handler result: {}", e),
RunErrorKind::Render,
)
})?;
if let Some(hooks) = hooks {
json_data = hooks
.run_post_dispatch(matches, ctx, json_data)
.map_err(|e| {
RunError::new(format!("Hook error: {}", e), RunErrorKind::Hook(e.phase))
})?;
}
let render_ctx = RenderContext::new(
output_mode,
standout_render::detect_terminal_width(),
theme,
&json_data,
);
let render_result = match (output_mode, structured_output_projection) {
(crate::OutputMode::Csv, Some(projection)) => {
standout_render::template::RenderResult::plain(
projection
.csv_projection()
.render(&json_data)
.map_err(|e| RunError::new(e.to_string(), RunErrorKind::Render))?,
)
}
_ => standout_render::template::render_auto_with_engine_split(
template_engine,
template,
&json_data,
theme,
output_mode,
context_registry,
&render_ctx,
)
.map_err(|e| RunError::new(e.to_string(), RunErrorKind::Render))?,
};
Ok(DispatchOutput::Text {
formatted: render_result.formatted,
raw: render_result.raw,
})
}
HandlerOutput::Silent => Ok(DispatchOutput::Silent),
HandlerOutput::Binary { data, filename } => Ok(DispatchOutput::Binary(data, filename)),
},
Err(e) => Err(RunError::new(
format!("Error: {}", e),
RunErrorKind::Handler,
)),
}
}
pub type DispatchFn = Rc<
RefCell<
dyn FnMut(
&ArgMatches,
&CommandContext,
Option<&Hooks>,
crate::OutputMode,
&crate::Theme,
) -> Result<DispatchOutput, RunError>,
>,
>;
pub fn dispatch(
dispatch_fn: &DispatchFn,
matches: &ArgMatches,
ctx: &CommandContext,
hooks: Option<&Hooks>,
output_mode: crate::OutputMode,
theme: &crate::Theme,
) -> Result<DispatchOutput, RunError> {
(dispatch_fn.borrow_mut())(matches, ctx, hooks, output_mode, theme)
}