feat(completions/zsh.rs): Complete positional arguments properly

This changes the way we complete positionals to complete them using
_arguments, as should be done, instead of completing their uppercase name
as a string.

Currently I made it offer _files completion for all positional arguments.
This can be improved to complete actual possible values of the arguments
and only complete files if the argument truly takes them. But this will
require further changes in clap to actually have the required
functionality to get this information.
This commit is contained in:
Segev Finer 2018-01-13 20:06:59 +02:00
parent d78341f640
commit e39aeab848
2 changed files with 33 additions and 24 deletions

View file

@ -167,24 +167,6 @@ fn subcommands_and_args_of(p: &Parser) -> String {
}
}
// Then the positional args
for arg in p.positionals() {
debugln!("ZshGen::subcommands_and_args_of:iter: arg={}", arg.b.name);
let a = format!(
"\"{name}:{help}\" \\",
name = arg.b.name.to_ascii_uppercase(),
help = arg.b
.help
.unwrap_or("")
.replace("[", "\\[")
.replace("]", "\\]")
);
if !a.is_empty() {
ret.push(a);
}
}
ret.join("\n")
}
@ -293,9 +275,10 @@ fn get_args_of(p: &Parser) -> String {
let mut ret = vec![String::from("_arguments -s -S -C \\")];
let opts = write_opts_of(p);
let flags = write_flags_of(p);
let sc_or_a = if p.has_subcommands() || p.has_positionals() {
let positionals = write_positionals_of(p);
let sc_or_a = if p.has_subcommands() {
format!(
"\"1:: :_{name}_commands\" \\",
"\":: :_{name}_commands\" \\",
name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__")
)
} else {
@ -313,6 +296,9 @@ fn get_args_of(p: &Parser) -> String {
if !flags.is_empty() {
ret.push(flags);
}
if !positionals.is_empty() {
ret.push(positionals);
}
if !sc_or_a.is_empty() {
ret.push(sc_or_a);
}
@ -434,3 +420,26 @@ fn write_flags_of(p: &Parser) -> String {
ret.join("\n")
}
fn write_positionals_of(p: &Parser) -> String {
debugln!("write_positionals_of;");
let mut ret = vec![];
for arg in p.positionals() {
debugln!("write_positionals_of:iter: arg={}", arg.b.name);
let a = format!(
"\"{optional}:{name}{help}:_files\" \\",
optional = if !arg.b.is_set(ArgSettings::Required) { ":" } else { "" },
name = arg.b.name,
help = arg.b
.help
.map_or("".to_owned(), |v| " -- ".to_owned() + v)
.replace("[", "\\[")
.replace("]", "\\]")
);
debugln!("write_positionals_of:iter: Wrote...{}", a);
ret.push(a);
}
ret.join("\n")
}

View file

@ -99,7 +99,8 @@ _myapp() {
'--help[Prints help information]' \
'-V[Prints version information]' \
'--version[Prints version information]' \
"1:: :_myapp_commands" \
"::file -- some input file:_files" \
":: :_myapp_commands" \
"*:: :->myapp" \
&& ret=0
case $state in
@ -133,7 +134,6 @@ _myapp_commands() {
local commands; commands=(
"test:tests things" \
"help:Prints this message or the help of the given subcommand(s)" \
"FILE:some input file" \
)
_describe -t commands 'myapp commands' commands "$@"
}
@ -388,7 +388,8 @@ _my_app() {
'--help[Prints help information]' \
'-V[Prints version information]' \
'--version[Prints version information]' \
"1:: :_my_app_commands" \
"::file -- some input file:_files" \
":: :_my_app_commands" \
"*:: :->my_app" \
&& ret=0
case $state in
@ -441,7 +442,6 @@ _my_app_commands() {
"some_cmd:tests other things" \
"some-cmd-with-hypens:" \
"help:Prints this message or the help of the given subcommand(s)" \
"FILE:some input file" \
)
_describe -t commands 'my_app commands' commands "$@"
}