clap: `TrailingVarArg` doesn't work without `--`

Maintainer’s notes

  • Workaround: call Command::allow_hyphen_values(true)

Rust Version

Stable

Affected Version of clap

Latest

Bug or Feature Request Summary

I am unable to write a program which accepts a variable amount of final args which include flag-like values without using a delimiter.

Expected Behavior Summary

I’d like to be able to have my variable amount of args be of any format, including flag-like options.

Actual Behavior Summary

Parsing fails.

Steps to Reproduce the issue

I have created a playground example which demonstrates the problem directly.

Sample Code or Link to Sample Code

Playground

fn parser<'a, 'b>() -> App<'a, 'b> {
    App::new("varargs")
        .setting(AppSettings::TrailingVarArg)
        // boolean
        .arg(Arg::with_name("prog-flag")
            .long("prog-flag")
            .takes_value(false))
        // path to executable
        .arg(Arg::with_name("EXECUTABLE")
            .takes_value(true)
            .required(true))
        // list of arguments to pass to executable
        .arg(Arg::with_name("ARGS")
            .takes_value(true)
            .multiple(true)
            .allow_hyphen_values(true))
}

#[test]
fn test_with_delimiter() {
    parser().get_matches_from_safe(vec!["--prog-flag", "executable", "--", "-a", "1"]).unwrap();
}

#[test]
fn test_without_delimiter() {
    parser().get_matches_from_safe(vec!["--prog-flag", "executable", "-a", "1"]).unwrap();
}

My exact use-case is that I have a positional argument which is a path to an executable, followed by a list of arguments to pass to that executable.

Example:

./my-program --prog-flag /usr/bin/watch -n 1 echo true

Internally, I’m using --prog-flag to customize my application’s behavior, the executable path to find the binary to execute, and the variable length of args to pass to the program as arguments.

I can’t seem to find a way to write the above without needing a delimiter (--) between executable and the argument list.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 13
  • Comments: 18 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Thanks for calling out that other case! I was able to reproduce that. I threw together #3389 as part of looking at this. long arguments are missing some of the checks that short arguments have. This PR just copied over one of them. Some more work is needed on it. I’m giving myself some pause to consider how disruptive of a change any of this is. My guess is I’ll consider it to not be a breaking change but will want it called out in a compatibility section in the CHANGELOG (like Rust does). I want to reserve those for minor releases (I am preparing for a minor release atm).

If anyone wants to pick this up, that’d be a big help.

@epage It seems that particular example works, but it still fails if you follow executable with a double-dash option. For example:

#[test]
fn test_without_delimiter() {
    parser()
        .try_get_matches_from(vec!["--prog-flag", "executable", "--foo", "1"])
        .unwrap();
}

As noted in #4039, since Command::allow_hyphen_values looks to be a workaround, I am de-prioritizing an immediate fix so we can evaluate some of the larger questions

As well, when we resolve this, we should

  • Ensure trailing_var_arg and last are cross-linked
  • Ensure trailing_var_arg discusses the role of allow_hyphen_values