Please complete the following tasks
Rust Version
rustc 1.95.0 (59807616e 2026-04-14)
Clap Version
4.6.1
Minimal reproducible code
I used clap_complete/examples/dynamic.rs.
I replaced the command name dynamic with dyn\amic (... clap::Command::new("dyn\\amic")...)
Details
fn command() -> clap::Command {
clap::Command::new("dyn\\amic")
.arg(
clap::Arg::new("input")
.long("input")
.short('i')
.value_hint(clap::ValueHint::FilePath),
)
.arg(
clap::Arg::new("format")
.long("format")
.short('F')
.value_parser(["json", "yaml", "toml"]),
)
.args_conflicts_with_subcommands(true)
}
fn main() {
clap_complete::CompleteEnv::with_factory(command).complete();
let cmd = command();
let matches = cmd.get_matches();
println!("{matches:#?}");
}
#[test]
fn verify_cli() {
command().debug_assert();
}
Steps to reproduce the bug with the above code
- Compile the app
- If on non-Windows platforms, rename the app, putting backslashes (
\) in the new name (e.g. my\app)
- Run
COMPLETE=fish ./target/debug/<app name>
Actual Behaviour
This will output something like:
complete --keep-order --exclusive --command "dyn\\amic" --arguments "(COMPLETE=fish "C:\\Users\\...t\\target\\debug\\my_app.exe" -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))"
Expected Behaviour
The output should be:
complete --keep-order --exclusive --command "dyn\\\\amic" --arguments "(COMPLETE=fish "C:\\\\Users\\\\...t\\\\target\\\\debug\\\\my_app.exe" -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))"
doubling the escaping for --command and --arguments.
Additionally, for --arguments, clap could use / instead of \ for the path separator, even on Windows. But that's not a full fix since non-Windows platforms can still have a \ in the directory/file names.
And alternatively for --command, don't explicitly use the option name (i.e. use just name instead of --command name).
Additional Context
The issue is because a first unescaping will be done when fish interprets the whole output (typically by source).
Then, for --arguments, there is a second unescaping that will be done during a completion, when fish interprets the --arguments value.
For --command, there is a second unescaping done by complete when processing its arguments. I believe it's a bug in fish, but I'm not certain (fish-shell/fish-shell#12712). When the --command is used implicitly, there is no 2nd unescaping.
Debug Output
No response
Please complete the following tasks
Rust Version
rustc 1.95.0 (59807616e 2026-04-14)
Clap Version
4.6.1
Minimal reproducible code
I used clap_complete/examples/dynamic.rs.
I replaced the command name
dynamicwithdyn\amic(... clap::Command::new("dyn\\amic")...)Details
Steps to reproduce the bug with the above code
\) in the new name (e.g.my\app)COMPLETE=fish ./target/debug/<app name>Actual Behaviour
This will output something like:
Expected Behaviour
The output should be:
doubling the escaping for
--commandand--arguments.Additionally, for
--arguments, clap could use/instead of\for the path separator, even on Windows. But that's not a full fix since non-Windows platforms can still have a\in the directory/file names.And alternatively for
--command, don't explicitly use the option name (i.e. use justnameinstead of--command name).Additional Context
The issue is because a first unescaping will be done when fish interprets the whole output (typically by
source).Then, for
--arguments, there is a second unescaping that will be done during a completion, when fish interprets the--argumentsvalue.For
--command, there is a second unescaping done bycompletewhen processing its arguments. I believe it's a bug in fish, but I'm not certain (fish-shell/fish-shell#12712). When the--commandis used implicitly, there is no 2nd unescaping.Debug Output
No response