///|
fn inherited_options(
inherited : ArrayView[OptionDef],
command : CommandDef,
) -> Array[OptionDef] {
inherited.to_owned() + command.options[:].filter(option => option.global)
}
///|
// Use argparse's own help routing to preserve inherited argument ordering.
// These are synthetic, validated command paths, never the caller's argv.
fn parser_help_at_path(
parser : @argparse.Command,
path : ArrayView[String],
) -> String? {
if path.is_empty() {
return Some(parser.render_help())
}
match parser.parse_outcome(argv=["help"] + path.to_owned()) {
Help(text) => Some(text + "\n")
_ => None
}
}
///|
fn render_command_help(command : CommandDef, base : String) -> String {
let extra : Array[String] = []
if !command.subcommands.is_empty() {
let locals = command.options.filter(option => {
option.required && !option.global
})
if !locals.is_empty() {
let names = locals.map(option => "--\{option.name}").join(", ")
let notice = command.required_scope_notice.unwrap_or(
"Local required options (\{names}) apply only to this command's own execution. Subcommands require their own local options and inherited globals.",
)
if !notice.is_empty() {
extra.push(notice)
}
}
}
if !command.examples.is_empty() {
extra.push("Examples:\n \{command.examples.join("\n ")}")
}
if extra.is_empty() {
base
} else {
"\{base}\n\{extra.join("\n\n")}\n"
}
}
///|
// Match complete help generated by the same parser, not diagnostic wording or
// categories. Preserve unfamiliar upstream output without aborting. Synthetic
// help routing avoids re-parsing caller input and preserves inherited ordering.
fn restore_help_for_command(
app : CliApp,
parser : @argparse.Command,
command : CommandDef,
path : ArrayView[String],
text : String,
help_only~ : Bool,
) -> String? {
if parser_help_at_path(parser, path) is Some(raw) {
let prefix = if help_only {
if text == raw.strip_suffix("\n").unwrap_or(raw[:]).to_owned() {
Some("")
} else {
None
}
} else {
text.strip_suffix(raw).map(prefix => prefix.to_owned())
}
if prefix is Some(prefix) {
let annotated = build_parser(app.root, version=app.version)
if parser_help_at_path(annotated, path) is Some(base) {
let rendered = render_command_help(command, base)
return Some(
if help_only {
rendered.strip_suffix("\n").unwrap_or(rendered[:]).to_owned()
} else {
"\{prefix}\{rendered}"
},
)
}
}
}
for child in command.subcommands {
if restore_help_for_command(
app,
parser,
child,
path.to_owned() + [child.name],
text,
help_only~,
)
is Some(rendered) {
return Some(rendered)
}
}
None
}
///|
fn restore_parser_help(
app : CliApp,
text : String,
help_only~ : Bool,
) -> String {
let parser = build_parser(app.root, version=app.version, defer_required=true)
restore_help_for_command(app, parser, app.root, [], text, help_only~).unwrap_or(
text,
)
}
///|
/// Renders root or nested help, including inherited globals and explicit
/// examples, without caller argv or execution. Unknown paths raise UnknownCommand.
pub fn CliApp::render_help(
self : CliApp,
command_path~ : ArrayView[String] = [],
) -> String raise CliError {
let (selected, globals) = for
name in command_path
command = self.root, globals = [] {
guard find_command_def(command.subcommands, name) is Some(child) else {
raise CliError::UnknownCommand(command_path.to_owned())
}
continue child, inherited_options(globals, command)
} nobreak {
(command, globals)
}
let parser = build_parser(self.root, version=self.version)
let base = parser_help_at_path(parser, command_path).unwrap_or_else(() => {
// Defensive fallback if a future upstream changes synthetic help routing.
let path = ([self.root.name] + command_path.to_owned()).join(" ")
let version = if command_path.is_empty() {
Some(self.version)
} else {
None
}
build_parser(
{
..selected,
name: path,
options: ReadOnlyArray::from_array(
globals + selected.options[:].to_owned(),
),
},
version?,
).render_help()
})
render_command_help(selected, base)
}