Skip to content

Commit

Permalink
feat(completions/zsh.rs): Complete positional arguments properly
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
segevfiner committed Jan 14, 2018
1 parent d78341f commit e39aeab
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 24 deletions.
49 changes: 29 additions & 20 deletions src/completions/zsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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);
}
Expand Down Expand Up @@ -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")
}
8 changes: 4 additions & 4 deletions tests/completions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 "$@"
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 "$@"
}
Expand Down

0 comments on commit e39aeab

Please sign in to comment.