src/cli/command.rs: improve usage imformation
This commit is contained in:
parent
f252ca654c
commit
2f3f2bb77f
@ -1,8 +1,6 @@
|
|||||||
use failure::*;
|
use failure::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
//use serde_json::Value;
|
//use serde_json::Value;
|
||||||
|
|
||||||
use crate::api_schema::*;
|
use crate::api_schema::*;
|
||||||
@ -20,9 +18,22 @@ enum ParameterDisplayStyle {
|
|||||||
Fixed,
|
Fixed,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_schema_type_text(schema: Arc<Schema>, _style: ParameterDisplayStyle) -> String {
|
/// CLI usage information format
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
enum DocumentationFormat {
|
||||||
|
/// text, command line only (one line)
|
||||||
|
Short,
|
||||||
|
/// text, list all options
|
||||||
|
Long,
|
||||||
|
/// text, include description
|
||||||
|
Full,
|
||||||
|
/// like full, but in pandoc json format
|
||||||
|
Pandoc,
|
||||||
|
}
|
||||||
|
|
||||||
let type_text = match *schema {
|
fn get_schema_type_text(schema: &Schema, _style: ParameterDisplayStyle) -> String {
|
||||||
|
|
||||||
|
let type_text = match schema {
|
||||||
Schema::Null => String::from("<null>"), // should not happen
|
Schema::Null => String::from("<null>"), // should not happen
|
||||||
Schema::String(_) => String::from("<string>"),
|
Schema::String(_) => String::from("<string>"),
|
||||||
Schema::Boolean(_) => String::from("<boolean>"),
|
Schema::Boolean(_) => String::from("<boolean>"),
|
||||||
@ -36,12 +47,32 @@ fn get_schema_type_text(schema: Arc<Schema>, _style: ParameterDisplayStyle) -> S
|
|||||||
|
|
||||||
fn get_property_description(
|
fn get_property_description(
|
||||||
name: &str,
|
name: &str,
|
||||||
schema: Arc<Schema>,
|
schema: &Schema,
|
||||||
style: ParameterDisplayStyle
|
style: ParameterDisplayStyle,
|
||||||
|
format: DocumentationFormat,
|
||||||
) -> String {
|
) -> String {
|
||||||
|
|
||||||
let type_text = get_schema_type_text(schema, style);
|
let type_text = get_schema_type_text(schema, style);
|
||||||
|
|
||||||
|
let (descr, default) = match schema {
|
||||||
|
Schema::Null => ("null", None),
|
||||||
|
Schema::String(ref schema) => (schema.description, schema.default.map(|v| v.to_owned())),
|
||||||
|
Schema::Boolean(ref schema) => (schema.description, schema.default.map(|v| v.to_string())),
|
||||||
|
Schema::Integer(ref schema) => (schema.description, schema.default.map(|v| v.to_string())),
|
||||||
|
Schema::Object(ref schema) => (schema.description, None),
|
||||||
|
Schema::Array(ref schema) => (schema.description, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
if format == DocumentationFormat::Pandoc {
|
||||||
|
panic!("implement me");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
let default_text = match default {
|
||||||
|
Some(text) => format!(" (default={})", text),
|
||||||
|
None => String::new(),
|
||||||
|
};
|
||||||
|
|
||||||
let display_name = match style {
|
let display_name = match style {
|
||||||
ParameterDisplayStyle::Arg => {
|
ParameterDisplayStyle::Arg => {
|
||||||
format!("--{}", name)
|
format!("--{}", name)
|
||||||
@ -51,14 +82,29 @@ fn get_property_description(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
format!(" {:-10} {}", display_name, type_text)
|
// fixme: wrap text
|
||||||
|
let mut text = format!(" {:-10} {}{}", display_name, type_text, default_text);
|
||||||
|
let indent = " ";
|
||||||
|
text.push('\n');
|
||||||
|
text.push_str(indent);
|
||||||
|
text.push_str(descr);
|
||||||
|
text.push('\n');
|
||||||
|
text.push('\n');
|
||||||
|
|
||||||
|
text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_usage_str(prefix: &str, cli_cmd: &CliCommand, indent: &str) -> String {
|
fn generate_usage_str(
|
||||||
|
prefix: &str,
|
||||||
|
cli_cmd: &CliCommand,
|
||||||
|
format: DocumentationFormat,
|
||||||
|
indent: &str) -> String {
|
||||||
|
|
||||||
let arg_param = &cli_cmd.arg_param;
|
let arg_param = &cli_cmd.arg_param;
|
||||||
let fixed_param = &cli_cmd.fixed_param;
|
let fixed_param = &cli_cmd.fixed_param;
|
||||||
let properties = &cli_cmd.info.parameters.properties;
|
let properties = &cli_cmd.info.parameters.properties;
|
||||||
|
let description = &cli_cmd.info.parameters.description;
|
||||||
|
|
||||||
let mut done_hash = HashSet::<&str>::new();
|
let mut done_hash = HashSet::<&str>::new();
|
||||||
let mut args = String::new();
|
let mut args = String::new();
|
||||||
@ -70,10 +116,17 @@ fn generate_usage_str(prefix: &str, cli_cmd: &CliCommand, indent: &str) -> Strin
|
|||||||
args.push('<'); args.push_str(positional_arg); args.push('>');
|
args.push('<'); args.push_str(positional_arg); args.push('>');
|
||||||
if *optional { args.push(']'); }
|
if *optional { args.push(']'); }
|
||||||
|
|
||||||
//arg_descr.push_str(&get_property_description(positional_arg, schema.clone(), ParameterDisplayStyle::Fixed));
|
|
||||||
done_hash.insert(positional_arg);
|
done_hash.insert(positional_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut arg_descr = String::new();
|
||||||
|
for positional_arg in arg_param {
|
||||||
|
let (_optional, schema) = properties.get(positional_arg).unwrap();
|
||||||
|
let param_descr = get_property_description(
|
||||||
|
positional_arg, &schema, ParameterDisplayStyle::Fixed, format);
|
||||||
|
arg_descr.push_str(¶m_descr);
|
||||||
|
}
|
||||||
|
|
||||||
let mut options = String::new();
|
let mut options = String::new();
|
||||||
|
|
||||||
let mut prop_names: Vec<&str> = properties.keys().map(|v| *v).collect();
|
let mut prop_names: Vec<&str> = properties.keys().map(|v| *v).collect();
|
||||||
@ -84,12 +137,12 @@ fn generate_usage_str(prefix: &str, cli_cmd: &CliCommand, indent: &str) -> Strin
|
|||||||
if done_hash.contains(prop) { continue; }
|
if done_hash.contains(prop) { continue; }
|
||||||
if fixed_param.contains(&prop) { continue; }
|
if fixed_param.contains(&prop) { continue; }
|
||||||
|
|
||||||
let type_text = get_schema_type_text(schema.clone(), ParameterDisplayStyle::Arg);
|
let type_text = get_schema_type_text(&schema, ParameterDisplayStyle::Arg);
|
||||||
|
|
||||||
if *optional {
|
if *optional {
|
||||||
|
|
||||||
options.push(' ');
|
options.push(' ');
|
||||||
options.push_str(&get_property_description(prop, schema.clone(), ParameterDisplayStyle::Arg));
|
options.push_str(&get_property_description(prop, &schema, ParameterDisplayStyle::Arg, format));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
args.push_str("--"); args.push_str(prop);
|
args.push_str("--"); args.push_str(prop);
|
||||||
@ -100,9 +153,39 @@ fn generate_usage_str(prefix: &str, cli_cmd: &CliCommand, indent: &str) -> Strin
|
|||||||
done_hash.insert(prop);
|
done_hash.insert(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match format {
|
||||||
|
DocumentationFormat::Short => {
|
||||||
format!("{}{}{}", indent, prefix, args)
|
format!("{}{}{}", indent, prefix, args)
|
||||||
}
|
}
|
||||||
|
DocumentationFormat::Long => {
|
||||||
|
let mut text = format!("{}{}{}\n", indent, prefix, args);
|
||||||
|
if arg_descr.len() > 0 {
|
||||||
|
text.push('\n');
|
||||||
|
text.push_str(&arg_descr);
|
||||||
|
}
|
||||||
|
if options.len() > 0 {
|
||||||
|
text.push('\n');
|
||||||
|
text.push_str(&options);
|
||||||
|
}
|
||||||
|
text
|
||||||
|
}
|
||||||
|
DocumentationFormat::Full => {
|
||||||
|
let mut text = format!("{}{}{}\n\n{}\n", indent, prefix, args, description);
|
||||||
|
if arg_descr.len() > 0 {
|
||||||
|
text.push('\n');
|
||||||
|
text.push_str(&arg_descr);
|
||||||
|
}
|
||||||
|
if options.len() > 0 {
|
||||||
|
text.push('\n');
|
||||||
|
text.push_str(&options);
|
||||||
|
}
|
||||||
|
text
|
||||||
|
}
|
||||||
|
DocumentationFormat::Pandoc => {
|
||||||
|
panic!("implement me");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn print_simple_usage_error(prefix: &str, cli_cmd: &CliCommand, err: Error) {
|
fn print_simple_usage_error(prefix: &str, cli_cmd: &CliCommand, err: Error) {
|
||||||
|
|
||||||
@ -113,7 +196,7 @@ fn print_simple_usage_error(prefix: &str, cli_cmd: &CliCommand, err: Error) {
|
|||||||
|
|
||||||
fn print_simple_usage(prefix: &str, cli_cmd: &CliCommand) {
|
fn print_simple_usage(prefix: &str, cli_cmd: &CliCommand) {
|
||||||
|
|
||||||
let usage = generate_usage_str(prefix, cli_cmd, "");
|
let usage = generate_usage_str(prefix, cli_cmd, DocumentationFormat::Long, "");
|
||||||
eprintln!("{}", usage);
|
eprintln!("{}", usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,10 +255,11 @@ fn print_nested_usage_error(prefix: &str, def: &CliCommandMap, err: Error) {
|
|||||||
|
|
||||||
eprintln!("Error: {}\n\nUsage:\n", err);
|
eprintln!("Error: {}\n\nUsage:\n", err);
|
||||||
|
|
||||||
print_nested_usage(prefix, def);
|
// print_nested_usage(prefix, def, DocumentationFormat::Short);
|
||||||
|
print_nested_usage(prefix, def, DocumentationFormat::Long);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_nested_usage(prefix: &str, def: &CliCommandMap) {
|
fn print_nested_usage(prefix: &str, def: &CliCommandMap, format: DocumentationFormat) {
|
||||||
|
|
||||||
let mut cmds: Vec<&String> = def.commands.keys().collect();
|
let mut cmds: Vec<&String> = def.commands.keys().collect();
|
||||||
cmds.sort();
|
cmds.sort();
|
||||||
@ -185,11 +269,11 @@ fn print_nested_usage(prefix: &str, def: &CliCommandMap) {
|
|||||||
|
|
||||||
match def.commands.get(cmd).unwrap() {
|
match def.commands.get(cmd).unwrap() {
|
||||||
CommandLineInterface::Simple(cli_cmd) => {
|
CommandLineInterface::Simple(cli_cmd) => {
|
||||||
let usage = generate_usage_str(&new_prefix, cli_cmd, "");
|
let usage = generate_usage_str(&new_prefix, cli_cmd, format, "");
|
||||||
eprintln!("{}", usage);
|
eprintln!("{}", usage);
|
||||||
}
|
}
|
||||||
CommandLineInterface::Nested(map) => {
|
CommandLineInterface::Nested(map) => {
|
||||||
print_nested_usage(&new_prefix, map);
|
print_nested_usage(&new_prefix, map, format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user