in unsupported/juno/crates/command_line/src/cl.rs [152:314]
fn build_help_impl(
&self,
prog_name: &str,
show_hidden: bool,
) -> Result<String, std::fmt::Error> {
// Collect information about the options.
let opts = self.as_slice();
let mut have_options = false;
// An entry per category, containing all text for that category
let mut cats: Vec<Vec<(String, Option<String>)>> = Vec::new();
// Positional argument description.
let mut pos_descs = String::new();
cats.resize(self.categories.len(), Vec::new());
fn add_value_desc(buf: &mut String, desc: Option<&str>) {
buf.push('<');
if let Some(vd) = desc {
buf.push_str(vd);
} else {
buf.push_str("value");
}
buf.push('>');
}
for opt in opts {
let info = opt.info();
if info.is_positional() {
if !pos_descs.is_empty() {
pos_descs.push(' ');
}
if let Some(d) = info.desc {
pos_descs.push_str(d);
} else {
add_value_desc(&mut pos_descs, info.value_desc);
if info.list {
pos_descs.push(cond!(info.min_count == 0, '*', '+'));
} else if info.min_count == 0 {
pos_descs.push('?');
}
}
continue;
}
have_options = true;
// Skip hidden options.
if info.hidden == Hidden::ReallyHidden || info.hidden == Hidden::Yes && !show_hidden {
continue;
}
let cat_index = info.category;
// If there is more than one category, the first time we append to it,
// we must generate its name and description.
if self.categories.len() > 1 && cats[cat_index].is_empty() {
// An empty line before every category except the first.
if cat_index != 0 {
cats[cat_index].push(("".into(), None));
}
// Name.
cats[cat_index].push((
format!("{}:", self.categories[cat_index].name.clone()),
None,
));
// Optional description.
if let Some(desc) = &self.categories[cat_index].desc {
cats[cat_index].push((desc.clone(), None));
}
// Another empty line.
cats[cat_index].push(("".into(), None));
}
let mut left = String::from(" ");
if let Some(sn) = info.short {
left.push('-');
left.push_str(sn);
if info.long.is_none()
&& info.expected_value != ExpectedValue::Disallowed
&& !info.is_enum_value()
{
left.push(' ');
if info.expected_value == ExpectedValue::Optional {
left.push('[');
}
add_value_desc(&mut left, info.value_desc);
if info.expected_value == ExpectedValue::Optional {
left.push(']');
}
}
}
if let Some(ln) = info.long {
if info.short.is_some() {
left.push_str(", ");
}
left.push_str("--");
left.push_str(ln);
if info.expected_value != ExpectedValue::Disallowed && !info.is_enum_value() {
if info.expected_value == ExpectedValue::Optional {
left.push('[');
}
left.push('=');
add_value_desc(&mut left, info.value_desc);
if info.expected_value == ExpectedValue::Optional {
left.push(']');
}
}
}
if info.is_enum_value() {
// An enum value generates descriptions for all alternatives.
cats[cat_index].push((left, Some(info.desc.unwrap_or("").to_string())));
for alt in info.values_desc.unwrap() {
cats[cat_index].push((format!(" ={}", alt.0), Some(format!(" {}", alt.1))));
}
} else if info.is_enum_option() {
// An enum option generates descriptions for all alternatives.
left.push_str(if let Some(d) = info.desc {
d
} else {
"Choose one of:"
});
cats[cat_index].push((left, None));
for alt in info.values_desc.unwrap() {
cats[cat_index].push((
format!(" {}{}", cond!(alt.0.len() > 1, "--", "-"), alt.0),
Some(alt.1.clone()),
));
}
} else {
cats[cat_index].push((left, Some(info.desc.unwrap_or("").to_string())));
}
}
let descs: Vec<(String, Option<String>)> = cats.iter().flatten().cloned().collect();
drop(cats);
// Calc the width of the left column.
let left_width = descs.iter().fold(0, |left_w, p| {
cond!(p.1.is_none(), left_w, left_w.max(p.0.len()))
});
let mut out = String::new();
writeln!(out, "OVERVIEW: {}\n", self.desc)?;
write!(out, "USAGE: {}", prog_name)?;
if have_options {
write!(out, " [options]")?;
}
if !pos_descs.is_empty() {
write!(out, " {}", pos_descs)?;
}
writeln!(out, "\n")?;
writeln!(out, "OPTIONS:\n")?;
for (left, right) in &descs {
match right {
Some(r) if !r.is_empty() => writeln!(out, "{0:1$} - {2}", left, left_width, r)?,
_ => writeln!(out, "{}", left)?,
}
}
Ok(out)
}