diff options
author | David Paleino <dapal@debian.org> | 2011-02-06 21:26:41 +0100 |
---|---|---|
committer | David Paleino <dapal@debian.org> | 2011-02-06 21:26:41 +0100 |
commit | 9920a8faedf704420571d8072ccab27e9dac40ba (patch) | |
tree | 733edf3b07be06c130d04aaa1884213326722cad /bash_completion | |
parent | f9748115fb4b2950fb4df7535fb723c4affde078 (diff) | |
download | bash-completion-9920a8faedf704420571d8072ccab27e9dac40ba.tar.gz |
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'bash_completion')
-rw-r--r-- | bash_completion | 447 |
1 files changed, 248 insertions, 199 deletions
diff --git a/bash_completion b/bash_completion index e7a4b6ec..66019379 100644 --- a/bash_completion +++ b/bash_completion @@ -2,7 +2,7 @@ # bash_completion - programmable completion functions for bash 3.2+ # # Copyright © 2006-2008, Ian Macdonald <ian@caliban.org> -# © 2009-2010, Bash Completion Maintainers +# © 2009-2011, Bash Completion Maintainers # <bash-completion-devel@lists.alioth.debian.org> # # This program is free software; you can redistribute it and/or modify @@ -23,7 +23,7 @@ # # http://bash-completion.alioth.debian.org/ # -# RELEASE: 1.1 +# RELEASE: 1.3 if [[ $- == *v* ]]; then BASH_COMPLETION_ORIGINAL_V_VALUE="-v" @@ -70,41 +70,42 @@ 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 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 '!*.@(zip|[ejw]ar|exe|pk3|wsz|zargo|xpi|sxw|o[tx]t|od[fgpst]|epub|apk)' unzip zipinfo complete -f -X '*.Z' compress znew # zcmp, zdiff, z*grep, zless, zmore intentionally not here, see Debian: #455510 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 -complete -f -X '!*.@(xz|lzma)' unxz xzcat -complete -f -X '!*.@(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)' ee -complete -f -X '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|GIF|JPG|JP?(E)G|TIF?(F)|PNG|P[BGP]M|BMP|X[BP]M|RLE|RGB|PCX|FITS|PM)' xv qiv +complete -f -X '!*.@(tlz|lzma)' lzcat lzegrep lzfgrep lzgrep lzless lzmore unlzma +complete -f -X '!*.@(?(t)xz|tlz|lzma)' unxz xzcat +complete -f -X '!*.lrz' lrunzip +complete -f -X '!*.@(gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx)' ee +complete -f -X '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm)' xv qiv complete -f -X '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv kghostview -complete -f -X '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' xdvi -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|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 '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' xdvi kdvi +complete -f -X '!*.dvi' dvips dviselect dvitype dvipdf advi dvipdfm dvipdfmx +complete -f -X '!*.[pf]df' acroread gpdf xpdf +complete -f -X '!*.@(?(e)ps|pdf)' kpdf +complete -f -X '!*.@(@(?(e)ps|?(E)PS|[pf]df|[PF]DF|dvi|DVI)?(.gz|.GZ|.bz2|.BZ2)|cb[rz]|djv?(u)|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|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?(2)|FB?(2)|mobi|MOBI|g3|G3|chm|CHM|fdf|FDF)?(.?(gz|GZ|bz2|BZ2)))' okular +complete -f -X '!*.@(?(e)ps|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|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|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 '!*.@(?(la)tex|texi|dtx|ins|ltx)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi +complete -f -X '!*.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|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]|m2t?(s)|M2T?(S)|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))?(.part)' xine aaxine fbxine +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]|m2t?(s)|M2T?(S)|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|iso|ISO)|+([0-9]).@(vdr|VDR))?(.part)' 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 -complete -f -X '!*.@(ogg|OGG|m3u|flac|spx)' ogg123 -complete -f -X '!*.@(mp3|MP3|ogg|OGG|pls|m3u)' gqmpeg freeamp +complete -f -X '!*.@(ogg|m3u|flac|spx)' ogg123 +complete -f -X '!*.@(mp3|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 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 '!*.@(mid?(i)|cmf)' playmidi +complete -f -X '!*.@(mid?(i)|rmi|rcp|[gr]36|g18|mod|xm|it|x3m|s[3t]m|kar)' timidity +complete -f -X '!*.@(m[eo]d|s[3t]m|xm|it)' modplugplay modplug123 +complete -f -X '*.@(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 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 '!*.@(zip|z|gz|tgz)' bzme # 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 @@ -113,22 +114,22 @@ complete -f -X '!*.@(sxc|stc|xls?([bmx])|xlw|xlt?([mx])|[ct]sv|ods|ots)' oocalc 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 '!*.s@(qlite?(3)|?(3)db)' sqlite3 +complete -f -X '!*.[rs]pm' rpm2cpio 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 +complete -f -X '!@(*.@(ks|jks|jceks|p12|pfx|bks|ubr|gkr|cer|crt|cert|p7b|pkipath|pem|p10|csr|crl)|cacerts)' portecle +complete -f -X '!*.@(mp[234c]|og[ag]|@(fl|a)ac|m4[abp]|spx|tta|w?(a)v|wma|aif?(f)|asf|ape)' kid3 kid3-qt # FINISH exclude -- do not remove this line # start of section containing compspecs that can be handled within bash # user commands see only users -complete -u su passwd write chfn groups slay w sux +complete -u su write chfn groups slay w sux runuser # bg completes with stopped jobs complete -A stopped -P '"%' -S '"' bg @@ -310,7 +311,7 @@ __reassemble_comp_words_by_ref() { ref="$2[$j]" eval $2[$j]=\${!ref}\${COMP_WORDS[i]} # Indicate new cword - [ $i = $COMP_CWORD ] && [[ ${COMP_WORDS[i]} ]] && eval $3=$j + [[ $i == $COMP_CWORD ]] && eval $3=$j done else # No, list of word completions separators hasn't changed; @@ -464,7 +465,7 @@ _get_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 + elif [[ "${#words[cword]}" -eq 0 || "$COMP_POINT" == "${#COMP_LINE}" ]]; then printf "%s" "${words[cword]}" else local i @@ -568,16 +569,32 @@ __ltrim_colon_completions() { # $ compgen -f "a\\\\\'b/" # Good (bash-3) # a\'b/c # -# See also: http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html +# 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 +# +# See also: +# - http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html +# - http://www.mail-archive.com/bash-completion-devel@lists.alioth.\ +# debian.org/msg01944.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 + if [[ ${BASH_VERSINFO[0]} -ge 4 ]]; then + # Leave out first character + printf -v $2 %s "${1:1}" + else + # Quote word, leaving out first character + printf -v $2 %q "${1:1}" + # Double-quote word (bash-3) printf -v $2 %q ${!2} fi elif [[ ${BASH_VERSINFO[0]} -le 3 && ${1:0:1} == '"' ]]; then @@ -593,16 +610,30 @@ _quote_readline_by_ref() } # _quote_readline_by_ref() +# This function turns on "-o filenames" behavior dynamically. It is present +# for bash < 4 reasons. See http://bugs.debian.org/272660#64 for info about +# the bash < 4 compgen hack. +_compopt_o_filenames() +{ + # We test for compopt availability first because directly invoking it on + # bash < 4 at this point may cause terminal echo to be turned off for some + # reason, see https://bugzilla.redhat.com/653669 for more info. + type compopt &>/dev/null && compopt -o filenames 2>/dev/null || \ + compgen -f /non-existing-dir/ >/dev/null +} + + # 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. +# completions with `.$1' and the uppercase version of it as file +# extension. # _filedir() { - local i IFS=$'\t\n' xspec + local i IFS=$'\n' xspec - __expand_tilde_by_ref cur + _tilde "$cur" || return 0 local -a toks local quoted tmp @@ -621,68 +652,14 @@ _filedir() } )) - # 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 + # Munge xspec to contain uppercase version too + [[ ${BASH_VERSINFO[0]} -ge 4 ]] && \ + xspec=${1:+"!*.@($1|${1^^})"} || \ + xspec=${1:+"!*.@($1|$(printf %s $1 | tr '[:lower:]' '[:upper:]'))"} + toks=( ${toks[@]-} $( compgen -f -X "$xspec" -- $quoted) ) fi + [ ${#toks[@]} -ne 0 ] && _compopt_o_filenames COMPREPLY=( "${COMPREPLY[@]}" "${toks[@]}" ) } # _filedir() @@ -705,13 +682,13 @@ _split_longopt() return 1 } -# This function tries to parse the output of $command --help +# This function tries to parse the help output of the given command. +# @param $1 command +# @param $2 command options (default: --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" + $1 ${2:---help} 2>&1 | sed -e '/^[[:space:]]*-/!d' -e 's|[,/]| |g' | \ + awk '{ print $1; if ($2 ~ /^-/) { print $2 } }' | sed -e 's|[<=].*||' } # This function completes on signal names @@ -746,6 +723,10 @@ _mac_addresses() "s/.*[[:space:]]\($re\)[[:space:]].*/\1/p" -ne \ "s/.*[[:space:]]\($re\)[[:space:]]*$/\1/p" ) ) + # /etc/ethers + COMPREPLY=( "${COMPREPLY[@]}" $( sed -ne \ + "s/^[[:space:]]*\($re\)[[:space:]].*/\1/p" /etc/ethers 2>/dev/null ) ) + COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- "$cur" ) ) __ltrim_colon_completions "$cur" } @@ -805,7 +786,27 @@ _available_interfaces() } +# Perform tilde (~) completion +# @return True (0) if completion needs further processing, +# False (> 0) if tilde is followed by a valid username, completions +# are put in COMPREPLY and no further processing is necessary. +_tilde() { + local result=0 + # Does $1 start with tilde (~) and doesn't contain slash (/)? + if [[ ${1:0:1} == "~" && $1 == ${1//\/} ]]; then + _compopt_o_filenames + # Try generate username completions + COMPREPLY=( $( compgen -P '~' -u "${1#\~}" ) ) + result=${#COMPREPLY[@]} + fi + return $result +} + + # Expand variable starting with tilde (~) +# We want to expand ~foo/... to /home/foo/... to avoid problems when +# word-to-complete starting with a tilde is fed to commands and ending up +# quoted instead of expanded. # 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. @@ -834,7 +835,7 @@ __expand_tilde_by_ref() { # becomes "~a". Double quotes allow eval. # 2: Remove * before the first slash (/), i.e. "~a/b" # becomes "b". Single quotes prevent eval. - # +-----1----+ +---2----+ + # +-----1----+ +---2----+ eval $1="${!1/%\/*}"/'${!1#*/}' else # No, $1 doesn't contain slash @@ -982,10 +983,10 @@ _installed_modules() # 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. +# @param $1 If -u, only return users/groups the user has access to in +# context of current completion. _usergroup() { - local IFS=$'\n' if [[ $cur = *\\\\* || $cur = *:*:* ]]; then # Give up early on if something seems horribly wrong. return @@ -996,19 +997,61 @@ _usergroup() local prefix prefix=${cur%%*([^:])} prefix=${prefix//\\} - COMPREPLY=( $( compgen -P "$prefix" -g -- "${cur#*[:]}" ) ) + local mycur="${cur#*[:]}" + if [[ $1 == -u ]]; then + _allowed_groups "$mycur" + else + local IFS=$'\n' + COMPREPLY=( $( compgen -g -- "$mycur" ) ) + fi + COMPREPLY=( $( compgen -P "$prefix" -W "${COMPREPLY[@]}" ) ) 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#*:}" ) ) + local mycur="${cur#*:}" + if [[ $1 == -u ]]; then + _allowed_groups "$mycur" + else + local IFS=$'\n' + COMPREPLY=( $( compgen -g -- "$mycur" ) ) + fi else # 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" ) ) + if [[ $1 == -u ]]; then + _allowed_users "$cur" + else + local IFS=$'\n' + COMPREPLY=( $( compgen -u -- "$cur" ) ) + fi + fi +} + +_allowed_users() +{ + if _complete_as_root; then + local IFS=$'\n' + COMPREPLY=( $( compgen -u -- "${1:-$cur}" ) ) + else + local IFS=$'\n ' + COMPREPLY=( $( compgen -W \ + "$( id -un 2>/dev/null || whoami 2>/dev/null )" -- "${1:-$cur}" ) ) + fi +} + +_allowed_groups() +{ + if _complete_as_root; then + local IFS=$'\n' + COMPREPLY=( $( compgen -g -- "$1" ) ) + else + local IFS=$'\n ' + COMPREPLY=( $( compgen -W \ + "$( id -Gn 2>/dev/null || groups 2>/dev/null )" -- "$1" ) ) fi } @@ -1164,7 +1207,8 @@ _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 +# files, as well as hostnames reported by avahi-browse if +# COMP_KNOWN_HOSTS_WITH_AVAHI is set to a non-empty value. 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 @@ -1201,12 +1245,10 @@ _known_hosts_real() [ -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" ) + for i in /etc/ssh/ssh_config "${HOME}/.ssh/config" \ + "${HOME}/.ssh2/config"; do + [ -r $i ] && config=( "${config[@]}" "$i" ) + done fi # Known hosts files from configs @@ -1228,28 +1270,16 @@ _known_hosts_real() 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 ) + # 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=( "${kh[@]}" $i ) + done + for i in /etc/ssh2/knownhosts ~/.ssh2/hostkeys; do + [ -d $i ] && khd=( "${khd[@]}" $i/*pub ) + done fi # If we have known_hosts files to use @@ -1259,16 +1289,16 @@ _known_hosts_real() awkcur=${awkcur//\./\\\.} curd=$awkcur - if [[ "$awkcur" == [0-9]*.* ]]; then - # Digits followed by a dot - just search for that - awkcur="^$awkcur.*" + if [[ "$awkcur" == [0-9]*[.:]* ]]; then + # Digits followed by a dot or a colon - 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.*\." + # Digits followed by no dot or colon - search for digits followed + # by a dot or a colon + awkcur="^$awkcur.*[.:]" elif [ -z "$awkcur" ]; then - # A blank - search for a dot or an alpha character - awkcur="[a-z.]" + # A blank - search for a dot, a colon, or an alpha character + awkcur="[a-z.:]" else awkcur="^$awkcur" fi @@ -1277,9 +1307,8 @@ _known_hosts_real() # 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); \ + sub(" .*$", "", $i); \ + sub("^\\[", "", $i); sub("\\](:[0-9]+)?$", "", $i); \ if ($i ~ /'"$awkcur"'/) {print $i} \ }}' "${kh[@]}" 2>/dev/null ) ) fi @@ -1310,12 +1339,14 @@ _known_hosts_real() -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 + # Add hosts reported by avahi-browse, if desired and it's available. + if [[ ${COMP_KNOWN_HOSTS_WITH_AVAHI:-} ]] && \ + type avahi-browse &>/dev/null; then + # 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 wasn't available (even if mentioned in the manpage) some + # time ago, so... COMPREPLY=( "${COMPREPLY[@]}" $( \ compgen -P "$prefix$user" -S "$suffix" -W \ "$( avahi-browse -cpr _workstation._tcp 2>/dev/null | \ @@ -1342,7 +1373,7 @@ complete -F _known_hosts traceroute traceroute6 tracepath tracepath6 ping \ # _cd() { - local cur IFS=$'\t\n' i j k + local cur IFS=$'\n' i j k _get_comp_words_by_ref cur # try to allow variable completion @@ -1351,8 +1382,7 @@ _cd() return 0 fi - # Enable -o filenames option, see Debian bug #272660 - compgen -f /non-existing-dir/ >/dev/null + _compopt_o_filenames # Use standard dir completion if no CDPATH or parameter starts with /, # ./ or ../ @@ -1365,7 +1395,7 @@ _cd() local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y) # we have a CDPATH, so loop on its contents - for i in ${CDPATH//:/$'\t'}; do + for i in ${CDPATH//:/$'\n'}; do # create an array of matched subdirs k="${#COMPREPLY[@]}" for j in $( compgen -d $i/$cur ); do @@ -1449,11 +1479,12 @@ _command_offset() _get_comp_words_by_ref cur if [[ $COMP_CWORD -eq 0 ]]; then + _compopt_o_filenames COMPREPLY=( $( compgen -c -- "$cur" ) ) else cmd=${COMP_WORDS[0]} - if complete -p $cmd &>/dev/null; then - cspec=$( complete -p $cmd ) + if complete -p ${cmd##*/} &>/dev/null; then + cspec=$( complete -p ${cmd##*/} ) if [ "${cspec#* -F }" != "$cspec" ]; then # complete -F <function> @@ -1475,68 +1506,74 @@ _command_offset() cspec=${cspec%% *} if [[ "$cspec" != @(dir|file)names ]]; then COMPREPLY=("${COMPREPLY[@]//\\\\:/:}") + else + _compopt_o_filenames fi fi elif [ -n "$cspec" ]; then cspec=${cspec#complete}; - cspec=${cspec%%$cmd}; + cspec=${cspec%%${cmd##*/}}; COMPREPLY=( $( eval compgen "$cspec" -- "$cur" ) ); fi + elif [ ${#COMPREPLY[@]} -eq 0 ]; then + _filedir fi fi - - [ ${#COMPREPLY[@]} -eq 0 ] && _filedir } -complete -F _command -o filenames nohup exec nice eval time ltrace then \ - else do vsound command xargs tsocks aoss padsp +complete -F _command aoss command do else eval exec ltrace nice nohup padsp \ + then time tsocks vsound xargs _root_command() { local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin + local root_command=$1 _command $1 $2 $3 } -complete -F _root_command -o filenames sudo fakeroot really gksudo gksu kdesudo +complete -F _root_command fakeroot gksu gksudo kdesudo really sudo + +# Return true if the completion should be treated as running as root +_complete_as_root() +{ + [[ $EUID -eq 0 || ${root_command:-} ]] +} _longopt() { - local cur prev + local cur prev split=false + _get_comp_words_by_ref -n = cur prev - _get_comp_words_by_ref cur prev + _split_longopt && split=true - if _split_longopt; then - case "$prev" in - *[Dd][Ii][Rr]*) - _filedir -d - ;; - *[Ff][Ii][Ll][Ee]*) - _filedir - ;; - esac - return 0 - fi + case "$prev" in + --*[Dd][Ii][Rr]*) + _filedir -d + return 0 + ;; + --*[Ff][Ii][Ll][Ee]*|--*[Pp][Aa][Tt][Hh]*) + _filedir + return 0 + ;; + esac + + $split && return 0 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 + elif [[ "$1" == @(mk|rm)dir ]]; then _filedir -d else _filedir fi } # makeinfo and texi2dvi are defined elsewhere. -for i in a2ps autoconf automake bc gprof ld nm objcopy objdump readelf strip \ - 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 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; do +for i in a2ps awk bash bc bison cat colordiff cp csplit \ + curl cut date df diff dir du enscript env expand fmt fold gperf gprof \ + grep grub head indent irb ld ldd less ln ls m4 md5sum mkdir mkfifo mknod \ + mv netstat nl nm objcopy objdump od paste patch pr ptx readelf rm rmdir \ + sed seq sha{,1,224,256,384,512}sum shar sort split strip tac tail tee \ + texindex touch tr uname unexpand uniq units vdir wc wget who; do have $i && complete -F _longopt -o default $i done unset i @@ -1545,7 +1582,7 @@ _filedir_xspec() { local IFS cur xspec - IFS=$'\t\n' + IFS=$'\n' COMPREPLY=() _get_comp_words_by_ref cur @@ -1570,14 +1607,26 @@ _filedir_xspec() } )) + # Munge xspec to contain uppercase version too + eval xspec="${xspec}" + local matchop=! + if [[ $xspec == !* ]]; then + xspec=${xspec#!} + matchop=@ + fi + [[ ${BASH_VERSINFO[0]} -ge 4 ]] && \ + xspec="$matchop($xspec|${xspec^^})" || \ + xspec="$matchop($xspec|$(printf %s $xspec | tr '[:lower:]' '[:upper:]'))" + toks=( ${toks[@]-} $( - eval compgen -f -X "$xspec" -- "\$(quote_readline "\$cur")" | { + eval compgen -f -X "!$xspec" -- "\$(quote_readline "\$cur")" | { while read -r tmp; do [ -n $tmp ] && printf '%s\n' $tmp done } )) + [ ${#toks[@]} -ne 0 ] && _compopt_o_filenames COMPREPLY=( "${toks[@]}" ) } list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' "$BASH_COMPLETION" | \ @@ -1599,7 +1648,7 @@ list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' "$BASH_COMPLETION" | if [ ${#list[@]} -gt 0 ]; then eval complete -r ${list[@]} # install new compspecs - eval complete -F _filedir_xspec -o filenames "${list[@]}" + eval complete -F _filedir_xspec "${list[@]}" fi unset list @@ -1608,8 +1657,8 @@ 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" + [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) \ + && -f $i && -r $i ]] && . "$i" done fi if [[ $BASH_COMPLETION_DIR != $BASH_COMPLETION_COMPAT_DIR && \ @@ -1617,8 +1666,8 @@ if [[ $BASH_COMPLETION_DIR != $BASH_COMPLETION_COMPAT_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" + [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) \ + && -f $i && -r $i ]] && . "$i" done fi unset i |