commit:     238b95dfeb8f32f592756797786a998b0f07c748
Author:     Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Sun Aug 31 18:49:57 2014 +0000
Commit:     Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Sun Aug 31 19:18:12 2014 +0000
URL:        
https://gitweb.gentoo.org/proj/gentoo-bashcomp.git/commit/?id=238b95df

Split common functions out of completions.

The goal is to install the reusable functions in helpersdir from where
they can be reused by other completions.

 completions/gentoo       | 390 +---------------------------------------------
 helpers/gentoo-common.sh | 395 +++++++++++++++++++++++++++++++++++++++++++++++
 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
@@ -1127,24 +757,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
 #

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
+}

Reply via email to