use cli_fmt::help::{ CliHelpStyle, DetailPageData, DetailPageTemplate, DetailSection, ExampleEntry, OptionEntry };
use crate::model::{ HelpCommandData, HelpParamData };
use crate::verbosity::HelpDisplayOptions;
#[ derive( Debug, Clone, Default ) ]
pub struct CliFmtRenderer
{
pub style : CliHelpStyle,
pub options : HelpDisplayOptions,
}
impl CliFmtRenderer
{
#[ must_use ]
pub fn new() -> Self
{
Self::default()
}
#[ must_use ]
pub fn with_style( mut self, style : CliHelpStyle ) -> Self
{
self.style = style;
self
}
#[ must_use ]
pub fn with_options( mut self, options : HelpDisplayOptions ) -> Self
{
self.options = options;
self
}
#[ must_use ]
pub fn render_param( &self, command : &HelpCommandData, param : &HelpParamData ) -> String
{
let mut page = DetailPageData::default();
page.label = "Parameter".into();
page.name = param.name.clone();
page.usage.push( format!( "{} {}::<{}>", command.name, param.name, param.kind_compact ) );
let desc_text = if param.description.is_empty() { ¶m.hint } else { ¶m.description };
if !desc_text.is_empty()
{
page.description.push( desc_text.clone() );
if !param.hint.is_empty() && param.hint != *desc_text
{
page.description.push( param.hint.clone() );
}
}
let mut facts = vec!
[
OptionEntry { name : "Kind".into(), desc : param.kind.clone() },
OptionEntry
{
name : "Required".into(),
desc : ( if param.optional { "no" } else { "yes" } ).into(),
},
];
if param.multiple
{
facts.push( OptionEntry { name : "Multiple".into(), desc : "yes".into() } );
}
if let Some( default ) = ¶m.default
{
facts.push( OptionEntry { name : "Default".into(), desc : default.clone() } );
}
if !param.aliases.is_empty()
{
facts.push( OptionEntry { name : "Aliases".into(), desc : param.aliases.join( ", " ) } );
}
if !param.validation_rules.is_empty()
{
facts.push( OptionEntry { name : "Validation".into(), desc : param.validation_rules.join( ", " ) } );
}
page.sections.push( DetailSection::new( "", facts ) );
if !param.choices.is_empty()
{
let choices = param.choices.iter()
.map( | choice | OptionEntry { name : choice.clone(), desc : String::new() } )
.collect();
page.sections.push( DetailSection::new( "Possible values", choices ) );
}
page.examples = param.examples.iter()
.map( | example | ExampleEntry { invocation : example.clone(), desc : None } )
.collect();
DetailPageTemplate::new( self.style.clone(), page ).render()
}
#[ must_use ]
pub fn render_command( &self, command : &HelpCommandData ) -> String
{
let mut page = DetailPageData::default();
page.label = "Command".into();
page.name = command.name.clone();
let mut usage = command.name.clone();
for param in &command.params
{
if param.optional
{
usage.push_str( &format!( " [{}::<{}>]", param.name, param.kind_compact ) );
}
else
{
usage.push_str( &format!( " {}::<{}>", param.name, param.kind_compact ) );
}
}
page.usage.push( usage );
if !command.description.is_empty()
{
page.description.push( command.description.clone() );
}
if !command.hint.is_empty() && command.hint != command.description
{
page.description.push( command.hint.clone() );
}
let mut facts = Vec::new();
if self.options.show_status && !command.status.is_empty()
{
facts.push( OptionEntry { name : "Status".into(), desc : command.status.clone() } );
}
if command.show_version && self.options.show_version && !command.version.is_empty()
{
facts.push( OptionEntry { name : "Version".into(), desc : command.version.clone() } );
}
if !command.aliases.is_empty() && self.options.show_aliases
{
facts.push( OptionEntry { name : "Aliases".into(), desc : command.aliases.join( ", " ) } );
}
if !command.tags.is_empty() && self.options.show_tags
{
facts.push( OptionEntry { name : "Tags".into(), desc : command.tags.join( ", " ) } );
}
page.sections.push( DetailSection::new( "", facts ) );
let params = command.params.iter().map( | param |
{
let desc_text = if param.description.is_empty() { ¶m.hint } else { ¶m.description };
let mut desc = desc_text.clone();
if param.optional
{
desc.push_str( " (optional)" );
}
if param.multiple
{
desc.push_str( " (multiple)" );
}
OptionEntry
{
name : format!( "{}::<{}>", param.name, param.kind_compact ),
desc,
}
} ).collect();
page.sections.push( DetailSection::new( "Parameters", params ) );
page.examples = command.examples.iter()
.map( | example | ExampleEntry { invocation : example.clone(), desc : None } )
.collect();
DetailPageTemplate::new( self.style.clone(), page ).render()
}
}