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 if cmd.has_subcommands() {
42 out.result_line(String::new());
43 out.result_line(format!(
44 "{path} — {}",
45 cmd.get_about().map(ToString::to_string).unwrap_or_default()
46 ));
47 for sub in cmd.get_subcommands() {
48 describe(out, sub, &path);
49 }
50 return;
51 }
52 out.result_line(String::new());
53 out.result_line(format!(
54 "{path} — {}",
55 cmd.get_about().map(ToString::to_string).unwrap_or_default()
56 ));
57 out.result_line(format!(" example: {}", example(cmd, &path)));
58 for arg in cmd.get_arguments() {
59 if matches!(arg.get_id().as_str(), "help" | "version") {
60 continue;
61 }
62 out.result_line(format!(" {}", describe_arg(arg)));
63 }
64}
65
66fn example(cmd: &clap::Command, path: &str) -> String {
71 use std::fmt::Write as _;
72 let mut example = path.to_owned();
73 for arg in cmd.get_arguments() {
74 if !arg.is_required_set() {
75 continue;
76 }
77 let value = format!("<{}>", arg.get_id().as_str().to_ascii_uppercase());
78 match arg.get_long() {
79 Some(long) => {
80 let _ = write!(example, " --{long} {value}");
81 }
82 None => {
83 let _ = write!(example, " {value}");
84 }
85 }
86 }
87 for group in cmd.get_groups() {
88 if !group.is_required_set() {
89 continue;
90 }
91 let alternatives: Vec<String> = group
92 .get_args()
93 .filter_map(|id| {
94 let arg = cmd.get_arguments().find(|arg| arg.get_id() == id)?;
95 Some(arg.get_long().map_or_else(
96 || arg.get_id().as_str().to_ascii_uppercase(),
97 |long| format!("--{long}"),
98 ))
99 })
100 .collect();
101 if !alternatives.is_empty() {
102 let _ = write!(example, " <{}>", alternatives.join("|"));
103 }
104 }
105 example
106}
107
108fn describe_arg(arg: &clap::Arg) -> String {
111 use std::fmt::Write as _;
112 let takes_value = arg.get_num_args().is_none_or(|num| num.takes_values());
113 let form = match (arg.get_long(), takes_value) {
114 (Some(long), true) => format!("--{long} <{}>", arg.get_id().as_str().to_ascii_uppercase()),
115 (Some(long), false) => format!("--{long}"),
116 (None, _) => format!("[{}]", arg.get_id().as_str().to_ascii_uppercase()),
117 };
118 let mut line = form;
119 if arg.is_required_set() {
120 line.push_str(" (required)");
121 }
122 if let Some(help) = arg.get_help() {
123 let _ = write!(line, " {help}");
124 }
125 let defaults = arg.get_default_values();
126 if !defaults.is_empty() {
127 let rendered: Vec<String> = defaults
128 .iter()
129 .map(|v| v.to_string_lossy().into_owned())
130 .collect();
131 let _ = write!(line, " (default: {})", rendered.join(", "));
132 }
133 line
134}