Some visible aliases missing in dynamic completion
C-bugA-completionS-triage
### Please complete the following tasks
- [x] I have searched the [discussions](https://github.com/clap-rs/clap/discussions)
- [x] I have searched the [open](https://github.com/clap-rs/clap/issues) and [rejected](https://github.com/clap-rs/clap/issues?q=is%3Aissue+label%3AS-wont-fix+is%3Aclosed) issues
### Rust Version
rustc 1.94.0 (4a4ef493e 2026-03-02)
### Clap Version
clap 4.5.60
clap_complete 4.6.0
### Minimal reproducible code
```rust
use clap::{CommandFactory, Parser, Subcommand};
use clap_complete::engine::complete;
use std::ffi::OsString;
#[derive(Parser)]
#[command(name = "test")]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand)]
enum Commands {
#[command(name = "install", visible_alias = "i")]
Install,
#[command(name = "remove", visible_alias = "rm")]
Remove,
}
fn main() {
let mut cmd = Cli::command();
println!("Completions for `cli-name`:");
let args: Vec<OsString> = vec![OsString::from("cli-name"), OsString::from("")];
let completions = complete(&mut cmd, args, 1, None).unwrap();
for c in &completions {
println!(" {}", c.get_value().to_string_lossy());
}
println!("Completions for `cli-name i`:");
let args: Vec<OsString> = vec![OsString::from("cli-name"), OsString::from("i")];
let completions = complete(&mut cmd, args, 1, None).unwrap();
for c in &completions {
println!(" {}", c.get_value().to_string_lossy());
}
println!("Completions for `cli-name in`");
let args: Vec<OsString> = vec![OsString::from("cli-name"), OsString::from("in")];
let completions = complete(&mut cmd, args, 1, None).unwrap();
for c in &completions {
println!(" {}", c.get_value().to_string_lossy());
}
}
```
### Steps to reproduce the bug with the above code
cargo run
### Actual Behaviour
When using dynamic completion with `clap_complete::engine::complete()`, visible aliases for subcommands are not all shown.
For example, with a subcommand named `install` and visible alias `i`:
- Typing `i<TAB>` shows only `i`
- Typing `in<TAB>` shows `install`
This happens because after sorting candidates alphabetically (`i` comes before `install`), the dedup logic removes `install` since it shares the same `id`.
### Expected Behaviour
Both the primary command name and all its visible aliases should appear in the completion list when the input matches them.
For `install` with alias `i`:
- Typing `i<TAB>` should show both `i` and `install`
- Typing `in<TAB>` should show `install`
This matches the behavior of static completion (`clap_complete::generate()`), which correctly includes all visible aliases.
### Additional Context
In `clap_complete/src/engine/complete.rs`:
1. `populate_command_candidate()` assigns the same `id` to a subcommand and all its visible aliases:
https://github.com/clap-rs/clap/blob/70f3bb31874ff24233f18c394982407ca90d0dcc/clap_complete/src/engine/complete.rs#L578-L587
2. `complete_subcommand` then sorts it
https://github.com/clap-rs/clap/blob/70f3bb31874ff24233f18c394982407ca90d0dcc/clap_complete/src/engine/complete.rs#L453
2. complete_arg() then deduplicates by id, keeping only the first occurrence which is subject to that sort
https://github.com/clap-rs/clap/blob/70f3bb31874ff24233f18c394982407ca90d0dcc/clap_complete/src/engine/complete.rs#L202-L209
### Debug Output
_No response_
3 条评论