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:54 UTC
(maven-mvnd) 01/01: Add zsh support to completion script
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