Repository: clap-rs/clap
Pull request #5791 (2024-10-28 20:12:59)

fix(zsh): Use _default as the completion fallback where the ValueHint is Unknown
This is consistent with bash where `compgen -f` is used in such cases. In long experience with completions distributed with zsh, the worst thing you can do is break filename completion as that's the minimum most user's expect. By default, _default just completes files. It is also far better to leave the final component blank from `ValueHint::Other` as using empty parentheses will cause zsh to do slightly more work for the same result.

For context, note that I'm a zsh developer and have a lot of experience of writing zsh completions manually.


Patch:
diff --git a/clap_complete/src/aot/shells/zsh.rs b/clap_complete/src/aot/shells/zsh.rs
index 364df24f..64420095 100644
--- a/clap_complete/src/aot/shells/zsh.rs
+++ b/clap_complete/src/aot/shells/zsh.rs
@@ -396,10 +396,8 @@ fn value_completion(arg: &Arg) -> Option<String> {
         // NB! If you change this, please also update the table in `ValueHint` documentation.
         Some(
             match arg.get_value_hint() {
-                ValueHint::Unknown => {
-                    return None;
-                }
-                ValueHint::Other => "( )",
+                ValueHint::Unknown => "_default",
+                ValueHint::Other => "",
                 ValueHint::AnyPath => "_files",
                 ValueHint::FilePath => "_files",
                 ValueHint::DirPath => "_files -/",


Test patch:
diff --git a/clap_complete/tests/snapshots/aliases.zsh b/clap_complete/tests/snapshots/aliases.zsh
index c39eee02..4a7323bc 100644
--- a/clap_complete/tests/snapshots/aliases.zsh
+++ b/clap_complete/tests/snapshots/aliases.zsh
@@ -15,10 +15,10 @@ _my-app() {
 
     local context curcontext="$curcontext" state line
     _arguments "${_arguments_options[@]}" : \
-'-o+[cmd option]: : ' \
-'-O+[cmd option]: : ' \
-'--option=[cmd option]: : ' \
-'--opt=[cmd option]: : ' \
+'-o+[cmd option]: :_default' \
+'-O+[cmd option]: :_default' \
+'--option=[cmd option]: :_default' \
+'--opt=[cmd option]: :_default' \
 '-f[cmd flag]' \
 '-F[cmd flag]' \
 '--flag[cmd flag]' \
@@ -27,7 +27,7 @@ _my-app() {
 '--help[Print help]' \
 '-V[Print version]' \
 '--version[Print version]' \
-'::positional:' \
+'::positional:_default' \
 && ret=0
 }
 
diff --git a/clap_complete/tests/snapshots/feature_sample.zsh b/clap_complete/tests/snapshots/feature_sample.zsh
index be965ac3..ff0f99f4 100644
--- a/clap_complete/tests/snapshots/feature_sample.zsh
+++ b/clap_complete/tests/snapshots/feature_sample.zsh
@@ -36,7 +36,7 @@ _my-app() {
         case $line[3] in
             (test)
 _arguments "${_arguments_options[@]}" : \
-'--case=[the case to test]: : ' \
+'--case=[the case to test]: :_default' \
 '-h[Print help]' \
 '--help[Print help]' \
 '-V[Print version]' \
diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive b/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive
index 52819144..ad827ab1 100644
--- a/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive
+++ b/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive
@@ -32,7 +32,7 @@ _exhaustive() {
         case $line[1] in
             (action)
 _arguments "${_arguments_options[@]}" : \
-'--set=[value]: : ' \
+'--set=[value]: :_default' \
 '--choice=[enum]: :(first second)' \
 '--set-true[bool]' \
 '*--count[number]' \
@@ -187,15 +187,15 @@ esac
 ;;
 (value)
 _arguments "${_arguments_options[@]}" : \
-'--delim=[]: : ' \
-'--tuple=[]: : : : ' \
-'--require-eq=[]: : ' \
+'--delim=[]: :_default' \
+'--tuple=[]: :_default: :_default' \
+'--require-eq=[]: :_default' \
 '--global[everywhere]' \
 '-h[Print help]' \
 '--help[Print help]' \
 '-V[Print version]' \
 '--version[Print version]' \
-'*;::term:' \
+'*;::term:_default' \
 && ret=0
 ;;
 (pacman)
@@ -272,16 +272,16 @@ _arguments "${_arguments_options[@]}" : \
 '--help[Print help]' \
 '-V[Print version]' \
 '--version[Print version]' \
-'::first:' \
-'::free:' \
+'::first:_default' \
+'::free:_default' \
 && ret=0
 ;;
 (alias)
 _arguments "${_arguments_options[@]}" : \
-'-o+[cmd option]: : ' \
-'-O+[cmd option]: : ' \
-'--option=[cmd option]: : ' \
-'--opt=[cmd option]: : ' \
+'-o+[cmd option]: :_default' \
+'-O+[cmd option]: :_default' \
+'--option=[cmd option]: :_default' \
+'--opt=[cmd option]: :_default' \
 '-f[cmd flag]' \
 '-F[cmd flag]' \
 '--flag[cmd flag]' \
@@ -291,14 +291,14 @@ _arguments "${_arguments_options[@]}" : \
 '--help[Print help]' \
 '-V[Print version]' \
 '--version[Print version]' \
-'::positional:' \
+'::positional:_default' \
 && ret=0
 ;;
 (hint)
 _arguments "${_arguments_options[@]}" : \
 '--choice=[]: :(bash fish zsh)' \
-'--unknown=[]: : ' \
-'--other=[]: :( )' \
+'--unknown=[]: :_default' \
+'--other=[]: :' \
 '-p+[]: :_files' \
 '--path=[]: :_files' \
 '-f+[]: :_files' \
diff --git a/clap_complete/tests/snapshots/special_commands.zsh b/clap_complete/tests/snapshots/special_commands.zsh
index 31fe192b..dc5323a4 100644
--- a/clap_complete/tests/snapshots/special_commands.zsh
+++ b/clap_complete/tests/snapshots/special_commands.zsh
@@ -36,7 +36,7 @@ _my-app() {
         case $line[3] in
             (test)
 _arguments "${_arguments_options[@]}" : \
-'--case=[the case to test]: : ' \
+'--case=[the case to test]: :_default' \
 '-h[Print help]' \
 '--help[Print help]' \
 '-V[Print version]' \
@@ -45,12 +45,12 @@ _arguments "${_arguments_options[@]}" : \
 ;;
 (some_cmd)
 _arguments "${_arguments_options[@]}" : \
-'--config=[the other case to test]: : ' \
+'--config=[the other case to test]: :_default' \
 '-h[Print help]' \
 '--help[Print help]' \
 '-V[Print version]' \
 '--version[Print version]' \
-'*::path:' \
+'*::path:_default' \
 && ret=0
 ;;
 (some-cmd-with-hyphens)
diff --git a/clap_complete/tests/snapshots/sub_subcommands.zsh b/clap_complete/tests/snapshots/sub_subcommands.zsh
index e51249c9..383f5f68 100644
--- a/clap_complete/tests/snapshots/sub_subcommands.zsh
+++ b/clap_complete/tests/snapshots/sub_subcommands.zsh
@@ -36,7 +36,7 @@ _my-app() {
         case $line[3] in
             (test)
 _arguments "${_arguments_options[@]}" : \
-'--case=[the case to test]: : ' \
+'--case=[the case to test]: :_default' \
 '-h[Print help]' \
 '--help[Print help]' \
 '-V[Print version]' \
diff --git a/clap_complete/tests/snapshots/subcommand_last.zsh b/clap_complete/tests/snapshots/subcommand_last.zsh
index 0aca7f8d..5bb3bd16 100644
--- a/clap_complete/tests/snapshots/subcommand_last.zsh
+++ b/clap_complete/tests/snapshots/subcommand_last.zsh
@@ -17,7 +17,7 @@ _my-app() {
     _arguments "${_arguments_options[@]}" : \
 '-h[Print help]' \
 '--help[Print help]' \
-'::free:' \
+'::free:_default' \
 ":: :_my-app_commands" \
 "*::: :->my-app" \
 && ret=0
diff --git a/clap_complete/tests/snapshots/two_multi_valued_arguments.zsh b/clap_complete/tests/snapshots/two_multi_valued_arguments.zsh
index 656b499f..341aa183 100644
--- a/clap_complete/tests/snapshots/two_multi_valued_arguments.zsh
+++ b/clap_complete/tests/snapshots/two_multi_valued_arguments.zsh
@@ -17,7 +17,7 @@ _my-app() {
     _arguments "${_arguments_options[@]}" : \
 '-h[Print help]' \
 '--help[Print help]' \
-'*::first -- first multi-valued argument:' \
+'*::first -- first multi-valued argument:_default' \
 && ret=0
 }
 
diff --git a/clap_complete/tests/snapshots/value_hint.zsh b/clap_complete/tests/snapshots/value_hint.zsh
index e52621e5..ff8fc71e 100644
--- a/clap_complete/tests/snapshots/value_hint.zsh
+++ b/clap_complete/tests/snapshots/value_hint.zsh
@@ -16,8 +16,8 @@ _my-app() {
     local context curcontext="$curcontext" state line
     _arguments "${_arguments_options[@]}" : \
 '--choice=[]: :(bash fish zsh)' \
-'--unknown=[]: : ' \
-'--other=[]: :( )' \
+'--unknown=[]: :_default' \
+'--other=[]: :' \
 '-p+[]: :_files' \
 '--path=[]: :_files' \
 '-f+[]: :_files' \
diff --git a/clap_complete/tests/snapshots/value_terminator.zsh b/clap_complete/tests/snapshots/value_terminator.zsh
index ea17d230..b87b1745 100644
--- a/clap_complete/tests/snapshots/value_terminator.zsh
+++ b/clap_complete/tests/snapshots/value_terminator.zsh
@@ -17,7 +17,7 @@ _my-app() {
     _arguments "${_arguments_options[@]}" : \
 '-h[Print help]' \
 '--help[Print help]' \
-'*;::arguments -- multi-valued argument with a value terminator:' \
+'*;::arguments -- multi-valued argument with a value terminator:_default' \
 && ret=0
 }