improve bash completion

This commit is contained in:
Dietmar Maurer 2018-12-12 07:51:43 +01:00
parent b6e8dd39aa
commit f46403cc65
1 changed files with 75 additions and 9 deletions

View File

@ -1,5 +1,6 @@
use failure::*; use failure::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::HashSet;
use crate::api::schema::*; use crate::api::schema::*;
use crate::api::router::*; use crate::api::router::*;
@ -83,16 +84,75 @@ fn handle_nested_command(def: &CliCommandMap, mut args: Vec<String>) -> Result<(
Ok(()) Ok(())
} }
fn print_completion(def: &CommandLineInterface, mut args: Vec<String>) { fn print_property_completion(schema: &Schema, arg: &str) {
// fixme
println!("");
}
fn record_done_arguments(done: &mut HashSet<String>, parameters: &ObjectSchema, list: &[String]) {
for arg in list {
if arg.starts_with("--") && arg.len() > 2 {
let prop_name = arg[2..].to_owned();
if let Some((_, schema)) = parameters.properties.get::<str>(&prop_name) {
match schema.as_ref() {
Schema::Array(_) => { /* do nothing */ }
_ => { done.insert(prop_name); }
}
}
}
}
}
fn print_simple_completion(
cli_cmd: &CliCommand,
mut done: &mut HashSet<String>,
arg_param: &[&str],
mut args: Vec<String>,
) {
// fixme: arg_param, fixed_param
//eprintln!("COMPL: {:?} {:?} {}", arg_param, args, args.len());
if !arg_param.is_empty() {
let prop_name = arg_param[0];
done.insert(prop_name.into());
if args.len() > 1 {
args.remove(0);
print_simple_completion(cli_cmd, done, &arg_param[1..], args);
return;
}
if let Some((_, schema)) = cli_cmd.info.parameters.properties.get(prop_name) {
if args.is_empty() {
print_property_completion(schema, "");
} else {
print_property_completion(schema, &args[0]);
}
}
return;
}
if args.is_empty() { return; }
let prefix = args.pop().unwrap(); // match on last arg
record_done_arguments(&mut done, &cli_cmd.info.parameters, &args);
for (name, (optional, schema)) in &cli_cmd.info.parameters.properties {
if done.contains(*name) { continue; }
let test = String::from("--") + name;
if test.starts_with(&prefix) {
println!("{}", test);
}
}
}
fn print_nested_completion(def: &CommandLineInterface, mut args: Vec<String>) {
match def { match def {
CommandLineInterface::Simple(cli_cmd) => { CommandLineInterface::Simple(cli_cmd) => {
// fixme: arg_param, fixed_param let mut done = HashSet::new();
if args.is_empty() { let fixed: Vec<String> = cli_cmd.fixed_param.iter().map(|s| s.to_string()).collect();
//for (name, (optional, schema)) in &cli_cmd.info.parameters.properties { record_done_arguments(&mut done, &cli_cmd.info.parameters, &fixed);
//println!("--{}", name); print_simple_completion(cli_cmd, &mut done, &cli_cmd.arg_param, args);
//}
}
return; return;
} }
CommandLineInterface::Nested(map) => { CommandLineInterface::Nested(map) => {
@ -104,7 +164,7 @@ fn print_completion(def: &CommandLineInterface, mut args: Vec<String>) {
} }
let first = args.remove(0); let first = args.remove(0);
if let Some(sub_cmd) = map.commands.get(&first) { if let Some(sub_cmd) = map.commands.get(&first) {
print_completion(sub_cmd, args); print_nested_completion(sub_cmd, args);
return; return;
} }
for cmd in map.commands.keys() { for cmd in map.commands.keys() {
@ -133,6 +193,7 @@ pub fn print_bash_completion(def: &CommandLineInterface) {
Err(e) => return, Err(e) => return,
}; };
let mut args = match shellwords::split(&cmdline) { let mut args = match shellwords::split(&cmdline) {
Ok(v) => v, Ok(v) => v,
Err(_) => return, Err(_) => return,
@ -140,9 +201,14 @@ pub fn print_bash_completion(def: &CommandLineInterface) {
args.remove(0); //no need for program name args.remove(0); //no need for program name
if cmdline.ends_with(char::is_whitespace) {
//eprintln!("CMDLINE {:?}", cmdline);
args.push("".into());
}
//eprintln!("COMP_ARGS {:?}", args); //eprintln!("COMP_ARGS {:?}", args);
print_completion(def, args); print_nested_completion(def, args);
} }
pub fn run_cli_command(def: &CommandLineInterface) -> Result<(), Error> { pub fn run_cli_command(def: &CommandLineInterface) -> Result<(), Error> {