From c3d398fcc6e400be546c28eb1fc25abfa5816eac Mon Sep 17 00:00:00 2001 From: David Paleino Date: Sun, 8 Jan 2012 00:19:18 +0100 Subject: Imported Upstream version 1.99 --- bash_completion | 360 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 217 insertions(+), 143 deletions(-) (limited to 'bash_completion') diff --git a/bash_completion b/bash_completion index 62ef87ed..374e20c3 100644 --- a/bash_completion +++ b/bash_completion @@ -24,7 +24,7 @@ # # http://bash-completion.alioth.debian.org/ # -# RELEASE: 1.90 +# RELEASE: 1.99 if [[ $- == *v* ]]; then BASH_COMPLETION_ORIGINAL_V_VALUE="-v" @@ -32,15 +32,15 @@ else BASH_COMPLETION_ORIGINAL_V_VALUE="+v" fi -if [[ -n $BASH_COMPLETION_DEBUG ]]; then +if [[ ${BASH_COMPLETION_DEBUG-} ]]; then set -v else set +v fi -# Alter the following to reflect the location of this file. +# Set the following to the location of the backwards compat completion dir. # -[ -n "$BASH_COMPLETION_COMPAT_DIR" ] || BASH_COMPLETION_COMPAT_DIR=/etc/bash_completion.d +: ${BASH_COMPLETION_COMPAT_DIR:=/etc/bash_completion.d} readonly BASH_COMPLETION_COMPAT_DIR # Blacklisted completions, causing problems with our code. @@ -102,6 +102,17 @@ _userland() [[ $userland == $1 ]] } +# This function sets correct SysV init directories +# +_sysvdirs() +{ + sysvdirs=( ) + [[ -d /etc/rc.d/init.d ]] && sysvdirs+=( /etc/rc.d/init.d ) + [[ -d /etc/init.d ]] && sysvdirs+=( /etc/init.d ) + # Slackware uses /etc/rc.d + [[ -f /etc/slackware-version ]] && sysvdirs=( /etc/rc.d ) +} + # This function checks whether we have a given program on the system. # _have() @@ -131,7 +142,8 @@ _rl_enabled() # This function shell-quotes the argument quote() { - echo \'${1//\'/\'\\\'\'}\' #'# Help vim syntax highlighting + local quoted=${1//\'/\'\\\'\'} + printf "'%s'" "$quoted" } # @see _quote_readline_by_ref() @@ -146,7 +158,7 @@ quote_readline() # This function shell-dequotes the argument dequote() { - eval echo "$1" 2> /dev/null + eval printf %s "$1" 2> /dev/null } @@ -245,24 +257,21 @@ __reassemble_comp_words_by_ref() # empty and is word made up of just word separator characters to # be excluded and is current word not preceded by whitespace in # original line? - while [[ $i -gt 0 && ${COMP_WORDS[$i]} && - ${COMP_WORDS[$i]//[^$exclude]} == ${COMP_WORDS[$i]} - ]]; do + while [[ $i -gt 0 && ${COMP_WORDS[$i]} == +([$exclude]) ]]; do # Is word separator not preceded by whitespace in original line # and are we not going to append to word 0 (the command # itself), then append to current word. - [[ ${line:0:1} != ' ' && ${line:0:1} != $'\t' ]] && - (( j >= 2 )) && ((j--)) + [[ $line != [$' \t']* ]] && (( j >= 2 )) && ((j--)) # Append word separator to current or new word ref="$2[$j]" eval $2[$j]=\${!ref}\${COMP_WORDS[i]} # Indicate new cword - [ $i = $COMP_CWORD ] && eval $3=$j + [[ $i == $COMP_CWORD ]] && eval $3=$j # Remove optional whitespace + word separator from line copy line=${line#*"${COMP_WORDS[$i]}"} # Start new word if word separator in original line is # followed by whitespace. - [[ ${line:0:1} == ' ' || ${line:0:1} == $'\t' ]] && ((j++)) + [[ $line == [$' \t']* ]] && ((j++)) # Indicate next word if available, else end *both* while and # for loop (( $i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2 @@ -295,14 +304,14 @@ __get_cword_at_cursor_by_ref() local cword words=() __reassemble_comp_words_by_ref "$1" words cword - local i cur cur2 index=$COMP_POINT lead=${COMP_LINE:0:$COMP_POINT} + local i cur index=$COMP_POINT lead=${COMP_LINE:0:$COMP_POINT} # Cursor not at position 0 and not leaded by just space(s)? if [[ $index -gt 0 && ( $lead && ${lead//[[:space:]]} ) ]]; then cur=$COMP_LINE for (( i = 0; i <= cword; ++i )); do while [[ # Current word fits in $cur? - "${#cur}" -ge ${#words[i]} && + ${#cur} -ge ${#words[i]} && # $cur doesn't match cword? "${cur:0:${#words[i]}}" != "${words[i]}" ]]; do @@ -313,11 +322,11 @@ __get_cword_at_cursor_by_ref() done # Does found word match cword? - if [[ "$i" -lt "$cword" ]]; then + if [[ $i -lt $cword ]]; then # No, cword lies further; - local old_size="${#cur}" - cur="${cur#${words[i]}}" - local new_size="${#cur}" + local old_size=${#cur} + cur="${cur#"${words[i]}"}" + local new_size=${#cur} index=$(( index - old_size + new_size )) fi done @@ -472,7 +481,7 @@ _get_cword() # _get_pword() { - if [ $COMP_CWORD -ge 1 ]; then + if [[ $COMP_CWORD -ge 1 ]]; then _get_cword "${@:-}" 1 fi } @@ -501,7 +510,7 @@ __ltrim_colon_completions() # Remove colon-word prefix from COMPREPLY items local colon_word=${1%${1##*:}} local i=${#COMPREPLY[*]} - while [ $((--i)) -ge 0 ]; do + while [[ $((--i)) -ge 0 ]]; do COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} done fi @@ -526,7 +535,7 @@ __ltrim_colon_completions() # @param $2 Name of variable to return result to _quote_readline_by_ref() { - if [[ ${1:0:1} == "'" ]]; then + if [[ $1 == \'* ]]; then # Leave out first character printf -v $2 %s "${1:1}" else @@ -536,7 +545,7 @@ _quote_readline_by_ref() # 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} + [[ ${!2} == \$* ]] && eval $2=${!2} } # _quote_readline_by_ref() @@ -581,9 +590,11 @@ _filedir() -n "$1" && "$1" != -d && ${#toks[@]} -lt 1 ]] && \ toks+=( $( compgen -f -- $quoted ) ) - [ ${#toks[@]} -ne 0 ] && compopt -o filenames 2>/dev/null - - COMPREPLY+=( "${toks[@]}" ) + if [[ ${#toks[@]} -ne 0 ]]; then + # 2>/dev/null for direct invocation, e.g. in the _filedir unit test + compopt -o filenames 2>/dev/null + COMPREPLY+=( "${toks[@]}" ) + fi } # _filedir() @@ -606,6 +617,20 @@ _split_longopt() return 1 } +# Complete variables. +# @return True (0) if variables were completed, +# False (> 0) if not. +_variables() +{ + if [[ $cur =~ ^(\$\{?)([A-Za-z0-9_]*)$ ]]; then + [[ $cur == *{* ]] && local suffix=} || local suffix= + COMPREPLY+=( $( compgen -P ${BASH_REMATCH[1]} -S "$suffix" -v -- \ + "${BASH_REMATCH[2]}" ) ) + return 0 + fi + return 1 +} + # Initialize completion and deal with various general things: do file # and variable completion where appropriate, and adjust prev, words, # and cword as if no redirections exist so that completions do not @@ -623,7 +648,7 @@ _split_longopt() # _init_completion() { - local exclude flag outx errx inx OPTIND=1 + local exclude= flag outx errx inx OPTIND=1 while getopts "n:e:o:i:s" flag "$@"; do case $flag in @@ -646,12 +671,7 @@ _init_completion() _get_comp_words_by_ref -n "$exclude<>&" cur prev words cword # Complete variable names. - if [[ $cur =~ ^(\$\{?)([A-Za-z0-9_]*)$ ]]; then - [[ $cur == *{* ]] && local suffix=} || local suffix= - COMPREPLY=( $( compgen -P ${BASH_REMATCH[1]} -S "$suffix" -v -- \ - "${BASH_REMATCH[2]}" ) ) - return 1 - fi + _variables && return 1 # Complete on files if current is a redirect possibly followed by a # filename, e.g. ">foo", or previous is a "bare" redirect, e.g. ">". @@ -690,7 +710,7 @@ _init_completion() [[ $cword -eq 0 ]] && return 1 prev=${words[cword-1]} - [[ $split ]] && _split_longopt && split=true + [[ ${split-} ]] && _split_longopt && split=true return 0 } @@ -727,14 +747,18 @@ __parse_options() } # Parse GNU style help output of the given command. -# @param $1 command +# @param $1 command; if "-", read from stdin and ignore rest of args # @param $2 command options (default: --help) # _parse_help() { - eval local cmd=$1 + eval local cmd=$( quote "$1" ) local line - "$cmd" ${2:---help} 2>&1 | while read -r line; do + { case $cmd in + -) cat ;; + *) "$( dequote "$cmd" )" ${2:---help} 2>&1 ;; + esac } \ + | while read -r line; do [[ $line == *([ $'\t'])-* ]] || continue # transform "-f FOO, --foo=FOO" to "-f , --foo=FOO" etc @@ -748,14 +772,18 @@ _parse_help() } # Parse BSD style usage output (options in brackets) of the given command. -# @param $1 command +# @param $1 command; if "-", read from stdin and ignore rest of args # @param $2 command options (default: --usage) # _parse_usage() { - eval local cmd=$1 + eval local cmd=$( quote "$1" ) local line match option i char - "$cmd" ${2:---usage} 2>&1 | while read -r line; do + { case $cmd in + -) cat ;; + *) "$( dequote "$cmd" )" ${2:---usage} 2>&1 ;; + esac } \ + | while read -r line; do while [[ $line =~ \[[[:space:]]*(-[^]]+)[[:space:]]*\] ]]; do match=${BASH_REMATCH[0]} @@ -793,9 +821,11 @@ _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?) + # Local interfaces (Linux: HWAddr, FreeBSD: ether) COMPREPLY+=( $( ifconfig -a 2>/dev/null | sed -ne \ - "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]]*$/\1/p" ) ) + "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]]*$/\1/p" -ne \ + "s/^[[:space:]]\{1,\}ether[[:space:]]\{1,\}\($re\)[[:space:]]*$/\1/p" \ + ) ) # ARP cache COMPREPLY+=( $( arp -an 2>/dev/null | sed -ne \ @@ -814,16 +844,16 @@ _mac_addresses() # _configured_interfaces() { - if [ -f /etc/debian_version ]; then + 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 + 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 + elif [[ -f /etc/pld-release ]]; then # PLD Linux COMPREPLY=( $( compgen -W "$( command ls -B \ /etc/sysconfig/interfaces | \ @@ -841,7 +871,7 @@ _configured_interfaces() _ip_addresses() { COMPREPLY+=( $( compgen -W \ - "$( PATH="$PATH:/sbin" ifconfig -a | + "$( PATH="$PATH:/sbin" LC_ALL=C ifconfig -a | sed -ne 's/.*addr:\([^[:space:]]*\).*/\1/p' \ -ne 's/.*inet[[:space:]]\{1,\}\([^[:space:]]*\).*/\1/p' )" \ -- "$cur" ) ) @@ -862,9 +892,9 @@ _available_interfaces() { local cmd - if [ "${1:-}" = -w ]; then + if [[ ${1:-} == -w ]]; then cmd="iwconfig" - elif [ "${1:-}" = -a ]; then + elif [[ ${1:-} == -a ]]; then cmd="ifconfig" else cmd="ifconfig -a" @@ -875,6 +905,14 @@ _available_interfaces() COMPREPLY=( $( compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur" ) ) } +# Echo number of CPUs, falling back to 1 on failure. +_ncpus() +{ + local var=NPROCESSORS_ONLN + [[ $OSTYPE == *linux* ]] && var=_$var + local n=$( getconf $var 2>/dev/null ) + printf %s ${n:-1} +} # Perform tilde (~) completion # @return True (0) if completion needs further processing, @@ -887,7 +925,8 @@ _tilde() # Try generate ~username completions COMPREPLY=( $( compgen -P '~' -u "${1#\~}" ) ) result=${#COMPREPLY[@]} - [ $result -gt 0 ] && compopt -o filenames 2>/dev/null + # 2>/dev/null for direct invocation, e.g. in the _tilde unit test + [[ $result -gt 0 ]] && compopt -o filenames 2>/dev/null fi return $result } @@ -918,9 +957,9 @@ _tilde() __expand_tilde_by_ref() { # Does $1 start with tilde (~)? - if [ "${!1:0:1}" = "~" ]; then + if [[ ${!1} == ~* ]]; then # Does $1 contain slash (/)? - if [ "${!1}" != "${!1//\/}" ]; then + if [[ ${!1} == */* ]]; then # Yes, $1 contains slash; # 1: Remove * including and after first slash (/), i.e. "~a/b" # becomes "~a". Double quotes allow eval. @@ -952,7 +991,7 @@ _expand() elif [[ "$cur" == \~* ]]; then cur=${cur#\~} COMPREPLY=( $( compgen -P '~' -u "$cur" ) ) - [ ${#COMPREPLY[@]} -eq 1 ] && eval COMPREPLY[0]=${COMPREPLY[0]} + [[ ${#COMPREPLY[@]} -eq 1 ]] && eval COMPREPLY[0]=${COMPREPLY[0]} return ${#COMPREPLY[@]} fi } @@ -1037,37 +1076,75 @@ _gids() # _backup_glob='@(#*#|*@(~|.@(bak|orig|rej|swp|dpkg*|rpm@(orig|new|save))))' +# Complete on xinetd services +# +_xinetd_services() +{ + local xinetddir=/etc/xinetd.d + if [[ -d $xinetddir ]]; then + local restore_nullglob=$(shopt -p nullglob); shopt -s nullglob + local -a svcs=( $( printf '%s\n' $xinetddir/!($_backup_glob) ) ) + $restore_nullglob + COMPREPLY+=( $( compgen -W '${svcs[@]#$xinetddir/}' -- "$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 + local sysvdirs + _sysvdirs local restore_nullglob=$(shopt -p nullglob); shopt -s nullglob - - COMPREPLY=( $( printf '%s\n' $sysvdir/!($_backup_glob|functions) ) ) - - if [ -d $famdir ]; then - COMPREPLY+=( $( printf '%s\n' $famdir/!($_backup_glob) ) ) - fi - + COMPREPLY=( $( printf '%s\n' ${sysvdirs[0]}/!($_backup_glob|functions) ) ) $restore_nullglob COMPREPLY+=( $( systemctl list-units --full --all 2>/dev/null | \ awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }' ) ) - COMPREPLY=( $( compgen -W '${COMPREPLY[@]#@($sysvdir|$famdir)/}' -- "$cur" ) ) + COMPREPLY=( $( compgen -W '${COMPREPLY[@]#${sysvdirs[0]}/}' -- "$cur" ) ) } +# This completes on a list of all available service scripts for the +# 'service' command and/or the SysV init.d directory, followed by +# that script's available commands +# +_service() +{ + local cur prev words cword + _init_completion || return + + # don't complete past 2nd token + [[ $cword -gt 2 ]] && return 0 + + if [[ $cword -eq 1 && $prev == ?(*/)service ]]; then + _services + [[ -e /etc/mandrake-release ]] && _xinetd_services + else + local sysvdirs + _sysvdirs + COMPREPLY=( $( compgen -W '`sed -e "y/|/ /" \ + -ne "s/^.*\(U\|msg_u\)sage.*{\(.*\)}.*$/\2/p" \ + ${sysvdirs[0]}/${prev##*/} 2>/dev/null` start stop' -- "$cur" ) ) + fi +} && +complete -F _service service +_sysvdirs +for svcdir in ${sysvdirs[@]}; do + for svc in $svcdir/!($_backup_glob); do + [[ -x $svc ]] && complete -F _service $svc + done +done +unset svc svcdir sysvdirs + # This function completes on modules # _modules() { local modpath modpath=/lib/modules/$1 - COMPREPLY=( $( compgen -W "$( command ls -R $modpath | \ + COMPREPLY=( $( compgen -W "$( command ls -RL $modpath | \ sed -ne 's/^\(.*\)\.k\{0,1\}o\(\.gz\)\{0,1\}$/\1/p' )" -- "$cur" ) ) } @@ -1172,7 +1249,7 @@ _fstypes() { local fss - if [ -e /proc/filesystems ] ; then + if [[ -e /proc/filesystems ]]; then # Linux fss="$( cut -d$'\t' -f2 /proc/filesystems ) $( awk '! /\*/ { print $NF }' /etc/filesystems 2>/dev/null )" @@ -1182,11 +1259,10 @@ _fstypes() $( 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 )" + $( [[ -d /etc/fs ]] && command ls /etc/fs )" fi - [ -n "$fss" ] && \ - COMPREPLY+=( $( compgen -W "$fss" -- "$cur" ) ) + [[ -n $fss ]] && COMPREPLY+=( $( compgen -W "$fss" -- "$cur" ) ) } # Get real command. @@ -1340,53 +1416,58 @@ _known_hosts_real() p) prefix=$OPTARG ;; esac done - [ $# -lt $OPTIND ] && echo "error: $FUNCNAME: missing mandatory argument CWORD" + [[ $# -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) + [[ $# -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+=( "$configfile" ) + if [[ -n $configfile ]]; then + [[ -r $configfile ]] && config+=( "$configfile" ) else - for i in /etc/ssh/ssh_config "${HOME}/.ssh/config" \ - "${HOME}/.ssh2/config"; do - [ -r $i ] && config+=( "$i" ) + for i in /etc/ssh/ssh_config ~/.ssh/config ~/.ssh2/config; do + [[ -r $i ]] && config+=( "$i" ) done fi # Known hosts files from configs - if [ ${#config[@]} -gt 0 ]; then - local OIFS=$IFS IFS=$'\n' + if [[ ${#config[@]} -gt 0 ]]; then + local OIFS=$IFS IFS=$'\n' j 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 ) ) + IFS=$OIFS for i in "${tmpkh[@]}"; do - # Remove possible quotes - i=${i//\"} - # Eval/expand possible `~' or `~user' - __expand_tilde_by_ref i - [ -r "$i" ] && kh+=( "$i" ) + # First deal with quoted entries... + while [[ $i =~ ^([^\"]*)\"([^\"]*)\"(.*)$ ]]; do + i=${BASH_REMATCH[1]}${BASH_REMATCH[3]} + j=${BASH_REMATCH[2]} + __expand_tilde_by_ref j # Eval/expand possible `~' or `~user' + [[ -r $j ]] && kh+=( "$j" ) + done + # ...and then the rest. + for j in $i; do + __expand_tilde_by_ref j # Eval/expand possible `~' or `~user' + [[ -r $j ]] && kh+=( "$j" ) + done done - IFS=$OIFS fi - if [ -z "$configfile" ]; then + if [[ -z $configfile ]]; then # Global and user known_hosts files for i in /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2 \ /etc/known_hosts /etc/known_hosts2 ~/.ssh/known_hosts \ ~/.ssh/known_hosts2; do - [ -r $i ] && kh+=( $i ) + [[ -r $i ]] && kh+=( "$i" ) done for i in /etc/ssh2/knownhosts ~/.ssh2/hostkeys; do - [ -d $i ] && khd+=( $i/*pub ) + [[ -d $i ]] && khd+=( "$i"/*pub ) done fi @@ -1404,23 +1485,25 @@ _known_hosts_real() # Digits followed by no dot or colon - search for digits followed # by a dot or a colon awkcur="^$awkcur.*[.:]" - elif [ -z "$awkcur" ]; then + elif [[ -z $awkcur ]]; then # A blank - search for a dot, a colon, or an alpha character awkcur="[a-z.:]" else awkcur="^$awkcur" fi - if [ ${#kh[@]} -gt 0 ]; then + if [[ ${#kh[@]} -gt 0 ]]; then # FS needs to look for a comma separated list COMPREPLY+=( $( awk 'BEGIN {FS=","} - /^\s*[^|\#]/ {for (i=1; i<=2; ++i) { \ - sub(" .*$", "", $i); \ + /^\s*[^|\#]/ { + sub("^@[^ ]+ +", ""); \ + sub(" .*$", ""); \ + for (i=1; i<=NF; ++i) { \ sub("^\\[", "", $i); sub("\\](:[0-9]+)?$", "", $i); \ - if ($i ~ /'"$awkcur"'/) {print $i} \ + if ($i !~ /[*?]/ && $i ~ /'"$awkcur"'/) {print $i} \ }}' "${kh[@]}" 2>/dev/null ) ) fi - if [ ${#khd[@]} -gt 0 ]; then + if [[ ${#khd[@]} -gt 0 ]]; then # Needs to look for files called # .../.ssh2/key_22_.pub # dont fork any processes, because in a cluster environment, @@ -1460,9 +1543,13 @@ _known_hosts_real() awk -F';' '/^=/ { print $7 }' | sort -u )" -- "$cur" ) ) fi + # Add hosts reported by ruptime. + COMPREPLY+=( $( compgen -W \ + "$( ruptime 2>/dev/null | awk '{ print $1 }' )" -- "$cur" ) ) + # 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 + if [[ -n ${COMP_KNOWN_HOSTS_WITH_HOSTFILE-1} ]]; then COMPREPLY+=( $( compgen -A hostname -P "$prefix$user" -S "$suffix" -- "$cur" ) ) fi @@ -1483,11 +1570,6 @@ _cd() _init_completion || return local IFS=$'\n' i j k - # try to allow variable completion - if [[ "$cur" == ?(\\)\$* ]]; then - COMPREPLY=( $( compgen -v -P '$' -- "${cur#?(\\)$}" ) ) - return 0 - fi compopt -o filenames @@ -1557,16 +1639,16 @@ _command_offset() # find new first word position, then # rewrite COMP_LINE and adjust COMP_POINT - local word_offset=$1 - local first_word=${COMP_WORDS[$word_offset]} char_offset i - for (( i=0; i <= ${#COMP_LINE}; i++ )); do - if [[ "${COMP_LINE:$i:${#first_word}}" == "$first_word" ]]; then - char_offset=$i - break - fi + local word_offset=$1 i j + for (( i=0; i < $word_offset; i++ )); do + for (( j=0; j <= ${#COMP_LINE}; j++ )); do + [[ "$COMP_LINE" == "${COMP_WORDS[i]}"* ]] && break + COMP_LINE=${COMP_LINE:1} + ((COMP_POINT--)) + done + COMP_LINE=${COMP_LINE#"${COMP_WORDS[i]}"} + ((COMP_POINT-=${#COMP_WORDS[i]})) 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 @@ -1575,7 +1657,7 @@ _command_offset() for (( i; i <= COMP_CWORD; i++ )); do unset COMP_WORDS[i] done - COMP_CWORD=$(( $COMP_CWORD - $word_offset )) + ((COMP_CWORD -= $word_offset)) COMPREPLY=() local cur @@ -1588,28 +1670,21 @@ _command_offset() else local cmd=${COMP_WORDS[0]} compcmd=${COMP_WORDS[0]} local cspec=$( complete -p $cmd 2>/dev/null ) + + # If we have no completion for $cmd yet, see if we have for basename + if [[ ! $cspec && $cmd == */* ]]; then + cspec=$( complete -p ${cmd##*/} 2>/dev/null ) + [[ $cspec ]] && compcmd=${cmd##*/} + fi + # If still nothing, just load it for the basename if [[ ! $cspec ]]; then - if [[ $cmd == */* ]]; then - # Load completion for full path - _completion_loader $cmd - if [[ $? -eq 124 ]]; then - # Success, but we may now have the full path completion... - cspec=$( complete -p $cmd 2>/dev/null ) - if [[ ! $cspec ]]; then - # ...or just the basename one. - compcmd=${cmd##*/} - cspec=$( complete -p $compcmd 2>/dev/null ) - fi - fi - else - # Simple, non-full path case. - _completion_loader $cmd - [[ $? -eq 124 ]] && cspec=$( complete -p $cmd 2>/dev/null ) - fi + compcmd=${cmd##*/} + _completion_loader $compcmd + cspec=$( complete -p $compcmd 2>/dev/null ) fi if [[ -n $cspec ]]; then - if [ "${cspec#* -F }" != "$cspec" ]; then + if [[ ${cspec#* -F } != $cspec ]]; then # complete -F # get function name @@ -1627,7 +1702,7 @@ _command_offset() while true; do # FIXME: should we take "+o opt" into account? t=${cspec#*-o } - if [ "$t" == "$cspec" ]; then + if [[ $t == $cspec ]]; then break fi opt=${t%% *} @@ -1639,7 +1714,9 @@ _command_offset() cspec=${cspec%%$compcmd} COMPREPLY=( $( eval compgen "$cspec" -- "$cur" ) ) fi - elif [ ${#COMPREPLY[@]} -eq 0 ]; then + elif [[ ${#COMPREPLY[@]} -eq 0 ]]; then + # XXX will probably never happen as long as completion loader loads + # *something* for every command thrown at it ($cspec != empty) _minimal fi fi @@ -1651,7 +1728,7 @@ _root_command() { local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin local root_command=$1 - _command $1 $2 $3 + _command } complete -F _root_command fakeroot gksu gksudo kdesudo really sudo @@ -1748,13 +1825,15 @@ _filedir_xspec() toks+=( $( eval compgen -f -X "!$xspec" -- "\$(quote_readline "\$cur")" | { while read -r tmp; do - [ -n $tmp ] && printf '%s\n' $tmp + [[ -n $tmp ]] && printf '%s\n' $tmp done } )) - [ ${#toks[@]} -ne 0 ] && compopt -o filenames - COMPREPLY=( "${toks[@]}" ) + if [[ ${#toks[@]} -ne 0 ]]; then + compopt -o filenames + COMPREPLY=( "${toks[@]}" ) + fi } _install_xspec() @@ -1778,7 +1857,8 @@ _install_xspec '!*.@(tlz|lzma)' lzcat lzegrep lzfgrep lzgrep lzless lzmore unlzm _install_xspec '!*.@(?(t)xz|tlz|lzma)' unxz xzcat _install_xspec '!*.lrz' lrunzip _install_xspec '!*.@(gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx)' ee -_install_xspec '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm)' xv qiv +_install_xspec '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm)' qiv +_install_xspec '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|?(e)ps)' xv _install_xspec '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv kghostview _install_xspec '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' xdvi kdvi _install_xspec '!*.dvi' dvips dviselect dvitype dvipdf advi dvipdfm dvipdfmx @@ -1801,8 +1881,7 @@ _install_xspec '!*.fig' xfig _install_xspec '!*.@(mid?(i)|cmf)' playmidi _install_xspec '!*.@(mid?(i)|rmi|rcp|[gr]36|g18|mod|xm|it|x3m|s[3t]m|kar)' timidity _install_xspec '!*.@(669|abc|am[fs]|d[bs]m|dmf|far|it|mdl|m[eo]d|mid?(i)|mt[2m]|okta|p[st]m|s[3t]m|ult|umx|wav|xm)' modplugplay modplug123 -_install_xspec '*.@(o|so|so.!(conf)|a|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class)' vi vim gvim rvim view rview rgvim rgview gview emacs xemacs sxemacs kate kwrite -_install_xspec '!*.@([eE][xX][eE]?(.[sS][oO])|[cC][oO][mM]|[sS][cC][rR])' wine +_install_xspec '*.@(o|so|so.!(conf|*/*)|a|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class)' vi vim gvim rvim view rview rgvim rgview gview emacs xemacs sxemacs kate kwrite _install_xspec '!*.@(zip|z|gz|tgz)' bzme # konqueror not here on purpose, it's more than a web/html browser _install_xspec '!*.@(?([xX]|[sS])[hH][tT][mM]?([lL]))' netscape mozilla lynx opera galeon dillo elinks amaya firefox mozilla-firefox iceweasel google-chrome chromium-browser epiphany @@ -1839,11 +1918,6 @@ _completion_loader() local compdir=./completions [[ $BASH_SOURCE == */* ]] && compdir="${BASH_SOURCE%/*}/completions" - # Special case for init.d scripts. - if [[ $1 == /etc?(/rc.d)/init.d/* ]]; then - . "$compdir/service" &>/dev/null && return 124 || return 1 - fi - # Try basename. . "$compdir/${1##*/}" &>/dev/null && return 124 @@ -1878,7 +1952,7 @@ if [[ -d $BASH_COMPLETION_COMPAT_DIR && -r $BASH_COMPLETION_COMPAT_DIR && \ && -f $i && -r $i ]] && . "$i" done fi -unset i +unset i _blacklist_glob # source user completion file [[ ${BASH_SOURCE[0]} != ~/.bash_completion && -r ~/.bash_completion ]] \ -- cgit v1.2.1