summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--completions/gentoo390
-rw-r--r--helpers/gentoo-common.sh395
2 files changed, 396 insertions, 389 deletions
diff --git a/completions/gentoo b/completions/gentoo
index 0e54841..30a1eb1 100644
--- a/completions/gentoo
+++ b/completions/gentoo
@@ -3,377 +3,7 @@
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License, v2 or later
-# Retrieve PORTDIR/PORTDIR_OVERLAY location.
-#
-# In order of highest to lowest priority:
-# /etc/portage/repos.conf{,/*}
-# /usr/share/portage/config/repos.conf
-# /etc/portage/make.conf
-# /etc/make.conf
-# /usr/share/portage/config/make.globals
-#
-# The first two files are in repos.conf format and must be parsed for the
-# variable "location". The rest are make.conf style and are simply sourced
-# for PORTDIR and PORTDIR_OVERLAY. While repos.conf overrides any value of
-# PORTDIR set in make.conf, PORTDIR_OVERLAY is incremental (combined across
-# available sources).
-#
-# This would be a hell of a lot simpler if we used portageq, but also about
-# 500 times slower.
-_portdir() {
- local mainreponame mainrepopath overlayname overlaypath
-
- if [[ -e @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/repos.conf ]]; then
- if [[ ${1} == -o ]]; then
- for overlayname in $(_parsereposconf -l); do
- overlaypath+=($(_parsereposconf ${overlayname} location))
- done
-
- source @GENTOO_PORTAGE_EPREFIX@/etc/make.conf 2>/dev/null
- source @GENTOO_PORTAGE_EPREFIX@/etc/portage/make.conf 2>/dev/null
-
- overlaypath+=(${PORTDIR_OVERLAY})
-
- # strip out duplicates
- overlaypath=($(printf "%s\n" "${overlaypath[@]}" | sort -u))
-
- echo "${overlaypath[@]}"
- else
- mainreponame=$(_parsereposconf DEFAULT main-repo)
- mainrepopath=$(_parsereposconf ${mainreponame} location)
-
- echo "${mainrepopath}"
- fi
- else
- source @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/make.globals 2>/dev/null
- source @GENTOO_PORTAGE_EPREFIX@/etc/make.conf 2>/dev/null
- source @GENTOO_PORTAGE_EPREFIX@/etc/portage/make.conf 2>/dev/null
-
- echo "${PORTDIR}"
-
- if [[ ${1} == -o ]]; then
- echo "${PORTDIR_OVERLAY}"
- fi
- fi
-}
-
-# _parsereposconf [-l] <repo> <variable>
-# -l lists available repos
-_parsereposconf() {
- local f insection line section v value var
-
- for f in @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/repos.conf \
- @GENTOO_PORTAGE_EPREFIX@/etc/portage/repos.conf \
- @GENTOO_PORTAGE_EPREFIX@/etc/portage/repos.conf/*.conf; do
-
- [[ -f ${f} ]] || continue
- insection=0
-
- while read -r line; do
- # skip comments and blank lines
- [[ -z ${line} || ${line} == '#'* ]] && continue
-
- if [[ ${insection} == 1 && ${line} == '['*']' ]]; then
- # End of the section we were interested in so stop
- secname+=(${line//[(\[|\])]/}) # record name for -l
- break
- elif [[ ${line} == '['*']' ]]; then
- # Entering a new section, check if it's the one we want
- section=${line//[(\[|\])]/}
- [[ ${section} == "${1}" ]] && insection=1
- secname+=(${section}) # record name for -l
- elif [[ ${insection} == 1 ]]; then
- # We're in the section we want, grab the values
- var=${line%%=*}
- var=${var// /}
- value=${line#*=}
- value=${value# }
- [[ ${var} == ${2} ]] && v=${value}
- fi
- continue
- done < "${f}"
- done
-
- if [[ ${1} == -l ]]; then
- echo "${secname[@]}"
- else
- echo "${v}"
- fi
-}
-
-# like _pkgname but completes on package names only (no category)
-_pkgname_only()
-{
- local i pd
- local cur="$1"
- shift
- local dir="$@"
-
- COMPREPLY=($(compgen -W "$(\
- for pd in $dir ; do \
- builtin cd ${pd}; \
- for i in *-*/${cur}*; do \
- [[ -d ${i} ]] && { local x=${i##*/} ; echo ${x%-[0-9]*}; } \
- done ; \
- done)" -- ${cur}))
-}
-
-#
-# This function completes package names.
-#
-# usage: pkgname <mode> <current-directory>
-#
-# Where mode is one of:
-# -A Search all available packages (except for those in the overlays)
-# -I Only search the installed packages
-#
-# TODO: Look at breaking this function out and making it a "universal"
-# category/package name completion function.
-#
-_pkgname()
-{
- local mode cur portdir only
- mode="$1"
- cur="$2"
- portdir=$(_portdir -o)
- # Ignore '=' at the beginning of the current completion
- [[ ${cur:1:1} == "=" ]] && cur=${cur:2}
- [[ ${cur:0:1} == "=" ]] && cur=${cur:1}
- case $mode in
- -I)
- # Complete either the category or the complete package name
- if [[ $cur == */* ]]; then
- COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$cur*" )" -- $cur))
- else
- COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$cur*" -S /)" -- $cur))
- fi
- # We may just have finished completing the category.
- # Make sure there isn't anything more to complete now.
- if [[ ${#COMPREPLY[@]} == 1 ]]; then
- COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$COMPREPLY*")" -- $cur))
- fi
-
- if [[ -z "${COMPREPLY}" ]] ; then
- only=1
- _pkgname_only ${cur} @GENTOO_PORTAGE_EPREFIX@/var/db/pkg
- fi
- ;;
- -A)
- # Complete either the category or the complete package name
- if [[ $cur == */* ]]; then
- # Once the category has been completed, it's safe to use ${portdir}
- # to continue completion.
- local ww=$(\
- for pd in ${portdir} ; do
- builtin cd ${pd};
- compgen -W "$(compgen -G "${cur}*")" -- "${cur}" ;
- done)
- COMPREPLY=($(\
- for x in ${ww}; do echo $x; done|sort -u
- ))
- # When we've completed most of the name, also display the version for
- # possible completion.
- if [[ ${#COMPREPLY[@]} -le 1 || ${cur:${#cur}-1:1} == "-" ]] \
- && [[ ${cur} != */ ]]; then
- # Use the portage cache to complete specific versions from
- COMPREPLY=(${COMPREPLY[@]} $(
- for pd in ${portdir}; do
- if [[ -d ${pd}/metadata/md5-cache ]]; then
- builtin cd ${pd}/metadata/md5-cache
- compgen -W "$(compgen -G "${cur}*")" -- "${cur}"
- elif [[ -d ${pd}/metadata/cache ]]; then
- builtin cd ${pd}/metadata/cache
- compgen -W "$(compgen -G "${cur}*")" -- "${cur}"
- fi
- done
- ))
- fi
- else
- # 1. Collect all the categories among ${portdir}
- local ww=$(\
- for pd in ${portdir}; do
- builtin cd ${pd};
- compgen -X "!@(*-*|virtual)" -S '/' -G "$cur*";
- done)
-
- # 2. Now ugly hack to delete duplicate categories
- local w x
- for x in ${ww} ; do w="${x}\n${w}"; done
- local words=$(echo -e ${w} | sort -u)
-
- COMPREPLY=($(compgen -W "$words" -- $cur))
-
- if [[ ${#COMPREPLY[@]} == 1 ]]; then
- COMPREPLY=($(compgen -W "$(
- for pd in ${portdir}; do
- if [[ -d ${pd}/metadata/md5-cache ]]; then
- builtin cd ${pd}/metadata/md5-cache
- compgen -G "$COMPREPLY*"
- elif [[ -d ${pd}/metadata/cache ]]; then
- builtin cd ${pd}/metadata/cache
- compgen -G "$COMPREPLY*"
- fi
- done
- )" -- $cur))
- fi
- fi
-
- if [[ -z "${COMPREPLY}" ]] ; then
- only=1
- _pkgname_only ${cur} ${portdir}
- fi
- ;;
- *)
- # Somebody screwed up! :-)
- ;;
- esac
- # 'equery' wants an '=' in front of specific package versions.
- # Add it if there is only one selected package and it isn't there already.
- if [[ ${#COMPREPLY[@]} == 1 && ${COMP_WORDS[COMP_CWORD]:0:1} != "=" ]]
- then
- [[ -z "${only}" ]] && COMPREPLY=("="$COMPREPLY)
- fi
-}
-
-#
-# This is an helper function for completion of "-o <list>" / "--option=<list>"
-# kind of command lines options.
-#
-# Usage: _list_compgen <current> <sep> <item1>[<sep><item2> ...]
-# - <current>: what we have so far on the command line
-# - <sep>: the separator character used in lists
-# - <itemN>: a valid item
-# Returns: the function outputs each possible completion (one per line),
-# and returns 0. Typical usage is COMPREPLY=($(_list_compgen ...)).
-#
-# Note: items must not contain the <sep> character (no backslash escaping has
-# been implemented).
-#
-_list_compgen()
-{
- # Read the three parameters.
- local current="${1}" ; shift
- local sep="${1}" ; shift
- local items="${*}"
-
- # This is the maximum number of "<current><sep><other_item>" possible
- # completions that should be listed in case <current> is a valid list.
- # Setting it to a negative value means "no bound" (always list everything).
- # Setting it to 0 means "never list anything" (only suggest <sep>).
- # Setting it to a positive value N means "list up to N possible items, and
- # only suggest <sep> if there are more".
- # It is probably not worth a parameter, thus it will defaults to my
- # prefered setting (1) if not already defined in the environment.
- local max_others_number=${max_others_number:-1}
-
- # Save IFS. The <sep> character will be used instead in the following.
- local saved_IFS="${IFS}"
- IFS="${sep}"
-
- # Split the current items list in two parts:
- # - current_item is the last one (maybe partial or even empty)
- # - prefix_item are items are the previous ones
- local current_item="${current##*${sep}}"
- local prefix_items="${current%${current_item}}"
-
- # Iterate through valid items to recognize those that are:
- # - partial matches of the <current_item>
- # - already used in the list prefix
- # - not used in the list prefix, and not an exact match of <current_item>
- # Also check whether the <current_item> is exactly a valid one.
- local matching_items
- local other_items
- local exact_match
- local my_item
- for my_item in ${items} ; do
- if [[ "${sep}${prefix_items}${sep}" == *"${sep}${my_item}${sep}"* ]] ; then
- # The item has already been used in the list prefix: ignore it.
- continue
- elif [[ "${my_item}" == "${current_item}" ]] ; then
- # The item _exactly_ matches the <current_item>: that means that we
- # will have to suggest some more items to add behind.
- exact_match=1
- elif [[ "${my_item}" == "${current_item}"* ]] ; then
- # The item matches the <current_item>: it will be a possible
- # completion. It will also be a possible additional item in case of
- # exact match.
- matching_items="${matching_items}${sep}${my_item}"
- other_items="${other_items}${sep}${my_item}"
- else
- # The item neither matches the <current_item> nor has been already
- # used: it will only be a possible additional item in case of exact
- # match.
- other_items="${other_items}${sep}${my_item}"
- fi
- done
- matching_items="${matching_items#${sep}}"
- other_items="${other_items#${sep}}"
-
- # Takes care of the case where <current_item> is not exactly valid but
- # there is only one matching item: force this completion, and handle it
- # just as an exact match.
- if [[ -z "${exact_match}" ]] \
- && [[ "${matching_items}" != *"${sep}"* ]] ; then
- exact_match=1
- current="${current%${current_item}}${matching_items}"
- current_item="${matching_items}"
- matching_items=""
- other_items="${sep}${other_items}${sep}"
- other_items="${other_items/${sep}${current_item}${sep}/${sep}}"
- other_items="${other_items#${sep}}"
- other_items="${other_items%${sep}}"
- fi
-
- # List all possible completions. They are stored in an array.
- # XXX: maybe if should be COMPREPLY directly? (with no output at the end)
- local my_compreply=()
- local i=0
- if [[ -n "${exact_match}" ]] ; then
- # Found an exact match? Then add "<current>".
- my_compreply[${i}]="${current}"
- let i++
- fi
- if [[ -n "${matching_items}" ]] ; then
- # Found some matching items?
- # Then add "<prefix_items><matching_item>".
- for my_item in ${matching_items} ; do
- my_compreply[${i}]="${prefix_items}${my_item}"
- let i++
- done
- fi
- if [[ -n "${exact_match}" ]] \
- && [[ -n "${other_items}" ]] ; then
- # Found an exact match and some other possible items remain?
- # First, count them:
- local count_others=0
- for my_item in ${other_items} ; do
- let count_others++
- done
- # Then decide how to behave depending on the max_others_number setting:
- if (( max_others_number < 0 )) \
- || (( count_others <= max_others_number )) ; then
- # List the possible "<current><sep><other_item>" completions.
- for my_item in ${other_items} ; do
- my_compreply[${i}]="${current}${sep}${my_item}"
- let i++
- done
- else # Only suggest adding the <sep> character.
- my_compreply[${i}]="${current}${sep}"
- let i++
- fi
- fi
-
- # Restore IFS.
- IFS="${saved_IFS}"
-
- # Output the array of possible completions and returns.
- local j=0
- while (( i > j )) ; do
- echo ${my_compreply[$j]}
- let j++
- done
- return 0
-}
+source "@helpersdir@/gentoo-common.sh"
#
# emerge completion command
@@ -1128,24 +758,6 @@ _browserconfig()
complete -F _browserconfig browser-config
#
-# Helper routine for the subcommand 'meta' of 'equery'
-# (Used two times, by _equery and _epkginfo, therefore in an extra function)
-#
-_equery_meta()
-{
- local cur="$1"
-
- case $cur in
- -*)
- COMPREPLY=($(compgen -W "--help -h --description -d --herd -H --keywords -k --maintainer -m --useflags -u --upstream -U --xml -x" -- $cur))
- ;;
- *)
- _pkgname -A $cur
- ;;
- esac
-}
-
-#
# Bash completion for the Gentoo 'equery' command
#
_equery()
diff --git a/helpers/gentoo-common.sh b/helpers/gentoo-common.sh
new file mode 100644
index 0000000..c0be688
--- /dev/null
+++ b/helpers/gentoo-common.sh
@@ -0,0 +1,395 @@
+# Gentoo Linux Bash Shell Command Completion
+# Common functions to use in other completions
+#
+# Copyright 1999-2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License, v2 or later
+
+# Retrieve PORTDIR/PORTDIR_OVERLAY location.
+#
+# In order of highest to lowest priority:
+# /etc/portage/repos.conf{,/*}
+# /usr/share/portage/config/repos.conf
+# /etc/portage/make.conf
+# /etc/make.conf
+# /usr/share/portage/config/make.globals
+#
+# The first two files are in repos.conf format and must be parsed for the
+# variable "location". The rest are make.conf style and are simply sourced
+# for PORTDIR and PORTDIR_OVERLAY. While repos.conf overrides any value of
+# PORTDIR set in make.conf, PORTDIR_OVERLAY is incremental (combined across
+# available sources).
+#
+# This would be a hell of a lot simpler if we used portageq, but also about
+# 500 times slower.
+_portdir() {
+ local mainreponame mainrepopath overlayname overlaypath
+
+ if [[ -e @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/repos.conf ]]; then
+ if [[ ${1} == -o ]]; then
+ for overlayname in $(_parsereposconf -l); do
+ overlaypath+=($(_parsereposconf ${overlayname} location))
+ done
+
+ source @GENTOO_PORTAGE_EPREFIX@/etc/make.conf 2>/dev/null
+ source @GENTOO_PORTAGE_EPREFIX@/etc/portage/make.conf 2>/dev/null
+
+ overlaypath+=(${PORTDIR_OVERLAY})
+
+ # strip out duplicates
+ overlaypath=($(printf "%s\n" "${overlaypath[@]}" | sort -u))
+
+ echo "${overlaypath[@]}"
+ else
+ mainreponame=$(_parsereposconf DEFAULT main-repo)
+ mainrepopath=$(_parsereposconf ${mainreponame} location)
+
+ echo "${mainrepopath}"
+ fi
+ else
+ source @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/make.globals 2>/dev/null
+ source @GENTOO_PORTAGE_EPREFIX@/etc/make.conf 2>/dev/null
+ source @GENTOO_PORTAGE_EPREFIX@/etc/portage/make.conf 2>/dev/null
+
+ echo "${PORTDIR}"
+
+ if [[ ${1} == -o ]]; then
+ echo "${PORTDIR_OVERLAY}"
+ fi
+ fi
+}
+
+# _parsereposconf [-l] <repo> <variable>
+# -l lists available repos
+_parsereposconf() {
+ local f insection line section v value var
+
+ for f in @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/repos.conf \
+ @GENTOO_PORTAGE_EPREFIX@/etc/portage/repos.conf \
+ @GENTOO_PORTAGE_EPREFIX@/etc/portage/repos.conf/*.conf; do
+
+ [[ -f ${f} ]] || continue
+ insection=0
+
+ while read -r line; do
+ # skip comments and blank lines
+ [[ -z ${line} || ${line} == '#'* ]] && continue
+
+ if [[ ${insection} == 1 && ${line} == '['*']' ]]; then
+ # End of the section we were interested in so stop
+ secname+=(${line//[(\[|\])]/}) # record name for -l
+ break
+ elif [[ ${line} == '['*']' ]]; then
+ # Entering a new section, check if it's the one we want
+ section=${line//[(\[|\])]/}
+ [[ ${section} == "${1}" ]] && insection=1
+ secname+=(${section}) # record name for -l
+ elif [[ ${insection} == 1 ]]; then
+ # We're in the section we want, grab the values
+ var=${line%%=*}
+ var=${var// /}
+ value=${line#*=}
+ value=${value# }
+ [[ ${var} == ${2} ]] && v=${value}
+ fi
+ continue
+ done < "${f}"
+ done
+
+ if [[ ${1} == -l ]]; then
+ echo "${secname[@]}"
+ else
+ echo "${v}"
+ fi
+}
+
+# like _pkgname but completes on package names only (no category)
+_pkgname_only()
+{
+ local i pd
+ local cur="$1"
+ shift
+ local dir="$@"
+
+ COMPREPLY=($(compgen -W "$(\
+ for pd in $dir ; do \
+ builtin cd ${pd}; \
+ for i in *-*/${cur}*; do \
+ [[ -d ${i} ]] && { local x=${i##*/} ; echo ${x%-[0-9]*}; } \
+ done ; \
+ done)" -- ${cur}))
+}
+
+#
+# This function completes package names.
+#
+# usage: pkgname <mode> <current-directory>
+#
+# Where mode is one of:
+# -A Search all available packages (except for those in the overlays)
+# -I Only search the installed packages
+#
+# TODO: Look at breaking this function out and making it a "universal"
+# category/package name completion function.
+#
+_pkgname()
+{
+ local mode cur portdir only
+ mode="$1"
+ cur="$2"
+ portdir=$(_portdir -o)
+ # Ignore '=' at the beginning of the current completion
+ [[ ${cur:1:1} == "=" ]] && cur=${cur:2}
+ [[ ${cur:0:1} == "=" ]] && cur=${cur:1}
+ case $mode in
+ -I)
+ # Complete either the category or the complete package name
+ if [[ $cur == */* ]]; then
+ COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$cur*" )" -- $cur))
+ else
+ COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$cur*" -S /)" -- $cur))
+ fi
+ # We may just have finished completing the category.
+ # Make sure there isn't anything more to complete now.
+ if [[ ${#COMPREPLY[@]} == 1 ]]; then
+ COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$COMPREPLY*")" -- $cur))
+ fi
+
+ if [[ -z "${COMPREPLY}" ]] ; then
+ only=1
+ _pkgname_only ${cur} @GENTOO_PORTAGE_EPREFIX@/var/db/pkg
+ fi
+ ;;
+ -A)
+ # Complete either the category or the complete package name
+ if [[ $cur == */* ]]; then
+ # Once the category has been completed, it's safe to use ${portdir}
+ # to continue completion.
+ local ww=$(\
+ for pd in ${portdir} ; do
+ builtin cd ${pd};
+ compgen -W "$(compgen -G "${cur}*")" -- "${cur}" ;
+ done)
+ COMPREPLY=($(\
+ for x in ${ww}; do echo $x; done|sort -u
+ ))
+ # When we've completed most of the name, also display the version for
+ # possible completion.
+ if [[ ${#COMPREPLY[@]} -le 1 || ${cur:${#cur}-1:1} == "-" ]] \
+ && [[ ${cur} != */ ]]; then
+ # Use the portage cache to complete specific versions from
+ COMPREPLY=(${COMPREPLY[@]} $(
+ for pd in ${portdir}; do
+ if [[ -d ${pd}/metadata/md5-cache ]]; then
+ builtin cd ${pd}/metadata/md5-cache
+ compgen -W "$(compgen -G "${cur}*")" -- "${cur}"
+ elif [[ -d ${pd}/metadata/cache ]]; then
+ builtin cd ${pd}/metadata/cache
+ compgen -W "$(compgen -G "${cur}*")" -- "${cur}"
+ fi
+ done
+ ))
+ fi
+ else
+ # 1. Collect all the categories among ${portdir}
+ local ww=$(\
+ for pd in ${portdir}; do
+ builtin cd ${pd};
+ compgen -X "!@(*-*|virtual)" -S '/' -G "$cur*";
+ done)
+
+ # 2. Now ugly hack to delete duplicate categories
+ local w x
+ for x in ${ww} ; do w="${x}\n${w}"; done
+ local words=$(echo -e ${w} | sort -u)
+
+ COMPREPLY=($(compgen -W "$words" -- $cur))
+
+ if [[ ${#COMPREPLY[@]} == 1 ]]; then
+ COMPREPLY=($(compgen -W "$(
+ for pd in ${portdir}; do
+ if [[ -d ${pd}/metadata/md5-cache ]]; then
+ builtin cd ${pd}/metadata/md5-cache
+ compgen -G "$COMPREPLY*"
+ elif [[ -d ${pd}/metadata/cache ]]; then
+ builtin cd ${pd}/metadata/cache
+ compgen -G "$COMPREPLY*"
+ fi
+ done
+ )" -- $cur))
+ fi
+ fi
+
+ if [[ -z "${COMPREPLY}" ]] ; then
+ only=1
+ _pkgname_only ${cur} ${portdir}
+ fi
+ ;;
+ *)
+ # Somebody screwed up! :-)
+ ;;
+ esac
+ # 'equery' wants an '=' in front of specific package versions.
+ # Add it if there is only one selected package and it isn't there already.
+ if [[ ${#COMPREPLY[@]} == 1 && ${COMP_WORDS[COMP_CWORD]:0:1} != "=" ]]
+ then
+ [[ -z "${only}" ]] && COMPREPLY=("="$COMPREPLY)
+ fi
+}
+
+#
+# This is an helper function for completion of "-o <list>" / "--option=<list>"
+# kind of command lines options.
+#
+# Usage: _list_compgen <current> <sep> <item1>[<sep><item2> ...]
+# - <current>: what we have so far on the command line
+# - <sep>: the separator character used in lists
+# - <itemN>: a valid item
+# Returns: the function outputs each possible completion (one per line),
+# and returns 0. Typical usage is COMPREPLY=($(_list_compgen ...)).
+#
+# Note: items must not contain the <sep> character (no backslash escaping has
+# been implemented).
+#
+_list_compgen()
+{
+ # Read the three parameters.
+ local current="${1}" ; shift
+ local sep="${1}" ; shift
+ local items="${*}"
+
+ # This is the maximum number of "<current><sep><other_item>" possible
+ # completions that should be listed in case <current> is a valid list.
+ # Setting it to a negative value means "no bound" (always list everything).
+ # Setting it to 0 means "never list anything" (only suggest <sep>).
+ # Setting it to a positive value N means "list up to N possible items, and
+ # only suggest <sep> if there are more".
+ # It is probably not worth a parameter, thus it will defaults to my
+ # prefered setting (1) if not already defined in the environment.
+ local max_others_number=${max_others_number:-1}
+
+ # Save IFS. The <sep> character will be used instead in the following.
+ local saved_IFS="${IFS}"
+ IFS="${sep}"
+
+ # Split the current items list in two parts:
+ # - current_item is the last one (maybe partial or even empty)
+ # - prefix_item are items are the previous ones
+ local current_item="${current##*${sep}}"
+ local prefix_items="${current%${current_item}}"
+
+ # Iterate through valid items to recognize those that are:
+ # - partial matches of the <current_item>
+ # - already used in the list prefix
+ # - not used in the list prefix, and not an exact match of <current_item>
+ # Also check whether the <current_item> is exactly a valid one.
+ local matching_items
+ local other_items
+ local exact_match
+ local my_item
+ for my_item in ${items} ; do
+ if [[ "${sep}${prefix_items}${sep}" == *"${sep}${my_item}${sep}"* ]] ; then
+ # The item has already been used in the list prefix: ignore it.
+ continue
+ elif [[ "${my_item}" == "${current_item}" ]] ; then
+ # The item _exactly_ matches the <current_item>: that means that we
+ # will have to suggest some more items to add behind.
+ exact_match=1
+ elif [[ "${my_item}" == "${current_item}"* ]] ; then
+ # The item matches the <current_item>: it will be a possible
+ # completion. It will also be a possible additional item in case of
+ # exact match.
+ matching_items="${matching_items}${sep}${my_item}"
+ other_items="${other_items}${sep}${my_item}"
+ else
+ # The item neither matches the <current_item> nor has been already
+ # used: it will only be a possible additional item in case of exact
+ # match.
+ other_items="${other_items}${sep}${my_item}"
+ fi
+ done
+ matching_items="${matching_items#${sep}}"
+ other_items="${other_items#${sep}}"
+
+ # Takes care of the case where <current_item> is not exactly valid but
+ # there is only one matching item: force this completion, and handle it
+ # just as an exact match.
+ if [[ -z "${exact_match}" ]] \
+ && [[ "${matching_items}" != *"${sep}"* ]] ; then
+ exact_match=1
+ current="${current%${current_item}}${matching_items}"
+ current_item="${matching_items}"
+ matching_items=""
+ other_items="${sep}${other_items}${sep}"
+ other_items="${other_items/${sep}${current_item}${sep}/${sep}}"
+ other_items="${other_items#${sep}}"
+ other_items="${other_items%${sep}}"
+ fi
+
+ # List all possible completions. They are stored in an array.
+ # XXX: maybe if should be COMPREPLY directly? (with no output at the end)
+ local my_compreply=()
+ local i=0
+ if [[ -n "${exact_match}" ]] ; then
+ # Found an exact match? Then add "<current>".
+ my_compreply[${i}]="${current}"
+ let i++
+ fi
+ if [[ -n "${matching_items}" ]] ; then
+ # Found some matching items?
+ # Then add "<prefix_items><matching_item>".
+ for my_item in ${matching_items} ; do
+ my_compreply[${i}]="${prefix_items}${my_item}"
+ let i++
+ done
+ fi
+ if [[ -n "${exact_match}" ]] \
+ && [[ -n "${other_items}" ]] ; then
+ # Found an exact match and some other possible items remain?
+ # First, count them:
+ local count_others=0
+ for my_item in ${other_items} ; do
+ let count_others++
+ done
+ # Then decide how to behave depending on the max_others_number setting:
+ if (( max_others_number < 0 )) \
+ || (( count_others <= max_others_number )) ; then
+ # List the possible "<current><sep><other_item>" completions.
+ for my_item in ${other_items} ; do
+ my_compreply[${i}]="${current}${sep}${my_item}"
+ let i++
+ done
+ else # Only suggest adding the <sep> character.
+ my_compreply[${i}]="${current}${sep}"
+ let i++
+ fi
+ fi
+
+ # Restore IFS.
+ IFS="${saved_IFS}"
+
+ # Output the array of possible completions and returns.
+ local j=0
+ while (( i > j )) ; do
+ echo ${my_compreply[$j]}
+ let j++
+ done
+ return 0
+}
+
+#
+# Helper routine for the subcommand 'meta' of 'equery'
+# (Used two times, by _equery and _epkginfo, therefore in an extra function)
+#
+_equery_meta()
+{
+ local cur="$1"
+
+ case $cur in
+ -*)
+ COMPREPLY=($(compgen -W "--help -h --description -d --herd -H --keywords -k --maintainer -m --useflags -u --upstream -U --xml -x" -- $cur))
+ ;;
+ *)
+ _pkgname -A $cur
+ ;;
+ esac
+}