use crate::types::*;
pub fn render_help(cmd: &CommandDef) -> String {
let mut out = String::new();
if !cmd.about.is_empty() {
out.push_str(cmd.about);
out.push_str("\n\n");
}
if cmd.name == "deno" {
out.push_str(&format!("Usage: {} [OPTIONS]", cmd.name));
} else {
out.push_str(&format!("Usage: deno {} [OPTIONS]", cmd.name));
}
let positionals: Vec<&ArgDef> =
cmd.all_args().filter(|a| a.positional).collect();
for pos in &positionals {
let name = pos.value_name.unwrap_or(pos.name).to_uppercase();
match pos.num_args {
NumArgs::Optional => out.push_str(&format!(" [{name}]")),
NumArgs::ZeroOrMore => out.push_str(&format!(" [{name}]...")),
NumArgs::OneOrMore => out.push_str(&format!(" <{name}>...")),
NumArgs::Exact(0) => {}
NumArgs::Exact(_) => out.push_str(&format!(" <{name}>")),
}
}
if !cmd.subcommands.is_empty() {
out.push_str(" [COMMAND]");
}
out.push('\n');
if !cmd.subcommands.is_empty() {
out.push_str("\nCommands:\n");
let max_name_len = cmd
.subcommands
.iter()
.filter(|s| !s.name.starts_with("json_reference"))
.map(|s| s.name.len())
.max()
.unwrap_or(0);
for sub in cmd.subcommands {
if sub.name.starts_with("json_reference") {
continue;
}
let short_about = sub.about.lines().next().unwrap_or("");
out.push_str(&format!(
" {:<width$} {}\n",
sub.name,
short_about,
width = max_name_len
));
}
}
let flags: Vec<&ArgDef> = cmd
.all_args()
.filter(|a| !a.positional && !a.hidden)
.collect();
if !flags.is_empty() {
out.push_str("\nOptions:\n");
for arg in &flags {
let mut flag_str = String::new();
if let Some(short) = arg.short {
flag_str.push_str(&format!("-{short}"));
if arg.long.is_some() {
flag_str.push_str(", ");
}
} else {
flag_str.push_str(" ");
}
if let Some(long) = arg.long {
flag_str.push_str(&format!("--{long}"));
match arg.num_args {
NumArgs::Exact(0) => {}
NumArgs::Optional => {
let vn = arg.value_name.unwrap_or("VALUE");
if arg.require_equals {
flag_str.push_str(&format!("[=<{vn}>]"));
} else {
flag_str.push_str(&format!(" [<{vn}>]"));
}
}
NumArgs::ZeroOrMore => {
let vn = arg.value_name.unwrap_or("VALUE");
if arg.require_equals {
flag_str.push_str(&format!("[={vn}...]"));
} else {
flag_str.push_str(&format!(" [{vn}...]"));
}
}
_ => {
let vn = arg.value_name.unwrap_or("VALUE");
flag_str.push_str(&format!(" <{vn}>"));
}
}
}
let help_lines: Vec<&str> = arg.help.split('\n').collect();
out.push_str(&format!(" {:<22} {}\n", flag_str, help_lines[0]));
for rest_line in &help_lines[1..] {
out.push_str(&format!("{:28}{}\n", "", rest_line));
}
}
}
out
}
pub fn render_root_help(cmd: &CommandDef) -> String {
render_help(cmd)
}
pub fn render_subcommand_help(root: &CommandDef, name: &str) -> Option<String> {
root.find_subcommand(name).map(render_help)
}