# Completion for eselect [] [] # Author: Wilke Schwiedop # Distributed under the terms of the GNU General Public License v2 _eselect() { local curr=${COMP_WORDS[COMP_CWORD]} possibles="" module_index=1 # Unset default completion COMPREPLY=() # Unfortunatly we can't source eselect to get to the variables directly, so this is a bit more complicated local ESELECT_DATA_PATH ESELECT_MODULES_PATH # Obtain ESELECT_DATA_PATH and ESELECT_MODULES_PATH . See eselect for more info ESELECT_DATA_PATH=$(sed -n -e 's/^ESELECT_DATA_PATH="\(.\+\)"$/\1/p' $(which eselect)) ESELECT_MODULES_PATH=( "${HOME}/.eselect/modules" "${ESELECT_DATA_PATH}/modules" ) # Hard-coded Actions. # Note: list-modules is hardcoded aswell, but not used in the modules. list-modules is added only when needed. ESELECT_KNOWN_ACTIONS="help usage version" # Hard-coded Options # TODO These could be read from ESELECT_KNOWN_OPTIONS ESELECT_KNOWN_OPTIONS="--no-colour" # If any word in ${COMP_WORDS[@]} is a default-action, we don't need further completion for i in ${COMP_WORDS[@]} ; do [[ $i == @(${ESELECT_KNOWN_ACTIONS//[[:space:]]/"|"}|list-modules) ]] && return 0 done # Skip all global-options while [[ ${COMP_WORDS[module_index]} == -* ]] ; do ((++module_index)) done # If this is true we're looking for a module name or an eselect-option. In short: "eselect " # Since we're skipping the global options, this may be < 0 if we have nothing but options in COMP_WORDS. if [[ $((COMP_CWORD-module_index)) -le 0 ]] ; then local path file for path in "${ESELECT_MODULES_PATH[@]}" ; do [[ -d ${path} ]] || continue for file in ${path}/*.eselect ; do [[ -f ${file} ]] || continue file=${file##*/} # strip path file=${file%%.eselect} # strip extension possibles+=" ${file}" done done possibles+=" list-modules ${ESELECT_KNOWN_ACTIONS}" # Include default actions and list-modules possibles+=" ${ESELECT_KNOWN_OPTIONS}" # Include default options # We already have a module, so we're looking for an action or even and option # In short: "eselect somemodule " else local modname=${COMP_WORDS[module_index]} modpath="" modfile="" for modpath in "${ESELECT_MODULES_PATH[@]}" ; do modfile="${modpath}/${modname}.eselect" [[ -f ${modfile} ]] && break done [[ -f ${modfile} ]] || return 1 # 404 File not found, so theres no way we get the info we need # We're looking for an action; In short: "eselect somemodule " if [[ $((COMP_CWORD-module_index)) -eq 1 ]] ; then possibles+=" ${ESELECT_KNOWN_ACTIONS}" # Include default actions # module-actions are simple bash functions in the module-file. # They follow the pattern "do_${action}()" and "do_${action} ()" respectively possibles+=" " possibles+=$(sed -n -e 's/^do_\([^ _\(]\+\).*/\1/p' ${modfile}) # We're looking for an option. # In short: "eselect somemodule someaction " else local action=${COMP_WORDS[module_index+1]} possibles+=" " possibles+=$( source ${modfile} &> /dev/null # functions describing options follow the pattern "describe_${action}_options()" if [[ $(type -t "describe_${action}_options" ) == "function" ]] ; then # we're only interested in --options-like-this # TODO The regexp could be improved to match only single "-" between letters echo $(describe_${action}_options | sed -n -e 's/^.*--\([[:alpha:]-]\+\).*/--\1/p') if [[ $(type -t "find_targets") == "function" ]] ; then $(describe_${action}_options | grep -q '/^') | find_targets fi fi ) fi fi # If we already completed something, remove already used words from completion. if [[ ${COMP_CWORD} -ge 2 ]] ; then # Our delete candidates are ${COMP_WORDS[@] without the first ("eselect") and last word ("$curr") local delete_candidates="${COMP_WORDS[@]:1:${COMP_CWORD}-1}" # Convert delete candidates to regexp delete_candidates=${delete_candidates//[[:space:]]/"|"} # Delete candidates begone! possibles=${possibles//@($delete_candidates)/""} # When removing a word, the delimiting spaces remain. Remove them aswell possibles=${possibles//" "/" "} fi COMPREPLY=( $(compgen -W "${possibles}" -- ${curr}) ) return 0 } complete -F _eselect eselect