release_kit/commands/
usage.rs1use clap::CommandFactory;
8
9use crate::cli::Cli;
10use crate::error::RkError;
11use crate::output::Output;
12
13pub fn run() -> Result<(), RkError> {
19 let out = Output::human();
20 let root = Cli::command();
21 out.result_line(format!(
22 "rk {} — {}",
23 env!("CARGO_PKG_VERSION"),
24 root.get_about()
25 .map(ToString::to_string)
26 .unwrap_or_default()
27 ));
28 for sub in root.get_subcommands() {
29 describe(out, sub, "rk");
30 }
31 out.next(&[
32 "rk doctor reports whether this host is ready".to_owned(),
33 "rk method --list starts the reading path".to_owned(),
34 ]);
35 Ok(())
36}
37
38fn describe(out: Output, cmd: &clap::Command, prefix: &str) {
40 let path = format!("{prefix} {}", cmd.get_name());
41 out.result_line(String::new());
42 out.result_line(format!(
43 "{path} — {}",
44 cmd.get_about().map(ToString::to_string).unwrap_or_default()
45 ));
46 let own: Vec<&clap::Arg> = cmd
47 .get_arguments()
48 .filter(|arg| !matches!(arg.get_id().as_str(), "help" | "version"))
49 .collect();
50 if !cmd.has_subcommands() || !own.is_empty() {
54 out.result_line(format!(" example: {}", example(cmd, &path)));
55 for arg in own {
56 out.result_line(format!(" {}", describe_arg(arg)));
57 }
58 }
59 for sub in cmd.get_subcommands() {
60 describe(out, sub, &path);
61 }
62}
63
64fn example(cmd: &clap::Command, path: &str) -> String {
69 use std::fmt::Write as _;
70 let mut example = path.to_owned();
71 for arg in cmd.get_arguments() {
72 if !arg.is_required_set() {
73 continue;
74 }
75 let value = format!("<{}>", arg.get_id().as_str().to_ascii_uppercase());
76 match arg.get_long() {
77 Some(long) => {
78 let _ = write!(example, " --{long} {value}");
79 }
80 None => {
81 let _ = write!(example, " {value}");
82 }
83 }
84 }
85 for group in cmd.get_groups() {
86 if !group.is_required_set() {
87 continue;
88 }
89 let alternatives: Vec<String> = group
90 .get_args()
91 .filter_map(|id| {
92 let arg = cmd.get_arguments().find(|arg| arg.get_id() == id)?;
93 Some(arg.get_long().map_or_else(
94 || arg.get_id().as_str().to_ascii_uppercase(),
95 |long| format!("--{long}"),
96 ))
97 })
98 .collect();
99 if !alternatives.is_empty() {
100 let _ = write!(example, " <{}>", alternatives.join("|"));
101 }
102 }
103 example
104}
105
106fn describe_arg(arg: &clap::Arg) -> String {
109 use std::fmt::Write as _;
110 let takes_value = arg.get_num_args().is_none_or(|num| num.takes_values());
111 let form = match (arg.get_long(), takes_value) {
112 (Some(long), true) => format!("--{long} <{}>", arg.get_id().as_str().to_ascii_uppercase()),
113 (Some(long), false) => format!("--{long}"),
114 (None, _) => format!("[{}]", arg.get_id().as_str().to_ascii_uppercase()),
115 };
116 let mut line = form;
117 if arg.is_required_set() {
118 line.push_str(" (required)");
119 }
120 if let Some(help) = arg.get_help() {
121 let _ = write!(line, " {help}");
122 }
123 let defaults = arg.get_default_values();
124 if !defaults.is_empty() {
125 let rendered: Vec<String> = defaults
126 .iter()
127 .map(|v| v.to_string_lossy().into_owned())
128 .collect();
129 let _ = write!(line, " (default: {})", rendered.join(", "));
130 }
131 line
132}