Repository: clap-rs/clap (language: rust)

Issue:
Fish completions include --no-files on subcommands
Hello! I first reported this issue downstream in https://github.com/MilesCranmer/rip2. The issue is that the completions generated for fish include `-f` which prevents files from being included in completion, which in this case is not desired.

Original issue: https://github.com/MilesCranmer/rip2/issues/39

Since I'm not familiar with rust I'll just elaborate on the issue itself, here are the completions generated from rip2:

```fish
complete -c rip -n "__fish_use_subcommand" -l graveyard -d 'Directory where deleted files rest' -r -F
complete -c rip -n "__fish_use_subcommand" -s d -l decompose -d 'Permanently deletes the graveyard'
complete -c rip -n "__fish_use_subcommand" -s s -l seance -d 'Prints files that were deleted in the current directory'
complete -c rip -n "__fish_use_subcommand" -s u -l unbury -d 'Restore the specified files or the last file if none are specified'
complete -c rip -n "__fish_use_subcommand" -s i -l inspect -d 'Print some info about TARGET before burying'
complete -c rip -n "__fish_use_subcommand" -s h -l help -d 'Print help'
complete -c rip -n "__fish_use_subcommand" -s V -l version -d 'Print version'
complete -c rip -n "__fish_use_subcommand" -f -a "completions" -d 'Generate shell completions file'
complete -c rip -n "__fish_use_subcommand" -f -a "graveyard" -d 'Print the graveyard path'
complete -c rip -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
complete -c rip -n "__fish_seen_subcommand_from completions" -s h -l help -d 'Print help'
complete -c rip -n "__fish_seen_subcommand_from graveyard" -s s -l seance -d 'Get the graveyard subdirectory of the current directory'
complete -c rip -n "__fish_seen_subcommand_from graveyard" -s h -l help -d 'Print help'
complete -c rip -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from completions; and not __fish_seen_subcommand_from graveyard; and not __fish_seen_subcommand_from help" -f -a "completions" -d 'Generate shell completions file'
complete -c rip -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from completions; and not __fish_seen_subcommand_from graveyard; and not __fish_seen_subcommand_from help" -f -a "graveyard" -d 'Print the graveyard path'
complete -c rip -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from completions; and not __fish_seen_subcommand_from graveyard; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
```

And it's these 3 that (in my testing) are the problematic `-f` flags:

```fish
complete -c rip -n "__fish_use_subcommand" -f -a "completions" -d 'Generate shell completions file'
complete -c rip -n "__fish_use_subcommand" -f -a "graveyard" -d 'Print the graveyard path'
complete -c rip -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
```

Removing those allows files to be included in completion. Here's the author's reply on their usage:

> For reference, the completions get generated by `clap_complete` here:
> 
> https://github.com/MilesCranmer/rip2/blob/75ea37ef4ea16ae64809e9c50999d95fd6a809bd/src/completions.rs#L24
> 
> I _think_ I'm specifying subcommands correctly here:
> 
> https://github.com/MilesCranmer/rip2/blob/75ea37ef4ea16ae64809e9c50999d95fd6a809bd/src/args.rs#L114


Discussion / hints:
Not knowing rip2, could you give an example of like

> Try completing
>
> ```console
> $ rip2 something\t
> ```
> Expected completions:
>
> Actual completions:

If I'm understanding correctly, it sounds like `rip2` takes subcommands *xor* positional arguments and the `-f` on subcommands is preventing the completion of the positional arguments and hoping a further elaboration like above can clarify the problem.
Here's an example of the issue:

```sh
touch great.sh
rip gr\t
```

Expected completions:

```sh
great.sh
graveyard
```

Actual completions

```
graveyard
```

Hopefully this is more clear, let me know if I can provide anything further.
Thanks!

To fix this, we'll need to check whether positionals are supported in addition to subcommands.

We should ensure a test has this covered in a commit before making the change so that the tests get updated along the way, showing how the behavior changed.

Fix patch:
diff --git a/clap_complete/src/shells/fish.rs b/clap_complete/src/shells/fish.rs
index 1c070b2fb98..a6177ae7df9 100644
--- a/clap_complete/src/shells/fish.rs
+++ b/clap_complete/src/shells/fish.rs
@@ -136,11 +136,14 @@ fn gen_fish_inner(
         buffer.push('\n');
     }
 
+    let has_positionals = cmd.get_positionals().next().is_some();
+    if !has_positionals {
+        basic_template.push_str(" -f");
+    }
     for subcommand in cmd.get_subcommands() {
         for subcommand_name in subcommand.get_name_and_visible_aliases() {
             let mut template = basic_template.clone();
 
-            template.push_str(" -f");
             template.push_str(format!(" -a \"{}\"", subcommand_name).as_str());
 
             if let Some(data) = subcommand.get_about() {


Test patch:
diff --git a/clap_complete/tests/snapshots/feature_sample.fish b/clap_complete/tests/snapshots/feature_sample.fish
index 60a0716b3c1..da54b624d0b 100644
--- a/clap_complete/tests/snapshots/feature_sample.fish
+++ b/clap_complete/tests/snapshots/feature_sample.fish
@@ -1,8 +1,8 @@
 complete -c my-app -n "__fish_use_subcommand" -s c -s C -l config -l conf -d 'some config file'
 complete -c my-app -n "__fish_use_subcommand" -s h -l help -d 'Print help'
 complete -c my-app -n "__fish_use_subcommand" -s V -l version -d 'Print version'
-complete -c my-app -n "__fish_use_subcommand" -f -a "test" -d 'tests things'
-complete -c my-app -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
+complete -c my-app -n "__fish_use_subcommand" -a "test" -d 'tests things'
+complete -c my-app -n "__fish_use_subcommand" -a "help" -d 'Print this message or the help of the given subcommand(s)'
 complete -c my-app -n "__fish_seen_subcommand_from test" -l case -d 'the case to test' -r
 complete -c my-app -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help'
 complete -c my-app -n "__fish_seen_subcommand_from test" -s V -l version -d 'Print version'
diff --git a/clap_complete/tests/snapshots/special_commands.fish b/clap_complete/tests/snapshots/special_commands.fish
index dd7d0b54eeb..c7eb3e7b19f 100644
--- a/clap_complete/tests/snapshots/special_commands.fish
+++ b/clap_complete/tests/snapshots/special_commands.fish
@@ -1,11 +1,11 @@
 complete -c my-app -n "__fish_use_subcommand" -s c -s C -l config -l conf -d 'some config file'
 complete -c my-app -n "__fish_use_subcommand" -s h -l help -d 'Print help'
 complete -c my-app -n "__fish_use_subcommand" -s V -l version -d 'Print version'
-complete -c my-app -n "__fish_use_subcommand" -f -a "test" -d 'tests things'
-complete -c my-app -n "__fish_use_subcommand" -f -a "some_cmd" -d 'tests other things'
-complete -c my-app -n "__fish_use_subcommand" -f -a "some-cmd-with-hyphens"
-complete -c my-app -n "__fish_use_subcommand" -f -a "some-hidden-cmd"
-complete -c my-app -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
+complete -c my-app -n "__fish_use_subcommand" -a "test" -d 'tests things'
+complete -c my-app -n "__fish_use_subcommand" -a "some_cmd" -d 'tests other things'
+complete -c my-app -n "__fish_use_subcommand" -a "some-cmd-with-hyphens"
+complete -c my-app -n "__fish_use_subcommand" -a "some-hidden-cmd"
+complete -c my-app -n "__fish_use_subcommand" -a "help" -d 'Print this message or the help of the given subcommand(s)'
 complete -c my-app -n "__fish_seen_subcommand_from test" -l case -d 'the case to test' -r
 complete -c my-app -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help'
 complete -c my-app -n "__fish_seen_subcommand_from test" -s V -l version -d 'Print version'
diff --git a/clap_complete/tests/snapshots/sub_subcommands.fish b/clap_complete/tests/snapshots/sub_subcommands.fish
index 7188ca31164..3b2b0ea3a91 100644
--- a/clap_complete/tests/snapshots/sub_subcommands.fish
+++ b/clap_complete/tests/snapshots/sub_subcommands.fish
@@ -1,10 +1,10 @@
 complete -c my-app -n "__fish_use_subcommand" -s c -s C -l config -l conf -d 'some config file'
 complete -c my-app -n "__fish_use_subcommand" -s h -l help -d 'Print help'
 complete -c my-app -n "__fish_use_subcommand" -s V -l version -d 'Print version'
-complete -c my-app -n "__fish_use_subcommand" -f -a "test" -d 'tests things'
-complete -c my-app -n "__fish_use_subcommand" -f -a "some_cmd" -d 'top level subcommand'
-complete -c my-app -n "__fish_use_subcommand" -f -a "some_cmd_alias" -d 'top level subcommand'
-complete -c my-app -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
+complete -c my-app -n "__fish_use_subcommand" -a "test" -d 'tests things'
+complete -c my-app -n "__fish_use_subcommand" -a "some_cmd" -d 'top level subcommand'
+complete -c my-app -n "__fish_use_subcommand" -a "some_cmd_alias" -d 'top level subcommand'
+complete -c my-app -n "__fish_use_subcommand" -a "help" -d 'Print this message or the help of the given subcommand(s)'
 complete -c my-app -n "__fish_seen_subcommand_from test" -l case -d 'the case to test' -r
 complete -c my-app -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help'
 complete -c my-app -n "__fish_seen_subcommand_from test" -s V -l version -d 'Print version'
diff --git a/clap_complete/tests/snapshots/subcommand_last.fish b/clap_complete/tests/snapshots/subcommand_last.fish
index 16d7fdb0203..c4cdd44065d 100644
--- a/clap_complete/tests/snapshots/subcommand_last.fish
+++ b/clap_complete/tests/snapshots/subcommand_last.fish
@@ -1,7 +1,7 @@
 complete -c my-app -n "__fish_use_subcommand" -s h -l help -d 'Print help'
-complete -c my-app -n "__fish_use_subcommand" -f -a "foo"
-complete -c my-app -n "__fish_use_subcommand" -f -a "bar"
-complete -c my-app -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
+complete -c my-app -n "__fish_use_subcommand" -a "foo"
+complete -c my-app -n "__fish_use_subcommand" -a "bar"
+complete -c my-app -n "__fish_use_subcommand" -a "help" -d 'Print this message or the help of the given subcommand(s)'
 complete -c my-app -n "__fish_seen_subcommand_from foo" -s h -l help -d 'Print help'
 complete -c my-app -n "__fish_seen_subcommand_from bar" -s h -l help -d 'Print help'
 complete -c my-app -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from foo bar help" -f -a "foo"