/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
libs/cli_parser/src/help.rs
185 строк
5 KB
Bartek Iwańczuk
refactor: cut over CLI flag parsing to deno_cli_parser (#35982)
07 авг 2026, 12:18
Не верифицирован
07 авг 2026, 12:18
7ee9311
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. //! Help text rendering for the Deno CLI parser. //! //! Walks a `CommandDef` and its `ArgDef` list to produce formatted help text. use crate::types::*; /// Render help text for a command. pub fn render_help(cmd: &CommandDef) -> String { let mut out = String::new(); // Header if !cmd.about.is_empty() { out.push_str(cmd.about); out.push_str("\n\n"); } // Usage line 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'); // Subcommands section 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; } // Only use the first line of about text in the commands table let short_about = sub.about.lines().next().unwrap_or(""); out.push_str(&format!( " {:<width$} {}\n", sub.name, short_about, width = max_name_len )); } } // Options section 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..] { // Indent to the description column; any further indentation is // baked into the help string itself (as it was for clap). out.push_str(&format!("{:26}{}\n", "", rest_line)); } } } // Permission options, mirroring clap's after-help. The permission args are // hidden from the table above and documented in this section instead. if has_permission_args(cmd) { out.push('\n'); out.push_str(crate::permission_help::PERMISSION_HELP); } // Environment variables (root help only), mirroring clap's after-help. if cmd.name == "deno" { out.push_str(&render_env_vars()); } out } /// Whether this command accepts the shared permission args, and so should get /// the "Permission options" section. fn has_permission_args(cmd: &CommandDef) -> bool { cmd .arg_groups .iter() .any(|g| std::ptr::eq(g.as_ptr(), crate::defs::PERMISSION_ARGS.as_ptr())) } /// Render the "Environment variables" section documented in `deno --help`. fn render_env_vars() -> String { use crate::env_vars::ENV_VARS; let mut out = String::from( "\nEnvironment variables:\nDocs: https://docs.deno.com/go/env-vars\n\n", ); let width = ENV_VARS.iter().map(|v| v.name.len()).max().unwrap_or(0) + 1; let entries: Vec<String> = ENV_VARS .iter() .map(|var| { let indent = " ".repeat(width); let desc = var.description.replace('\n', &format!("\n {indent}")); let mut entry = format!( " {}{}{}", var.name, " ".repeat(width - var.name.len()), desc ); if let Some(example) = var.example { entry.push_str(&format!("\n {} {}", indent, example)); } entry }) .collect(); out.push_str(&entries.join("\n")); out.push('\n'); out } /// Render help for the root command when called with `deno --help`. pub fn render_root_help(cmd: &CommandDef) -> String { render_help(cmd) } /// Find a subcommand by name in the root and render its help. pub fn render_subcommand_help(root: &CommandDef, name: &str) -> Option<String> { root.find_subcommand(name).map(render_help) }