Skip to content

clap_complete: completions for args following subcommand are missing #5139

Description

@scootermon

Please complete the following tasks

Rust Version

rustc 1.72.1 (d5c2e9c34 2023-09-13)

Clap Version

clap: 4.4.4, clap_complete: 4.4.1

Minimal reproducible code

fn main() {
    #[derive(Clone, clap::ValueEnum)]
    enum Enum {
        A,
        B,
        C,
    }

    // create a dummy command with a subcommand, which in turn takes an enum arg
    let mut app = clap::Command::new("mre").subcommand(
        clap::Command::new("subcmd").arg(
            clap::Arg::new("arg")
                .required(true)
                .value_parser(clap::builder::EnumValueParser::<Enum>::new()),
        ),
    );

    // ask clap_complete to generate completions for the argument following the subcommand
    let completions = clap_complete::dynamic::complete(
        &mut app,
        vec!["mre".into(), "subcmd".into(), "".into()],
        2,
        None,
    )
    .unwrap();
    // this will panic because 'A', 'B', 'C' are missing (only '-h' and '--help' are listed)
    assert!(completions.len() >= 3);
}

Steps to reproduce the bug with the above code

cargo run is enough as long as the "unstable-dynamic" is active for clap_complete.

Actual Behaviour

clap_complete doesn't suggest any values for arguments following a subcommand.

Expected Behaviour

It should suggest possible values for arguments following a subcommand.

Additional Context

The reason for this seems fairly straight-forward:

The code responsible for adding the arg value completions uses the pos_index passed into the function to find the correct clap::Arg:

if let Some(positional) = cmd
.get_positionals()
.find(|p| p.get_index() == Some(pos_index))
{
completions.extend(complete_arg_value(arg.to_value(), positional, current_dir));
}

This fails because the pos_index in our example is set to 0. The pos_index is always set to 0 when clap_complete encounters a subcommand:

if let Some(next_cmd) = current_cmd.find_subcommand(value) {
current_cmd = next_cmd;
pos_index = 0;
continue;
}

I fail to see why this is done. If the value is set to 1 instead, the example starts working.

Debug Output

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: bug

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions