summaryrefslogtreecommitdiff
path: root/Completion/Unix/Command
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Unix/Command')
-rw-r--r--Completion/Unix/Command/_composer850
-rw-r--r--Completion/Unix/Command/_git12
-rw-r--r--Completion/Unix/Command/_ipsec179
-rw-r--r--Completion/Unix/Command/_swanctl225
4 files changed, 1256 insertions, 10 deletions
diff --git a/Completion/Unix/Command/_composer b/Completion/Unix/Command/_composer
new file mode 100644
index 000000000..2b9f2cd32
--- /dev/null
+++ b/Completion/Unix/Command/_composer
@@ -0,0 +1,850 @@
+#compdef composer composer.phar
+
+# Notes:
+# - With some re-arranging, this function could be used as a base for completing
+# any Symfony Console application. It's worth mentioning that most Console
+# applications provide their help output in structured XML and JSON formats,
+# and a helper function could be written to parse these and produce basic
+# completion similar to what `_arguments --` does. But it wouldn't be fully
+# featured like this
+# - Completing arbitrary package names from Packagist, even with caching enabled
+# (which it is by default here), can be very slow; it may even hang the shell.
+# To disable the fetching of remote packages and use only local cache/JSON
+# information for completion, set the fetch-packages style as follows:
+# zstyle ':completion:*:composer:*' fetch-packages no
+# - @todo We don't complete custom commands (including script aliases). This is
+# easy to do in the general case, but it probably requires some clever caching
+# to avoid introducing a noticeable lag to every completion operation, due to
+# the way command resolution works and the fact that discovering custom
+# commands requires making slow calls to Composer
+# - @todo We don't complete version constraints
+
+# Check cache validity
+__composer_cache_policy() {
+ # Invalidate if the cache is over a week old
+ [[ -n $1(#qmw+1N) ]] && return 0
+
+ __composer_update_work_dir
+
+ # Invalidate if the current project JSON file is newer than the cache
+ [[ -e $_composer_work_dir/composer.json ]] &&
+ [[ $_composer_work_dir/composer.json -nt $1 ]]
+}
+
+# _call_program wrapper (same eval/quoting rules apply)
+# $1 => tag
+# $2 ... => composer arguments
+(( $+functions[__composer_call] )) ||
+__composer_call() {
+ local -a cmd
+
+ __composer_update_work_dir
+
+ cmd=( ${_composer_cmd:-composer} -d${_composer_work_dir:-${(q)PWD}} )
+ (( _composer_is_global )) && cmd+=( global )
+
+ _call_program $1 $cmd "${@[2,-1]}"
+}
+
+# Resolve potentially abbreviated/aliased command name to canonical name
+# $1 => name of scalar parameter to set
+# $2 => provided command name
+(( $+functions[__composer_resolve_cmd] )) ||
+__composer_resolve_cmd() {
+ local __i __ret=1
+ local -a __cmds __tmp=( ${(@)_composer_cmds%%:*} )
+
+ __cmds=( $__tmp[(r)$2] )
+ (( $#__cmds )) || __cmds=( ${(M)__tmp:#$2*} )
+
+ if (( $#__cmds == 1 )); then
+ 2=$__cmds[1]
+ (( $+_composer_cmd_aliases[$2] )) && 2=$_composer_cmd_aliases[$2]
+ __ret=0
+ else
+ 3=$__cmds[1]
+
+ # An ambiguous prefix match isn't ambiguous if all the matches are aliases
+ # of each other
+ for (( __i = 2; __i <= $#__cmds; __i++ )); do
+ if [[ $_composer_cmd_aliases[$__cmds[__i]] == $3 ]]; then
+ __cmds[__i]=()
+ elif [[ $_composer_cmd_aliases[$3] == $__cmds[__i] ]]; then
+ 3=$__cmds[__i]
+ __cmds[__i]=()
+ fi
+ done
+
+ if (( $#__cmds == 1 )); then
+ 2=$3
+ __ret=0
+ elif (( $#__cmds )); then
+ _message -e ambiguous-commands "ambiguous command: $2 ($__cmds)"
+ else
+ # @todo Too annoying without handling custom commands
+ : _message -e unrecognized-commands "unrecognized command: $2"
+ fi
+ fi
+ : ${(P)1::=$2}
+ return __ret
+}
+
+# Remove already-used global options (this is a bit silly admittedly)
+# $1 ... => options given (e.g. ${(k)opt_args})
+(( $+functions[__composer_prune_global_opts] )) ||
+__composer_prune_global_opts() {
+ local opt
+ local -a excls specs remove
+
+ for opt in $@; do
+ specs=( ${(M)_composer_global_opts:#(*[\*\)]|)${opt}[=+-]#\[*} )
+ excls=( ${=${(@)${(@M)specs#\([^\)]##\)}//[ \(\)]/ }} )
+ remove+=(
+ # Don't remove used options like *-v
+ ${specs:#(*\)|)\*${opt}[=+-]#\[*}
+ # But do remove them if a used option excludes them
+ ${(M)_composer_global_opts:#(*[\*\)]|)(${(j<|>)~${(@b)excls}})[=+-]#\[*}
+ )
+ done
+
+ _composer_global_opts=( ${_composer_global_opts:#(${(j<|>)~${(@b)remove}})} )
+}
+
+# Update the working directory from opt_args/PWD. This is a little irritating to
+# deal with; for now we're just calling it anywhere it might be important
+(( $+functions[__composer_update_work_dir] )) ||
+__composer_update_work_dir() {
+ if [[ -n ${(v)opt_args[(i)(-d|--working-dir)]} ]]; then
+ eval _composer_work_dir=${(v)opt_args[(i)(-d|--working-dir)]}
+ elif [[ -z $_composer_work_dir ]]; then
+ _composer_work_dir=$PWD
+ fi
+}
+
+# Complete local/vendored binaries
+(( $+functions[__composer_binaries] )) ||
+__composer_binaries() {
+ local -a expl tmp
+
+ tmp=( ${(f)"$( __composer_call exec-list exec -l )"} )
+ tmp=( ${(@)tmp%%[[:space:]]##} )
+ [[ $tmp[1] == *: ]] && tmp[1]=()
+ tmp=( ${(@)tmp##[\*-][[:space:]]#} )
+ tmp=( ${(@)tmp%%[[:space:]]##\(local\)} )
+
+ _wanted -x commands expl binary compadd -a "$@" - tmp
+}
+
+# Complete commands
+(( $+functions[__composer_commands] )) ||
+__composer_commands() {
+ _describe -t commands command _composer_cmds
+}
+
+# Complete package licences
+(( $+functions[__composer_licenses] )) ||
+__composer_licenses() {
+ # These are just the ones the Composer documentation recommends; the full list
+ # of supported identifiers can be found at https://spdx.org/licenses/. If
+ # other functions need to complete licences in the future, it might be wise to
+ # break this out into a _licenses type
+ local -a tmp=(
+ 'Apache-2.0:Apache License 2.0'
+ 'BSD-2-Clause:BSD 2-Clause "Simplified" License'
+ 'BSD-3-Clause:BSD 3-Clause "New" or "Revised" License'
+ 'BSD-4-Clause:BSD 4-Clause "Original" or "Old" License'
+ 'GPL-2.0-only:GNU General Public License v2.0 only'
+ 'GPL-2.0-or-later:GNU General Public License v2.0 or later'
+ 'GPL-3.0-only:GNU General Public License v3.0 only'
+ 'GPL-3.0-or-later:GNU General Public License v3.0 or later'
+ 'LGPL-2.1-only:GNU Lesser General Public License v2.1 only'
+ 'LGPL-2.1-or-later:GNU Lesser General Public License v2.1 or later'
+ 'LGPL-3.0-only:GNU Lesser General Public License v3.0 only'
+ 'LGPL-3.0-or-later:GNU Lesser General Public License v3.0 or later'
+ 'MIT:MIT License'
+ 'proprietary:proprietary/closed-source license'
+ )
+ _describe -t licenses 'package license' tmp
+}
+
+# Complete packages
+# --pairs => complete as package:constraint pairs
+# --vendor => complete only vendored (installed) packages
+(( $+functions[__composer_packages] )) ||
+__composer_packages() {
+ local cwd
+ local -a pairs vendor home_dirs pkgs
+
+ __composer_update_work_dir
+
+ zparseopts -D -E - -vendor=vendor -pairs=pairs
+
+ (( $#pairs )) && compset -P '*[:= ]' && {
+ _message -e versions 'version constraint'
+ return
+ }
+
+ home_dirs=(
+ $COMPOSER_HOME(#q/N)
+ $HOME/.composer(#q/N)
+ $HOME/.config/composer(#q/N)
+ ${XDG_CONFIG_HOME:-/@err@}/composer(#q/N)
+ )
+
+ pkgs=( $_composer_work_dir/vendor/*/*(#q/N) )
+
+ # Trying to work out the path to the vendor directory when we're global is
+ # tedious, so we'll just take everything we can find
+ (( ! $#vendor || _composer_is_global )) &&
+ pkgs+=( $^home_dirs/vendor/*/*(#q/N) )
+
+ (( $#vendor )) || pkgs+=(
+ ${COMPOSER_CACHE_DIR:-/@err@}/files/*/*(#q/N)
+ $^home_dirs/cache/files/*/*(#q/N)
+ )
+
+ pkgs=( ${(@M)pkgs%%[^/]##/[^/]##} )
+
+ (( $#vendor )) || {
+ pkgs+=(
+ ${(f)"$(
+ _call_program packages-json \
+ command grep -soE ${(qq):-'"[^/]+\\?/[^/]+"\s*:'} -- \
+ ${(qq)_composer_work_dir}/composer.json
+ )"//[$':" \t\\']/}
+ ${(@)${(f)"$(
+ _call_program packages-lock \
+ command grep -soE ${(qq):-'"name"\s*:\s*"[^/]+\\?/[^/]+"'} -- \
+ ${(qq)_composer_work_dir}/composer.lock
+ )"//\"name\"/}//[$':" \t\\']/}
+ )
+
+ zstyle -T ":completion:*:*:$service:*" fetch-packages && {
+ { (( ! $#_composer_cache_pkgs )) || _cache_invalid composer-pkgs } &&
+ ! _retrieve_cache composer-pkgs && {
+ _composer_cache_pkgs=( ${(f)"$(
+ __composer_call packages-fetch show -aN |
+ LC_ALL=C tr -d '\t ' # Seems faster than ${...//.../} here
+ )"} )
+ _store_cache composer-pkgs _composer_cache_pkgs
+ }
+ pkgs+=( $_composer_cache_pkgs )
+ }
+ }
+
+ (( $#pkgs )) || {
+ _message -e packages package
+ return
+ }
+
+ if [[ $PREFIX == */* ]]; then
+ _description packages expl "${PREFIX%%/*}/* package"
+ else
+ _description packages expl 'package vendor'
+ fi
+ _multi_parts "${(@)expl}" "$@" / pkgs
+}
+
+# Complete package repositories
+(( $+functions[__composer_repositories] )) ||
+__composer_repositories() {
+ _alternative \
+ 'urls:repository URL:_urls' \
+ 'files:repository JSON configuration file:_files -g "*.json(#q-.)"' \
+ 'json:repository JSON configuration object:'
+}
+
+# Complete composer.json scripts
+(( $+functions[__composer_scripts] )) ||
+__composer_scripts() {
+ local -a expl tmp
+
+ tmp=( ${(f)"$( __composer_call run-script-list run-script -l )"} )
+ tmp=( ${(@)tmp##[[:space:]]##} )
+ tmp=( ${(@)tmp%%[[:space:]]##} )
+ [[ $tmp[1] == *: ]] && tmp[1]=()
+ tmp=( ${(@)tmp##[\*-][[:space:]]#} )
+ tmp=( ${(@)tmp%%[[:space:]]*} )
+
+ _wanted -x commands expl script compadd -a "$@" - tmp
+}
+
+# Complete package stabilities
+(( $+functions[__composer_stabilities] )) ||
+__composer_stabilities() {
+ local -a expl
+ _wanted stabilities expl 'package stability' compadd "$@" - \
+ stable RC beta alpha dev
+}
+
+# Complete package types
+(( $+functions[__composer_types] )) ||
+__composer_types() {
+ local -a expl
+ # Only the first four here are official types listed in the documentation; the
+ # others are popular custom types
+ _wanted types expl 'package type' compadd "$@" - \
+ composer-plugin library metapackage project \
+ cakephp-plugin cantao-module drupal-module magento2-module package \
+ phpcodesniffer-standard silverstripe-module symfony-bundle \
+ typo3-cms-extension wordpress-plugin yii2-extension
+}
+
+(( $+functions[_composer_archive] )) ||
+_composer_archive() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--dir=[specify output directory]:output directory:_files -/' \
+ '--file=[specify output file name]:output file name (without extension):_files' \
+ '(-f --format)'{-f+,--format=}'[specify archive format]:archive format:(tar zip)' \
+ '1:: :__composer_packages' \
+ '2:: :_guard "^-*" "version constraint"'
+}
+
+(( $+functions[_composer_check-platform-reqs] )) ||
+_composer_check-platform-reqs() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--no-dev[do not check require-dev package requirements]'
+}
+
+(( $+functions[_composer_config] )) ||
+_composer_config() {
+ local ret=1
+ local -a context expl line state state_descr cmd tmp
+ local -A opt_args
+
+ # -a and -f can be used together, in which case auth.json will be looked up in
+ # the base directory of the -f file. -f and -g can't be used together, but -f
+ # can still be used to specify config.json with `composer global config`
+ _arguments -s -S : \
+ $_composer_global_opts \
+ + '(a)' '(A l u : *)'{-a,--auth}'[edit auth.json (with -e)]' \
+ + '(A)' '(a e u)--absolute[display absolute *-dir setting paths]' \
+ + '(e)' '(A l u : *)'{-e,--editor}'[open configuration in $EDITOR]' \
+ + '(f)' '(g)'{-f+,--file=}'[specify {composer,config}.json path]:configuration file:_files' \
+ + '(g)' {-g,--global}'[use global config.json]' \
+ + '(l)' '(a e u : *)'{-l,--list}'[list configuration settings]' \
+ + '(u)' '(a A e l *)--unset[unset specified setting key]' \
+ + k '(a e l)1: :->key' \
+ + v '(a e l u)*:: :->val' \
+ && ret=0
+ __composer_update_work_dir
+
+ case $state in
+ key)
+ # `composer config` doesn't seem to actually respect -d...
+ tmp=( ${(v)opt_args[(i)([^-]##-|)(-f|--file)]} )
+ cmd=( config -f$^tmp $opt_args[(i)([^-]##-|)(-g|--global)] -l )
+
+ tmp=( ${(@M)${(f)"$( __composer_call config-list $cmd )"}#\[*\]} )
+ tmp=( ${(@)tmp//[ \]\[]/} )
+
+ _wanted setting-keys expl 'setting key' compadd -a "$@" - tmp && ret=0
+ ;;
+ val)
+ case $words[1] in
+ *[.-]dirs#|home)
+ _wanted setting-values expl 'setting value' _files -/ "$@" && ret=0
+ ;;
+ *[.-]domains#)
+ _wanted setting-values expl 'setting value' _hosts "$@" && ret=0
+ ;;
+ *[.-]urls#)
+ _wanted setting-values expl 'setting value' _urls "$@" && ret=0
+ ;;
+ *)
+ # If we wanted we could get specific about booleans, etc., here
+ _wanted setting-values expl 'setting value' _default "$@" && ret=0
+ ;;
+ esac
+ ;;
+ esac
+
+ return ret
+}
+
+(( $+functions[_composer_create-project] )) ||
+_composer_create-project() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(--no-dev)--dev[install require-dev packages]' \
+ '--ignore-platform-reqs[ignore PHP platform requirements]' \
+ '(--remove-vcs)--keep-vcs[do not remove VCS directory]' \
+ '!(--no-plugins)--no-custom-installers' \
+ '(--dev)--no-dev[do not install require-dev packages]' \
+ '--no-install[skip installation of package dependencies]' \
+ '--no-progress[do not display download progress]' \
+ '--no-secure-http[do not use HTTPS]' \
+ '--no-scripts[prevent execution of scripts defined in root package]' \
+ '(--prefer-source)--prefer-dist[prefer installation from dist]' \
+ '(--prefer-dist)--prefer-source[prefer installation from source]' \
+ '(--keep-vcs)--remove-vcs[force removal of VCS directory]' \
+ '--repository=[specify package repository]: :__composer_repositories' \
+ '!(--repository)--repository_url:repository URL:_urls' \
+ '(-s --stability)'{-s+,--stability=}'[specify minimum stability]: :__composer_stabilities' \
+ '1: :__composer_packages' \
+ '2::project directory:_files -/' \
+ '3:: :_guard "^-*" "version constraint"'
+}
+
+(( $+functions[_composer_depends] )) ||
+_composer_depends() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(-r --recursive)'{-r,--recursive}'[resolve recursively up to root package]' \
+ '(-t --tree)'{-t,--tree}'[display in tree format]' \
+ '1: :__composer_packages --vendor' \
+ '2:: :_guard "^-*" "version constraint"'
+}
+
+(( $+functions[_composer_dump-autoload] )) ||
+_composer_dump-autoload() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--apcu[use APCu to cache found/not-found classes]' \
+ '--no-dev[ignore autoload-dev rules]' \
+ '--no-scripts[prevent execution of scripts defined in composer.json]' \
+ + '(a)' '(o)'{-a,--classmap-authoritative}'[autoload from class maps only (implies -o)]' \
+ + '(o)' {-o,--optimize}'[use class maps for PSR-0/4 packages]'
+}
+
+(( $+functions[_composer_exec] )) ||
+_composer_exec() {
+ local ret=1
+ local -a context line state state_descr
+ local -A opt_args
+
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(: * -l --list)'{-l,--list}'[display available binaries]' \
+ '1: :__composer_binaries' \
+ '*: :->next' \
+ && ret=0
+
+ # Can't use *:: here, it won't complete subsequent options
+ [[ $state == next ]] && {
+ shift words
+ (( CURRENT-- ))
+ unset _composer_cmd
+ _normal && ret=0
+ }
+
+ return ret
+}
+
+(( $+functions[_composer_global] )) ||
+_composer_global() {
+ _composer_is_global=1
+ _composer "$@"
+}
+
+(( $+functions[_composer_help] )) ||
+_composer_help() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--format=[specify output format]:output format [txt]:(json md txt xml)' \
+ '--raw[output raw help (with text format)]' \
+ '1: :__composer_commands'
+}
+
+(( $+functions[_composer_home] )) ||
+_composer_home() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(-H --homepage)'{-H,--homepage}'[use home page instead of repository]' \
+ '(-s --show)'{-s,--show}'[display URL only (do not open)]' \
+ '*: :__composer_packages' \
+}
+
+(( $+functions[_composer_init] )) ||
+_composer_init() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--author=[specify package author]:package author' \
+ '--description=[specify package description]:package description' \
+ '--homepage=[specify package home page]:package home page:_urls' \
+ '(-l --license)'{-l+,--license=}'[specify package license]: :__composer_licenses' \
+ '--name=[specify package name]: :__composer_packages' \
+ '*--repository=[specify custom package repository]: :__composer_repositories' \
+ '*--require=[specify package to require]: :__composer_packages --pairs' \
+ '*--require-dev=[specify package to require for development]: :__composer_packages --pairs' \
+ '(-s --stability)'{-s+,--stability=}'[specify minimum stability]: :__composer_stabilities' \
+ '--type=-[specify package type]:: :__composer_types'
+}
+
+(( $+functions[_composer_install] )) ||
+_composer_install() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(--no-dev)--dev[install require-dev packages]' \
+ '--dry-run[do not actually install (implies -v)]' \
+ '--ignore-platform-reqs[ignore PHP platform requirements]' \
+ '!(--no-plugins)--no-custom-installers' \
+ '(--dev)--no-dev[do not install require-dev packages]' \
+ '--no-progress[do not display download progress]' \
+ '--no-scripts[prevent execution of scripts defined in composer.json]' \
+ '--no-suggest[do not display package suggestions]' \
+ '(--prefer-source)--prefer-dist[prefer installation from dist]' \
+ '(--prefer-dist)--prefer-source[prefer installation from source]' \
+ + '(a)' '(n o)'{-a,--classmap-authoritative}'[autoload from class maps only (implies -o)]' \
+ + '(A)' '(n)--apcu-autoloader[use APCu to cache found/not-found classes]' \
+ + '(n)' '(a A o)--no-autoload[skip autoloader generation]' \
+ + '(o)' '(n)'{-o,--optimize}'[use class maps for PSR-0/4 packages]'
+}
+
+(( $+functions[_composer_licenses] )) ||
+_composer_licenses() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--no-dev[ignore require-dev packages]' \
+ '--format=[specify output format]:output format [text]:(json text)'
+}
+
+(( $+functions[_composer_list] )) ||
+_composer_list() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--format=[specify output format]:output format [txt]:(json md txt xml)' \
+ '--raw[output raw help (with text format)]' \
+ '1: :_guard "^-*" namespace'
+}
+
+(( $+functions[_composer_outdated] )) ||
+_composer_outdated() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--format=[specify output format]:output format [text]:(json text)' \
+ '--strict[return non-zero exit code if there are outdated packages]' \
+ '1: :__composer_packages --vendor' \
+ + '(a)' '(D I)'{-a,--all}'[display all installed packages]' \
+ + '(D)' '(a)'{-D,--direct}'[display only packages directly required by root package]' \
+ + '(I)' '(a)*--ignore=[ignore specified package (with -o)]: :__composer_packages' \
+ + '(m)' '(a)'{-m,--minor-only}'[display only packages with minor semver updates (with -o)]' \
+ + '(o)' '!(a)'{-o,--outdated}
+}
+
+(( $+functions[_composer_prohibits] )) ||
+_composer_prohibits() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(-r --recursive)'{-r,--recursive}'[resolve recursively up to root package]' \
+ '(-t --tree)'{-t,--tree}'[display in tree format]' \
+ '1: :__composer_packages --vendor' \
+ '2:: :_guard "^-*" "version constraint"'
+}
+
+(( $+functions[_composer_remove] )) ||
+_composer_remove() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--dev[remove package from require-dev]' \
+ '--ignore-platform-reqs[ignore PHP platform requirements]' \
+ '(--dev)--no-dev[do not install require-dev packages]' \
+ '--no-progress[do not display download progress]' \
+ '--no-scripts[prevent execution of scripts defined in composer.json]' \
+ '(--update-no-dev)--no-update[do not update dependencies]' \
+ '(--update-with-dependencies)--no-update-with-dependencies[do not update inherited dependencies]' \
+ '(--no-update)--update-no-dev[update dependencies with --no-dev option]' \
+ '(--no-update-with-dependencies)--update-with-dependencies[update inherited dependencies]' \
+ '*: :__composer_packages --vendor' \
+ + '(a)' '(n o)'{-a,--classmap-authoritative}'[autoload from class maps only (implies -o)]' \
+ + '(A)' '(n)--apcu-autoloader[use APCu to cache found/not-found classes]' \
+ + '(n)' '(a A o)--no-autoload[skip autoloader generation]' \
+ + '(o)' '(n)'{-o,--optimize}'[use class maps for PSR-0/4 packages]'
+}
+
+(( $+functions[_composer_require] )) ||
+_composer_require() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--dev[add package to require-dev]' \
+ '--ignore-platform-reqs[ignore PHP platform requirements]' \
+ '--no-progress[do not display download progress]' \
+ '--no-scripts[prevent execution of scripts defined in composer.json]' \
+ '--no-suggest[do not display package suggestions]' \
+ '(--prefer-source)--prefer-dist[prefer installation from dist]' \
+ '--prefer-lowest[prefer lowest versions of dependencies]' \
+ '(--prefer-dist)--prefer-source[prefer installation from source]' \
+ '--prefer-stable[prefer stable versions of dependencies]' \
+ '--sort-packages[sort packages when adding/updating dependencies]' \
+ '(--no-update)--update-no-dev[update dependencies with --no-dev option]' \
+ '*: :__composer_packages --pairs' \
+ + '(a)' '(n o)'{-a,--classmap-authoritative}'[autoload from class maps only (implies -o)]' \
+ + '(A)' '(n)--apcu-autoloader[use APCu to cache found/not-found classes]' \
+ + '(n)' '(a A o)--no-autoload[skip autoloader generation]' \
+ + '(o)' '(n)'{-o,--optimize}'[use class maps for PSR-0/4 packages]' \
+ + '(u)' \
+ '(--update-no-dev)--no-update[do not update dependencies]' \
+ '--update-with-dependencies[update inherited dependencies, except root requirements]' \
+ '--update-with-all-dependencies[update all inherited dependencies]'
+}
+
+(( $+functions[_composer_run-script] )) ||
+_composer_run-script() {
+ local ret=1
+ local -a context line state state_descr
+ local -A opt_args
+
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(--no-dev)--dev[enable dev mode]' \
+ '(: * -l --list)'{-l,--list}'[display available scripts]' \
+ '(--dev)--no-dev[disable dev mode]' \
+ '--timeout=[specify script timeout]:timeout (seconds)' \
+ '1: :__composer_scripts' \
+ '*: :->next' \
+ && ret=0
+
+ # Can't use *:: here, it won't complete subsequent options
+ [[ $state == next ]] && {
+ shift words
+ (( CURRENT-- ))
+ unset _composer_cmd
+ _normal && ret=0
+ }
+
+ return ret
+}
+
+(( $+functions[_composer_search] )) ||
+_composer_search() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(-N --only-name)'{-N,--only-name}'[search package names only]' \
+ '(-t --type)'{-t+,--type=}'[search for specified package type]: :__composer_types' \
+ '*: :__composer_packages'
+}
+
+(( $+functions[_composer_self-update] )) ||
+_composer_self-update() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ + '(c)' \
+ '--preview[force update to preview channel]' \
+ '--snapshot[force update to snapshot channel]' \
+ '--stable[force update to stable channel]' \
+ + '(C)' '(u)--set-channel-only[set channel as default and exit]' \
+ + u \
+ '(C -r --rollback)--clean-backups[delete old back-ups during update]' \
+ '(C)--no-progress[do not display download progress]' \
+ '(c C -r --rollback)'{-r,--rollback}'[roll back to earlier installation]' \
+ '(C)--update-keys[prompt for key update]' \
+ '(C)1: :_guard "^-*" "Composer version"'
+}
+
+(( $+functions[_composer_show] )) ||
+_composer_show() {
+ local ret=1
+ local -a context line state state_descr
+ local -A opt_args
+
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '--format=[specify output format]:output format [text]:(json text)' \
+ '--strict[return non-zero exit code if there are outdated packages]' \
+ '1: :->pkgs' \
+ '2:: :_guard "^-*" "version constraint"' \
+ + '(a)' '(D I s t)'{-a,--available}'[display only available packages]' \
+ + '(A)' '(D I s t)--all[display all packages]' \
+ + '(D)' '(a A p s)'{-D,--direct}'[display only packages directly required by root package]' \
+ + '(i)' '(s)'{-i,--installed}'[display only installed packages]' \
+ + '(I)' '(a A s t)*--ignore=[ignore specified package (with -o)]: :__composer_packages' \
+ + '(l)' '(s t)'{-l,--latest}'[display only latest version of installed packages]' \
+ + '(m)' '(a A s t)'{-m,--minor-only}'[display only packages with minor semver updates (with -o)]' \
+ + '(N)' '(P)'{-N,--name-only}'[display package names only]' \
+ + '(o)' '(l t s)'{-o,--outdated}'[like -l, but display only outdated packages]' \
+ + '(p)' '(D)'{-p,--platform}'[display only PHP platform packages]' \
+ + '(P)' '(a A N)'{-P,--path}'[display package file paths]' \
+ + '(s)' '(a A I l o t)'{-s,--self}'[display root package information]' \
+ + '(t)' '(a A I l o s)'{-t,--tree}'[display in tree format]' \
+ && ret=0
+
+ [[ $state == pkgs ]] &&
+ if [[ -n $opt_args[(i)[aA]-*] ]]; then
+ __composer_packages && ret=0
+ else
+ __composer_packages --vendor && ret=0
+ fi
+
+ return ret
+}
+
+(( $+functions[_composer_suggests] )) ||
+_composer_suggests() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(--by-suggestion)--by-package[group results by suggesting package]' \
+ '(--by-package)--by-suggestion[group results by suggested package]' \
+ '--no-dev[exclude suggestions from require-dev packages]' \
+ '*: :__composer_packages --vendor'
+}
+
+(( $+functions[_composer_update] )) ||
+_composer_update() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(--no-dev)--dev[install require-dev packages]' \
+ '--dry-run[do not actually update (implies -v)]' \
+ '(-i -n --interactive --no-interaction)'{-i,--interactive}'[update with interactive interface]' \
+ '--ignore-platform-reqs[ignore PHP platform requirements]' \
+ '--lock[update composer.lock hash only]' \
+ '!(--no-plugins)--no-custom-installers' \
+ '(--dev)--no-dev[do not install require-dev packages]' \
+ '--no-progress[do not display download progress]' \
+ '--no-scripts[prevent execution of scripts defined in composer.json]' \
+ '--no-suggest[do not display package suggestions]' \
+ '(--prefer-source)--prefer-dist[prefer installation from dist]' \
+ '--prefer-lowest[prefer lowest versions of dependencies]' \
+ '(--prefer-dist)--prefer-source[prefer installation from source]' \
+ '--prefer-stable[prefer stable versions of dependencies]' \
+ '--root-reqs[update only root-package dependencies]' \
+ '*:: :__composer_packages --vendor' \
+ + '(a)' '(n o)'{-a,--classmap-authoritative}'[autoload from class maps only (implies -o)]' \
+ + '(A)' '(n)--apcu-autoloader[use APCu to cache found/not-found classes]' \
+ + '(n)' '(a A o)--no-autoload[skip autoloader generation]' \
+ + '(o)' '(n)'{-o,--optimize}'[use class maps for PSR-0/4 packages]' \
+ + '(u)' \
+ '--with-dependencies[update dependencies of whitelisted packages, except root requirements]' \
+ '--with-all-dependencies[update all dependencies of whitelisted packages]'
+}
+
+(( $+functions[_composer_validate] )) ||
+_composer_validate() {
+ _arguments -s -S : \
+ $_composer_global_opts \
+ '(-A --with-dependencies)'{-A,--with-dependencies}'[validate composer.json of installed dependencies]' \
+ '--no-check-all[do not validate completely]' \
+ '--no-check-lock[ignore out-of-date composer.lock]' \
+ '--no-check-publish[ignore publish errors]' \
+ '--strict[return non-zero exit code for warnings as well as errors]' \
+ '1::composer.json file:_files -g "*.json(#q-.)"'
+}
+
+_composer() {
+ local ret=1 tmp helps cmd
+ local -a context line state state_descr
+ local -A opt_args
+
+ # These are meant for use by helper functions; we check for set-ness first in
+ # case of `composer global`
+ (( $+_composer_cmd )) || {
+ local _composer_cmd=$words[1] _composer_is_global=0 _composer_work_dir=
+ local -a _composer_cmds _composer_global_opts _composer_cache_pkgs
+ local -A _composer_cmd_aliases
+
+ # alias -> canonical (mappings derived from source)
+ _composer_cmd_aliases=(
+ browse home
+ clearcache clear-cache
+ dumpautoload dump-autoload
+ i install
+ info show
+ selfupdate self-update
+ u update
+ upgrade update
+ why depends
+ why-not prohibits
+ )
+ # Official commands (see note at top about custom ones)
+ _composer_cmds=(
+ about:'display short information about Composer'
+ archive:'create archive of project/package'
+ check-platform-reqs:'check that platform requirements are satisfied'
+ clear{-,}cache:'clear internal package cache'
+ config:'set configuration options'
+ create-project:'create new project from package'
+ {depends,why}:'display packages depending on package'
+ diagnose:'diagnose system problems'
+ dump{-,}autoload:'dump class autoloader'
+ exec:'execute vendored binary/script'
+ global:'run command in global Composer directory'
+ help:'display help information'
+ {home,browse}:'open package home page or repository in browser'
+ init:'create basic composer.json'
+ {install,i}:'install packages in composer.{lock,json}'
+ licenses:'display dependency license information'
+ list:'display supported commands'
+ outdated:'display outdated packages'
+ {prohibits,why-not}:'display packages preventing package from being installed'
+ remove:'remove and uninstall required package'
+ require:'add and install required package'
+ run-script:'run scripts in composer.json'
+ search:'search packages'
+ self{-,}update:'upgrade Composer'
+ {show,info}:'display package information'
+ status:'display locally modified packages'
+ suggests:'display package suggestions'
+ {update,u,upgrade}:'upgrade packages in composer.json and update composer.lock'
+ validate:'validate composer.{json,lock}'
+ )
+ # Global options (can be used both before and after a command)
+ _composer_global_opts=(
+ '(-h --help)'{-h,--help}'[display help information]'
+ '(: * -)'{-V,--version}'[display version information]'
+
+ # Symfony handles -vv and -vvv specially
+ '(-q -v --quiet --verbose)'{-q,--quiet}'[reduce output verbosity]'
+ '(-q --quiet --verbose)*-v[increase output verbosity]'
+ '(-q --quiet --verbose)--verbose[increase output verbosity]'
+
+ '(--no-ansi)--ansi[force ANSI (color) output]'
+ '(--ansi)--no-ansi[disable ANSI (color) output]'
+
+ '(-n --no-interaction)'{-n,--no-interaction}'[run non-interactively]'
+
+ '--no-plugins[disable plug-ins]'
+ '--profile[display timing and memory usage information]'
+ '(-d --working-dir)'{-d+,--working-dir=}'[specify working directory]:working directory:_files -/'
+ )
+
+ # Use caching by default; Composer is very slow
+ zstyle -s ":completion:*:*:$service:*" cache-policy tmp
+ [[ -n $tmp ]] ||
+ zstyle ":completion:*:*:$service:*" cache-policy __composer_cache_policy
+
+ zstyle -s ":completion:*:*:$service:*" use-cache tmp
+ [[ -n $tmp ]] ||
+ zstyle ":completion:*:*:$service:*" use-cache yes
+ }
+
+ # Symfony's Application class naively intercepts --version and --help no
+ # matter where they appear on the command line. --version is handled
+ # sufficiently by the global option spec above; for --help, we need to
+ # simulate the help command
+ [[ -n $words[(r)(-h|--help)] ]] && {
+ helps=${#${(M)words[2,CURRENT]:#(-h|--help)}}
+ words=( "$words[1]" help "${(@)words[2,CURRENT]:#(-h|--help)}" )
+ (( CURRENT -= helps - 1 ))
+ __composer_prune_global_opts -h --help
+ }
+
+ _arguments -s -S -A '-*' : \
+ $_composer_global_opts \
+ '1: :__composer_commands' \
+ '*:: :->next' \
+ && ret=0
+ __composer_update_work_dir
+
+ [[ $state == next ]] && {
+ # Resolve abbreviated/aliased command names and ensure that $words[1] works
+ # as expected in our helper functions
+ __composer_resolve_cmd cmd $words[1]
+ words[1]=$_composer_cmd
+
+ # Don't offer global options again after they've been given
+ __composer_prune_global_opts ${(k)opt_args}
+ # This is intentionally done twice
+ [[ $cmd == help ]] && __composer_prune_global_opts -h --help
+
+ if (( $+functions[_composer_$cmd] )); then
+ _composer_$cmd "$@" && ret=0
+ else
+ _arguments -s -S : $_composer_global_opts && ret=0
+ fi
+ }
+
+ return ret
+}
+
+_composer "$@"
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 093464625..0ebbbe861 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -2017,15 +2017,6 @@ _git-subtree () {
(( $+functions[_git-tag] )) ||
_git-tag () {
- local -a message_opts
-
- if (( words[(I)-[asu]] )); then
- message_opts=(
- '(-m --message -F --file)'{-m+,--message=}'[specify tag message]:message'
- '(-m --message -F --file)'{-F+,--file=}'[read tag message from given file]:message file:_files'
- )
- fi
-
_arguments \
- creation \
'(-a --annotate -s --sign -u --local-user)'{-a,--annotate}'[create an unsigned, annotated tag]' \
@@ -2035,7 +2026,8 @@ _git-tag () {
'(-f --force)'{-f,--force}'[replace existing tag]' \
'--create-reflog[create a reflog]' \
'--cleanup=[cleanup message]:mode:((verbatim\:"no cleanup" whitespace\:"remove leading and trailing whitespace" strip\:"remove leading and trailing whitespace and comments"))' \
- $message_opts \
+ '(-m --message -F --file)'{-F+,--file=}'[read tag message from given file]:message file:_files' \
+ '(-m --message -F --file)'{-m+,--message=}'[specify tag message]:message' \
': :__git_tags' \
':: :__git_commits' \
- deletion \
diff --git a/Completion/Unix/Command/_ipsec b/Completion/Unix/Command/_ipsec
new file mode 100644
index 000000000..631d2bc9a
--- /dev/null
+++ b/Completion/Unix/Command/_ipsec
@@ -0,0 +1,179 @@
+#compdef ipsec strongswan
+
+# Completion for the ipsec script (aka strongswan on some systems) provided by
+# FreeS/WAN, Openswan, Libreswan, and strongSwan. See also strongSwan's swanctl.
+#
+# As with swanctl, elevated privileges are usually required to complete SA names
+# and the like; consider setting the gain-privileges style as follows:
+# zstyle ':completion:*:(ipsec|strongswan)/*' gain-privileges yes
+#
+# @todo We don't complete pool names or virtual IPs
+
+# Complete connection (IKE SA) names and optionally SA/instance names
+# --instances => also complete SA/instance names
+(( $+functions[_ipsec_connections] )) ||
+_ipsec_connections() {
+ local -a instances tmp ipsec_conns ipsec_insts
+
+ zparseopts -D -E -a instances - -instances
+
+ tmp=( ${(f)${"$(
+ _call_program -p ipsec-status ${_ipsec_cmd:-$words[1]} statusall
+ )"#*$'\n'[[:space:]]#[Cc]onnections:[[:space:]]#$'\n'}} )
+ tmp=( ${(@M)tmp:#[[:space:]]#[^[:space:]]##:[[:space:]]##?*} )
+ tmp=( ${(@)${(@)tmp##[[:space:]]##}%%:*} )
+
+ ipsec_conns=( ${(@)tmp%%['[{']<->['}]']} )
+ ipsec_insts=( ${(@M)tmp:#*['[{']<->['}]']} )
+
+ (( $#ipsec_conns )) || {
+ _message -e connections 'connection name'
+ return
+ }
+
+ tmp=( 'connections:connection name:compadd -a - ipsec_conns' )
+ (( $#instances && $#ipsec_insts )) &&
+ tmp+=( 'instances:connection SA/instance name:compadd -a - ipsec_insts' )
+
+ _alternative $tmp
+}
+
+# Complete arguments to /usr/lib/ipsec/starter. This is rarely invoked directly,
+# and there is almost no documentation on it, but the start/restart commands
+# pass options to it
+(( $+functions[_ipsec_starter] )) ||
+_ipsec_starter() {
+ _arguments : \
+ '(--nofork)--attach-gdb[start daemon under gdb (implies --nofork)]' \
+ '--auto-update[specify select time-out]:select time-out (seconds)' \
+ '--conf[specify path to ipsec.conf]:ipsec.conf file:_files' \
+ '--daemon[specify daemon name]:daemon name' \
+ '--nofork[do not fork daemon]' \
+ + '(d)' \
+ '--debug[set log level 2]' \
+ '--debug-more[set log level 3]' \
+ '--debug-all[set log level 4]' \
+ '--nolog[set log level 0]'
+}
+
+_ipsec() {
+ local ret=1 variant _ipsec_cmd=$words[1]
+ local -a context line state state_descr tmp
+ local -A opt_args
+
+ _pick_variant -r variant \
+ freeswan='(#i)frees/#wan' \
+ libreswan='(#i)libreswan' \
+ openswan='(#i)openswan' \
+ strongswan='(#i)strongswan' \
+ unix \
+ --version
+
+ # Provide only basic completion for non-strongSwan implementations
+ if [[ $variant == unix ]]; then
+ _default
+ return
+ elif [[ $variant == (free|libre|open)* ]]; then
+ tmp=( ${(f)"$( _call_program ipsec-help $words[1] --help )"} )
+ tmp=( ${(@M)tmp:#($' '|$'\t')*} )
+ tmp=( ${(@)tmp:#*[':/<>()[]']*} )
+ tmp=( ${(f)${(F)tmp//[[:space:]]##/$'\n'}} )
+
+ _arguments -S -A '-*' : \
+ '(: * -)--help[display help information]' \
+ '(: * -)--version[display version information]' \
+ "(-)1:command:(${(j< >)${(@q-)tmp}})" \
+ '(-)2: :_default'
+ return
+ fi
+
+ _arguments -A '-*' \
+ '(: * -)--confdir[display path to configuration directory (IPSEC_CONFDIR)]' \
+ '(: * -)--copyright[display copyright information]' \
+ '(: * -)--directory[display path to libexec/utility directory (IPSEC_DIR)]' \
+ '(: * -)--help[display help information]' \
+ '(: * -)--piddir[display path to PID directory (IPSEC_PIDDIR)]' \
+ '(: * -)--version[display version information]' \
+ '(: * -)--versioncode[display brief version information]' \
+ '1:command:((
+ down\:"terminate IPsec connection/SA"
+ down-srcip\:"terminate IKE SAs by client virtual IP"
+ leases\:"display IP address/pool status"
+ listaacerts\:"display X.509 authorization authority certificates"
+ listacerts\:"display X.509 attribute certificates"
+ listalgs\:"display loaded algorithms"
+ listall\:"execute all list commands"
+ listcacerts\:"display X.509 certificate authority certificates"
+ listcainfos\:"display certificate authority information"
+ listcerts\:"display X.509/OpenPGP certificates"
+ listcounters\:"display IKE counter information"
+ listcrls\:"display certificate revocation lists"
+ listgroups\:"display groups for user authorization profiles"
+ listocsp\:"display OCSP revocation information"
+ listocspcerts\:"display X.509 OCSP signer certificates"
+ listplugins\:"display loaded plug-in features"
+ listpubkeys\:"display RSA public keys"
+ purgecerts\:"purge cached certificates"
+ purgecrl\:"purge cached certificate revocation lists"
+ purgeike\:"purge IKE SAs without a quick mode or CHILD_SA"
+ purgeocsp\:"purge cached OCSP information"
+ reload\:"reload entire configuration (send SIGUSR1)"
+ rereadacerts\:"re-read attribute certificates"
+ rereadaacerts\:"flush and re-read authorization authority certificates"
+ rereadall\:"execute all re-read commands"
+ rereadcacerts\:"flush and re-read certificate authority certificates"
+ rereadcrls\:"re-read certificate revocation lists"
+ rereadocspcerts\:"re-read OCSP certificates"
+ rereadsecrets\:"flush and re-read secrets"
+ resetcounters\:"reset IKE counter information"
+ restart\:"equivalent to stop + start"
+ route\:"insert kernel IPsec policy for connection"
+ start\:"start IKE daemon"
+ status\:"display concise connection status"
+ statusall\:"display detailed connection status"
+ stop\:"terminate all IPsec connections and stop IKE daemon"
+ stroke\:"issue stroke command"
+ unroute\:"remove kernel IPsec policy for connection"
+ up\:"bring up IPsec connection"
+ update\:"reload changes in configuration (send SIGHUP)"
+ ))' \
+ '*:: :->next' \
+ && ret=0
+
+ [[ $state == next ]] &&
+ case $words[1] in
+ down)
+ _arguments : '1: :_ipsec_connections --instances' && ret=0
+ ;;
+ listcounters|resetcounters|route|status|statusall|unroute|up)
+ _arguments : '1: :_ipsec_connections' && ret=0
+ ;;
+ down-srcip)
+ _arguments : \
+ '1:virtual IP address (start)' \
+ '2::virtual IP address (end)' \
+ && ret=0
+ ;;
+ leases)
+ _arguments : '1:pool name' '2::virtual IP address' && ret=0
+ ;;
+ list*~list(counters|plugins))
+ _arguments : '--utc[use UTC for time fields]' && ret=0
+ ;;
+ start|restart)
+ _ipsec_starter && ret=0
+ ;;
+ stroke)
+ _arguments -s -S -A '-*' \
+ '(: * -)'{-h,--help}'[display help information]' \
+ '(-d --daemon)'{-d+,--daemon=}'[specify daemon name]:daemon name' \
+ '1: :_guard "^-*" "stroke command"' \
+ '*:stroke command argument:_default' \
+ && ret=0
+ ;;
+ esac
+
+ return ret
+}
+
+_ipsec "$@"
diff --git a/Completion/Unix/Command/_swanctl b/Completion/Unix/Command/_swanctl
new file mode 100644
index 000000000..ba2f5402d
--- /dev/null
+++ b/Completion/Unix/Command/_swanctl
@@ -0,0 +1,225 @@
+#compdef swanctl
+
+# Completion for strongSwan's swanctl. See also ipsec, which is deprecated but
+# still supported by strongSwan, and also used by Openswan/Libreswan.
+#
+# Note that in most cases elevated privileges are required to connect to the
+# VICI socket, so the gain-privileges style may be necessary to complete SA
+# names and the like: zstyle ':completion:*:swanctl/*' gain-privileges yes
+#
+# Other notes:
+# - One of swanctl's selling points is that it can provide 'raw' structured
+# responses for scripting, etc. In practice, though, the output formatted for
+# humans seems easier to 'parse' from the shell than the plist-like raw output
+# - @todo We don't complete authority names, pool names, peer IPs, etc.
+
+# Complete connection names, SA names, or SA unique IDs. The distinctions
+# between concepts like 'connections' and 'SAs' are very blurry here, partially
+# for convenience and partially due to author confusion
+# --child => complete only child/CHILD_SA names/IDs
+# --ids => complete unique SA IDs rather than connection/SA names
+# --ike => complete only connection/IKE_SA names/IDs
+(( $+functions[_swanctl_connections] )) ||
+_swanctl_connections() {
+ local i which
+ local -a expl tmp matches
+ local -A opts
+
+ zparseopts -D -E -A opts - -child -ids -ike
+
+ tmp=( ${(@M)${(f)"$(
+ _call_program -p swanctl-sas $words[1] -l
+ )"}:#[^:]##: \#<->*} )
+ (( $+opts[--ids] )) || tmp+=( ${(@M)${(f)"$(
+ _call_program -p swanctl-conns $words[1] -L
+ )"}:#[^:]##: ([A-Z][A-Za-z0-9]#|),*} )
+
+ for i in $tmp; do
+ if (( $+opts[--child] )) && [[ $i != [[:space:]]* ]]; then
+ continue
+ elif (( $+opts[--ike] )) && [[ $i == [[:space:]]* ]]; then
+ continue
+ fi
+
+ # <name>: #<unique id>, ...
+ i=${i//[#:,]/ }
+
+ if (( $+opts[--ids] )); then
+ matches+=( "${i[(w)2]}:${i[(w)1]} #${i[(w)2]}" )
+ else
+ matches+=( ${i[(w)1]} )
+ fi
+ done
+
+ if (( $+opts[--ids] )); then
+ matches=( ${(onu)matches} )
+ if (( $+opts[--child] )); then
+ which=CHILD_
+ elif (( $+opts[--ike] )); then
+ which=IKE_
+ fi
+ _describe -x2Vt sa-ids "${which}SA unique ID" matches
+ else
+ if (( $+opts[--child] )); then
+ which='child '
+ elif (( $+opts[--ike] )); then
+ which='IKE '
+ fi
+ _wanted -x connections expl "${which}connection/SA name" compadd - $matches
+ fi
+}
+
+_swanctl() {
+ # Although swanctl will correctly parse multiple short options in the first
+ # word, as in `swanctl -lh`, it won't actually *do* anything with the
+ # subsequent options -- so we'll require that they be separated. Also, --help
+ # doesn't take any further options, so just stop if we've got that
+ if (( CURRENT == 2 )) || [[ $words[2] == (-h*|--help) ]]; then
+ _arguments : \
+ '(-)'{-a,--load-pools}'[(re)load pool configuration]' \
+ '(-)'{-A,--list-pools}'[display loaded pool configurations]' \
+ '(-)'{-b,--load-authorities}'[(re)load authority configuration]' \
+ '(-)'{-B,--list-authorities}'[display loaded authority configurations]' \
+ '(-)'{-c,--load-conns}'[(re)load connection configuration]' \
+ '(-)'{-C,--counters}'[display or reset IKE event counters]' \
+ '(-)'{-d,--redirect}'[redirect IKE_SA]' \
+ '(-)'{-f,--flush-certs}'[flush cached certificates]' \
+ '(-)'{-g,--list-algs}'[display loaded algorithms]' \
+ '(-)'{-h,--help}'[display help information]' \
+ '(-)'{-i,--initiate}'[initiate a connection]' \
+ '(-)'{-l,--list-sas}'[display currently active IKE_SAs]' \
+ '(-)'{-L,--list-conns}'[display loaded configurations]' \
+ '(-)'{-m,--monitor-sa}'[monitor for IKE_SA and CHILD_SA changes]' \
+ '(-)'{-p,--install}'[install trap or shunt policy]' \
+ '(-)'{-P,--list-pols}'[display currently installed policies]' \
+ '(-)'{-q,--load-all}'[load credentials, authorities, pools, and connections]' \
+ '(-)'{-r,--reload-settings}'[reload daemon strongswan.conf]' \
+ '(-)'{-R,--rekey}'[rekey SA]' \
+ '(-)'{-s,--load-creds}'[(re)load credentials]' \
+ '(-)'{-S,--stats}'[display daemon statistics]' \
+ '(-)'{-t,--terminate}'[terminate connection]' \
+ '(-)'{-T,--log}'[trace logging output]' \
+ '(-)'{-u,--uninstall}'[uninstall trap or shunt policy]' \
+ '(-)'{-v,--version}'[display version information]' \
+ '(-)'{-x,--list-certs}'[display stored certificates]'
+ return
+ fi
+
+ local ret=1 cmd
+ local -a args cert_flags cert_types
+
+ cert_flags=( aa any ca none ocsp )
+ cert_types=( ocsp_response pubkey x509 x509_ac x509_crl )
+
+ if [[ $words[2] == -[^-]* ]]; then
+ cmd=${(M)words[2]#??}
+ else
+ cmd=$words[2]
+ fi
+ words=( $words[1] "${(@)words[3,-1]}" )
+ (( CURRENT-- ))
+
+ # Technically, only -v, -u, and -+ are truly global command options. However,
+ # in practice, all commands also support -h, -P, and -r
+ args=(
+ '(: * -)'{-h,--help}'[display help information]'
+ '(-P -r --pretty --raw)'{-P,--pretty}'[dump raw response message in pretty print]'
+ '(-P -r --pretty --raw)'{-r,--raw}'[dump raw response message]'
+ # https://wiki.strongswan.org/projects/strongswan/wiki/LoggerConfiguration
+ # https://github.com/strongswan/strongswan/blob/master/src/libstrongswan/utils/debug.h
+ '(-v --debug)'{-v+,--debug=}'[specify debug level]:debug level [1]:((
+ -1\:"absolutely silent (SILENT)"
+ 0\:"basic auditing (AUDIT)"
+ 1\:"generic control flow with errors (CTRL)"
+ 2\:"detailed control flow (DIAG)"
+ 3\:"raw binary blobs (RAW)"
+ 4\:"sensitive data (PRIVATE)"
+ ))'
+ '(-u --uri)'{-u+,--uri=}'[specify service URI to connect to]:VICI service URI:_urls'
+ '(-+ --options)'{'-\++',--options=}'[read command-line options from specified file]:options file:_files'
+ )
+
+ case $cmd in
+ -A|--list-pools) args+=(
+ '(-n --name)'{-n+,--name=}'[filter by specified pool name]:pool name'
+ '(-l --leases)'{-l,--leases}'[display leases of each pool]'
+ ) ;;
+ -B|--list-authorities) args+=(
+ '(-n --name)'{-n+,--name=}'[filter by specified authority name]:authority name'
+ ) ;;
+ -C|--counters) args+=(
+ '(-a -n --all --name)'{-a,--all}'[display/reset counters for all tracked connections]'
+ '(-a -n --all --name)'{-n+,--name=}'[specify connection name]: :_swanctl_connections --ike'
+ '(-r --reset)'{-r,--reset}'[reset counters]'
+ ) ;;
+ -d|--redirect) args+=(
+ '(-d --peer-id)'{-d+,--peer-id=}'[redirect by IKE_SA matching specified peer identity]:peer identity'
+ '(-g --gateway)'{-g+,--gateway=}'[redirect to specified gateway]:target gateway'
+ '(-i --ike)'{-i+,--ike=}'[redirect by specified IKE_SA name]: :_swanctl_connections --ike'
+ '(-I --ike-id)'{-I+,--ike-id=}'[redirect by specified IKE_SA unique ID]: :_swanctl_connections --ids --ike'
+ '(-p --peer-ip)'{-p+,--peer-ip=}'[redirect by IKE_SA matching specified peer IP]:peer IP address'
+ ) ;;
+ -f|--flush-certs) args+=(
+ '(-t --type)'{-t+,--type=}"[filter by specified certificate type]:certificate type:(
+ ${(j< >)${(@q-)cert_types}}
+ )"
+ ) ;;
+ -i|--initiate) args+=(
+ '(-c --child)'{-c+,--child=}'[specify CHILD_SA name]: :_swanctl_connections --child'
+ '(-i --ike)'{-i+,--ike=}"[specify CHILD_SA's connection name]: :_swanctl_connections --ike"
+ '(-t --timeout)'{-t+,--timeout=}'[specify timeout before detaching]:timeout (seconds)'
+ ) ;;
+ -l|--list-sas) args+=(
+ '(-i --ike)'{-i+,--ike=}'[filter by specified IKE_SA name]: :_swanctl_connections --ike'
+ '(-I --ike-id)'{-I+,--ike-id=}'[filter by specified IKE_SA unique ID]: :_swanctl_connections --ids --ike'
+ '(-n --noblock)'{-n,--noblock}'[do not wait for IKE_SAs in use]'
+ ) ;;
+ -p|-u|--install|--uninstall) args+=(
+ '(-c --child)'{-c+,--child=}'[specify CHILD_SA name]: :_swanctl_connections --child'
+ '(-i --ike)'{-i+,--ike=}"[specify CHILD_SA's connection name]: :_swanctl_connections --ike"
+ ) ;;
+ -P|--list-pols) args+=(
+ '(-c --child)'{-c+,--child=}'[filter by specified CHILD_SA name]: :_swanctl_connections --child'
+ '(-d --drop)'{-d,--drop}'[list drop policies]'
+ '(-p --pass)'{-p,--pass}'[list bypass policies]'
+ '(-t --trap)'{-t,--trap}'[list trap policies]'
+ ) ;;
+ -q|-s|--load-all|--load-creds) args+=(
+ '(-c --clear)'{-c,--clear}'[clear previously loaded credentials]'
+ '(-n --noprompt)'{-n,--noprompt}'[do not prompt for passwords]'
+ ) ;;
+ -R|--rekey) args+=(
+ '(-c --child)'{-c+,--child=}'[rekey by specified CHILD_SA name]: :_swanctl_connections --child'
+ '(-C --child-id)'{-C+,--child-id=}'[rekey by specified CHILD_SA unique ID]: :_swanctl_connections --ids --child'
+ '(-i --ike)'{-i+,--ike=}'[rekey by specified IKE_SA name]: :_swanctl_connections --ike'
+ '(-I --ike-id)'{-I+,--ike-id=}'[rekey by specified IKE_SA unique ID]: :_swanctl_connections --ids --ike'
+ ) ;;
+ -t|--terminate) args+=(
+ '(-t --timeout)'{-t+,--timeout=}'[specify timeout before detaching]:timeout (seconds)'
+ '(-c --child)'{-c+,--child=}'[terminate by specified CHILD_SA name]: :_swanctl_connections --child'
+ '(-C --child-id)'{-C+,--child-id=}'[terminate by specified CHILD_SA unique ID]: :_swanctl_connections --ids --child'
+ '(-i --ike)'{-i+,--ike=}'[terminate by specified IKE_SA name]: :_swanctl_connections --ike'
+ '(-I --ike-id)'{-I+,--ike-id=}'[terminate by specified IKE_SA unique ID]: :_swanctl_connections --ids --ike'
+ ) ;;
+ -v|--version) args+=(
+ '(-d --daemon)'{-d,--daemon}'[query daemon version]'
+ ) ;;
+ -x|--list-certs) args+=(
+ '(-f --flag)'{-f+,--flag=}"[filter by specified X.509 certificate flag]:certificate flag:(
+ ${(j< >)${(@q-)cert_flags}}
+ )"
+ '(-p --pem)'{-p,--pem}'[display PEM encoding of certificate]'
+ '(-s --subject)'{-s+,--subject=}'[filter by specified certificate subject]:certificate subject'
+ '(-S --short)'{-S,--short}'[omit some certificate details]'
+ '(-t --type)'{-t+,--type=}"[filter by specified certificate type]:certificate type:(
+ ${(j< >)${(@q-)cert_types}}
+ )"
+ '(-u --utc)'{-u,--utc}'[use UTC for time fields]'
+ ) ;;
+ esac
+
+ _arguments -s -S : $args && ret=0
+ return ret
+}
+
+_swanctl "$@"