epage / clapng

A full featured, fast Command Line Argument Parser for Rust
docs.rs/clap
Apache License 2.0
0 stars 0 forks source link

zsh: optional flag with takes_value breaks completions #155

Open epage opened 2 years ago

epage commented 2 years ago

Issue by kpcyrd Tuesday Apr 14, 2020 at 14:34 GMT Originally opened as https://github.com/clap-rs/clap/issues/1822


Make sure you completed the following tasks

Code

use std::io::stdout;
use clap::{App, Arg, SubCommand, Shell};

fn app() -> App<'static, 'static> {
    App::new("completion-bug")
        .arg(
            Arg::with_name("foo")
                .short("f")
                .long("foo")
                .takes_value(true)
        )
        .subcommand(SubCommand::with_name("zsh"))
        .subcommand(SubCommand::with_name("bash"))
}

fn main() {
    let args = app().get_matches();
    eprintln!("{:?}", args);

    let shell = match args.subcommand() {
        ("zsh", _) => Shell::Zsh,
        ("bash", _) => Shell::Bash,
        _ => unreachable!(),
    };

    app().gen_completions_to("completion-bug", shell, &mut stdout());
}

Steps to reproduce the issue

cargo run -- zsh > ~/.zsh_completions/_completion-bug # you might need to tweak this for your setup
zsh

# this works
completion-bug z<tab>
# this doesn't
completion-bug -f x z<tab>
# this does something unexpected
completion-bug -f z<tab>

Version

Actual Behavior Summary

completion-bug -f x z<tab> doesn't complete anything.

This affects https://github.com/kpcyrd/sn0int because it has a lot of nested subcommands but it's very common to start the command with sn0int -w foo which breaks the completions for everything afterwards.

The bash completions work correctly.

Expected Behavior Summary

completion-bug -f x z<tab> should complete to completion-bug -f x zsh

Additional context

This bug was originally reported as https://github.com/TeXitoi/structopt/issues/369 and then ported over to pure clap. The completions generated by the structopt program and the clap program are identical.

epage commented 2 years ago

Comment by pksunkara Sunday Aug 16, 2020 at 07:57 GMT


@intgr I couldn't reproduce this when this issue was created. Do you want to take a look at this?

epage commented 2 years ago

Comment by intgr Sunday Aug 16, 2020 at 18:05 GMT


This is a bug indeed, the same issue affects zsh built-in git completions too, for example:

git --git-dir .git commi<TAB> should complete to commit but doesn't.

A workaround is using = in --arg= to separate argument value.

This works: git --git-dir=.git commi<TAB>

EDIT: Sorry, my bad, the above works with git but not clap's generated completions file.

I'll have to dig some more in zsh documentation to see if this is can be fixed in clap or if it's a bug in zsh itself.

If this is helpful for anyone, here's clap 3.x compatible version of the bug report's code: ```rust use clap::{App, Arg}; use clap_generate::generators::{Bash, Zsh}; use std::io::stdout; fn app() -> App<'static> { App::new("completion-bug") .arg(Arg::new("foo").short('f').long("foo").takes_value(true)) .subcommand(App::new("zsh")) .subcommand(App::new("bash")) } fn main() { let args = app().get_matches(); eprintln!("{:?}", args); match args.subcommand() { ("zsh", _) => { let mut app = app(); clap_generate::generate::(&mut app, "completion-bug", &mut stdout()); } ("bash", _) => { let mut app = app(); clap_generate::generate::(&mut app, "completion-bug", &mut stdout()); } _ => unreachable!(), }; } ```
epage commented 2 years ago

Comment by intgr Sunday Aug 16, 2020 at 19:03 GMT


As far as I can tell, clap is annotating the arguments correctly per zsh documentation (http://zsh.sourceforge.net/Doc/Release/Completion-System.html)

From the generated file:

'-f+[]' \

Documentation:

The first argument may appear immediately after optname in the same word, or may appear as a separate word after the option. For example, ‘-foo+:...’ specifies that the completed option and argument will look like either ‘-fooarg’ or ‘-foo arg’.

'--foo=[]' \

The argument may appear as the next word, or in same word as the option name provided that it is separated from it by an equals sign, for example ‘-foo=arg’ or ‘-foo arg’.


I looked at git completions and I still don't understand why --git-dir=.git works with git completions but --foo=x doesn't work with clap's generated file. But in any case the behavior of --git-dir .git is wrong in zsh's built-in git completions as well.

I don't consume the sort of hard drugs necessary to get in the same frame of mind as zsh developers, I don't wish to investigate this further, sorry. :)

epage commented 2 years ago

Comment by pksunkara Sunday Aug 16, 2020 at 20:07 GMT


Thanks for your help @intgr