# bash_completion - programmable completion functions for bash 3.x # (backwards compatible with bash 2.05b) # # Copyright © 2006-2008, Ian Macdonald # © 2008, David Paleino # © 2008, Luk Claes # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # The latest version of this software can be obtained here: # # http://bash-completion.alioth.debian.org/ # # RELEASE: 20080617.5 LOCAL_BASH_COMPLETION_DIR=$HOME/.bash_completion.d _debug() { test -n "$DEBUG" && echo "$1" } if [[ $- == *v* ]]; then BASH_COMPLETION_ORIGINAL_V_VALUE="-v" else BASH_COMPLETION_ORIGINAL_V_VALUE="+v" fi if [[ -n $BASH_COMPLETION_DEBUG ]]; then set -v else set +v fi # Set a couple of useful vars # UNAME=$( uname -s ) # strip OS type and version under Cygwin (e.g. CYGWIN_NT-5.1 => Cygwin) UNAME=${UNAME/CYGWIN_*/Cygwin} RELEASE=$( uname -r ) # 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" 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 # Turn on extended globbing and programmable completion shopt -s extglob progcomp # A lot of the following one-liners were taken directly from the # completion examples provided with the bash 2.04 source distribution # Make directory commands see only directories complete -d pushd # The following section lists completions that are redefined later # Do NOT break these over multiple lines. # # START exclude -- do NOT remove this line complete -f -X '!*.?(t)bz?(2)' bunzip2 # TODO: see #455510 #complete -f -X '!*.?(t)bz?(2)' bzcat bzcmp bzdiff bzegrep bzfgrep bzgrep complete -f -X '!*.*' bzcat bzcmp bzdiff bzegrep bzfgrep bzgrep complete -f -X '!*.@(zip|ZIP|jar|JAR|egg|EGG|exe|EXE|pk3|war|wsz|ear|zargo|xpi|sxw|swc|ott|od[fgpst])' unzip zipinfo complete -f -X '*.Z' compress znew complete -f -X '!*.@(Z|gz|tgz|Gz|dz)' gunzip # TODO: see #455510 #complete -f -X '!*.@(Z|gz|tgz|Gz|dz)' zcmp zdiff zcat zegrep zfgrep zgrep zless zmore complete -f -X '!*.*' zcmp zdiff zcat zegrep zfgrep zgrep zless zmore complete -f -X '!*.Z' uncompress 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|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|svg|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|SVG)' display 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 '!*.@(@(?(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)?(.gz|.GZ|.bz2|.BZ2)|cb(r|z)|CB(R|Z)|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)ps|?(E)PS)' ps2pdf 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 '!*.@(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|mp3|MP3|m4[pv]|M4[PV]|ogg|OGG|ogm|OGM|mp4|MP4|wav|WAV|asx|ASX|mng|MNG|srt)' xine aaxine fbxine kaffeine 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 '!*.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)' timidity 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 '!*.@(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 complete -f -X '!*.@(sxw|stw|sxg|sgl|doc|dot|rtf|txt|htm|html|odt|ott|odm)' oowriter complete -f -X '!*.@(sxi|sti|pps|ppt|pot|odp|otp)' ooimpress complete -f -X '!*.@(sxc|stc|xls|xlw|xlt|csv|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 # 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 usermod userdel passwd chage write chfn groups slay w sux # group commands see only groups [ -n "$bash205" ] && complete -g groupmod groupdel newgrp 2>/dev/null # bg completes with stopped jobs complete -A stopped -P '"%' -S '"' bg # other job commands complete -j -P '"%' -S '"' fg jobs disown # readonly and unset complete with shell variables complete -v readonly unset # set completes with set options complete -A setopt set # shopt completes with shopt options complete -A shopt shopt # helptopics complete -A helptopic help # unalias completes with aliases complete -a unalias # bind completes with readline bindings (make this more intelligent) complete -A binding bind # type and which complete on commands complete -c command type which # builtin completes on builtins complete -b builtin # start of section containing completion functions called by other functions # This function checks whether we have a given program on the system. # No need for bulky functions in memory if we don't. # have() { unset -v have 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 # [ $UNAME != Linux ] && have gsed && alias sed=gsed # This function checks whether a given readline variable # is `on'. # _rl_enabled() { [[ "$( bind -v )" = *$1+([[:space:]])on* ]] } # This function shell-quotes the argument quote() { echo \'${1//\'/\'\\\'\'}\' #'# Help vim syntax highlighting } # This function quotes the argument in a way so that readline dequoting # results in the original argument quote_readline() { local t="${1//\\/\\\\}" echo \'${t//\'/\'\\\'\'}\' #'# Help vim syntax highlighting } # This function shell-dequotes the argument dequote() { eval echo "$1" } # 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.) # # # Accepts an optional parameter indicating which characters out of # $COMP_WORDBREAKS should NOT be considered word breaks. This is useful # for things like scp where we want to return host:path and not only path. _get_cword() { if [[ "${#COMP_WORDS[COMP_CWORD]}" -eq 0 ]] || [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then echo "${COMP_WORDS[COMP_CWORD]}" else local i local cur="$COMP_LINE" local index="$COMP_POINT" for (( i = 0; i <= COMP_CWORD; ++i )); do while [[ "${#cur}" -ge ${#COMP_WORDS[i]} ]] && [[ "${cur:0:${#COMP_WORDS[i]}}" != "${COMP_WORDS[i]}" ]]; do cur="${cur:1}" index="$(( index - 1 ))" done if [[ "$i" -lt "$COMP_CWORD" ]]; then local old_size="${#cur}" cur="${cur#${COMP_WORDS[i]}}" local new_size="${#cur}" index="$(( index - old_size + new_size ))" fi done if [[ "${COMP_WORDS[COMP_CWORD]:0:${#cur}}" != "$cur" ]]; then # We messed up! At least return the whole word so things # keep working echo "${COMP_WORDS[COMP_CWORD]}" else echo "${cur:0:$index}" fi fi } # 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. # _filedir() { local IFS=$'\t\n' xspec _expand || return 0 local toks=( ) tmp while read -r tmp; do [[ -n $tmp ]] && toks[${#toks[@]}]=$tmp done < <( compgen -d -- "$(quote_readline "$cur")" ) if [[ "$1" != -d ]]; then xspec=${1:+"!*.$1"} while read -r tmp; do [[ -n $tmp ]] && toks[${#toks[@]}]=$tmp done < <( compgen -f -X "$xspec" -- "$(quote_readline "$cur")" ) fi COMPREPLY=( "${COMPREPLY[@]}" "${toks[@]}" ) } # This function completes on signal names # _signals() { local i # standard signal completion is rather braindead, so we need # to hack around to get what we want here, which is to # complete on a dash, followed by the signal name minus # the SIG prefix COMPREPLY=( $( compgen -A signal SIG${cur#-} )) for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do COMPREPLY[i]=-${COMPREPLY[i]#SIG} done } # This function completes on configured network interfaces # _configured_interfaces() { if [ -f /etc/debian_version ]; then # Debian system COMPREPLY=( $( sed -ne 's|^iface \([^ ]\+\).*$|\1|p' \ /etc/network/interfaces ) ) elif [ -f /etc/SuSE-release ]; then # SuSE system COMPREPLY=( $( command ls \ /etc/sysconfig/network/ifcfg-* | \ sed -ne 's|.*ifcfg-\('$cur'.*\)|\1|p' ) ) elif [ -f /etc/pld-release ]; then # PLD Linux COMPREPLY=( $( command ls -B \ /etc/sysconfig/interfaces | \ sed -ne 's|.*ifcfg-\('$cur'.*\)|\1|p' ) ) else # Assume Red Hat COMPREPLY=( $( command ls \ /etc/sysconfig/network-scripts/ifcfg-* | \ sed -ne 's|.*ifcfg-\('$cur'.*\)|\1|p' ) ) fi } # This function completes on all available network interfaces # -a: restrict to active interfaces only # -w: restrict to wireless interfaces only # _available_interfaces() { local cmd if [ "${1:-}" = -w ]; then cmd="iwconfig" elif [ "${1:-}" = -a ]; then cmd="ifconfig" else cmd="ifconfig -a" fi COMPREPLY=( $( eval $cmd 2>/dev/null | \ sed -ne 's|^\('$cur'[^[:space:][:punct:]]\{1,\}\).*$|\1|p') ) } # This function expands tildes in pathnames # _expand() { # FIXME: Why was this here? #[ "$cur" != "${cur%\\}" ] && cur="$cur\\" # expand ~username type directory specifications if [[ "$cur" == \~*/* ]]; then eval cur=$cur elif [[ "$cur" == \~* ]]; then cur=${cur#\~} COMPREPLY=( $( compgen -P '~' -u $cur ) ) return ${#COMPREPLY[@]} fi } # This function completes on process IDs. # AIX and Solaris ps prefers X/Open syntax. [ $UNAME = SunOS -o $UNAME = AIX ] && _pids() { COMPREPLY=( $( compgen -W '$( command ps -efo pid | sed 1d )' -- $cur )) } || _pids() { COMPREPLY=( $( compgen -W '$( command ps axo pid | sed 1d )' -- $cur ) ) } # This function completes on process group IDs. # AIX and SunOS prefer X/Open, all else should be BSD. [ $UNAME = SunOS -o $UNAME = AIX ] && _pgids() { COMPREPLY=( $( compgen -W '$( command ps -efo pgid | sed 1d )' -- $cur )) } || _pgids() { COMPREPLY=( $( compgen -W '$( command ps axo pgid | sed 1d )' -- $cur )) } # This function completes on user IDs # _uids() { if type getent &>/dev/null; then COMPREPLY=( $( getent passwd | \ awk -F: '{if ($3 ~ /^'$cur'/) print $3}' ) ) elif type perl &>/dev/null; then COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($uid) = (getpwent)[2]) { print $uid . "\n" }'"'"' )' -- $cur ) ) else # make do with /etc/passwd COMPREPLY=( $( awk 'BEGIN {FS=":"} {if ($3 ~ /^'$cur'/) print $3}'\ /etc/passwd ) ) fi } # This function completes on group IDs # _gids() { if type getent &>/dev/null; then COMPREPLY=( $( getent group | \ awk -F: '{if ($3 ~ /^'$cur'/) print $3}' ) ) 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 ) ) fi } # This function completes on services # _services() { local sysvdir famdir [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d || sysvdir=/etc/init.d famdir=/etc/xinetd.d COMPREPLY=( $( builtin echo $sysvdir/!(*.rpmsave|*.rpmorig|*~|functions)) ) if [ -d $famdir ]; then COMPREPLY=( "${COMPREPLY[@]}" $( builtin echo $famdir/!(*.rpmsave|*.rpmorig|*~)) ) fi COMPREPLY=( $( compgen -W '${COMPREPLY[@]#@($sysvdir|$famdir)/}' -- $cur ) ) } # This function complete on modules # _modules() { local modpath modpath=/lib/modules/$1 COMPREPLY=( $( command ls -R $modpath | \ sed -ne 's/^\('$cur'.*\)\.k\?o\(\|.gz\)$/\1/p') ) } # This function completes on installed modules # _installed_modules() { COMPREPLY=( $( compgen -W "$( /sbin/lsmod | \ awk '{if (NR != 1) print $1}' )" -- $1 ) ) } # this function complete on user:group format # _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##*[.:]} ) ) else COMPREPLY=( $( compgen -S : -u -- $cur ) ) fi } # this function count the number of mandatory args # _count_args() { args=1 for (( i=1; i < COMP_CWORD; i++ )); do if [[ "${COMP_WORDS[i]}" != -* ]]; then args=$(($args+1)) fi done } _source_local_bash_completion() { # source completion directory definitions if [ -n "$(complete | grep "post-review")" ] then return 2 fi if [ -x $LOCAL_BASH_COMPLETION_DIR ] then for i in $LOCAL_BASH_COMPLETION_DIR/* do local invalid="`echo $i | grep -E '.*(~|\.bak|\.swp|\.dpkg.*|\.rpm.*)'`" if [[ ! -n "$invalid" ]] && [[ -e "$i" ]] then _debug "sourcing $i" source $i fi done fi unset i } _source_local_bash_completion unset _source_local_bash_completion # vim:filetype=sh