Repository: clap-rs/clap
Pull request #2359 (2021-02-22 15:00:11)

fix: Do not look for subcommands in fish completion if none exist
Fish completions currently insert `-n "__fish_use_subcommand"` to detect subcommands and disable completions of top-level flags. There are unfortunately false positives, so there are no flag completions after you've typed e.g. `rg -C 10` because `10` is taken as a subcommand.

This change disables that detection when there are no subcommands defined in the first place, as an easy fix for some cases.


Patch:
diff --git a/clap_generate/src/generators/shells/fish.rs b/clap_generate/src/generators/shells/fish.rs
index 859212bc..e16be054 100644
--- a/clap_generate/src/generators/shells/fish.rs
+++ b/clap_generate/src/generators/shells/fish.rs
@@ -44,14 +44,17 @@ fn gen_fish_inner(root_command: &str, app: &App, buffer: &mut String) {
     //      -n "__fish_use_subcommand"               # complete for command "myprog"
     //      -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1"
 
-    let mut basic_template = format!("complete -c {} -n ", root_command);
+    let mut basic_template = format!("complete -c {}", root_command);
     let mut bin_name = app.get_bin_name().unwrap();
 
     if root_command == bin_name {
-        basic_template.push_str("\"__fish_use_subcommand\"");
+        if app.has_subcommands() {
+            basic_template.push_str(" -n \"__fish_use_subcommand\"");
+        }
     } else {
         bin_name = &app.get_name();
-        basic_template.push_str(format!("\"__fish_seen_subcommand_from {}\"", bin_name).as_str());
+        basic_template
+            .push_str(format!(" -n \"__fish_seen_subcommand_from {}\"", bin_name).as_str());
     }
 
     debug!("gen_fish_inner: bin_name={}", bin_name);


Test patch:
diff --git a/clap_generate/tests/completions/fish.rs b/clap_generate/tests/completions/fish.rs
index 0d82adb6..432c98de 100644
--- a/clap_generate/tests/completions/fish.rs
+++ b/clap_generate/tests/completions/fish.rs
@@ -112,14 +112,14 @@ fn build_app_special_help() -> App<'static> {
         )
 }
 
-static FISH_SPECIAL_HELP: &str = r#"complete -c my_app -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'
-complete -c my_app -n "__fish_use_subcommand" -s V -l version -d 'Prints version information'
-complete -c my_app -n "__fish_use_subcommand" -l single-quotes -d 'Can be \'always\', \'auto\', or \'never\''
-complete -c my_app -n "__fish_use_subcommand" -l double-quotes -d 'Can be "always", "auto", or "never"'
-complete -c my_app -n "__fish_use_subcommand" -l backticks -d 'For more information see `echo test`'
-complete -c my_app -n "__fish_use_subcommand" -l backslash -d 'Avoid \'\\n\''
-complete -c my_app -n "__fish_use_subcommand" -l brackets -d 'List packages [filter]'
-complete -c my_app -n "__fish_use_subcommand" -l expansions -d 'Execute the shell command with $SHELL'
+static FISH_SPECIAL_HELP: &str = r#"complete -c my_app -s h -l help -d 'Prints help information'
+complete -c my_app -s V -l version -d 'Prints version information'
+complete -c my_app -l single-quotes -d 'Can be \'always\', \'auto\', or \'never\''
+complete -c my_app -l double-quotes -d 'Can be "always", "auto", or "never"'
+complete -c my_app -l backticks -d 'For more information see `echo test`'
+complete -c my_app -l backslash -d 'Avoid \'\\n\''
+complete -c my_app -l brackets -d 'List packages [filter]'
+complete -c my_app -l expansions -d 'Execute the shell command with $SHELL'
 "#;
 
 #[test]
@@ -151,8 +151,8 @@ fn build_app_with_aliases() -> App<'static> {
         .arg(Arg::new("positional"))
 }
 
-static FISH_ALIASES: &str = r#"complete -c cmd -n "__fish_use_subcommand" -s o -s O -l option -l opt -d 'cmd option' -r
-complete -c cmd -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'
-complete -c cmd -n "__fish_use_subcommand" -s V -l version -d 'Prints version information'
-complete -c cmd -n "__fish_use_subcommand" -s f -s F -l flag -l flg -d 'cmd flag'
+static FISH_ALIASES: &str = r#"complete -c cmd -s o -s O -l option -l opt -d 'cmd option' -r
+complete -c cmd -s h -l help -d 'Prints help information'
+complete -c cmd -s V -l version -d 'Prints version information'
+complete -c cmd -s f -s F -l flag -l flg -d 'cmd flag'
 "#;
diff --git a/clap_generate/tests/value_hints.rs b/clap_generate/tests/value_hints.rs
index 5391a202..2cf678ff 100644
--- a/clap_generate/tests/value_hints.rs
+++ b/clap_generate/tests/value_hints.rs
@@ -130,20 +130,20 @@ _my_app_commands() {
 
 _my_app "$@""#;
 
-static FISH_VALUE_HINTS: &str = r#"complete -c my_app -n "__fish_use_subcommand" -l choice -r -f -a "bash fish zsh"
-complete -c my_app -n "__fish_use_subcommand" -l unknown -r
-complete -c my_app -n "__fish_use_subcommand" -l other -r -f
-complete -c my_app -n "__fish_use_subcommand" -s p -l path -r -F
-complete -c my_app -n "__fish_use_subcommand" -s f -l file -r -F
-complete -c my_app -n "__fish_use_subcommand" -s d -l dir -r -f -a "(__fish_complete_directories)"
-complete -c my_app -n "__fish_use_subcommand" -s e -l exe -r -F
-complete -c my_app -n "__fish_use_subcommand" -l cmd-name -r -f -a "(__fish_complete_command)"
-complete -c my_app -n "__fish_use_subcommand" -s c -l cmd -r -f -a "(__fish_complete_command)"
-complete -c my_app -n "__fish_use_subcommand" -s u -l user -r -f -a "(__fish_complete_users)"
-complete -c my_app -n "__fish_use_subcommand" -s h -l host -r -f -a "(__fish_print_hostnames)"
-complete -c my_app -n "__fish_use_subcommand" -l url -r -f
-complete -c my_app -n "__fish_use_subcommand" -l email -r -f
-complete -c my_app -n "__fish_use_subcommand" -l help -d 'Prints help information'
+static FISH_VALUE_HINTS: &str = r#"complete -c my_app -l choice -r -f -a "bash fish zsh"
+complete -c my_app -l unknown -r
+complete -c my_app -l other -r -f
+complete -c my_app -s p -l path -r -F
+complete -c my_app -s f -l file -r -F
+complete -c my_app -s d -l dir -r -f -a "(__fish_complete_directories)"
+complete -c my_app -s e -l exe -r -F
+complete -c my_app -l cmd-name -r -f -a "(__fish_complete_command)"
+complete -c my_app -s c -l cmd -r -f -a "(__fish_complete_command)"
+complete -c my_app -s u -l user -r -f -a "(__fish_complete_users)"
+complete -c my_app -s h -l host -r -f -a "(__fish_print_hostnames)"
+complete -c my_app -l url -r -f
+complete -c my_app -l email -r -f
+complete -c my_app -l help -d 'Prints help information'
 "#;
 
 #[test]