summaryrefslogtreecommitdiff
path: root/bash_completion
diff options
context:
space:
mode:
authorDavid Paleino <dapal@debian.org>2010-06-16 18:20:29 +0200
committerDavid Paleino <dapal@debian.org>2010-06-16 18:20:29 +0200
commitf9748115fb4b2950fb4df7535fb723c4affde078 (patch)
tree20875f42b219a5d56e8a7e98840f6dbced003ae0 /bash_completion
parente5a9b6220e93ca656fd9774c6aefa78241edca6f (diff)
downloadbash-completion-f9748115fb4b2950fb4df7535fb723c4affde078.tar.gz
Imported Upstream version 1.2upstream/1.2
Diffstat (limited to 'bash_completion')
-rw-r--r--bash_completion1524
1 files changed, 749 insertions, 775 deletions
diff --git a/bash_completion b/bash_completion
index e1c40544..e7a4b6ec 100644
--- a/bash_completion
+++ b/bash_completion
@@ -1,9 +1,8 @@
#
-# bash_completion - programmable completion functions for bash 3.x
-# (backwards compatible with bash 2.05b)
+# bash_completion - programmable completion functions for bash 3.2+
#
# Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
-# © 2009, Bash Completion Maintainers
+# © 2009-2010, Bash Completion Maintainers
# <bash-completion-devel@lists.alioth.debian.org>
#
# This program is free software; you can redistribute it and/or modify
@@ -56,33 +55,6 @@ case ${UNAME} in
*) USERLAND=${UNAME} ;;
esac
-# features supported by bash 2.05 and higher
-if [ ${BASH_VERSINFO[0]} -eq 2 ] && [[ ${BASH_VERSINFO[1]} > 04 ]] ||
- [ ${BASH_VERSINFO[0]} -gt 2 ]; then
- declare -r bash205=$BASH_VERSION 2>/dev/null || :
- default="-o default"
- dirnames="-o dirnames"
- filenames="-o filenames"
- compopt=:
-fi
-# features supported by bash 2.05b and higher
-if [ ${BASH_VERSINFO[0]} -eq 2 ] && [[ ${BASH_VERSINFO[1]} = "05b" ]] ||
- [ ${BASH_VERSINFO[0]} -gt 2 ]; then
- declare -r bash205b=$BASH_VERSION 2>/dev/null || :
- nospace="-o nospace"
-fi
-# features supported by bash 3.0 and higher
-if [ ${BASH_VERSINFO[0]} -gt 2 ]; then
- declare -r bash3=$BASH_VERSION 2>/dev/null || :
- bashdefault="-o bashdefault"
- plusdirs="-o plusdirs"
-fi
-# features supported by bash 4.0 and higher
-if [ ${BASH_VERSINFO[0]} -gt 3 ]; then
- declare -r bash4=$BASH_VERSION 2>/dev/null || :
- compopt=compopt
-fi
-
# Turn on extended globbing and programmable completion
shopt -s extglob progcomp
@@ -97,11 +69,11 @@ complete -d pushd
#
# START exclude -- do NOT remove this line
# bzcmp, bzdiff, bz*grep, bzless, bzmore intentionally not here, see Debian: #455510
-complete -f -X '!*.?(t)bz?(2)' bunzip2 bzcat
-complete -f -X '!*.@(zip|ZIP|jar|JAR|exe|EXE|pk3|war|wsz|ear|zargo|xpi|sxw|ott|od[fgpst]|epub)' unzip zipinfo
+complete -f -X '!*.?(t)bz?(2)' bunzip2 bzcat pbunzip2 pbzcat
+complete -f -X '!*.@(zip|ZIP|[ejw]ar|[EJW]AR|exe|EXE|pk3|wsz|zargo|xpi|sxw|o[tx]t|od[fgpst]|epub)' unzip zipinfo
complete -f -X '*.Z' compress znew
# zcmp, zdiff, z*grep, zless, zmore intentionally not here, see Debian: #455510
-complete -f -X '!*.@(Z|gz|tgz|Gz|dz)' gunzip zcat
+complete -f -X '!*.@(Z|[gGd]z|t[ag]z)' gunzip zcat unpigz
complete -f -X '!*.Z' uncompress
# lzcmp, lzdiff intentionally not here, see Debian: #455510
complete -f -X '!*.lzma' lzcat lzegrep lzfgrep lzgrep lzless lzmore unlzma
@@ -114,13 +86,13 @@ complete -f -X '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' kdvi
complete -f -X '!*.@(dvi|DVI)' dvips dviselect dvitype dvipdf advi dvipdfm dvipdfmx
complete -f -X '!*.@(pdf|PDF)' acroread gpdf xpdf
complete -f -X '!*.@(?(e)ps|?(E)PS|pdf|PDF)' kpdf
-complete -f -X '!*.@(@(?(e)ps|?(E)PS|pdf|PDF|dvi|DVI)?(.gz|.GZ|.bz2|.BZ2)|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX)' evince
-complete -f -X '!*.@(?(e|x)ps|?(E|X)PS|pdf|PDF|dvi|DVI|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|epub|EPUB|odt|ODT|fb|FB|mobi|MOBI|g3|G3|chm|CHM)?(.?(gz|GZ|bz2|BZ2))' okular
+complete -f -X '!*.@(@(?(e)ps|?(E)PS|pdf|PDF|dvi|DVI)?(.gz|.GZ|.bz2|.BZ2)|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|fdf|FDF)' evince
+complete -f -X '!*.@(okular|@(?(e|x)ps|?(E|X)PS|pdf|PDF|dvi|DVI|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|epub|EPUB|odt|ODT|fb|FB|mobi|MOBI|g3|G3|chm|CHM|fdf|FDF)?(.?(gz|GZ|bz2|BZ2)))' okular
complete -f -X '!*.@(?(e)ps|?(E)PS|pdf|PDF)' ps2pdf ps2pdf12 ps2pdf13 ps2pdf14 ps2pdfwr
complete -f -X '!*.texi*' makeinfo texi2html
-complete -f -X '!*.@(?(la)tex|?(LA)TEX|texi|TEXI|dtx|DTX|ins|INS)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi
+complete -f -X '!*.@(?(la)tex|?(LA)TEX|texi|TEXI|dtx|DTX|ins|INS|ltx|LTX)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi
complete -f -X '!*.@(mp3|MP3)' mpg123 mpg321 madplay
-complete -f -X '!*@(.@(mp?(e)g|MP?(E)G|wma|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|viv|rm|ram|yuv|mov|MOV|qt|QT|wmv|mp[234]|MP[234]|m4[pv]|M4[PV]|mkv|MKV|og[gmv]|OG[GMV]|wav|WAV|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM)|+([0-9]).@(vdr|VDR))' xine aaxine fbxine kaffeine
+complete -f -X '!*@(.@(mp?(e)g|MP?(E)G|wma|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|wmv|mp[234]|MP[234]|m4[pv]|M4[PV]|mkv|MKV|og[gmv]|OG[GMV]|t[ps]|T[PS]|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM)|+([0-9]).@(vdr|VDR))' xine aaxine fbxine kaffeine dragon
complete -f -X '!*.@(avi|asf|wmv)' aviplay
complete -f -X '!*.@(rm?(j)|ra?(m)|smi?(l))' realplay
complete -f -X '!*.@(mpg|mpeg|avi|mov|qt)' xanim
@@ -129,12 +101,12 @@ complete -f -X '!*.@(mp3|MP3|ogg|OGG|pls|m3u)' gqmpeg freeamp
complete -f -X '!*.fig' xfig
complete -f -X '!*.@(mid?(i)|MID?(I)|cmf|CMF)' playmidi
complete -f -X '!*.@(mid?(i)|MID?(I)|rmi|RMI|rcp|RCP|[gr]36|[GR]36|g18|G18|mod|MOD|xm|XM|it|IT|x3m|X3M|s[3t]m|S[3T]M|kar|KAR)' timidity
-complete -f -X '!*.@(m[eo]d|M[EO]D|s[3t]m|S[3T]M|xm|XM|it|IT)' modplugplay
-complete -f -X '*.@(o|so|so.!(conf)|a|rpm|gif|GIF|jp?(e)g|JP?(E)G|mp3|MP3|mp?(e)g|MPG|avi|AVI|asf|ASF|ogg|OGG|class|CLASS)' vi vim gvim rvim view rview rgvim rgview gview
-complete -f -X '*.@(o|so|so.!(conf)|a|rpm|gif|GIF|jp?(e)g|JP?(E)G|mp3|MP3|mp?(e)g|MPG|avi|AVI|asf|ASF|ogg|OGG|class|CLASS)' emacs
-complete -f -X '!*.@(exe|EXE|com|COM|scr|SCR|exe.so)' wine
+complete -f -X '!*.@(m[eo]d|M[EO]D|s[3t]m|S[3T]M|xm|XM|it|IT)' modplugplay modplug123
+complete -f -X '*.@(o|so|so.!(conf)|a|rpm|gif|GIF|jp?(e)g|JP?(E)G|mp3|MP3|mp?(e)g|MPG|avi|AVI|asf|ASF|ogg|OGG|class|CLASS)' vi vim gvim rvim view rview rgvim rgview gview emacs xemacs sxemacs kate kwrite
+complete -f -X '!*.@([eE][xX][eE]?(.[sS][oO])|[cC][oO][mM]|[sS][cC][rR])' wine
complete -f -X '!*.@(zip|ZIP|z|Z|gz|GZ|tgz|TGZ)' bzme
-complete -f -X '!*.@(?([xX]|[sS])[hH][tT][mM]?([lL]))' netscape mozilla lynx opera galeon curl dillo elinks amaya
+# konqueror not here on purpose, it's more than a web/html browser
+complete -f -X '!*.@(?([xX]|[sS])[hH][tT][mM]?([lL]))' netscape mozilla lynx opera galeon dillo elinks amaya firefox mozilla-firefox iceweasel google-chrome chromium-browser epiphany
complete -f -X '!*.@(sxw|stw|sxg|sgl|doc?([mx])|dot?([mx])|rtf|txt|htm|html|odt|ott|odm)' oowriter
complete -f -X '!*.@(sxi|sti|pps?(x)|ppt?([mx])|pot?([mx])|odp|otp)' ooimpress
complete -f -X '!*.@(sxc|stc|xls?([bmx])|xlw|xlt?([mx])|[ct]sv|ods|ots)' oocalc
@@ -142,12 +114,15 @@ complete -f -X '!*.@(sxd|std|sda|sdd|odg|otg)' oodraw
complete -f -X '!*.@(sxm|smf|mml|odf)' oomath
complete -f -X '!*.odb' oobase
complete -f -X '!*.rpm' rpm2cpio
-complete -f -X '!*.sqlite' sqlite3
+complete -f -X '!*.s@(qlite?(3)|?(3)db)' sqlite3
complete -f -X '!*.aux' bibtex
complete -f -X '!*.po' poedit gtranslator kbabel lokalize
complete -f -X '!*.@([Pp][Rr][Gg]|[Cc][Ll][Pp])' harbour gharbour hbpp
complete -f -X '!*.[Hh][Rr][Bb]' hbrun
complete -f -X '!*.ly' lilypond ly2dvi
+complete -f -X '!*.@(dif?(f)|?(d)patch)?(.@([gx]z|bz2|lzma))' cdiff
+complete -f -X '!*.@(dif?(f)|?(d)patch)' kompare
+complete -f -X '!*.lyx' lyx
# FINISH exclude -- do not remove this line
# start of section containing compspecs that can be handled within bash
@@ -193,14 +168,12 @@ complete -b builtin
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"
}
-# use GNU sed if we have it, since its extensions are still used in our code
-#
-[ $USERLAND != GNU ] && have gsed && alias sed=gsed
-
# This function checks whether a given readline variable
# is `on'.
#
@@ -215,19 +188,14 @@ quote()
echo \'${1//\'/\'\\\'\'}\' #'# Help vim syntax highlighting
}
-# This function quotes the argument in a way so that readline dequoting
-# results in the original argument
+# @see _quote_readline_by_ref()
quote_readline()
{
- if [ -n "$bash4" ] ; then
- # This function isn't really necessary on bash 4
- # See: http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html
- echo "${1}"
- return
- fi
- local t="${1//\\/\\\\}"
- echo \'${t//\'/\'\\\'\'}\' #'# Help vim syntax highlighting
-}
+ local quoted
+ _quote_readline_by_ref "$1" ret
+ printf %s "$ret"
+} # quote_readline()
+
# This function shell-dequotes the argument
dequote()
@@ -235,189 +203,490 @@ dequote()
eval echo "$1" 2> /dev/null
}
-# 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 --------> ^
-# it will complete just "foo", not "foobar", which is what the user wants.)
-# @param $1 string (optional) Characters out of $COMP_WORDBREAKS which should
+
+# 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.
-# NOTE: This parameter only applies to bash-4.
+# 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
-_get_cword()
-{
- if [ -n "$bash4" ] ; then
- __get_cword4 "$@"
+ # 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
- __get_cword3
+ cur2=${cur:0:$index}
fi
-} # _get_cword()
+
+ local "$2" "$3" "$4" &&
+ _upvars -a${#words[@]} $2 "${words[@]}" -v $3 "$cword" -v $4 "$cur2"
+}
-# Get the word to complete on bash-3, where words are not broken by
-# COMP_WORDBREAKS characters and the COMP_CWORD variables look like this, for
-# example:
+# 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
#
-# $ a b:c<TAB>
-# COMP_CWORD: 1
-# COMP_CWORDS:
-# 0: a
-# 1: b:c
+# Example usage:
#
-# See also:
-# _get_cword, main routine
-# __get_cword4, bash-4 variant
+# $ _get_comp_words_by_ref -n : cur prev
#
-__get_cword3()
+_get_comp_words_by_ref()
{
- if [[ "${#COMP_WORDS[COMP_CWORD]}" -eq 0 ]] || [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then
- printf "%s" "${COMP_WORDS[COMP_CWORD]}"
+ 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 <= COMP_CWORD; ++i )); do
+ for (( i = 0; i <= cword; ++i )); do
while [[
- # Current COMP_WORD fits in $cur?
- "${#cur}" -ge ${#COMP_WORDS[i]} &&
- # $cur doesn't match COMP_WORD?
- "${cur:0:${#COMP_WORDS[i]}}" != "${COMP_WORDS[i]}"
- ]]; do
+ # 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="$(( index - 1 ))"
+ ((index--))
done
- # Does found COMP_WORD matches COMP_CWORD?
- if [[ "$i" -lt "$COMP_CWORD" ]]; then
- # No, COMP_CWORD lies further;
+ # Does found word matches cword?
+ if [[ "$i" -lt "$cword" ]]; then
+ # No, cword lies further;
local old_size="${#cur}"
- cur="${cur#${COMP_WORDS[i]}}"
+ cur="${cur#${words[i]}}"
local new_size="${#cur}"
- index="$(( index - old_size + new_size ))"
+ index=$(( index - old_size + new_size ))
fi
done
- if [[ "${COMP_WORDS[COMP_CWORD]:0:${#cur}}" != "$cur" ]]; then
+ if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then
# We messed up! At least return the whole word so things
# keep working
- printf "%s" "${COMP_WORDS[COMP_CWORD]}"
+ printf "%s" "${words[cword]}"
else
printf "%s" "${cur:0:$index}"
fi
fi
-} # __get_cword3()
+} # _get_cword()
-# Get the word to complete on bash-4, where words are splitted by
-# COMP_WORDBREAKS characters (default is " \t\n\"'><=;|&(:") and the COMP_CWORD
-# variables look like this, for example:
+# 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()
#
-# $ a b:c<TAB>
-# COMP_CWORD: 3
-# COMP_CWORDS:
-# 0: a
-# 1: b
-# 2: :
-# 3: c
+_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:
#
-# @oaram $1 string
-# $1 string (optional) 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.
-# See also:
-# _get_cword, main routine
-# __get_cword3, bash-3 variant
+# # Remove colon (:) from list of word completion separators
+# COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
#
-__get_cword4()
-{
- local i
- local LC_CTYPE=C
- local WORDBREAKS=$COMP_WORDBREAKS
- # Strip single quote (') and double quote (") from WORDBREAKS to
- # workaround a bug in bash-4.0, where quoted words are split
- # unintended, see:
- # http://www.mail-archive.com/bug-bash@gnu.org/msg06095.html
- # This fixes simple quoting (e.g. $ a "b<TAB> returns "b instead of b)
- # but still fails quoted spaces (e.g. $ a "b c<TAB> returns c instead
- # of "b c).
- WORDBREAKS=${WORDBREAKS//\"/}
- WORDBREAKS=${WORDBREAKS//\'/}
- if [ -n "$1" ]; then
- for (( i=0; i<${#1}; ++i )); do
- local char=${1:$i:1}
- WORDBREAKS=${WORDBREAKS//$char/}
+# 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
- local cur=${COMP_LINE:0:$COMP_POINT}
- local tmp=$cur
- local word_start=`expr "$tmp" : '.*['"$WORDBREAKS"']'`
- while [ "$word_start" -ge 2 ]; do
- # Get character before $word_start
- local char=${cur:$(( $word_start - 2 )):1}
- # If the WORDBREAK character isn't escaped, exit loop
- if [ "$char" != "\\" ]; then
- break
+} # __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
- # The WORDBREAK character is escaped;
- # Recalculate $word_start
- tmp=${COMP_LINE:0:$(( $word_start - 2 ))}
- word_start=`expr "$tmp" : '.*['"$WORDBREAKS"']'`
- done
+ elif [[ ${BASH_VERSINFO[0]} -le 3 && ${1:0:1} == '"' ]]; then
+ printf -v $2 %q "${1:1}"
+ else
+ printf -v $2 %q "$1"
+ fi
- cur=${cur:$word_start}
- printf "%s" "$cur"
-} # __get_cword4()
+ # 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.
-# If passed -d, it completes only on directories. If passed anything else,
-# it's assumed to be a file glob to complete on.
+# @param $1 If `-d', complete only on directories. Otherwise filter/pick only
+# completions with `.$1' as file extension.
#
_filedir()
{
- local IFS=$'\t\n' xspec
+ local i IFS=$'\t\n' xspec
- _expand || return 0
+ __expand_tilde_by_ref cur
local -a toks
- local tmp
+ local quoted tmp
- # TODO: I've removed a "[ -n $tmp ] &&" before `echo $tmp',
- # and everything works again. If this bug
- # suddenly appears again (i.e. "cd /b<TAB>"
- # becomes "cd /"), remember to check for
- # other similar conditionals (here and
- # _filedir_xspec()). --David
- # NOTE: The comment above has been moved outside of the subshell below,
- # because quotes-in-comments-in-a-subshell cause errors on
- # bash-3.1. See also:
- # http://www.mail-archive.com/bug-bash@gnu.org/msg01667.html
+ _quote_readline_by_ref "$cur" quoted
toks=( ${toks[@]-} $(
- compgen -d -- "$(quote_readline "$cur")" | {
- while read -r tmp; do
- echo $tmp
- done
-}
-))
+ 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<TAB>" becomes "cd /"),
+ # remember to check for other similar conditionals (here
+ # and _filedir_xspec()). --David
+ printf '%s\n' $tmp
+ done
+ }
+ ))
-if [[ "$1" != -d ]]; then
- xspec=${1:+"!*.$1"}
- toks=( ${toks[@]-} $(
- compgen -f -X "$xspec" -- "$(quote_readline "$cur")" | {
- while read -r tmp; do
- [ -n $tmp ] && echo $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/<TAB> # Becomes: foo 'a&b/f'
+ # $ foo a'&b/<TAB> # 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<TAB>
+ # a\ b/ a\$b/
+ #
+ # whereas with `-o filenames' active the completions look
+ # like:
+ #
+ # $ ls a<TAB>
+ # 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.
@@ -441,11 +710,8 @@ _split_longopt()
_parse_help() {
local cmd
cmd=$1
- $cmd --help | \
- grep -- "^[[:space:]]*-" | \
- tr "," " " | \
- awk '{print $1; if ($2 ~ /-.*/) { print $2 } }' | \
- sed -e "s:=.*::g"
+ $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
@@ -464,29 +730,49 @@ _signals()
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=( $( sed -ne 's|^iface \([^ ]\+\).*$|\1|p' \
- /etc/network/interfaces ) )
+ COMPREPLY=( $( compgen -W "$( sed -ne 's|^iface \([^ ]\{1,\}\).*$|\1|p'\
+ /etc/network/interfaces )" -- "$cur" ) )
elif [ -f /etc/SuSE-release ]; then
# SuSE system
- COMPREPLY=( $( command ls \
- /etc/sysconfig/network/ifcfg-* | \
- sed -ne 's|.*ifcfg-\('"$cur"'.*\)|\1|p' ) )
+ 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=( $( command ls -B \
- /etc/sysconfig/interfaces | \
- sed -ne 's|.*ifcfg-\('"$cur"'.*\)|\1|p' ) )
+ COMPREPLY=( $( compgen -W "$( command ls -B \
+ /etc/sysconfig/interfaces | \
+ sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) )
else
# Assume Red Hat
- COMPREPLY=( $( command ls \
- /etc/sysconfig/network-scripts/ifcfg-* | \
- sed -ne 's|.*ifcfg-\('"$cur"'.*\)|\1|p' ) )
+ COMPREPLY=( $( compgen -W "$( printf '%s\n' \
+ /etc/sysconfig/network-scripts/ifcfg-* | \
+ sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) )
fi
}
@@ -513,10 +799,51 @@ _available_interfaces()
cmd="ifconfig -a"
fi
- COMPREPLY=( $( eval $cmd 2>/dev/null | \
- sed -ne 's|^\('"$cur"'[^[:space:][:punct:]]\{1,\}\).*$|\1|p') )
+ 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()
@@ -540,7 +867,7 @@ _expand()
# This function completes on process IDs.
# AIX and Solaris ps prefers X/Open syntax.
-[ $UNAME = SunOS -o $UNAME = AIX ] &&
+[[ $UNAME == SunOS || $UNAME == AIX ]] &&
_pids()
{
COMPREPLY=( $( compgen -W '$( command ps -efo pid | sed 1d )' -- "$cur" ))
@@ -552,7 +879,7 @@ _pids()
# This function completes on process group IDs.
# AIX and SunOS prefer X/Open, all else should be BSD.
-[ $UNAME = SunOS -o $UNAME = AIX ] &&
+[[ $UNAME == SunOS || $UNAME == AIX ]] &&
_pgids()
{
COMPREPLY=( $( compgen -W '$( command ps -efo pgid | sed 1d )' -- "$cur" ))
@@ -564,13 +891,11 @@ _pgids()
# This function completes on process names.
# AIX and SunOS prefer X/Open, all else should be BSD.
-[ $UNAME = SunOS -o $UNAME = AIX ] &&
+[[ $UNAME == SunOS || $UNAME == AIX ]] &&
_pnames()
{
- COMPREPLY=( $( compgen -W '$( command ps -efo comm | \
- sed -e 1d -e "s:.*/::" -e "s/^-//" \
- -e "s/^<defunct>$//")' \
- -- "$cur" ) )
+ COMPREPLY=( $( compgen -X '<defunct>' -W '$( command ps -efo comm | \
+ sed -e 1d -e "s:.*/::" -e "s/^-//" | sort -u )' -- "$cur" ) )
} ||
_pnames()
{
@@ -582,11 +907,9 @@ _pnames()
# 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 -W '$( command ps axo command= | \
- sed -e "s/ .*//; s:.*/::; s/:$//;" \
- -e "s/^[[(-]//; s/[])]$//" \
- -e "s/^<defunct>$//")' \
- -- "$cur" ) )
+ COMPREPLY=( $( compgen -X '<defunct>' -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
@@ -608,14 +931,13 @@ _uids()
_gids()
{
if type getent &>/dev/null; then
- COMPREPLY=( $( getent group | \
- awk -F: '{if ($3 ~ /^'"$cur"'/) print $3}' ) )
+ 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=( $( awk 'BEGIN {FS=":"} {if ($3 ~ /^'"$cur"'/) print $3}'\
- /etc/group ) )
+ COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/group )' -- "$cur" ) )
fi
}
@@ -626,10 +948,12 @@ _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=( $( builtin echo $sysvdir/!(*.rpm@(orig|new|save)|*~|functions)) )
+ COMPREPLY=( $( printf '%s\n' \
+ $sysvdir/!(*.rpm@(orig|new|save)|*~|functions) ) )
if [ -d $famdir ]; then
- COMPREPLY=( "${COMPREPLY[@]}" $( builtin echo $famdir/!(*.rpm@(orig|new|save)|*~)) )
+ COMPREPLY=( "${COMPREPLY[@]}" $( printf '%s\n' \
+ $famdir/!(*.rpm@(orig|new|save)|*~) ) )
fi
COMPREPLY=( $( compgen -W '${COMPREPLY[@]#@($sysvdir|$famdir)/}' -- "$cur" ) )
@@ -641,8 +965,8 @@ _modules()
{
local modpath
modpath=/lib/modules/$1
- COMPREPLY=( $( command ls -R $modpath | \
- sed -ne 's/^\('"$cur"'.*\)\.k\?o\(\|.gz\)$/\1/p') )
+ 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
@@ -650,22 +974,41 @@ _modules()
_installed_modules()
{
COMPREPLY=( $( compgen -W "$( PATH="$PATH:/sbin" lsmod | \
- awk '{if (NR != 1) print $1}' )" -- $1 ) )
+ awk '{if (NR != 1) print $1}' )" -- "$1" ) )
}
-# This function completes on user:group format
+# 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'
- cur=${cur//\\\\ / }
- if [[ $cur = *@(\\:|.)* ]] && [ -n "$bash205" ]; then
- user=${cur%%*([^:.])}
- COMPREPLY=( $(compgen -P ${user/\\\\} -g -- ${cur##*[.:]}) )
- elif [[ $cur = *:* ]] && [ -n "$bash205" ]; then
- COMPREPLY=( $( compgen -g -- ${cur##*[.:]} ) )
+ if [[ $cur = *\\\\* || $cur = *:*:* ]]; then
+ # Give up early on if something seems horribly wrong.
+ return
+ elif [[ $cur = *\\:* ]]; then
+ # Completing group after 'user\:gr<TAB>'.
+ # 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<TAB>'.
+ # Reply with a list of unprefixed groups since readline with split on :
+ # and only replace the 'gr' part
+ COMPREPLY=( $( compgen -g -- "${cur#*:}" ) )
else
- COMPREPLY=( $( compgen -S : -u -- "$cur" ) )
+ # Completing a partial 'usernam<TAB>'.
+ #
+ # 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
}
@@ -673,8 +1016,32 @@ _usergroup()
#
_shells()
{
- COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W '$( grep "^[[:space:]]*/" \
- /etc/shells 2>/dev/null )' -- "$cur" ) )
+ 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.
@@ -682,28 +1049,47 @@ _shells()
# - 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() {
+_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
+ 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 count the number of mandatory args
-#
+# 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=1; i < COMP_CWORD; i++ )); do
- if [[ "${COMP_WORDS[i]}" != -* ]]; then
- args=$(($args+1))
- fi
+ for i in "${words[@]:1:cword-1}"; do
+ [[ "$i" != -* ]] && args=$(($args+1))
done
}
@@ -712,7 +1098,7 @@ _count_args()
_pci_ids()
{
COMPREPLY=( ${COMPREPLY[@]:-} $( compgen -W \
- "$( PATH="$PATH:/sbin" lspci -n | awk '{print $3}')" -- "$cur" ) )
+ "$( PATH="$PATH:/sbin" lspci -n | awk '{print $3}')" -- "$cur" ) )
}
# This function completes on USB IDs
@@ -720,411 +1106,29 @@ _pci_ids()
_usb_ids()
{
COMPREPLY=( ${COMPREPLY[@]:-} $( compgen -W \
- "$( PATH="$PATH:/sbin" lsusb | awk '{print $6}' )" -- "$cur" ) )
-}
-
-# start of section containing completion functions for external programs
-
-# a little help for FreeBSD ports users
-[ $UNAME = FreeBSD ] && complete -W 'index search fetch fetch-list \
-extract patch configure build install reinstall \
-deinstall clean clean-depends kernel buildworld' make
-
-# 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
-#
-{ have service || [ -d /etc/init.d/ ]; } &&
- _service()
- {
- local cur prev sysvdir
-
- COMPREPLY=()
- prev=${COMP_WORDS[COMP_CWORD-1]}
- cur=`_get_cword`
-
- # don't complete for things like killall, ssh and mysql if it's
- # the standalone command, rather than the init script
- [[ ${COMP_WORDS[0]} != @(*init.d/!(functions|~)|service) ]] && return 0
-
- # don't complete past 2nd token
- [ $COMP_CWORD -gt 2 ] && return 0
-
- [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d \
- || sysvdir=/etc/init.d
-
- if [[ $COMP_CWORD -eq 1 ]] && [[ $prev == "service" ]]; then
- _services
- else
- COMPREPLY=( $( compgen -W '`sed -ne "y/|/ /; \
- s/^.*\(U\|msg_u\)sage.*{\(.*\)}.*$/\1/p" \
- $sysvdir/${prev##*/} 2>/dev/null`' -- "$cur" ) )
- fi
-
- return 0
- } &&
- complete -F _service service
- [ -d /etc/init.d/ ] && complete -F _service $default \
- $(for i in /etc/init.d/*; do echo ${i##*/}; done)
-
- # chown(1) completion
- #
- _chown()
- {
- local cur prev split=false
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- _split_longopt && split=true
-
- case "$prev" in
- --from)
- _usergroup
- return 0
- ;;
- --reference)
- _filedir
- return 0
- ;;
- esac
-
- $split && return 0
-
- # options completion
- if [[ "$cur" == -* ]]; then
- COMPREPLY=( $( compgen -W '-c -h -f -R -v --changes \
- --dereference --no-dereference --from --silent --quiet \
- --reference --recursive --verbose --help --version' -- "$cur" ) )
- else
- _count_args
-
- case $args in
- 1)
- _usergroup
- ;;
- *)
- _filedir
- ;;
- esac
- fi
- }
- complete -F _chown $filenames chown
-
- # chgrp(1) completion
- #
- _chgrp()
- {
- local cur prev split=false
-
- COMPREPLY=()
- cur=`_get_cword`
- cur=${cur//\\\\/}
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- _split_longopt && split=true
-
- if [[ "$prev" == --reference ]]; then
- _filedir
- return 0
- fi
-
- $split && return 0
-
- # options completion
- if [[ "$cur" == -* ]]; then
- COMPREPLY=( $( compgen -W '-c -h -f -R -v --changes \
- --dereference --no-dereference --silent --quiet \
- --reference --recursive --verbose --help --version' -- "$cur" ) )
- return 0
- fi
-
- # first parameter on line or first since an option?
- if [ $COMP_CWORD -eq 1 ] && [[ "$cur" != -* ]] || \
- [[ "$prev" == -* ]] && [ -n "$bash205" ]; then
- local IFS=$'\n'
- COMPREPLY=( $( compgen -g "$cur" 2>/dev/null ) )
- else
- _filedir || return 0
- fi
-
- return 0
- }
- complete -F _chgrp $filenames chgrp
-
- # umount(8) completion. This relies on the mount point being the third
- # space-delimited field in the output of mount(8)
- #
- _umount()
- {
- local cur IFS=$'\n'
-
- COMPREPLY=()
- cur=`_get_cword`
-
- COMPREPLY=( $( compgen -W '$( mount | cut -d" " -f 3 )' -- "$cur" ) )
-
- return 0
- }
- complete -F _umount $dirnames umount
-
- # mount(8) completion. This will pull a list of possible mounts out of
- # /etc/{,v}fstab, unless the word being completed contains a ':', which
- # would indicate the specification of an NFS server. In that case, we
- # query the server for a list of all available exports and complete on
- # that instead.
- #
- _mount()
- {
- local cur i sm host prev
-
- COMPREPLY=()
- cur=`_get_cword`
- [[ "$cur" == \\ ]] && cur="/"
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- for i in {,/usr}/{,s}bin/showmount; do [ -x $i ] && sm=$i && break; done
-
- if [ -n "$sm" ] && [[ "$cur" == *:* ]]; then
- COMPREPLY=( $( $sm -e ${cur%%:*} | sed 1d | \
- grep ^${cur#*:} | awk '{print $1}' ) )
- elif [[ "$cur" == //* ]]; then
- host=${cur#//}
- host=${host%%/*}
- if [ -n "$host" ]; then
- COMPREPLY=( $( compgen -W "$( echo $( smbclient -d 0 -NL $host 2>/dev/null|
- sed -ne '/^['"$'\t '"']*Sharename/,/^$/p' |
- sed -ne '3,$s|^[^A-Za-z]*\([^'"$'\t '"']*\).*$|//'$host'/\1|p' ) )" -- "$cur" ) )
- fi
- elif [ -r /etc/vfstab ]; then
- # Solaris
- COMPREPLY=( $( compgen -W "$( awk '! /^[ \t]*#/ {if ($3 ~ /\//) print $3}' /etc/vfstab )" -- "$cur" ) )
- elif [ ! -e /etc/fstab ]; then
- # probably Cygwin
- COMPREPLY=( $( compgen -W "$( mount | awk '! /^[ \t]*#/ {if ($3 ~ /\//) print $3}' )" -- "$cur" ) )
- else
- # probably Linux
- if [ $prev = -L ]; then
- COMPREPLY=( $( compgen -W '$(sed -ne "s/^[[:space:]]*LABEL=\([^[:space:]]*\).*/\1/p" /etc/fstab )' -- "$cur" ) )
- elif [ $prev = -U ]; then
- COMPREPLY=( $( compgen -W '$(sed -ne "s/^[[:space:]]*UUID=\([^[:space:]]*\).*/\1/p" /etc/fstab )' -- "$cur" ) )
- else
- COMPREPLY=( $( compgen -W "$( awk '! /^[ \t]*#/ {if ($2 ~ /\//) print $2}' /etc/fstab )" -- "$cur" ) )
- fi
- fi
-
- return 0
- }
- complete -F _mount $default $dirnames mount
-
- # Linux rmmod(8) completion. This completes on a list of all currently
- # installed kernel modules.
- #
- have rmmod && {
- _rmmod()
- {
- local cur
-
- COMPREPLY=()
- cur=`_get_cword`
-
- _installed_modules "$cur"
- return 0
- }
- complete -F _rmmod rmmod
-
- # Linux insmod(8), modprobe(8) and modinfo(8) completion. This completes on a
- # list of all available modules for the version of the kernel currently
- # running.
- #
- _insmod()
- {
- local cur prev modpath
-
- COMPREPLY=()
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- # behave like lsmod for modprobe -r
- if [ $1 = "modprobe" ] &&
- [ "${COMP_WORDS[1]}" = "-r" ]; then
- _installed_modules "$cur"
- return 0
- fi
-
- # do filename completion if we're giving a path to a module
- if [[ "$cur" == */* ]]; then
- _filedir '@(?(k)o?(.gz))'
- return 0
- fi
-
- if [ $COMP_CWORD -gt 1 ] &&
- [[ "${COMP_WORDS[COMP_CWORD-1]}" != -* ]]; then
- # do module parameter completion
- COMPREPLY=( $( /sbin/modinfo -p ${COMP_WORDS[1]} 2>/dev/null | \
- awk '{if ($1 ~ /^parm:/ && $2 ~ /^'"$cur"'/) { print $2 } \
- else if ($1 !~ /:/ && $1 ~ /^'"$cur"'/) { print $1 }}' ) )
- else
- _modules $(uname -r)
- fi
-
- return 0
- }
- complete -F _insmod $filenames insmod modprobe modinfo
+ "$( PATH="$PATH:/sbin" lsusb | awk '{print $6}' )" -- "$cur" ) )
}
-# renice(8) completion
-#
-_renice()
+# CD device names
+_cd_devices()
{
- local command cur curopt i
-
- COMPREPLY=()
- cur=`_get_cword`
- command=$1
-
- i=0
- # walk back through command line and find last option
- while [ $i -le $COMP_CWORD -a ${#COMPREPLY[@]} -eq 0 ]; do
- curopt=${COMP_WORDS[COMP_CWORD-$i]}
- case "$curopt" in
- -u)
- COMPREPLY=( $( compgen -u -- "$cur" ) )
- ;;
- -g)
- _pgids
- ;;
- -p|$command)
- _pids
- ;;
- esac
- i=$(( ++i ))
- done
+ COMPREPLY=( "${COMPREPLY[@]}"
+ $( compgen -f -d -X "!*/?([amrs])cd*" -- "${cur:-/dev/}" ) )
}
-complete -F _renice renice
-# kill(1) completion
-#
-_kill()
+# DVD device names
+_dvd_devices()
{
- local cur
-
- COMPREPLY=()
- cur=`_get_cword`
-
- if [ $COMP_CWORD -eq 1 ] && [[ "$cur" == -* ]]; then
- # return list of available signals
- _signals
- else
- # return list of available PIDs
- _pids
- fi
+ COMPREPLY=( "${COMPREPLY[@]}"
+ $( compgen -f -d -X "!*/?(r)dvd*" -- "${cur:-/dev/}" ) )
}
-complete -F _kill kill
-
-# killall(1) (Linux and FreeBSD) and pkill(1) completion.
-#
-[ $UNAME = Linux -o $UNAME = FreeBSD ] || have pkill &&
-_killall()
-{
- local cur
-
- COMPREPLY=()
- cur=`_get_cword`
-
- if [ $COMP_CWORD -eq 1 ] && [[ "$cur" == -* ]]; then
- _signals
- else
- _pnames
- fi
-
- return 0
-}
-[ $UNAME = Linux -o $UNAME = FreeBSD ] && complete -F _killall killall
-have pkill && complete -F _killall pkill
-
-# pgrep(1) completion.
-#
-[ $UNAME = Linux ] || have pgrep &&
-_pgrep()
-{
- local cur
- COMPREPLY=()
- cur=`_get_cword`
-
- _pnames
-
- return 0
-}
-have pgrep && complete -F _pgrep pgrep
-
-# Linux pidof(8) completion.
-[ $UNAME = Linux ] && complete -F _pgrep pidof
-
-# Red Hat & Debian GNU/Linux if{up,down} completion
-#
-[ $USERLAND = GNU ] && { have ifup || have ifdown; } &&
-_ifupdown()
-{
- local cur
-
- COMPREPLY=()
- cur=`_get_cword`
-
- if [ $COMP_CWORD -eq 1 ]; then
- _configured_interfaces
- COMPREPLY=( $(compgen -W '${COMPREPLY[@]}' -- "$cur") )
- fi
-
- return 0
-} &&
-complete -F _ifupdown ifup ifdown
-[ $USERLAND = GNU ] && have ifstatus && complete -F _ifupdown ifstatus
-
-# Linux ipsec(8) completion (for FreeS/WAN)
-#
-[ $UNAME = Linux ] && have ipsec &&
-_ipsec()
-{
- local cur
-
- COMPREPLY=()
- cur=`_get_cword`
-
-
- if [ $COMP_CWORD -eq 1 ]; then
- COMPREPLY=( $( compgen -W 'auto barf eroute klipsdebug look \
- manual pluto ranbits rsasigkey \
- setup showdefaults showhostkey spi \
- spigrp tncfg whack' -- "$cur" ) )
- return 0
- fi
-
- case ${COMP_WORDS[1]} in
- auto)
- COMPREPLY=( $( compgen -W '--asynchronous --up --add --delete \
- --replace --down --route --unroute \
- --ready --status --rereadsecrets' \
- -- "$cur" ) )
- ;;
- manual)
- COMPREPLY=( $( compgen -W '--up --down --route --unroute \
- --union' -- "$cur" ) )
- ;;
- ranbits)
- COMPREPLY=( $( compgen -W '--quick --continuous --bytes' \
- -- "$cur" ) )
- ;;
- setup)
- COMPREPLY=( $( compgen -W '--start --stop --restart' -- "$cur" ) )
- ;;
- *)
- ;;
- esac
+# start of section containing completion functions for external programs
- return 0
-} &&
-complete -F _ipsec ipsec
+# a little help for FreeBSD ports users
+[ $UNAME = FreeBSD ] && complete -W 'index search fetch fetch-list extract \
+ patch configure build install reinstall deinstall clean clean-depends \
+ kernel buildworld' make
# This function provides simple user@host completion
#
@@ -1132,7 +1136,7 @@ _user_at_host() {
local cur
COMPREPLY=()
- cur=`_get_cword`
+ _get_comp_words_by_ref -n : cur
if [[ $cur == *@* ]]; then
_known_hosts_real "$cur"
@@ -1142,7 +1146,7 @@ _user_at_host() {
return 0
}
-shopt -u hostcomplete && complete -F _user_at_host $nospace talk ytalk finger
+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.
@@ -1153,14 +1157,15 @@ _known_hosts()
# 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)"
-}
+ [[ "$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 known_hosts files.
-# Also hosts from HOSTFILE (compgen -A hostname) are added, unless
+# 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
@@ -1171,7 +1176,7 @@ _known_hosts()
_known_hosts_real()
{
local configfile flag prefix
- local cur curd awkcur user suffix aliases global_kh user_kh hosts i host
+ local cur curd awkcur user suffix aliases i host
local -a kh khd config
local OPTIND=1
@@ -1186,7 +1191,7 @@ _known_hosts_real()
[ $# -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 echo ${!OPTIND}; shift; done)
+ $(while [ $# -ge $OPTIND ]; do printf '%s\n' ${!OPTIND}; shift; done)
[[ $cur == *@* ]] && user=${cur%@*}@ && cur=${cur#*@}
kh=()
@@ -1204,24 +1209,26 @@ _known_hosts_real()
config=( "${config[@]}" "${HOME}/.ssh2/config" )
fi
+ # Known hosts files from configs
if [ ${#config[@]} -gt 0 ]; then
local OIFS=$IFS IFS=$'\n'
- # expand path (if present) to global known hosts file
- global_kh=($( sed -ne 's/^[ \t]*[Gg][Ll][Oo][Bb][Aa][Ll][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee]['"$'\t '"']*\(.*\)$/"\1"/p' "${config[@]}" ))
- for (( i=0; i < ${#global_kh[@]}; i++ )); do
- global_kh[i]=$(echo "${global_kh[i]//\"/}")
- done
- # expand path (if present) to user known hosts file
- user_kh=($( sed -ne 's/^[ \t]*[Uu][Ss][Ee][Rr][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee]['"$'\t '"']*\(.*\)$/"\1"/p' "${config[@]}" ))
- for (( i=0; i < ${#user_kh[@]}; i++ )); do
- user_kh[i]=$(echo "${user_kh[i]//\"/}")
+ 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
- [ -r "$global_kh" ] &&
- kh=( "${kh[@]}" "${global_kh[@]}" )
if [ -z "$configfile" ]; then
[ -r /etc/ssh/ssh_known_hosts ] &&
kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts )
@@ -1236,8 +1243,6 @@ _known_hosts_real()
fi
# User known_hosts files
- [ -r "$user_kh" ] &&
- kh=( "${kh[@]}" "${user_kh[@]}" )
if [ -z "$configfile" ]; then
[ -r ~/.ssh/known_hosts ] &&
kh=( "${kh[@]}" ~/.ssh/known_hosts )
@@ -1248,7 +1253,7 @@ _known_hosts_real()
fi
# If we have known_hosts files to use
- if [ ${#kh[@]} -gt 0 -o ${#khd[@]} -gt 0 -o -n "$configfile" ]; then
+ if [[ ${#kh[@]} -gt 0 || ${#khd[@]} -gt 0 ]]; then
# Escape slashes and dots in paths for awk
awkcur=${cur//\//\\\/}
awkcur=${awkcur//\./\\\.}
@@ -1270,7 +1275,7 @@ _known_hosts_real()
if [ ${#kh[@]} -gt 0 ]; then
# FS needs to look for a comma separated list
- COMPREPLY=( $( awk 'BEGIN {FS=","}
+ COMPREPLY=( "${COMPREPLY[@]}" $( awk 'BEGIN {FS=","}
/^\s*[^|\#]/ {for (i=1; i<=2; ++i) { \
gsub(" .*$", "", $i); \
gsub("[\\[\\]]", "", $i); \
@@ -1284,34 +1289,13 @@ _known_hosts_real()
# dont fork any processes, because in a cluster environment,
# there can be hundreds of hostkeys
for i in "${khd[@]}" ; do
- if [[ "$i" == *key_22_$awkcurd*.pub ]] && [ -r "$i" ] ; then
+ if [[ "$i" == *key_22_$curd*.pub && -r "$i" ]]; then
host=${i/#*key_22_/}
host=${host/%.pub/}
COMPREPLY=( "${COMPREPLY[@]}" $host )
fi
done
fi
- # append any available aliases from config files
- if [ ${#config[@]} -gt 0 ] && [ -n "$aliases" ]; then
- local host_aliases=$( sed -ne 's/^[ \t]*[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\?['"$'\t '"']\+\([^#*?]*\)\(#.*\)\?$/\2/p' "${config[@]}" )
- hosts=$( compgen -W "$host_aliases" -- "$cur" )
- COMPREPLY=( "${COMPREPLY[@]}" $hosts )
- fi
-
- # Add hosts reported by avahi, if it's available
- # and if the daemon is started.
- # 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
- if [ -n "$(pidof avahi-daemon)" ]; then
- COMPREPLY=( "${COMPREPLY[@]}" $(
- compgen -W "$( avahi-browse -cpr _workstation._tcp | \
- grep ^= | cut -d\; -f7 | sort -u )" -- "$cur" ) )
- fi
- fi
# apply suffix and prefix
for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
@@ -1319,23 +1303,47 @@ _known_hosts_real()
done
fi
- # Add results of normal hostname completion, unless `COMP_KNOWN_HOSTS_WITH_HOSTFILE'
- # is set to an empty value.
+ # 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" ) )
+ COMPREPLY=( "${COMPREPLY[@]}"
+ $( compgen -A hostname -P "$prefix$user" -S "$suffix" -- "$cur" ) )
fi
+ __ltrim_colon_completions "$prefix$user$cur"
+
return 0
-}
-complete -F _known_hosts traceroute traceroute6 tracepath tracepath6 \
-ping ping6 fping fping6 telnet host nslookup rsh rlogin ftp dig ssh-installkeys mtr
+} # _known_hosts_real()
+complete -F _known_hosts traceroute traceroute6 tracepath tracepath6 ping \
+ ping6 fping fping6 telnet host nslookup rsh rlogin ftp dig mtr \
+ ssh-installkeys showmount
# This meta-cd function observes the CDPATH variable, so that cd additionally
# completes on directories under those specified in CDPATH.
#
_cd()
{
- local IFS=$'\t\n' cur=`_get_cword` i j k
+ local cur IFS=$'\t\n' i j k
+ _get_comp_words_by_ref cur
# try to allow variable completion
if [[ "$cur" == ?(\\)\$* ]]; then
@@ -1348,7 +1356,7 @@ _cd()
# Use standard dir completion if no CDPATH or parameter starts with /,
# ./ or ../
- if [ -z "${CDPATH:-}" ] || [[ "$cur" == ?(.)?(.)/* ]]; then
+ if [[ -z "${CDPATH:-}" || "$cur" == ?(.)?(.)/* ]]; then
_filedir -d
return 0
fi
@@ -1372,7 +1380,7 @@ _cd()
if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
i=${COMPREPLY[0]}
- if [ "$i" == "$cur" ] && [[ $i != "*/" ]]; then
+ if [[ "$i" == "$cur" && $i != "*/" ]]; then
COMPREPLY[0]="${i}/"
fi
fi
@@ -1380,9 +1388,9 @@ _cd()
return 0
}
if shopt -q cdable_vars; then
- complete -v -F _cd $nospace cd
+ complete -v -F _cd -o nospace cd
else
- complete -F _cd $nospace cd
+ complete -F _cd -o nospace cd
fi
# a wrapper method for the next one, when the offset is unknown
@@ -1409,7 +1417,7 @@ _command()
_command_offset()
{
local cur func cline cspec noglob cmd i char_offset word_offset \
- _COMMAND_FUNC _COMMAND_FUNC_ARGS
+ _COMMAND_FUNC _COMMAND_FUNC_ARGS
word_offset=$1
@@ -1438,7 +1446,7 @@ _command_offset()
COMP_CWORD=$(( $COMP_CWORD - $word_offset ))
COMPREPLY=()
- cur=`_get_cword`
+ _get_comp_words_by_ref cur
if [[ $COMP_CWORD -eq 0 ]]; then
COMPREPLY=( $( compgen -c -- "$cur" ) )
@@ -1479,21 +1487,21 @@ _command_offset()
[ ${#COMPREPLY[@]} -eq 0 ] && _filedir
}
-complete -F _command $filenames nohup exec nice eval time ltrace then \
- else do vsound command xargs tsocks
+complete -F _command -o filenames nohup exec nice eval time ltrace then \
+ else do vsound command xargs tsocks aoss padsp
_root_command()
{
- PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin _command $1 $2 $3
+ local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin
+ _command $1 $2 $3
}
-complete -F _root_command $filenames sudo fakeroot really gksudo gksu kdesudo
+complete -F _root_command -o filenames sudo fakeroot really gksudo gksu kdesudo
_longopt()
{
local cur prev
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
+ _get_comp_words_by_ref cur prev
if _split_longopt; then
case "$prev" in
@@ -1508,8 +1516,8 @@ _longopt()
fi
if [[ "$cur" == -* ]]; then
- COMPREPLY=( $( compgen -W "$( $1 --help 2>&1 | sed -e '/--/!d' \
- -e 's/.*\(--[-A-Za-z0-9]\+\).*/\1/' |sort -u )"\
+ 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
@@ -1519,68 +1527,33 @@ _longopt()
}
# makeinfo and texi2dvi are defined elsewhere.
for i in a2ps autoconf automake bc gprof ld nm objcopy objdump readelf strip \
- bison diff patch enscript cp df dir du ln ls mkfifo mknod mv rm \
+ bison colordiff diff patch enscript cp df dir du ln ls mkfifo mknod mv rm \
touch vdir awk gperf grep grub indent less m4 sed shar date \
tee who texindex cat csplit cut expand fmt fold head \
md5sum nl od paste pr ptx sha1sum sort split tac tail tr unexpand \
- uniq wc ldd bash id irb mkdir rmdir; do
- have $i && complete -F _longopt $filenames $i
+ uniq wc ldd bash id irb mkdir rmdir wget curl; do
+ have $i && complete -F _longopt -o filenames $i
done
# These commands do not use filenames, so '-o filenames' is not needed.
-for i in env netstat seq uname units wget; do
- have $i && complete -F _longopt $default $i
+for i in env netstat seq uname units; do
+ have $i && complete -F _longopt -o default $i
done
unset i
-# look(1) completion
-#
-have look &&
-_look()
-{
- local cur
-
- COMPREPLY=()
- cur=`_get_cword`
-
- if [ $COMP_CWORD = 1 ]; then
- COMPREPLY=( $( compgen -W '$(look "$cur" 2>/dev/null)' ) )
- fi
-} &&
-complete -F _look $default look
-
-# id(1) completion
-#
-have id &&
-_id()
-{
- local cur
-
- COMPREPLY=()
- cur=`_get_cword`
-
- if [[ "$cur" == -* ]]; then
- COMPREPLY=( $( compgen -W '-a -g --group -G --groups -n --name\
- -r --real -u --user --help --version' -- "$cur" ) )
- else
- COMPREPLY=( $( compgen -u "$cur" ) )
- fi
-} &&
-complete -F _id id
-
_filedir_xspec()
{
local IFS cur xspec
IFS=$'\t\n'
COMPREPLY=()
- cur=`_get_cword`
+ _get_comp_words_by_ref cur
_expand || return 0
# get first exclusion compspec that matches this command
- xspec=$( sed -ne $'/^complete .*[ \t]'${1##*/}$'\([ \t]\|$\)/{p;q;}' \
- $BASH_COMPLETION )
+ 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%% *}
@@ -1592,7 +1565,7 @@ _filedir_xspec()
compgen -d -- "$(quote_readline "$cur")" | {
while read -r tmp; do
# see long TODO comment in _filedir() --David
- echo $tmp
+ printf '%s\n' $tmp
done
}
))
@@ -1600,14 +1573,14 @@ _filedir_xspec()
toks=( ${toks[@]-} $(
eval compgen -f -X "$xspec" -- "\$(quote_readline "\$cur")" | {
while read -r tmp; do
- [ -n $tmp ] && echo $tmp
+ [ -n $tmp ] && printf '%s\n' $tmp
done
}
))
COMPREPLY=( "${toks[@]}" )
}
-list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' $BASH_COMPLETION | \
+list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' "$BASH_COMPLETION" | \
# read exclusion compspecs
(
while read line
@@ -1619,41 +1592,42 @@ list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' $BASH_COMPLETION | \
line=${line##*\'}
list=( "${list[@]}" $line )
done
- echo "${list[@]}"
+ printf '%s ' "${list[@]}"
)
) )
# remove previous compspecs
if [ ${#list[@]} -gt 0 ]; then
eval complete -r ${list[@]}
# install new compspecs
- eval complete -F _filedir_xspec $filenames "${list[@]}"
+ eval complete -F _filedir_xspec -o filenames "${list[@]}"
fi
unset list
# source completion directory definitions
-if [ -d $BASH_COMPLETION_COMPAT_DIR -a -r $BASH_COMPLETION_COMPAT_DIR -a \
- -x $BASH_COMPLETION_COMPAT_DIR ]; then
- for i in $BASH_COMPLETION_COMPAT_DIR/*; do
- [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)) ]] &&
- [ \( -f $i -o -h $i \) -a -r $i ] && . $i
+if [[ -d $BASH_COMPLETION_COMPAT_DIR && -r $BASH_COMPLETION_COMPAT_DIR && \
+ -x $BASH_COMPLETION_COMPAT_DIR ]]; then
+ for i in $(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR"); do
+ i=$BASH_COMPLETION_COMPAT_DIR/$i
+ [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)) \
+ && ( -f $i || -h $i ) && -r $i ]] && . "$i"
done
fi
-if [ -d $BASH_COMPLETION_DIR -a -r $BASH_COMPLETION_DIR -a \
- $BASH_COMPLETION_DIR != $BASH_COMPLETION_COMPAT_DIR -a \
- -x $BASH_COMPLETION_DIR ]; then
- for i in $BASH_COMPLETION_DIR/*; do
- [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)) ]] &&
- [ \( -f $i -o -h $i \) -a -r $i ] && . $i
+if [[ $BASH_COMPLETION_DIR != $BASH_COMPLETION_COMPAT_DIR && \
+ -d $BASH_COMPLETION_DIR && -r $BASH_COMPLETION_DIR && \
+ -x $BASH_COMPLETION_DIR ]]; then
+ for i in $(LC_ALL=C command ls "$BASH_COMPLETION_DIR"); do
+ i=$BASH_COMPLETION_DIR/$i
+ [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)) \
+ && ( -f $i || -h $i ) && -r $i ]] && . "$i"
done
fi
unset i
# source user completion file
-[ $BASH_COMPLETION != ~/.bash_completion -a -r ~/.bash_completion ] \
+[[ $BASH_COMPLETION != ~/.bash_completion && -r ~/.bash_completion ]] \
&& . ~/.bash_completion
unset -f have
-unset UNAME USERLAND default dirnames filenames have nospace bashdefault \
- plusdirs compopt
+unset UNAME USERLAND have
set $BASH_COMPLETION_ORIGINAL_V_VALUE
unset BASH_COMPLETION_ORIGINAL_V_VALUE