From 0afd5d366097ac254bca5a4a54f2f788c6185060 Mon Sep 17 00:00:00 2001 From: Jephte CLAIN Date: Mon, 30 Sep 2013 11:48:13 +0400 Subject: [PATCH] completion pour les commandes ruinst, runs, rruns --- .udir | 2 +- lib/bashrc.d/bash_completion.nutools | 12 +- ulib/.ulib_version | 2 +- ulib/bash_completion | 1372 ++++++++++++++++++++++++++ 4 files changed, 1385 insertions(+), 3 deletions(-) create mode 100644 ulib/bash_completion diff --git a/.udir b/.udir index ddabc45..65f606e 100644 --- a/.udir +++ b/.udir @@ -16,7 +16,7 @@ kvm_service= # Faut-il installer le service openvz-fix-etchosts? openvz_service= configure_variables=(dest uninst_utools rm_utools kvm_service openvz_service) -configure_dest_for=(bashrc profile lib/uinst/conf lib/uinst/rootconf lib/profile.d/nutools lib/init.d/kvm-stop-all legacy/sysinc/utools legacy/sysinc/system_caps legacy/sysinc/private/init) +configure_dest_for=(bashrc profile lib/uinst/conf lib/uinst/rootconf lib/profile.d/nutools lib/bashrc.d/bash_completion.nutools lib/init.d/kvm-stop-all legacy/sysinc/utools legacy/sysinc/system_caps legacy/sysinc/private/init) config_scripts=(lib/uinst/conf lib/uinst/system_caps.legacy) install_profiles=true profiledir=lib/profile.d diff --git a/lib/bashrc.d/bash_completion.nutools b/lib/bashrc.d/bash_completion.nutools index 61307a0..5d50c25 100644 --- a/lib/bashrc.d/bash_completion.nutools +++ b/lib/bashrc.d/bash_completion.nutools @@ -1,8 +1,18 @@ # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 +[ -n "$BASH_COMPLETION" ] || source "@@dest@@/ulib/bash_completion" if [ -n "$BASH_COMPLETION" ]; then - if [ -f "$BASH_COMPLETION_DIR/ssh" ]; then + if [ -n "$BASH_COMPLETION_DIR" -a -f "$BASH_COMPLETION_DIR/ssh" ]; then shopt -u hostcomplete complete -F _ssh ussh cssh fi + + function _nutools_h() { + local cur prev + _get_comp_words_by_ref cur prev + if [ "$prev" == "-h" -o "$prev" == "-H" ]; then + _known_hosts_real "$cur" + fi + } + complete -F _nutools_h -o default ruinst runs rruns fi diff --git a/ulib/.ulib_version b/ulib/.ulib_version index d00491f..0cfbf08 100644 --- a/ulib/.ulib_version +++ b/ulib/.ulib_version @@ -1 +1 @@ -1 +2 diff --git a/ulib/bash_completion b/ulib/bash_completion new file mode 100644 index 0000000..1f3c3f5 --- /dev/null +++ b/ulib/bash_completion @@ -0,0 +1,1372 @@ +##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 +## Fonctions pour l'autocomplétion bash, si le package bash-completion n'est pas installé +##@cooked nocomments +##@require base +uprovide bash_completion + +if [ -z "$BASH_COMPLETION" ]; then + BASH_COMPLETION=1 + shopt -s extglob progcomp + +##--start[RIPPED from /etc/bash_completion-----------------------------------]-- +UNAME=$( uname -s ) +# strip OS type and version under Cygwin (e.g. CYGWIN_NT-5.1 => Cygwin) +UNAME=${UNAME/CYGWIN_*/Cygwin} + +case ${UNAME} in + Linux|GNU|GNU/*) USERLAND=GNU ;; + *) USERLAND=${UNAME} ;; +esac +##--end[RIPPED from /etc/bash_completion-------------------------------------]-- + +##--start[RIPPED from /etc/bash_completion-----------------------------------]-- +# start of section containing completion functions called by other functions + +# This function checks whether we have a given program on the system. +# No need for bulky functions in memory if we don't. +# +have() +{ + unset -v have + # Completions for system administrator commands are installed as well in + # case completion is attempted via `sudo command ...'. + PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin type $1 &>/dev/null && + have="yes" +} + +# This function checks whether a given readline variable +# is `on'. +# +_rl_enabled() +{ + [[ "$( bind -v )" = *$1+([[:space:]])on* ]] +} + +# This function shell-quotes the argument +quote() +{ + echo \'${1//\'/\'\\\'\'}\' #'# Help vim syntax highlighting +} + +# @see _quote_readline_by_ref() +quote_readline() +{ + local quoted + _quote_readline_by_ref "$1" ret + printf %s "$ret" +} # quote_readline() + + +# This function shell-dequotes the argument +dequote() +{ + eval echo "$1" 2> /dev/null +} + + +# Assign variable one scope above the caller +# Usage: local "$1" && _upvar $1 "value(s)" +# Param: $1 Variable name to assign value to +# Param: $* Value(s) to assign. If multiple values, an array is +# assigned, otherwise a single value is assigned. +# NOTE: For assigning multiple variables, use '_upvars'. Do NOT +# use multiple '_upvar' calls, since one '_upvar' call might +# reassign a variable to be used by another '_upvar' call. +# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference +_upvar() { + if unset -v "$1"; then # Unset & validate varname + if (( $# == 2 )); then + eval $1=\"\$2\" # Return single value + else + eval $1=\(\"\${@:2}\"\) # Return array + fi + fi +} + + +# Assign variables one scope above the caller +# Usage: local varname [varname ...] && +# _upvars [-v varname value] | [-aN varname [value ...]] ... +# Available OPTIONS: +# -aN Assign next N values to varname as array +# -v Assign single value to varname +# Return: 1 if error occurs +# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference +_upvars() { + if ! (( $# )); then + echo "${FUNCNAME[0]}: usage: ${FUNCNAME[0]} [-v varname"\ + "value] | [-aN varname [value ...]] ..." 1>&2 + return 2 + fi + while (( $# )); do + case $1 in + -a*) + # Error checking + [[ ${1#-a} ]] || { echo "bash: ${FUNCNAME[0]}: \`$1': missing"\ + "number specifier" 1>&2; return 1; } + printf %d "${1#-a}" &> /dev/null || { echo "bash:"\ + "${FUNCNAME[0]}: \`$1': invalid number specifier" 1>&2 + return 1; } + # Assign array of -aN elements + [[ "$2" ]] && unset -v "$2" && eval $2=\(\"\${@:3:${1#-a}}\"\) && + shift $((${1#-a} + 2)) || { echo "bash: ${FUNCNAME[0]}:"\ + "\`$1${2+ }$2': missing argument(s)" 1>&2; return 1; } + ;; + -v) + # Assign single value + [[ "$2" ]] && unset -v "$2" && eval $2=\"\$3\" && + shift 3 || { echo "bash: ${FUNCNAME[0]}: $1: missing"\ + "argument(s)" 1>&2; return 1; } + ;; + *) + echo "bash: ${FUNCNAME[0]}: $1: invalid option" 1>&2 + return 1 ;; + esac + done +} + + +# Reassemble command line words, excluding specified characters from the +# list of word completion separators (COMP_WORDBREAKS). +# @param $1 chars Characters out of $COMP_WORDBREAKS which should +# NOT be considered word breaks. This is useful for things like scp where +# we want to return host:path and not only path, so we would pass the +# colon (:) as $1 here. +# @param $2 words Name of variable to return words to +# @param $3 cword Name of variable to return cword to +# +__reassemble_comp_words_by_ref() { + local exclude i j ref + # Exclude word separator characters? + if [[ $1 ]]; then + # Yes, exclude word separator characters; + # Exclude only those characters, which were really included + exclude="${1//[^$COMP_WORDBREAKS]}" + fi + + # Default to cword unchanged + eval $3=$COMP_CWORD + # Are characters excluded which were former included? + if [[ $exclude ]]; then + # Yes, list of word completion separators has shrunk; + # Re-assemble words to complete + for (( i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do + # Is current word not word 0 (the command itself) and is word not + # empty and is word made up of just word separator characters to be + # excluded? + while [[ $i -gt 0 && ${COMP_WORDS[$i]} && + ${COMP_WORDS[$i]//[^$exclude]} == ${COMP_WORDS[$i]} + ]]; do + [ $j -ge 2 ] && ((j--)) + # Append word separator to current word + ref="$2[$j]" + eval $2[$j]=\${!ref}\${COMP_WORDS[i]} + # Indicate new cword + [ $i = $COMP_CWORD ] && eval $3=$j + # Indicate next word if available, else end *both* while and for loop + (( $i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2 + done + # Append word to current word + ref="$2[$j]" + eval $2[$j]=\${!ref}\${COMP_WORDS[i]} + # Indicate new cword + [ $i = $COMP_CWORD ] && [[ ${COMP_WORDS[i]} ]] && eval $3=$j + done + else + # No, list of word completions separators hasn't changed; + eval $2=\( \"\${COMP_WORDS[@]}\" \) + fi +} # __reassemble_comp_words_by_ref() + + +# @param $1 exclude Characters out of $COMP_WORDBREAKS which should NOT be +# considered word breaks. This is useful for things like scp where +# we want to return host:path and not only path, so we would pass the +# colon (:) as $1 in this case. Bash-3 doesn't do word splitting, so this +# ensures we get the same word on both bash-3 and bash-4. +# @param $2 words Name of variable to return words to +# @param $3 cword Name of variable to return cword to +# @param $4 cur Name of variable to return current word to complete to +# @see ___get_cword_at_cursor_by_ref() +__get_cword_at_cursor_by_ref() { + local cword words=() + __reassemble_comp_words_by_ref "$1" words cword + + local i cur2 + local cur="$COMP_LINE" + local index="$COMP_POINT" + for (( i = 0; i <= cword; ++i )); do + while [[ + # Current word fits in $cur? + "${#cur}" -ge ${#words[i]} && + # $cur doesn't match cword? + "${cur:0:${#words[i]}}" != "${words[i]}" + ]]; do + # Strip first character + cur="${cur:1}" + # Decrease cursor position + ((index--)) + done + + # Does found word matches cword? + if [[ "$i" -lt "$cword" ]]; then + # No, cword lies further; + local old_size="${#cur}" + cur="${cur#${words[i]}}" + local new_size="${#cur}" + index=$(( index - old_size + new_size )) + fi + done + + if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then + # We messed up. At least return the whole word so things keep working + cur2=${words[cword]} + else + cur2=${cur:0:$index} + fi + + local "$2" "$3" "$4" && + _upvars -a${#words[@]} $2 "${words[@]}" -v $3 "$cword" -v $4 "$cur2" +} + + +# Get the word to complete and optional previous words. +# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases +# where the user is completing in the middle of a word. +# (For example, if the line is "ls foobar", +# and the cursor is here --------> ^ +# Also one is able to cross over possible wordbreak characters. +# Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES] +# Available VARNAMES: +# cur Return cur via $cur +# prev Return prev via $prev +# words Return words via $words +# cword Return cword via $cword +# +# Available OPTIONS: +# -n EXCLUDE Characters out of $COMP_WORDBREAKS which should NOT be +# considered word breaks. This is useful for things like scp +# where we want to return host:path and not only path, so we +# would pass the colon (:) as -n option in this case. Bash-3 +# doesn't do word splitting, so this ensures we get the same +# word on both bash-3 and bash-4. +# -c VARNAME Return cur via $VARNAME +# -p VARNAME Return prev via $VARNAME +# -w VARNAME Return words via $VARNAME +# -i VARNAME Return cword via $VARNAME +# +# Example usage: +# +# $ _get_comp_words_by_ref -n : cur prev +# +_get_comp_words_by_ref() +{ + local exclude flag i OPTIND=1 + local cur cword words=() + local upargs=() upvars=() vcur vcword vprev vwords + + while getopts "c:i:n:p:w:" flag "$@"; do + case $flag in + c) vcur=$OPTARG ;; + i) vcword=$OPTARG ;; + n) exclude=$OPTARG ;; + p) vprev=$OPTARG ;; + w) vwords=$OPTARG ;; + esac + done + while [[ $# -ge $OPTIND ]]; do + case ${!OPTIND} in + cur) vcur=cur ;; + prev) vprev=prev ;; + cword) vcword=cword ;; + words) vwords=words ;; + *) echo "bash: $FUNCNAME(): \`${!OPTIND}': unknown argument" \ + 1>&2; return 1 + esac + let "OPTIND += 1" + done + + __get_cword_at_cursor_by_ref "$exclude" words cword cur + + [[ $vcur ]] && { upvars+=("$vcur" ); upargs+=(-v $vcur "$cur" ); } + [[ $vcword ]] && { upvars+=("$vcword"); upargs+=(-v $vcword "$cword"); } + [[ $vprev ]] && { upvars+=("$vprev" ); upargs+=(-v $vprev + "${words[cword - 1]}"); } + [[ $vwords ]] && { upvars+=("$vwords"); upargs+=(-a${#words[@]} $vwords + "${words[@]}"); } + + (( ${#upvars[@]} )) && local "${upvars[@]}" && _upvars "${upargs[@]}" +} + + +# Get the word to complete. +# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases +# where the user is completing in the middle of a word. +# (For example, if the line is "ls foobar", +# and the cursor is here --------> ^ +# @param $1 string Characters out of $COMP_WORDBREAKS which should NOT be +# considered word breaks. This is useful for things like scp where +# we want to return host:path and not only path, so we would pass the +# colon (:) as $1 in this case. Bash-3 doesn't do word splitting, so this +# ensures we get the same word on both bash-3 and bash-4. +# @param $2 integer Index number of word to return, negatively offset to the +# current word (default is 0, previous is 1), respecting the exclusions +# given at $1. For example, `_get_cword "=:" 1' returns the word left of +# the current word, respecting the exclusions "=:". +# @deprecated Use `_get_comp_words_by_ref cur' instead +# @see _get_comp_words_by_ref() +_get_cword() +{ + local LC_CTYPE=C + local cword words + __reassemble_comp_words_by_ref "$1" words cword + + # return previous word offset by $2 + if [[ ${2//[^0-9]/} ]]; then + printf "%s" "${words[cword-$2]}" + elif [[ "${#words[cword]}" -eq 0 ]] || [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then + printf "%s" "${words[cword]}" + else + local i + local cur="$COMP_LINE" + local index="$COMP_POINT" + for (( i = 0; i <= cword; ++i )); do + while [[ + # Current word fits in $cur? + "${#cur}" -ge ${#words[i]} && + # $cur doesn't match cword? + "${cur:0:${#words[i]}}" != "${words[i]}" + ]]; do + # Strip first character + cur="${cur:1}" + # Decrease cursor position + ((index--)) + done + + # Does found word matches cword? + if [[ "$i" -lt "$cword" ]]; then + # No, cword lies further; + local old_size="${#cur}" + cur="${cur#${words[i]}}" + local new_size="${#cur}" + index=$(( index - old_size + new_size )) + fi + done + + if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then + # We messed up! At least return the whole word so things + # keep working + printf "%s" "${words[cword]}" + else + printf "%s" "${cur:0:$index}" + fi + fi +} # _get_cword() + + +# Get word previous to the current word. +# This is a good alternative to `prev=${COMP_WORDS[COMP_CWORD-1]}' because bash4 +# will properly return the previous word with respect to any given exclusions to +# COMP_WORDBREAKS. +# @deprecated Use `_get_comp_words_by_ref cur prev' instead +# @see _get_comp_words_by_ref() +# +_get_pword() +{ + if [ $COMP_CWORD -ge 1 ]; then + _get_cword "${@:-}" 1; + fi +} + + +# If the word-to-complete contains a colon (:), left-trim COMPREPLY items with +# word-to-complete. +# On bash-3, and bash-4 with a colon in COMP_WORDBREAKS, words containing +# colons are always completed as entire words if the word to complete contains +# a colon. This function fixes this, by removing the colon-containing-prefix +# from COMPREPLY items. +# The preferred solution is to remove the colon (:) from COMP_WORDBREAKS in +# your .bashrc: +# +# # Remove colon (:) from list of word completion separators +# COMP_WORDBREAKS=${COMP_WORDBREAKS//:} +# +# See also: Bash FAQ - E13) Why does filename completion misbehave if a colon +# appears in the filename? - http://tiswww.case.edu/php/chet/bash/FAQ +# @param $1 current word to complete (cur) +# @modifies global array $COMPREPLY +# +__ltrim_colon_completions() { + # If word-to-complete contains a colon, + # and bash-version < 4, + # or bash-version >= 4 and COMP_WORDBREAKS contains a colon + if [[ + "$1" == *:* && ( + ${BASH_VERSINFO[0]} -lt 4 || + (${BASH_VERSINFO[0]} -ge 4 && "$COMP_WORDBREAKS" == *:*) + ) + ]]; then + # Remove colon-word prefix from COMPREPLY items + local colon_word=${1%${1##*:}} + local i=${#COMPREPLY[*]} + while [ $((--i)) -ge 0 ]; do + COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} + done + fi +} # __ltrim_colon_completions() + + +# This function quotes the argument in a way so that readline dequoting +# results in the original argument. This is necessary for at least +# `compgen' which requires its arguments quoted/escaped: +# +# $ ls "a'b/" +# c +# $ compgen -f "a'b/" # Wrong, doesn't return output +# $ compgen -f "a\'b/" # Good (bash-4) +# a\'b/c +# $ compgen -f "a\\\\\'b/" # Good (bash-3) +# a\'b/c +# +# See also: http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html +# @param $1 Argument to quote +# @param $2 Name of variable to return result to +_quote_readline_by_ref() +{ + if [[ ${1:0:1} == "'" ]]; then + # Quote word, leaving out first character + printf -v $2 %q "${1:1}" + if [[ ${BASH_VERSINFO[0]} -le 3 ]]; then + # Double-quote word on bash-3 + printf -v $2 %q ${!2} + fi + elif [[ ${BASH_VERSINFO[0]} -le 3 && ${1:0:1} == '"' ]]; then + printf -v $2 %q "${1:1}" + else + printf -v $2 %q "$1" + fi + + # If result becomes quoted like this: $'string', re-evaluate in order to + # drop the additional quoting. See also: http://www.mail-archive.com/ + # bash-completion-devel@lists.alioth.debian.org/msg01942.html + [[ ${!2:0:1} == '$' ]] && eval $2=${!2} +} # _quote_readline_by_ref() + + +# This function performs file and directory completion. It's better than +# simply using 'compgen -f', because it honours spaces in filenames. +# @param $1 If `-d', complete only on directories. Otherwise filter/pick only +# completions with `.$1' as file extension. +# +_filedir() +{ + local i IFS=$'\t\n' xspec + + __expand_tilde_by_ref cur + + local -a toks + local quoted tmp + + _quote_readline_by_ref "$cur" quoted + toks=( ${toks[@]-} $( + compgen -d -- "$quoted" | { + while read -r tmp; do + # TODO: I have removed a "[ -n $tmp ] &&" before 'printf ..', + # and everything works again. If this bug suddenly + # appears again (i.e. "cd /b" becomes "cd /"), + # remember to check for other similar conditionals (here + # and _filedir_xspec()). --David + printf '%s\n' $tmp + done + } + )) + + # On bash-3, special characters need to be escaped extra. This is + # unless the first character is a single quote ('). If the single + # quote appears further down the string, bash default completion also + # fails, e.g.: + # + # $ ls 'a&b/' + # f + # $ foo 'a&b/ # Becomes: foo 'a&b/f' + # $ foo a'&b/ # Nothing happens + # + if [[ "$1" != -d ]]; then + xspec=${1:+"!*.$1"} + if [[ ${cur:0:1} == "'" && ${BASH_VERSINFO[0]} -ge 4 ]]; then + toks=( ${toks[@]-} $( + eval compgen -f -X \"\$xspec\" -- $quoted + ) ) + else + toks=( ${toks[@]-} $( + compgen -f -X "$xspec" -- $quoted + ) ) + fi + if [ ${#toks[@]} -ne 0 ]; then + # If `compopt' is available, set `-o filenames' + compopt &>/dev/null && compopt -o filenames || + # No, `compopt' isn't available; + # Is `-o filenames' set? + [[ ( + ${COMP_WORDS[0]} && + "$(complete -p ${COMP_WORDS[0]})" == *"-o filenames"* + ) ]] || { + # No, `-o filenames' isn't set; + # Emulate `-o filenames' + # NOTE: A side-effect of emulating `-o filenames' is that + # backslash escape characters are visible within the list + # of presented completions, e.g. the completions look + # like: + # + # $ foo a + # a\ b/ a\$b/ + # + # whereas with `-o filenames' active the completions look + # like: + # + # $ ls a + # a b/ a$b/ + # + for ((i=0; i < ${#toks[@]}; i++)); do + # If directory exists, append slash (/) + if [[ ${cur:0:1} != "'" ]]; then + [[ -d ${toks[i]} ]] && toks[i]="${toks[i]}"/ + if [[ ${cur:0:1} == '"' ]]; then + toks[i]=${toks[i]//\\/\\\\} + toks[i]=${toks[i]//\"/\\\"} + toks[i]=${toks[i]//\$/\\\$} + else + toks[i]=$(printf %q ${toks[i]}) + fi + fi + done + } + fi + fi + + COMPREPLY=( "${COMPREPLY[@]}" "${toks[@]}" ) +} # _filedir() + + +# This function splits $cur=--foo=bar into $prev=--foo, $cur=bar, making it +# easier to support both "--foo bar" and "--foo=bar" style completions. +# Returns 0 if current option was split, 1 otherwise. +# +_split_longopt() +{ + if [[ "$cur" == --?*=* ]]; then + # Cut also backslash before '=' in case it ended up there + # for some reason. + prev="${cur%%?(\\)=*}" + cur="${cur#*=}" + return 0 + fi + + return 1 +} + +# This function tries to parse the output of $command --help +# +_parse_help() { + local cmd + cmd=$1 + $cmd --help 2>&1 | command grep -- "^[[:space:]]*-" | tr "," " " | \ + awk '{print $1; if ($2 ~ /-.*/) { print $2 } }' | sed -e "s:=.*::g" +} + +# This function completes on signal names +# +_signals() +{ + local i + + # standard signal completion is rather braindead, so we need + # to hack around to get what we want here, which is to + # complete on a dash, followed by the signal name minus + # the SIG prefix + COMPREPLY=( $( compgen -A signal SIG${cur#-} )) + for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do + COMPREPLY[i]=-${COMPREPLY[i]#SIG} + done +} + +# This function completes on known mac addresses +# +_mac_addresses() +{ + local re='\([A-Fa-f0-9]\{2\}:\)\{5\}[A-Fa-f0-9]\{2\}' + local PATH="$PATH:/sbin:/usr/sbin" + + # Local interfaces (Linux only?) + COMPREPLY=( "${COMPREPLY[@]}" $( ifconfig -a 2>/dev/null | sed -ne \ + "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]]*$/\1/p" ) ) + + # ARP cache + COMPREPLY=( "${COMPREPLY[@]}" $( arp -an 2>/dev/null | sed -ne \ + "s/.*[[:space:]]\($re\)[[:space:]].*/\1/p" -ne \ + "s/.*[[:space:]]\($re\)[[:space:]]*$/\1/p" ) ) + + COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- "$cur" ) ) + __ltrim_colon_completions "$cur" +} + +# This function completes on configured network interfaces +# +_configured_interfaces() +{ + if [ -f /etc/debian_version ]; then + # Debian system + COMPREPLY=( $( compgen -W "$( sed -ne 's|^iface \([^ ]\{1,\}\).*$|\1|p'\ + /etc/network/interfaces )" -- "$cur" ) ) + elif [ -f /etc/SuSE-release ]; then + # SuSE system + COMPREPLY=( $( compgen -W "$( printf '%s\n' \ + /etc/sysconfig/network/ifcfg-* | \ + sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) ) + elif [ -f /etc/pld-release ]; then + # PLD Linux + COMPREPLY=( $( compgen -W "$( command ls -B \ + /etc/sysconfig/interfaces | \ + sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) ) + else + # Assume Red Hat + COMPREPLY=( $( compgen -W "$( printf '%s\n' \ + /etc/sysconfig/network-scripts/ifcfg-* | \ + sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) ) + fi +} + +# This function completes on available kernels +# +_kernel_versions() +{ + COMPREPLY=( $( compgen -W '$( command ls /lib/modules )' -- "$cur" ) ) +} + +# This function completes on all available network interfaces +# -a: restrict to active interfaces only +# -w: restrict to wireless interfaces only +# +_available_interfaces() +{ + local cmd + + if [ "${1:-}" = -w ]; then + cmd="iwconfig" + elif [ "${1:-}" = -a ]; then + cmd="ifconfig" + else + cmd="ifconfig -a" + fi + + COMPREPLY=( $( eval PATH="$PATH:/sbin" $cmd 2>/dev/null | \ + awk '/^[^ \t]/ { print $1 }' ) ) + COMPREPLY=( $( compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur" ) ) +} + + +# Expand variable starting with tilde (~) +# Only the first portion of the variable from the tilde up to the first slash +# (~../) is expanded. The remainder of the variable, containing for example +# a dollar sign variable ($) or asterisk (*) is not expanded. +# Example usage: +# +# $ v="~"; __expand_tilde_by_ref v; echo "$v" +# +# Example output: +# +# v output +# -------- ---------------- +# ~ /home/user +# ~foo/bar /home/foo/bar +# ~foo/$HOME /home/foo/$HOME +# ~foo/a b /home/foo/a b +# ~foo/* /home/foo/* +# +# @param $1 Name of variable (not the value of the variable) to expand +__expand_tilde_by_ref() { + # Does $1 start with tilde (~)? + if [ "${!1:0:1}" = "~" ]; then + # Does $1 contain slash (/)? + if [ "${!1}" != "${!1//\/}" ]; then + # Yes, $1 contains slash; + # 1: Remove * including and after first slash (/), i.e. "~a/b" + # becomes "~a". Double quotes allow eval. + # 2: Remove * before the first slash (/), i.e. "~a/b" + # becomes "b". Single quotes prevent eval. + # +-----1----+ +---2----+ + eval $1="${!1/%\/*}"/'${!1#*/}' + else + # No, $1 doesn't contain slash + eval $1="${!1}" + fi + fi +} # __expand_tilde_by_ref() + + +# This function expands tildes in pathnames +# +_expand() +{ + # FIXME: Why was this here? + #[ "$cur" != "${cur%\\}" ] && cur="$cur\\" + + # Expand ~username type directory specifications. We want to expand + # ~foo/... to /home/foo/... to avoid problems when $cur starting with + # a tilde is fed to commands and ending up quoted instead of expanded. + + if [[ "$cur" == \~*/* ]]; then + eval cur=$cur + elif [[ "$cur" == \~* ]]; then + cur=${cur#\~} + COMPREPLY=( $( compgen -P '~' -u "$cur" ) ) + [ ${#COMPREPLY[@]} -eq 1 ] && eval COMPREPLY[0]=${COMPREPLY[0]} + return ${#COMPREPLY[@]} + fi +} + +# This function completes on process IDs. +# AIX and Solaris ps prefers X/Open syntax. +[[ $UNAME == SunOS || $UNAME == AIX ]] && +_pids() +{ + COMPREPLY=( $( compgen -W '$( command ps -efo pid | sed 1d )' -- "$cur" )) +} || +_pids() +{ + COMPREPLY=( $( compgen -W '$( command ps axo pid= )' -- "$cur" ) ) +} + +# This function completes on process group IDs. +# AIX and SunOS prefer X/Open, all else should be BSD. +[[ $UNAME == SunOS || $UNAME == AIX ]] && +_pgids() +{ + COMPREPLY=( $( compgen -W '$( command ps -efo pgid | sed 1d )' -- "$cur" )) +} || +_pgids() +{ + COMPREPLY=( $( compgen -W '$( command ps axo pgid= )' -- "$cur" )) +} + +# This function completes on process names. +# AIX and SunOS prefer X/Open, all else should be BSD. +[[ $UNAME == SunOS || $UNAME == AIX ]] && +_pnames() +{ + COMPREPLY=( $( compgen -X '' -W '$( command ps -efo comm | \ + sed -e 1d -e "s:.*/::" -e "s/^-//" | sort -u )' -- "$cur" ) ) +} || +_pnames() +{ + # FIXME: completes "[kblockd/0]" to "0". Previously it was completed + # to "kblockd" which isn't correct either. "kblockd/0" would be + # arguably most correct, but killall from psmisc 22 treats arguments + # containing "/" specially unless -r is given so that wouldn't quite + # work either. Perhaps it'd be best to not complete these to anything + # for now. + # Not using "ps axo comm" because under some Linux kernels, it + # truncates command names (see e.g. http://bugs.debian.org/497540#19) + COMPREPLY=( $( compgen -X '' -W '$( command ps axo command= | \ + sed -e "s/ .*//" -e "s:.*/::" -e "s/:$//" -e "s/^[[(-]//" \ + -e "s/[])]$//" | sort -u )' -- "$cur" ) ) +} + +# This function completes on user IDs +# +_uids() +{ + if type getent &>/dev/null; then + COMPREPLY=( $( compgen -W '$( getent passwd | cut -d: -f3 )' -- "$cur" ) ) + elif type perl &>/dev/null; then + COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($uid) = (getpwent)[2]) { print $uid . "\n" }'"'"' )' -- "$cur" ) ) + else + # make do with /etc/passwd + COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/passwd )' -- "$cur" ) ) + fi +} + +# This function completes on group IDs +# +_gids() +{ + if type getent &>/dev/null; then + COMPREPLY=( $( compgen -W '$( getent group | cut -d: -f3 )' \ + -- "$cur" ) ) + elif type perl &>/dev/null; then + COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($gid) = (getgrent)[2]) { print $gid . "\n" }'"'"' )' -- "$cur" ) ) + else + # make do with /etc/group + COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/group )' -- "$cur" ) ) + fi +} + +# This function completes on services +# +_services() +{ + local sysvdir famdir + [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d || sysvdir=/etc/init.d + famdir=/etc/xinetd.d + COMPREPLY=( $( printf '%s\n' \ + $sysvdir/!(*.rpm@(orig|new|save)|*~|functions) ) ) + + if [ -d $famdir ]; then + COMPREPLY=( "${COMPREPLY[@]}" $( printf '%s\n' \ + $famdir/!(*.rpm@(orig|new|save)|*~) ) ) + fi + + COMPREPLY=( $( compgen -W '${COMPREPLY[@]#@($sysvdir|$famdir)/}' -- "$cur" ) ) +} + +# This function completes on modules +# +_modules() +{ + local modpath + modpath=/lib/modules/$1 + COMPREPLY=( $( compgen -W "$( command ls -R $modpath | \ + sed -ne 's/^\(.*\)\.k\{0,1\}o\(\.gz\)\{0,1\}$/\1/p' )" -- "$cur" ) ) +} + +# This function completes on installed modules +# +_installed_modules() +{ + COMPREPLY=( $( compgen -W "$( PATH="$PATH:/sbin" lsmod | \ + awk '{if (NR != 1) print $1}' )" -- "$1" ) ) +} + +# This function completes on user or user:group format; as for chown and cpio. +# +# The : must be added manually; it will only complete usernames initially. +# The legacy user.group format is not supported. +# +# It assumes compopt -o filenames; but doesn't touch it. +_usergroup() +{ + local IFS=$'\n' + if [[ $cur = *\\\\* || $cur = *:*:* ]]; then + # Give up early on if something seems horribly wrong. + return + elif [[ $cur = *\\:* ]]; then + # Completing group after 'user\:gr'. + # Reply with a list of groups prefixed with 'user:', readline will + # escape to the colon. + local prefix + prefix=${cur%%*([^:])} + prefix=${prefix//\\} + COMPREPLY=( $( compgen -P "$prefix" -g -- "${cur#*[:]}" ) ) + elif [[ $cur = *:* ]]; then + # Completing group after 'user:gr'. + # Reply with a list of unprefixed groups since readline with split on : + # and only replace the 'gr' part + COMPREPLY=( $( compgen -g -- "${cur#*:}" ) ) + else + # Completing a partial 'usernam'. + # + # Don't suffix with a : because readline will escape it and add a + # slash. It's better to complete into 'chown username ' than 'chown + # username\:'. + COMPREPLY=( $( compgen -u -- "$cur" ) ) + fi +} + +# This function completes on valid shells +# +_shells() +{ + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W \ + '$( command grep "^[[:space:]]*/" /etc/shells 2>/dev/null )' \ + -- "$cur" ) ) +} + +# This function completes on valid filesystem types +# +_fstypes() +{ + local fss + + if [ -e /proc/filesystems ] ; then + # Linux + fss="$( cut -d$'\t' -f2 /proc/filesystems ) + $( awk '! /\*/ { print $NF }' /etc/filesystems 2>/dev/null )" + else + # Generic + fss="$( awk '/^[ \t]*[^#]/ { print $3 }' /etc/fstab 2>/dev/null ) + $( awk '/^[ \t]*[^#]/ { print $3 }' /etc/mnttab 2>/dev/null ) + $( awk '/^[ \t]*[^#]/ { print $4 }' /etc/vfstab 2>/dev/null ) + $( awk '{ print $1 }' /etc/dfs/fstypes 2>/dev/null ) + $( [ -d /etc/fs ] && command ls /etc/fs )" + fi + + [ -n "$fss" ] && \ + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$fss" -- "$cur" ) ) +} + +# Get real command. +# - arg: $1 Command +# - stdout: Filename of command in PATH with possible symbolic links resolved. +# Empty string if command not found. +# - return: True (0) if command found, False (> 0) if not. +_realcommand() +{ + type -P "$1" > /dev/null && { + if type -p realpath > /dev/null; then + realpath "$(type -P "$1")" + elif type -p readlink > /dev/null; then + readlink -f "$(type -P "$1")" + else + type -P "$1" + fi + } +} + +# This function returns the first arugment, excluding options +# @param $1 chars Characters out of $COMP_WORDBREAKS which should +# NOT be considered word breaks. See __reassemble_comp_words_by_ref. +_get_first_arg() +{ + local i + + arg= + for (( i=1; i < COMP_CWORD; i++ )); do + if [[ "${COMP_WORDS[i]}" != -* ]]; then + arg=${COMP_WORDS[i]} + break + fi + done +} + + +# This function counts the number of args, excluding options +# @param $1 chars Characters out of $COMP_WORDBREAKS which should +# NOT be considered word breaks. See __reassemble_comp_words_by_ref. +_count_args() +{ + local i cword words + __reassemble_comp_words_by_ref "$1" words cword + + args=1 + for i in "${words[@]:1:cword-1}"; do + [[ "$i" != -* ]] && args=$(($args+1)) + done +} + +# This function completes on PCI IDs +# +_pci_ids() +{ + COMPREPLY=( ${COMPREPLY[@]:-} $( compgen -W \ + "$( PATH="$PATH:/sbin" lspci -n | awk '{print $3}')" -- "$cur" ) ) +} + +# This function completes on USB IDs +# +_usb_ids() +{ + COMPREPLY=( ${COMPREPLY[@]:-} $( compgen -W \ + "$( PATH="$PATH:/sbin" lsusb | awk '{print $6}' )" -- "$cur" ) ) +} + +# CD device names +_cd_devices() +{ + COMPREPLY=( "${COMPREPLY[@]}" + $( compgen -f -d -X "!*/?([amrs])cd*" -- "${cur:-/dev/}" ) ) +} + +# DVD device names +_dvd_devices() +{ + COMPREPLY=( "${COMPREPLY[@]}" + $( compgen -f -d -X "!*/?(r)dvd*" -- "${cur:-/dev/}" ) ) +} +##--end[RIPPED from /etc/bash_completion-------------------------------------]-- + +##--start[RIPPED from /etc/bash_completion-----------------------------------]-- +# start of section containing completion functions for external programs + +# This function provides simple user@host completion +# +_user_at_host() { + local cur + + COMPREPLY=() + _get_comp_words_by_ref -n : cur + + if [[ $cur == *@* ]]; then + _known_hosts_real "$cur" + else + COMPREPLY=( $( compgen -u -- "$cur" ) ) + fi + + return 0 +} +shopt -u hostcomplete && complete -F _user_at_host -o nospace talk ytalk finger + +# NOTE: Using this function as a helper function is deprecated. Use +# `_known_hosts_real' instead. +_known_hosts() +{ + local options + COMPREPLY=() + + # NOTE: Using `_known_hosts' as a helper function and passing options + # to `_known_hosts' is deprecated: Use `_known_hosts_real' instead. + [[ "$1" == -a || "$2" == -a ]] && options=-a + [[ "$1" == -c || "$2" == -c ]] && options="$options -c" + _known_hosts_real $options "$(_get_cword :)" +} # _known_hosts() + +# Helper function for completing _known_hosts. +# This function performs host completion based on ssh's config and known_hosts +# files, as well as hostnames reported by avahi-browse. Also hosts from +# HOSTFILE (compgen -A hostname) are added, unless +# COMP_KNOWN_HOSTS_WITH_HOSTFILE is set to an empty value. +# Usage: _known_hosts_real [OPTIONS] CWORD +# Options: -a Use aliases +# -c Use `:' suffix +# -F configfile Use `configfile' for configuration settings +# -p PREFIX Use PREFIX +# Return: Completions, starting with CWORD, are added to COMPREPLY[] +_known_hosts_real() +{ + local configfile flag prefix + local cur curd awkcur user suffix aliases i host + local -a kh khd config + + local OPTIND=1 + while getopts "acF:p:" flag "$@"; do + case $flag in + a) aliases='yes' ;; + c) suffix=':' ;; + F) configfile=$OPTARG ;; + p) prefix=$OPTARG ;; + esac + done + [ $# -lt $OPTIND ] && echo "error: $FUNCNAME: missing mandatory argument CWORD" + cur=${!OPTIND}; let "OPTIND += 1" + [ $# -ge $OPTIND ] && echo "error: $FUNCNAME("$@"): unprocessed arguments:"\ + $(while [ $# -ge $OPTIND ]; do printf '%s\n' ${!OPTIND}; shift; done) + + [[ $cur == *@* ]] && user=${cur%@*}@ && cur=${cur#*@} + kh=() + + # ssh config files + if [ -n "$configfile" ]; then + [ -r "$configfile" ] && + config=( "${config[@]}" "$configfile" ) + else + [ -r /etc/ssh/ssh_config ] && + config=( "${config[@]}" "/etc/ssh/ssh_config" ) + [ -r "${HOME}/.ssh/config" ] && + config=( "${config[@]}" "${HOME}/.ssh/config" ) + [ -r "${HOME}/.ssh2/config" ] && + config=( "${config[@]}" "${HOME}/.ssh2/config" ) + fi + + # Known hosts files from configs + if [ ${#config[@]} -gt 0 ]; then + local OIFS=$IFS IFS=$'\n' + local -a tmpkh + # expand paths (if present) to global and user known hosts files + # TODO(?): try to make known hosts files with more than one consecutive + # spaces in their name work (watch out for ~ expansion + # breakage! Alioth#311595) + tmpkh=( $( awk 'sub("^[ \t]*([Gg][Ll][Oo][Bb][Aa][Ll]|[Uu][Ss][Ee][Rr])[Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee][ \t]+", "") { print $0 }' "${config[@]}" | sort -u ) ) + for i in "${tmpkh[@]}"; do + # Remove possible quotes + i=${i//\"} + # Eval/expand possible `~' or `~user' + __expand_tilde_by_ref i + [ -r "$i" ] && kh=( "${kh[@]}" "$i" ) + done + IFS=$OIFS + fi + + # Global known_hosts files + if [ -z "$configfile" ]; then + [ -r /etc/ssh/ssh_known_hosts ] && + kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts ) + [ -r /etc/ssh/ssh_known_hosts2 ] && + kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts2 ) + [ -r /etc/known_hosts ] && + kh=( "${kh[@]}" /etc/known_hosts ) + [ -r /etc/known_hosts2 ] && + kh=( "${kh[@]}" /etc/known_hosts2 ) + [ -d /etc/ssh2/knownhosts ] && + khd=( "${khd[@]}" /etc/ssh2/knownhosts/*pub ) + fi + + # User known_hosts files + if [ -z "$configfile" ]; then + [ -r ~/.ssh/known_hosts ] && + kh=( "${kh[@]}" ~/.ssh/known_hosts ) + [ -r ~/.ssh/known_hosts2 ] && + kh=( "${kh[@]}" ~/.ssh/known_hosts2 ) + [ -d ~/.ssh2/hostkeys ] && + khd=( "${khd[@]}" ~/.ssh2/hostkeys/*pub ) + fi + + # If we have known_hosts files to use + if [[ ${#kh[@]} -gt 0 || ${#khd[@]} -gt 0 ]]; then + # Escape slashes and dots in paths for awk + awkcur=${cur//\//\\\/} + awkcur=${awkcur//\./\\\.} + curd=$awkcur + + if [[ "$awkcur" == [0-9]*.* ]]; then + # Digits followed by a dot - just search for that + awkcur="^$awkcur.*" + elif [[ "$awkcur" == [0-9]* ]]; then + # Digits followed by no dot - search for digits followed + # by a dot + awkcur="^$awkcur.*\." + elif [ -z "$awkcur" ]; then + # A blank - search for a dot or an alpha character + awkcur="[a-z.]" + else + awkcur="^$awkcur" + fi + + if [ ${#kh[@]} -gt 0 ]; then + # FS needs to look for a comma separated list + COMPREPLY=( "${COMPREPLY[@]}" $( awk 'BEGIN {FS=","} + /^\s*[^|\#]/ {for (i=1; i<=2; ++i) { \ + gsub(" .*$", "", $i); \ + gsub("[\\[\\]]", "", $i); \ + gsub(":[0-9]+$", "", $i); \ + if ($i ~ /'"$awkcur"'/) {print $i} \ + }}' "${kh[@]}" 2>/dev/null ) ) + fi + if [ ${#khd[@]} -gt 0 ]; then + # Needs to look for files called + # .../.ssh2/key_22_.pub + # dont fork any processes, because in a cluster environment, + # there can be hundreds of hostkeys + for i in "${khd[@]}" ; do + if [[ "$i" == *key_22_$curd*.pub && -r "$i" ]]; then + host=${i/#*key_22_/} + host=${host/%.pub/} + COMPREPLY=( "${COMPREPLY[@]}" $host ) + fi + done + fi + + # apply suffix and prefix + for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do + COMPREPLY[i]=$prefix$user${COMPREPLY[i]}$suffix + done + fi + + # append any available aliases from config files + if [[ ${#config[@]} -gt 0 && -n "$aliases" ]]; then + local hosts=$( sed -ne 's/^[ \t]*[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\{0,1\}['"$'\t '"']\{1,\}\([^#*?]*\)\(#.*\)\{0,1\}$/\2/p' "${config[@]}" ) + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -P "$prefix$user" \ + -S "$suffix" -W "$hosts" -- "$cur" ) ) + fi + + # Add hosts reported by avahi-browse, if it's available. + # The original call to avahi-browse also had "-k", to avoid lookups into + # avahi's services DB. We don't need the name of the service, and if it + # contains ";", it may mistify the result. But on Gentoo (at least), + # -k isn't available (even if mentioned in the manpage), so... + if type avahi-browse >&/dev/null; then + COMPREPLY=( "${COMPREPLY[@]}" $( \ + compgen -P "$prefix$user" -S "$suffix" -W \ + "$( avahi-browse -cpr _workstation._tcp 2>/dev/null | \ + awk -F';' '/^=/ { print $7 }' | sort -u )" -- "$cur" ) ) + fi + + # Add results of normal hostname completion, unless + # `COMP_KNOWN_HOSTS_WITH_HOSTFILE' is set to an empty value. + if [ -n "${COMP_KNOWN_HOSTS_WITH_HOSTFILE-1}" ]; then + COMPREPLY=( "${COMPREPLY[@]}" + $( compgen -A hostname -P "$prefix$user" -S "$suffix" -- "$cur" ) ) + fi + + __ltrim_colon_completions "$prefix$user$cur" + + return 0 +} # _known_hosts_real() +##--end[RIPPED from /etc/bash_completion-------------------------------------]-- + +##--start[RIPPED from /etc/bash_completion-----------------------------------]-- +# a wrapper method for the next one, when the offset is unknown +_command() +{ + local offset i + + # find actual offset, as position of the first non-option + offset=1 + for (( i=1; i <= COMP_CWORD; i++ )); do + if [[ "${COMP_WORDS[i]}" != -* ]]; then + offset=$i + break + fi + done + _command_offset $offset +} + +# A meta-command completion function for commands like sudo(8), which need to +# first complete on a command, then complete according to that command's own +# completion definition - currently not quite foolproof (e.g. mount and umount +# don't work properly), but still quite useful. +# +_command_offset() +{ + local cur func cline cspec noglob cmd i char_offset word_offset \ + _COMMAND_FUNC _COMMAND_FUNC_ARGS + + word_offset=$1 + + # rewrite current completion context before invoking + # actual command completion + + # find new first word position, then + # rewrite COMP_LINE and adjust COMP_POINT + local first_word=${COMP_WORDS[$word_offset]} + for (( i=0; i <= ${#COMP_LINE}; i++ )); do + if [[ "${COMP_LINE:$i:${#first_word}}" == "$first_word" ]]; then + char_offset=$i + break + fi + done + COMP_LINE=${COMP_LINE:$char_offset} + COMP_POINT=$(( COMP_POINT - $char_offset )) + + # shift COMP_WORDS elements and adjust COMP_CWORD + for (( i=0; i <= COMP_CWORD - $word_offset; i++ )); do + COMP_WORDS[i]=${COMP_WORDS[i+$word_offset]} + done + for (( i; i <= COMP_CWORD; i++ )); do + unset COMP_WORDS[i]; + done + COMP_CWORD=$(( $COMP_CWORD - $word_offset )) + + COMPREPLY=() + _get_comp_words_by_ref cur + + if [[ $COMP_CWORD -eq 0 ]]; then + COMPREPLY=( $( compgen -c -- "$cur" ) ) + else + cmd=${COMP_WORDS[0]} + if complete -p $cmd &>/dev/null; then + cspec=$( complete -p $cmd ) + if [ "${cspec#* -F }" != "$cspec" ]; then + # complete -F + + # get function name + func=${cspec#*-F } + func=${func%% *} + + if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then + $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}" + else + $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" + fi + + # remove any \: generated by a command that doesn't + # default to filenames or dirnames (e.g. sudo chown) + # FIXME: I'm pretty sure this does not work! + if [ "${cspec#*-o }" != "$cspec" ]; then + cspec=${cspec#*-o } + cspec=${cspec%% *} + if [[ "$cspec" != @(dir|file)names ]]; then + COMPREPLY=("${COMPREPLY[@]//\\\\:/:}") + fi + fi + elif [ -n "$cspec" ]; then + cspec=${cspec#complete}; + cspec=${cspec%%$cmd}; + COMPREPLY=( $( eval compgen "$cspec" -- "$cur" ) ); + fi + fi + fi + + [ ${#COMPREPLY[@]} -eq 0 ] && _filedir +} +##--end[RIPPED from /etc/bash_completion-------------------------------------]-- + +##--start[RIPPED from /etc/bash_completion-----------------------------------]-- +_root_command() +{ + local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin + _command $1 $2 $3 +} +##--end[RIPPED from /etc/bash_completion-------------------------------------]-- + +##--start[RIPPED from /etc/bash_completion-----------------------------------]-- +_longopt() +{ + local cur prev + + _get_comp_words_by_ref cur prev + + if _split_longopt; then + case "$prev" in + *[Dd][Ii][Rr]*) + _filedir -d + ;; + *[Ff][Ii][Ll][Ee]*) + _filedir + ;; + esac + return 0 + fi + + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "$( $1 --help 2>&1 | \ + sed -ne 's/.*\(--[-A-Za-z0-9]\{1,\}\).*/\1/p' | sort -u )" \ + -- "$cur" ) ) + elif [[ "$1" == rmdir ]]; then + _filedir -d + else + _filedir + fi +} +##--end[RIPPED from /etc/bash_completion-------------------------------------]-- + +##--start[RIPPED from /etc/bash_completion-----------------------------------]-- +_filedir_xspec() +{ + local IFS cur xspec + + IFS=$'\t\n' + COMPREPLY=() + _get_comp_words_by_ref cur + + _expand || return 0 + + # get first exclusion compspec that matches this command + xspec=$( awk "/^complete[ \t]+.*[ \t]${1##*/}([ \t]|\$)/ { print \$0; exit }" \ + "$BASH_COMPLETION" ) + # prune to leave nothing but the -X spec + xspec=${xspec#*-X } + xspec=${xspec%% *} + + local -a toks + local tmp + + toks=( ${toks[@]-} $( + compgen -d -- "$(quote_readline "$cur")" | { + while read -r tmp; do + # see long TODO comment in _filedir() --David + printf '%s\n' $tmp + done + } + )) + + toks=( ${toks[@]-} $( + eval compgen -f -X "$xspec" -- "\$(quote_readline "\$cur")" | { + while read -r tmp; do + [ -n $tmp ] && printf '%s\n' $tmp + done + } + )) + + COMPREPLY=( "${toks[@]}" ) +} +##--end[RIPPED from /etc/bash_completion-------------------------------------]-- +fi