clap-rs / clap

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

Support `allow_hyphen_values` in native completions #5594

Closed shannmu closed 2 days ago

shannmu commented 1 month ago

Please complete the following tasks

Clap Version

master

Describe your use case

use clap::{CommandFactory, Parser};
use clap_complete::dynamic::shells::CompleteCommand;
#[derive(Parser, Debug)]
#[clap(name = "dynamic", about = "A dynamic command line tool")]
struct Cli {
    /// The subcommand to run complete
    #[command(subcommand)]
    complete: Option<CompleteCommand>,
    /// Output format
    #[clap(short = 'F', long, value_parser = ["--json", "--yaml", "--toml"], allow_hyphen_values = true)]
    format: Option<String>,
    #[clap(long)]
    json: Option<String>,
}
fn main() {
    let cli = Cli::parse();
    if let Some(completions) = cli.complete {
        completions.complete(&mut Cli::command());
    }
    // normal logic continues...
}

For the command line:

dynamic --format --json --js[TAB]

There is no completion generated. it should be:

dynamic --format --json --json 

This seems to be a very specific use case, but it shows that there is an error in parsing during dynamic completion when the allow_hyphen_values setting is enabled, or that allow_hyphen_values is not being considered.

Describe the solution you'd like

https://github.com/clap-rs/clap/blob/5efa52ad4501393d50e236d10a979313a61d4929/clap_complete/src/dynamic/completer.rs#L76 https://github.com/clap-rs/clap/blob/5efa52ad4501393d50e236d10a979313a61d4929/clap_complete/src/dynamic/completer.rs#L79 https://github.com/clap-rs/clap/blob/5efa52ad4501393d50e236d10a979313a61d4929/clap_complete/src/dynamic/completer.rs#L112 do something more in these branches

Alternatives, if applicable

No response

Additional Context

There are also user cases related to the mistaken parsing.

Case 1

use clap::{CommandFactory, Parser};
use clap_complete::dynamic::shells::CompleteCommand;
#[derive(Parser, Debug)]
#[clap(name = "dynamic", about = "A dynamic command line tool")]
struct Cli {
    /// The subcommand to run complete
    #[command(subcommand)]
    complete: Option<CompleteCommand>,
    /// Output format
    #[clap(short = 'F', long, value_parser = ["json", "yaml", "toml"], allow_hyphen_values = true)]
    format: Option<String>,
    #[clap(value_parser = ["--pos_a"], index = 1)]
    positional_a: Option<String>,
    #[clap(value_parser = ["pos_b"], index = 2)]
    positional_b: Option<String>,
}
fn main() {
    let cli = Cli::parse();
    if let Some(completions) = cli.complete {
        completions.complete(&mut Cli::command());
    }
    // normal logic continues...
}

For the command line

dynamic --format json --pos_a [TAB]

completions are:

--format  --help    --pos_a   -F        -h        help

it should be:

pos_b --format  --help    -F        -h        help

Case 2

use clap::{CommandFactory, Parser};
use clap_complete::dynamic::shells::CompleteCommand;
#[derive(Parser, Debug)]
#[clap(name = "dynamic", about = "A dynamic command line tool")]
struct Cli {
    /// The subcommand to run complete
    #[command(subcommand)]
    complete: Option<CompleteCommand>,
    /// Output format
    #[clap(short = 'F', long, value_parser = ["json", "yaml", "toml"], allow_hyphen_values = true)]
    format: Option<String>,
    #[clap(value_parser = ["-a"], index = 1)]
    positional_a: Option<String>,
    #[clap(value_parser = ["pos_b"], index = 2)]
    positional_b: Option<String>,
}
fn main() {
    let cli = Cli::parse();
    if let Some(completions) = cli.complete {
        completions.complete(&mut Cli::command());
    }
    // normal logic continues...
}

For the command line

dynamic --format json -a [TAB]

completions are:

--format  --help    -F        -a        -h        help

it should be:

pos_b --format  --help    -F        -h        help
shannmu commented 1 month ago

Track issue: https://github.com/clap-rs/clap/issues/3166

shannmu commented 1 month ago

There is a related case https://github.com/clap-rs/clap/pull/5602#discussion_r1705107817.