You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/03/17 08:02:53 UTC

(maven-mvnd) branch unified-bash-zsh-completion created (now 7f7db5ec)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a change to branch unified-bash-zsh-completion
in repository https://gitbox.apache.org/repos/asf/maven-mvnd.git


      at 7f7db5ec Add zsh support to completion script

This branch includes the following new commits:

     new 7f7db5ec Add zsh support to completion script

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(maven-mvnd) 01/01: Add zsh support to completion script

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch unified-bash-zsh-completion
in repository https://gitbox.apache.org/repos/asf/maven-mvnd.git

commit 7f7db5ec52bdd1373abd22853737715c8650e81d
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Tue Mar 17 09:02:45 2026 +0100

    Add zsh support to completion script
    
    Make the existing bash completion script work in both bash and zsh
    by auto-detecting the shell and adapting behavior accordingly:
    
    - Add shell detection via $ZSH_VERSION / $BASH_VERSION
    - Load bashcompinit in zsh for bash-style completion compatibility
    - Use typeset instead of declare/compgen for zsh
    - Use ${(P)var} instead of ${!var} for indirect expansion in zsh
    - Accept 'zsh' as valid --completion argument in Completion.java
    - Update README.adoc with zsh instructions
    
    Based on the approach from PR #1514 by janweinschenker, consolidated
    into the single existing script to avoid duplication.
    
    Co-Authored-By: Jan Weinschenker <ja...@users.noreply.github.com>
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
 README.adoc                                        |  8 +++--
 .../java/org/mvndaemon/mvnd/client/Completion.java |  7 ++--
 .../completion-templates/mvnd-bash-completion.bash | 37 +++++++++++++++++++---
 dist/src/main/distro/bin/mvnd-bash-completion.bash | 37 +++++++++++++++++++---
 4 files changed, 73 insertions(+), 16 deletions(-)

diff --git a/README.adoc b/README.adoc
index 55a0f4ea..bb888a6e 100644
--- a/README.adoc
+++ b/README.adoc
@@ -106,13 +106,15 @@ $ asdf install mvnd latest
 
 === Set up completion
 
-Optionally, you can set up completion as follows:
+Optionally, you can set up completion in bash or zsh as follows:
 [source,shell]
 ----
-# ensure that MVND_HOME points to your mvnd distribution, note that sdkman does it for you
+# bash: ensure that MVND_HOME points to your mvnd distribution, note that sdkman does it for you
 $ echo 'source $MVND_HOME/bin/mvnd-bash-completion.bash' >> ~/.bashrc
+
+# zsh: same script works in zsh (it auto-detects the shell)
+$ echo 'source $MVND_HOME/bin/mvnd-bash-completion.bash' >> ~/.zshrc
 ----
-`bash` is the only shell supported at this time.
 
 === Install manually
 
diff --git a/client/src/main/java/org/mvndaemon/mvnd/client/Completion.java b/client/src/main/java/org/mvndaemon/mvnd/client/Completion.java
index f971f82a..40241f1e 100644
--- a/client/src/main/java/org/mvndaemon/mvnd/client/Completion.java
+++ b/client/src/main/java/org/mvndaemon/mvnd/client/Completion.java
@@ -27,12 +27,13 @@ import java.nio.file.Path;
 public class Completion {
 
     public static String getCompletion(String shell, DaemonParameters daemonParameters) {
-        if (!"bash".equals(shell)) {
-            throw new IllegalArgumentException("Unexpected --completion value: '" + shell + "'; expected: 'bash'");
+        if (!"bash".equals(shell) && !"zsh".equals(shell)) {
+            throw new IllegalArgumentException(
+                    "Unexpected --completion value: '" + shell + "'; expected: 'bash' or 'zsh'");
         }
         final Path bashCompletionPath = daemonParameters.mvndHome().resolve("bin/mvnd-bash-completion.bash");
         if (!Files.isRegularFile(bashCompletionPath)) {
-            throw new IllegalStateException("Bash completion file does not exist: " + bashCompletionPath);
+            throw new IllegalStateException("Completion file does not exist: " + bashCompletionPath);
         }
         try {
             return new String(Files.readAllBytes(bashCompletionPath), StandardCharsets.UTF_8);
diff --git a/client/src/test/resources/completion-templates/mvnd-bash-completion.bash b/client/src/test/resources/completion-templates/mvnd-bash-completion.bash
index 95eea34f..5cc83b7e 100644
--- a/client/src/test/resources/completion-templates/mvnd-bash-completion.bash
+++ b/client/src/test/resources/completion-templates/mvnd-bash-completion.bash
@@ -17,10 +17,26 @@
 # Adapted from https://github.com/juven/maven-bash-completion/blob/master/bash_completion.bash by Juven Xu and others
 # under Apache License Version 2.0
 
+# Detect shell type and set up zsh compatibility if needed
+if [ -n "$ZSH_VERSION" ]; then
+    __MVND_SHELL="zsh"
+    # Load bashcompinit for bash-style completions in zsh
+    autoload -Uz bashcompinit 2>/dev/null && bashcompinit
+    # Define COMP_WORDBREAKS if not set (bash sets this automatically)
+    [[ -z "$COMP_WORDBREAKS" ]] && COMP_WORDBREAKS=$' \t\n"\'><=;|&(:'
+else
+    __MVND_SHELL="bash"
+fi
+
 function_exists()
 {
-    declare -F $1 > /dev/null
-    return $?
+    if [ "$__MVND_SHELL" = "zsh" ]; then
+        typeset -f $1 > /dev/null 2>&1
+        return $?
+    else
+        declare -F $1 > /dev/null
+        return $?
+    fi
 }
 
 # This function can be used to access a tokenized list of words
@@ -288,7 +304,12 @@ _mvnd()
     local plugin_goals_formatter="formatter:format|formatter:help|formatter:validate"
 
     ## some plugin (like jboss-as) has '-' which is not allowed in shell var name, to use '_' then replace
-    local common_plugins=`compgen -v | grep "^plugin_goals_.*" | sed 's/plugin_goals_//g' | tr '_' '-' | tr '\n' '|'`
+    local common_plugins
+    if [ "$__MVND_SHELL" = "zsh" ]; then
+        common_plugins=$(typeset + | grep "^plugin_goals_" | sed 's/plugin_goals_//g' | tr '_' '-' | tr '\n' '|')
+    else
+        common_plugins=`compgen -v | grep "^plugin_goals_.*" | sed 's/plugin_goals_//g' | tr '_' '-' | tr '\n' '|'`
+    fi
 
     local options="-Dmaven.test.skip=true|-DskipTests|-DskipITs|-Dtest|-Dit.test|-DfailIfNoTests|-Dmaven.surefire.debug|-DenableCiProfile|-Dpmd.skip=true|-Dcheckstyle.skip=true|-Dtycho.mode=maven|-Dmaven.javadoc.skip=true|-Dgwt.compiler.skip|-Dcobertura.skip=true|-Dfindbugs.skip=true||-DperformRelease=true|-Dgpg.skip=true|-DforkCount|${mvnd_properties}"
 
@@ -334,8 +355,14 @@ _mvnd()
         for plugin in $common_plugins; do
           if [[ ${cur} == ${plugin}:* ]]; then
             ## note that here is an 'unreplace', see the comment at common_plugins
-            var_name="plugin_goals_${plugin//-/_}"
-            COMPREPLY=( $(compgen -W "${!var_name}" -S ' ' -- ${cur}) )
+            local var_name="plugin_goals_${plugin//-/_}"
+            local var_value
+            if [ "$__MVND_SHELL" = "zsh" ]; then
+                var_value="${(P)var_name}"
+            else
+                var_value="${!var_name}"
+            fi
+            COMPREPLY=( $(compgen -W "${var_value}" -S ' ' -- ${cur}) )
           fi
         done
 
diff --git a/dist/src/main/distro/bin/mvnd-bash-completion.bash b/dist/src/main/distro/bin/mvnd-bash-completion.bash
index cce9a82f..a2ea1801 100755
--- a/dist/src/main/distro/bin/mvnd-bash-completion.bash
+++ b/dist/src/main/distro/bin/mvnd-bash-completion.bash
@@ -17,10 +17,26 @@
 # Adapted from https://github.com/juven/maven-bash-completion/blob/master/bash_completion.bash by Juven Xu and others
 # under Apache License Version 2.0
 
+# Detect shell type and set up zsh compatibility if needed
+if [ -n "$ZSH_VERSION" ]; then
+    __MVND_SHELL="zsh"
+    # Load bashcompinit for bash-style completions in zsh
+    autoload -Uz bashcompinit 2>/dev/null && bashcompinit
+    # Define COMP_WORDBREAKS if not set (bash sets this automatically)
+    [[ -z "$COMP_WORDBREAKS" ]] && COMP_WORDBREAKS=$' \t\n"\'><=;|&(:'
+else
+    __MVND_SHELL="bash"
+fi
+
 function_exists()
 {
-    declare -F $1 > /dev/null
-    return $?
+    if [ "$__MVND_SHELL" = "zsh" ]; then
+        typeset -f $1 > /dev/null 2>&1
+        return $?
+    else
+        declare -F $1 > /dev/null
+        return $?
+    fi
 }
 
 # This function can be used to access a tokenized list of words
@@ -288,7 +304,12 @@ _mvnd()
     local plugin_goals_formatter="formatter:format|formatter:help|formatter:validate"
 
     ## some plugin (like jboss-as) has '-' which is not allowed in shell var name, to use '_' then replace
-    local common_plugins=`compgen -v | grep "^plugin_goals_.*" | sed 's/plugin_goals_//g' | tr '_' '-' | tr '\n' '|'`
+    local common_plugins
+    if [ "$__MVND_SHELL" = "zsh" ]; then
+        common_plugins=$(typeset + | grep "^plugin_goals_" | sed 's/plugin_goals_//g' | tr '_' '-' | tr '\n' '|')
+    else
+        common_plugins=`compgen -v | grep "^plugin_goals_.*" | sed 's/plugin_goals_//g' | tr '_' '-' | tr '\n' '|'`
+    fi
 
     local options="-Dmaven.test.skip=true|-DskipTests|-DskipITs|-Dtest|-Dit.test|-DfailIfNoTests|-Dmaven.surefire.debug|-DenableCiProfile|-Dpmd.skip=true|-Dcheckstyle.skip=true|-Dtycho.mode=maven|-Dmaven.javadoc.skip=true|-Dgwt.compiler.skip|-Dcobertura.skip=true|-Dfindbugs.skip=true||-DperformRelease=true|-Dgpg.skip=true|-DforkCount|${mvnd_properties}"
 
@@ -334,8 +355,14 @@ _mvnd()
         for plugin in $common_plugins; do
           if [[ ${cur} == ${plugin}:* ]]; then
             ## note that here is an 'unreplace', see the comment at common_plugins
-            var_name="plugin_goals_${plugin//-/_}"
-            COMPREPLY=( $(compgen -W "${!var_name}" -S ' ' -- ${cur}) )
+            local var_name="plugin_goals_${plugin//-/_}"
+            local var_value
+            if [ "$__MVND_SHELL" = "zsh" ]; then
+                var_value="${(P)var_name}"
+            else
+                var_value="${!var_name}"
+            fi
+            COMPREPLY=( $(compgen -W "${var_value}" -S ' ' -- ${cur}) )
           fi
         done