| # ------------------------------------------------------------ | |
| # Licensed to the Apache Software Foundation (ASF) under one | |
| # or more contributor license agreements. See the NOTICE file | |
| # distributed with this work for additional information | |
| # regarding copyright ownership. The ASF licenses this file | |
| # to you under the Apache License, Version 2.0 (the | |
| # "License"); you may not use this file except in compliance | |
| # with the License. You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, | |
| # software distributed under the License is distributed on an | |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| # KIND, either express or implied. See the License for the | |
| # specific language governing permissions and limitations | |
| # under the License. | |
| # ------------------------------------------------------------ | |
| # Programmable completion for the Subversion svn command under bash. Source | |
| # this file (or on some systems add it to ~/.bash_completion and start a new | |
| # shell) and bash's completion mechanism will know all about svn's options! | |
| # Provides completion for the svnadmin, svndumpfilter, svnlook and svnsync | |
| # commands as well. Who wants to read man pages/help text... | |
| # Known to work with bash 3.* with programmable completion and extended | |
| # pattern matching enabled (use 'shopt -s extglob progcomp' to enable | |
| # these if they are not already enabled). | |
| shopt -s extglob | |
| # Tree helper functions which only use bash, to ease readability. | |
| # look for value associated to key from stdin in K/V hash file format | |
| # val=$(_svn_read_hashfile svn:realmstring < some/file) | |
| function _svn_read_hashfile() | |
| { | |
| local tkey=$1 key= val= | |
| while true; do | |
| read tag len | |
| [ $tag = 'END' ] && break | |
| [ $tag != 'K' ] && { | |
| #echo "unexpected tag '$tag' instead of 'K'" >&2 | |
| return | |
| } | |
| read -r -n $len key ; read | |
| read tag len | |
| [ $tag != 'V' ] && { | |
| #echo "unexpected tag '$tag' instead of 'V'" >&2 | |
| return | |
| } | |
| read -r -n $len val ; read | |
| if [[ $key = $tkey ]] ; then | |
| echo "$val" | |
| return | |
| fi | |
| done | |
| #echo "target key '$tkey' not found" >&2 | |
| } | |
| # _svn_grcut shell-regular-expression | |
| # extract filenames from 'svn status' output | |
| function _svn_grcut() | |
| { | |
| local re=$1 line= old_IFS | |
| # fix IFS, so that leading spaces are not ignored by next read. | |
| # (there is a leading space in svn status output if only a prop is changed) | |
| old_IFS="$IFS" | |
| IFS=$'\n' | |
| while read -r line ; do | |
| [[ ! $re || $line == $re ]] && echo "${line/????????/}" | |
| done | |
| IFS="$old_IFS" | |
| } | |
| # extract stuff from svn info output | |
| # _svn_info (URL|Repository Root) | |
| function _svn_info() | |
| { | |
| local what=$1 line= | |
| LANG=C LC_MESSAGES=C svn info --non-interactive 2> /dev/null | \ | |
| while read line ; do | |
| [[ $line == *"$what: "* ]] && echo ${line#*: } | |
| done | |
| } | |
| # broken since svn 1.7 | FIXME: change to svn status -v ? | |
| # _svn_lls (dir|file|all) files... | |
| # list svn-managed files from list | |
| # some 'svn status --all-files' would be welcome here? | |
| function _svn_lls() | |
| { | |
| local opt=$1 f= | |
| shift | |
| for f in "$@" ; do | |
| # could try to check in .svn/entries? hmmm... | |
| if [[ $opt == @(dir|all) && -d "$f" ]] ; then | |
| echo "$f/" | |
| elif [[ $opt == @(file|all) ]] ; then | |
| # split f in directory/file names | |
| local dn= fn="$f" | |
| [[ "$f" == */* ]] && dn=${f%\/*}/ fn=${f##*\/} | |
| # ??? this does not work for just added files, because they | |
| # do not have a content reference yet... | |
| [ -f "${dn}.svn/text-base/${fn}.svn-base" ] && echo "$f" | |
| fi | |
| done | |
| } | |
| # try to complete TARGET | |
| # 1. [nothing] lists available protocols | |
| # 2. svn+ssh:// lists servers from .ssh/known_hosts | |
| # 3. http[s]:// lists already used svn servers | |
| # 4. file:// lists files from dir | |
| # 5. ^/ or protocol except file:/ triggers svn ls | |
| # this code expects bash 4, $cur is split by : too | |
| # | |
| # $1 'all' | 'remote_only' | |
| # return true if found something | |
| function _svn_complete_target() { | |
| # echo -e "\n_svn_complete_target: [$cur] 1:[${COMP_WORDS[COMP_CWORD]}] 2:[${COMP_WORDS[COMP_CWORD-1]}] 3:[${COMP_WORDS[COMP_CWORD-2]}] | [${COMP_WORDS[@]}] [$COMP_WORDBREAKS]" | |
| local prefix=${COMP_WORDS[COMP_CWORD-2]} | |
| local colon=${COMP_WORDS[COMP_CWORD-1]} | |
| # see about COMP_WORDBREAKS workaround in prop completion | |
| if [[ $prefix == "file" && "$colon" == ":" ]] | |
| then | |
| # file completion for file:// urls | |
| COMPREPLY=( $(compgen -d -S '/' -X '*/.*' -- $cur ) ) | |
| return | |
| elif [[ ( $1 == "all" && $cur == ^/* ) || ( "$colon" == ":" && $cur == //*/* ) ]] | |
| then # we already hava a protocoll and host: autocomplete for svn ls ^/bla | svn ls remote_url | svn checkout remote_url | |
| local p | |
| if [ "$colon" == ":" ] ; then | |
| p="$prefix$colon" | |
| fi | |
| if [[ $cur =~ ((.*/)([^/]*)) ]] # url = everything up to the last / | |
| then | |
| local url="${BASH_REMATCH[2]}" | |
| local path="${BASH_REMATCH[3]}" | |
| local remote_files="$(svn ls --non-interactive "$p$url" 2> /dev/null )" | |
| COMPREPLY=( $(compgen -P "$url" -W "$remote_files" -- "$path" ) ) | |
| compopt -o nospace | |
| return 0 | |
| fi | |
| elif [[ "$colon" == ":" ]] | |
| then | |
| # get known servers | |
| # svn+ssh:// | |
| if [[ $prefix == "svn+ssh" && $cur =~ (^//(.*)) ]] ; then | |
| local server_start=${BASH_REMATCH[2]} | |
| # debian & suse: /usr/share/bash-completion/bash_completion | |
| local suffix=/ | |
| _known_hosts_real -p // "$server_start" | |
| else | |
| local urls= file= | |
| for file in ~/.subversion/auth/svn.simple/* ; do | |
| if [ -r $file ] ; then | |
| local url=$(_svn_read_hashfile svn:realmstring < $file) | |
| url=${url/*</} | |
| url=${url/>*/} | |
| urls="$urls $url" | |
| fi | |
| done | |
| # only suggest/show possible suffixes | |
| local suffix=$cur c= choices= | |
| for c in $urls ; do | |
| [[ $c == $prefix:* ]] && choices="$choices ${c#*:}" | |
| done | |
| COMPREPLY=( $(compgen -W "$choices" -- $suffix ) ) | |
| fi | |
| compopt -o nospace | |
| return | |
| else | |
| # show schemas | |
| if [ $1 == 'all' ] ; then | |
| COMPREPLY=( $(compgen -W "^/ $urlSchemas" -- $cur) ) | |
| else | |
| COMPREPLY=( $(compgen -W "$urlSchemas" -- $cur) ) | |
| fi | |
| compopt -o nospace | |
| return | |
| fi | |
| #echo "nothing found" | |
| return 1 | |
| } | |
| # This completion guides the command/option order along the one suggested | |
| # by "svn help", although other syntaxes are allowed. | |
| # | |
| # - there is a "real" parser to check for what is available and deduce what | |
| # can be suggested further. | |
| # - the syntax should be coherent with subversion/svn/{cl.h,main.c} | |
| # - although it is not a good practice, mixed options and arguments | |
| # is supported by the completion as it is by the svn command. | |
| # - the completion works in the middle of a line, | |
| # but not really in the middle of an argument or option. | |
| # - property names are completed: see comments about issues related to handling | |
| # ":" within property names although it is a word completion separator. | |
| # - unknown properties are assumed to be simple file properties. | |
| # - --revprop and --revision options are forced to revision properties | |
| # as they are mandatory in this case. | |
| # - argument values are suggested to some other options, eg directory names | |
| # for --config-dir. | |
| # - values for some options can be extended with environment variables: | |
| # SVN_BASH_FILE_PROPS: other properties on files/directories | |
| # SVN_BASH_REV_PROPS: other properties on revisions | |
| # SVN_BASH_ENCODINGS: encodings to be suggested | |
| # SVN_BASH_MIME_TYPE: mime types to be suggested | |
| # SVN_BASH_KEYWORDS: "svn:keywords" substitutions to be suggested | |
| # SVN_BASH_USERNAME: usernames suggested for --username | |
| # SVN_BASH_COMPL_EXT: completion extensions for file arguments, based on the | |
| # current subcommand, so that for instance only modified files are | |
| # suggested for 'revert', only not svn-managed files for 'add', and so on. | |
| # Possible values are: | |
| # - username: guess usernames from ~/.subversion/auth/... | |
| # - urls: guess urls from ~/.subversion/auth/... or others | |
| # - svnstatus: use 'svn status' for completion | |
| # - recurse: allow recursion (expensive) | |
| # - externals: recurse into externals (very expensive) | |
| # Former options are reasonable, but beware that both later options | |
| # may be unadvisable if used on large working copies. | |
| # None of these costly completions are activated by default. | |
| # Argument completion outside a working copy results in an error message. | |
| # Filenames with spaces are not completed properly. | |
| # | |
| # TODO | |
| # - other options? | |
| # - obsolete options could be removed from auto-comp? (e.g. -N) | |
| # - obsolete commands could be removed? (e.g. resolved) | |
| # - completion does not work properly when editing in the middle of the line | |
| # status/previous are those at the end of the line, not at the entry position | |
| # - url completion should select more cases where it is relevant | |
| # - url completion of http:// schemas could suggest sub directories? | |
| # - add completion for experimental 'obliterate' feature? | |
| _svn() | |
| { | |
| local cur cmds cmdOpts pOpts mOpts rOpts qOpts nOpts optsParam opt | |
| COMPREPLY=() | |
| cur=${COMP_WORDS[COMP_CWORD]} | |
| # Possible expansions, without pure-prefix abbreviations such as "up". | |
| cmds='add auth blame annotate praise cat changelist cl checkout co cleanup' | |
| cmds="$cmds commit ci copy cp delete remove rm diff export help import" | |
| cmds="$cmds info list ls lock log merge mergeinfo mkdir move mv rename" | |
| cmds="$cmds patch propdel pdel propedit pedit propget pget proplist" | |
| cmds="$cmds plist propset pset relocate resolve resolved revert status" | |
| cmds="$cmds switch unlock update upgrade" | |
| # help options have a strange command status... | |
| local helpOpts='--help -h' | |
| # all special options that have a command status | |
| local specOpts="--version $helpOpts" | |
| # options that require a parameter | |
| # note: continued lines must end '|' continuing lines must start '|' | |
| optsParam="-r|--revision|--username|--password|--targets" | |
| optsParam="$optsParam|-x|--extensions|-m|--message|-F|--file" | |
| optsParam="$optsParam|--encoding|--diff-cmd|--diff3-cmd|--editor-cmd" | |
| optsParam="$optsParam|--old|--new|--config-dir|--config-option" | |
| optsParam="$optsParam|--native-eol|-l|--limit|-c|--change" | |
| optsParam="$optsParam|--depth|--set-depth|--with-revprop" | |
| optsParam="$optsParam|--cl|--changelist|--accept|--show-revs" | |
| optsParam="$optsParam|--show-item" | |
| # svn:* and other (env SVN_BASH_*_PROPS) properties | |
| local svnProps revProps allProps psCmds propCmds | |
| # svn and user configured "file" (or directory) properties | |
| # the "svn:mergeinfo" prop is not included by default because it is | |
| # managed automatically, so there should be no need to edit it by hand. | |
| svnProps="svn:keywords svn:executable svn:needs-lock svn:externals | |
| svn:ignore svn:eol-style svn:mime-type $SVN_BASH_FILE_PROPS" | |
| # svn and user configured revision properties | |
| revProps="svn:author svn:log svn:date $SVN_BASH_REV_PROPS" | |
| # all properties as an array variable | |
| allProps=( $svnProps $revProps ) | |
| # subcommands that expect property names | |
| psCmds='propset|pset|ps' | |
| propCmds="$psCmds|propget|pget|pg|propedit|pedit|pe|propdel|pdel|pd" | |
| # possible URL schemas to access a subversion server | |
| local urlSchemas='file:/// http:// https:// svn:// svn+ssh://' | |
| # Parse arguments and set various variables about what was found. | |
| # | |
| # cmd: the current command if available | |
| # isPropCmd: whether it expects a property name argument | |
| # isPsCmd: whether it also expects a property value argument | |
| # isHelpCmd: whether it is about help | |
| # nExpectArgs: how many arguments are expected by the command | |
| # help: help requested about this command (if cmd=='help') | |
| # prop: property name (if appropriate) | |
| # isRevProp: is it a special revision property | |
| # val: property value (if appropriate, under pset) | |
| # options: all options encountered | |
| # hasRevPropOpt: is --revprop set | |
| # hasRevisionOpt: is --revision set | |
| # hasRelocateOpt: is --relocate set | |
| # hasReintegrateOpt: is --reintegrate set | |
| # acceptOpt: the value of --accept | |
| # nargs: how many arguments were found | |
| # stat: status of parsing at the 'current' word | |
| # | |
| # prev: previous command in the loop | |
| # last: status of last parameter analyzed | |
| # i: index | |
| local cmd= isPropCmd= isPsCmd= isHelpCmd= nExpectArgs= isCur= i=0 | |
| local prev= help= prop= val= isRevProp= last='none' nargs=0 stat= | |
| local options= hasRevPropOpt= hasRevisionOpt= hasRelocateOpt= | |
| local acceptOpt= URL= hasReintegrateOpt= | |
| for opt in "${COMP_WORDS[@]}" | |
| do | |
| # get status of current word (from previous iteration) | |
| [[ $isCur ]] && stat=$last | |
| # are we processing the current word | |
| isCur= | |
| [[ $i -eq $COMP_CWORD ]] && isCur=1 | |
| let i++ | |
| # FIRST must be the "svn" command | |
| [ $last = 'none' ] && { last='first'; continue ; } | |
| # SKIP option arguments | |
| if [[ $prev == @($optsParam) ]] ; then | |
| # record accept value | |
| [[ $prev = '--accept' ]] && acceptOpt=$opt | |
| prev='' | |
| last='skip' | |
| continue ; | |
| fi | |
| # Argh... This looks like a bash bug... | |
| # Redirections are passed to the completion function | |
| # although it is managed by the shell directly... | |
| # It matters because we want to tell the user when no more | |
| # completion is available, so it does not necessary | |
| # fallback to the default case. | |
| if [[ $prev == @(<|>|>>|[12]>|[12]>>) ]] ; then | |
| prev='' | |
| last='skip' | |
| continue ; | |
| fi | |
| prev=$opt | |
| # get the subCoMmanD | |
| if [[ ! $cmd && $opt \ | |
| && ( $opt != -* || $opt == @(${specOpts// /|}) ) ]] | |
| then | |
| cmd=$opt | |
| [[ $cmd == @($propCmds) ]] && isPropCmd=1 | |
| [[ $cmd == @($psCmds) ]] && isPsCmd=1 | |
| [[ $cmd == @(${helpOpts// /|}) ]] && cmd='help' | |
| [[ $cmd = 'help' ]] && isHelpCmd=1 | |
| # HELP about a command asked with an option | |
| if [[ $isHelpCmd && $cmd && $cmd != 'help' && ! $help ]] | |
| then | |
| help=$cmd | |
| cmd='help' | |
| fi | |
| last='cmd' | |
| continue | |
| fi | |
| # HELP about a command | |
| if [[ $isHelpCmd && ! $help && $opt && $opt != -* ]] | |
| then | |
| help=$opt | |
| last='help' | |
| continue | |
| fi | |
| # PROPerty name | |
| if [[ $isPropCmd && ! $prop && $opt && $opt != -* ]] | |
| then | |
| prop=$opt | |
| [[ $prop == @(${revProps// /|}) ]] && isRevProp=1 | |
| last='prop' | |
| continue | |
| fi | |
| # property VALue | |
| if [[ $isPsCmd && $prop && ! $val && $opt != -* ]] ; | |
| then | |
| val=$opt | |
| last='val' | |
| continue | |
| fi | |
| if [[ $last != 'onlyarg' ]] | |
| then | |
| # more OPTions | |
| case $opt in | |
| -r|--revision|--revision=*) | |
| hasRevisionOpt=1 | |
| ;; | |
| --revprop) | |
| hasRevPropOpt=1 | |
| # restrict to revision properties! | |
| allProps=( $revProps ) | |
| # on revprops, only one URL is expected | |
| nExpectArgs=1 | |
| ;; | |
| -h|--help) | |
| isHelpCmd=1 | |
| ;; | |
| -F|--file) | |
| val='-F' | |
| ;; | |
| --relocate) | |
| hasRelocateOpt=1 | |
| ;; | |
| --reintegrate) | |
| hasReintegrateOpt=1 | |
| ;; | |
| esac | |
| # no more options, only arguments, whatever they look like. | |
| if [[ $opt = '--' && ! $isCur ]] ; then | |
| last='onlyarg' | |
| continue | |
| fi | |
| # options are recorded... | |
| if [[ $opt == -* ]] ; then | |
| # but not the current one! | |
| [[ ! $isCur ]] && options="$options $opt " | |
| last='opt' | |
| continue | |
| fi | |
| else | |
| # onlyarg | |
| let nargs++ | |
| continue | |
| fi | |
| # then we have an argument | |
| if [[ $cmd = 'merge' && ! $URL ]] ; then | |
| # fist argument is the source URL for the merge | |
| URL=$opt | |
| fi | |
| last='arg' | |
| let nargs++ | |
| done | |
| # end opt option processing... | |
| [[ $stat ]] || stat=$last | |
| # suggest all subcommands, including special help | |
| if [[ ! $cmd || $stat = 'cmd' ]] | |
| then | |
| COMPREPLY=( $( compgen -W "$cmds $specOpts" -- $cur ) ) | |
| return 0 | |
| fi | |
| # suggest all subcommands | |
| if [[ $stat = 'help' || ( $isHelpCmd && ! $help ) ]] | |
| then | |
| COMPREPLY=( $( compgen -W "$cmds" -- $cur ) ) | |
| return 0 | |
| fi | |
| # URL completion | |
| if [[ $cmd == @(co|checkout|ls|list) && $stat = 'arg' && \ | |
| $SVN_BASH_COMPL_EXT == *urls* ]] | |
| then | |
| if [[ $cmd == @(ls|list) ]] ; then | |
| _svn_complete_target 'all' && return | |
| else | |
| _svn_complete_target 'remote_only' && return | |
| fi | |
| fi | |
| if [[ $cmd = 'merge' || $cmd = 'mergeinfo' ]] | |
| then | |
| local here=$(_svn_info URL) | |
| # suggest a possible URL for merging | |
| if [[ ! $URL && $stat = 'arg' ]] ; then | |
| # we assume a 'standard' repos with branches and trunk | |
| if [[ "$here" == */branches/* ]] ; then | |
| # we guess that it is a merge from the trunk | |
| COMPREPLY=( $(compgen -W ${here/\/branches\/*/\/trunk} -- $cur ) ) | |
| return 0 | |
| elif [[ "$here" == */trunk* ]] ; then | |
| # we guess that it is a merge from a branch | |
| COMPREPLY=( $(compgen -W ${here/\/trunk*/\/branches\/} -- $cur ) ) | |
| compopt -o nospace | |
| return 0 | |
| else | |
| # no se, let us suggest the repository root... | |
| COMPREPLY=( $(compgen -W $(_svn_info Root)/ -- $cur ) ) | |
| compopt -o nospace | |
| return 0 | |
| fi | |
| # this part is broken with bash 4 URL contains https only | |
| elif [[ $URL == */branches/* && $here == */trunk* && \ | |
| ! $hasReintegrateOpt && $cur = '' && $stat = 'arg' ]] ; then | |
| # force --reintegrate only if the current word is empty | |
| COMPREPLY=( $(compgen -W '--reintegrate' -- $cur ) ) | |
| return 0 | |
| # autocomplete for svn merge ^/bla | |
| else | |
| _svn_complete_target 'all' && return | |
| fi | |
| fi | |
| # help about option arguments | |
| if [[ $stat = 'skip' ]] | |
| then | |
| local previous=${COMP_WORDS[COMP_CWORD-1]} | |
| local values= dirs= beep= exes= | |
| [[ $previous = '--config-dir' ]] && dirs=1 | |
| # external editor, diff, diff3... | |
| [[ $previous = --*-cmd ]] && exes=1 | |
| [[ $previous = '--native-eol' ]] && values='LF CR CRLF' | |
| # just to suggest that a number is expected. hummm. | |
| [[ $previous = '--limit' ]] && values='0 1 2 3 4 5 6 7 8 9' | |
| # some special partial help about --revision option. | |
| [[ $previous = '--revision' || $previous = '-r' ]] && \ | |
| values='HEAD BASE PREV COMMITTED 0 {' | |
| [[ $previous = '--encoding' ]] && \ | |
| values="latin1 utf8 $SVN_BASH_ENCODINGS" | |
| [[ $previous = '--extensions' || $previous = '-x' ]] && \ | |
| values="--unified --ignore-space-change \ | |
| --ignore-all-space --ignore-eol-style --show-c-functions" | |
| [[ $previous = '--depth' ]] && \ | |
| values='empty files immediates infinity' | |
| [[ $previous = '--set-depth' ]] && \ | |
| values='empty exclude files immediates infinity' | |
| [[ $previous = '--accept' ]] && \ | |
| { | |
| # the list is different for 'resolve' | |
| if [[ $cmd = 'resolve' ]] ; then | |
| # from svn help resolve | |
| values='base working mine-full theirs-full' | |
| else # checkout merge switch update | |
| values="postpone base mine-full theirs-full edit launch \ | |
| mine-conflict theirs-conflict" | |
| fi | |
| } | |
| [[ $previous = '--show-revs' ]] && values='merged eligible' | |
| [[ $previous = '--show-item' ]] && values="kind url relative-url \ | |
| repos-root-url repos-uuid revision last-changed-revision \ | |
| last-changed-date last-changed-author wc-root" | |
| if [[ $previous = '--username' ]] ; then | |
| values="$SVN_BASH_USERNAME" | |
| if [[ $SVN_BASH_COMPL_EXT == *username* ]] ; then | |
| local file= | |
| # digest? others? | |
| for file in ~/.subversion/auth/svn.simple/* ; do | |
| if [ -r $file ] ; then | |
| values="$values $(_svn_read_hashfile username < $file)" | |
| fi | |
| done | |
| fi | |
| [[ ! "$values" ]] && beep=1 | |
| fi | |
| # could look at ~/.subversion/ ? | |
| # hmmm... this option should not exist | |
| [[ $previous = '--password' ]] && beep=1 | |
| # TODO: provide help about other options such as: | |
| # --old --new --with-revprop | |
| # if the previous option required a parameter, do something | |
| # or fallback on ordinary filename expansion | |
| [[ $values ]] && COMPREPLY=( $( compgen -W "$values" -- $cur ) ) | |
| [[ $dirs ]] && COMPREPLY=( $( compgen -o dirnames -- $cur ) ) | |
| [[ $exes ]] && COMPREPLY=( $( compgen -c -- $cur ) ) | |
| [[ $beep ]] && | |
| { | |
| # 'no known completion'. hummm. | |
| echo -en "\a" | |
| COMPREPLY=( '' ) | |
| } | |
| return 0 | |
| fi | |
| # provide allowed property names after property commands | |
| if [[ $isPropCmd && ( ! $prop || $stat = 'prop' ) && $cur != -* ]] | |
| then | |
| # | |
| # Ok, this part is pretty ugly. | |
| # | |
| # The issue is that ":" is a completion word separator, | |
| # which is a good idea for file:// urls but not within | |
| # property names... | |
| # | |
| # The first idea was to remove locally ":" from COMP_WORDBREAKS | |
| # and then put it back in all cases but in property name | |
| # completion. It does not always work. There is a strange bug | |
| # where one may get "svn:svn:xxx" in some unclear cases. | |
| # | |
| # Thus the handling is reprogrammed here... | |
| # The code assumes that property names look like *:*, | |
| # but it also works reasonably well with simple names. | |
| # | |
| # This hack is broken in bash4... not sure what to do about it, | |
| # especially while keeping the bash3 compatibility:-( | |
| local choices= | |
| if [[ $cur == *:* ]] | |
| then | |
| # only suggest/show possible suffixes | |
| local prefix=${cur%:*} suffix=${cur#*:} c= | |
| for c in ${allProps[@]} ; do | |
| [[ $c == $prefix:* ]] && choices="$choices ${c#*:}" | |
| done | |
| # everything will be appended to the prefix because ':' is | |
| # a separator, so cur is restricted to the suffix part. | |
| cur=$suffix | |
| else | |
| # only one choice is fine | |
| COMPREPLY=( $( compgen -W "${allProps[*]}" -- $cur ) ) | |
| [ ${#COMPREPLY[@]} -eq 1 ] && return 0 | |
| # no ':' so only suggest prefixes? | |
| local seen= n=0 last= c= | |
| for c in ${allProps[@]%:*} ; do | |
| # do not put the same prefix twice... | |
| if [[ $c == $cur* && ( ! $seen || $c != @($seen) ) ]] | |
| then | |
| let n++ | |
| last=$c | |
| choices="$choices $c:" | |
| if [[ $seen ]] | |
| then | |
| seen="$seen|$c*" | |
| else | |
| seen="$c*" | |
| fi | |
| fi | |
| done | |
| # supply two choices to force a partial completion and a beep | |
| [[ $n -eq 1 ]] && choices="$last:1 $last:2" | |
| fi | |
| COMPREPLY=( $( compgen -W "$choices" -- $cur ) ) | |
| return 0 | |
| fi | |
| # force mandatory --revprop option on revision properties | |
| if [[ $isRevProp && ! $hasRevPropOpt ]] | |
| then | |
| COMPREPLY=( $( compgen -W '--revprop' -- $cur ) ) | |
| return 0 | |
| fi | |
| # force mandatory --revision option on revision properties | |
| if [[ $isRevProp && $hasRevPropOpt && ! $hasRevisionOpt ]] | |
| then | |
| COMPREPLY=( $( compgen -W '--revision' -- $cur ) ) | |
| return 0 | |
| fi | |
| # possible completion when setting property values | |
| if [[ $isPsCmd && $prop && ( ! $val || $stat = 'val' ) ]] | |
| then | |
| # ' is a reminder for an arbitrary value | |
| local values="\' --file" | |
| case $prop in | |
| svn:keywords) | |
| # just a subset? | |
| values="Id Rev URL Date Author Header \' $SVN_BASH_KEYWORDS" | |
| ;; | |
| svn:executable|svn:needs-lock) | |
| # hmmm... canonical value * is special to the shell. | |
| values='\\*' | |
| ;; | |
| svn:eol-style) | |
| values='native LF CR CRLF' | |
| ;; | |
| svn:mime-type) | |
| # could read /etc/mime.types if available. overkill. | |
| values="text/ text/plain text/html text/xml text/rtf | |
| image/ image/png image/gif image/jpeg image/tiff | |
| audio/ audio/midi audio/mpeg | |
| video/ video/mpeg video/mp4 | |
| application/ application/octet-stream | |
| $SVN_BASH_MIME_TYPE" | |
| ;; | |
| esac | |
| COMPREPLY=( $( compgen -W "$values" -- $cur ) ) | |
| # special case for --file... return even if within an option | |
| [[ ${COMPREPLY} ]] && return 0 | |
| fi | |
| # maximum number of additional arguments expected in various forms | |
| case $cmd in | |
| merge) | |
| nExpectArgs=3 | |
| ;; | |
| mergeinfo) | |
| nExpectArgs=1 | |
| ;; | |
| copy|cp|move|mv|rename|ren|export|import) | |
| nExpectArgs=2 | |
| ;; | |
| switch|sw) | |
| [[ ! $hasRelocateOpt ]] && nExpectArgs=2 | |
| ;; | |
| help|h) | |
| nExpectArgs=0 | |
| ;; | |
| --version) | |
| nExpectArgs=0 | |
| ;; | |
| esac | |
| # the maximum number of arguments is reached for a command | |
| if [[ $nExpectArgs && $nargs -gt $nExpectArgs ]] | |
| then | |
| # some way to tell 'no completion at all'... is there a better one? | |
| # Do not say 'file completion' here. | |
| echo -en "\a" | |
| COMPREPLY=( '' ) | |
| return 0 | |
| fi | |
| # if not typing an option, | |
| # then fallback on filename expansion... | |
| if [[ $cur != -* || $stat = 'onlyarg' ]] ; then | |
| # do we allow possible expensive completion here? | |
| if [[ $SVN_BASH_COMPL_EXT == *svnstatus* ]] ; then | |
| # build status command and options | |
| # "--quiet" removes 'unknown' files | |
| local status='svn status --non-interactive' | |
| [[ $SVN_BASH_COMPL_EXT == *recurse* ]] || \ | |
| status="$status --non-recursive" | |
| # I'm not sure that it can work with externals in call cases | |
| # the output contains translatable sentences (even with quiet) | |
| [[ $SVN_BASH_COMPL_EXT == *externals* ]] || \ | |
| status="$status --ignore-externals" | |
| local cs= files= | |
| # subtlety: must not set $cur* if $cur is empty in some cases | |
| [[ $cur ]] && cs=$cur* | |
| # 'files' is set according to the current subcommand | |
| case $cmd in | |
| st*) # status completion must include all files | |
| files=$cur* | |
| ;; | |
| ci|commit|revert|di*) # anything edited | |
| files=$($status $cs| _svn_grcut '@([MADR!]*| M*|_M*)') | |
| ;; | |
| add) # unknown files | |
| files=$($status $cs| _svn_grcut '\?*') | |
| ;; | |
| unlock) # unlock locked files | |
| files=$($status $cs| _svn_grcut '@(??L*|?????[KOTB]*)') | |
| ;; | |
| resolve*) # files in conflict | |
| files=$($status $cs| _svn_grcut '@(?C*|C*)') | |
| ;; | |
| praise|blame|ann*) # any svn file but added | |
| files=$( _svn_lls all $cur* ) | |
| ;; | |
| p*) # prop commands | |
| if [[ $cmd == @($propCmds) && \ | |
| $prop == @(svn:ignore|svn:externals) ]] ; then | |
| # directory specific props | |
| files=$( _svn_lls dir . $cur* ) | |
| else | |
| # ??? added directories appear twice: foo foo/ | |
| files="$( _svn_lls all $cur* ) | |
| $($status $cs | _svn_grcut 'A*' )" | |
| fi | |
| ;; | |
| info) # information on any file | |
| files="$( _svn_lls all $cur* ) | |
| $($status $cs | _svn_grcut 'A*' )" | |
| ;; | |
| remove|rm|del*|move|mv|rename) # changing existing files | |
| files=$( _svn_lls all $cur* ) | |
| ;; | |
| mkdir) # completion in mkdir can only be for subdirs? | |
| files=$( _svn_lls dir $cur* ) | |
| ;; | |
| log|lock|up*|cl*|switch) # misc, all but added files | |
| files=$( _svn_lls all $cur* ) | |
| ;; | |
| merge) # may do a better job? URL/WCPATH | |
| files=$( _svn_lls all $cur* ) | |
| ;; | |
| ls|list) # better job? what about URLs? | |
| files=$( _svn_lls all $cur* ) | |
| ;; | |
| *) # other commands: changelist export import cat mergeinfo | |
| local fallback=1 | |
| ;; | |
| esac | |
| # when not recursive, some relevant files may exist | |
| # within subdirectories, so they are added here. | |
| # should it be restricted to svn-managed subdirs? no?? | |
| if [[ $SVN_BASH_COMPL_EXT != *recurse* ]] ; then | |
| files="$files $( _svn_lls dir $cur* )" | |
| fi | |
| # set completion depending on computed 'files' | |
| if [[ $files ]] ; then | |
| COMPREPLY=( $( compgen -W "$files" -- $cur ) ) | |
| # if empty, set to nope? | |
| [[ "${COMPREPLY[*]}" ]] || COMPREPLY=( '' ) | |
| elif [[ ! $fallback ]] ; then | |
| # this suggests no completion... | |
| echo -en "\a" | |
| COMPREPLY=( '' ) | |
| fi | |
| fi | |
| # else fallback to ordinary filename completion... | |
| return 0 | |
| fi | |
| # otherwise build possible options for the command | |
| pOpts="--username --password --no-auth-cache --non-interactive \ | |
| --trust-server-cert-failures \ | |
| --force-interactive" | |
| mOpts="-m --message -F --file --encoding --force-log --with-revprop" | |
| rOpts="-r --revision" | |
| qOpts="-q --quiet" | |
| nOpts="-N --non-recursive --depth" | |
| gOpts="-g --use-merge-history" | |
| cOpts="--cl --changelist" | |
| cmdOpts= | |
| case $cmd in | |
| --version) | |
| cmdOpts="$qOpts" | |
| ;; | |
| add) | |
| cmdOpts="--auto-props --no-auto-props --force --targets \ | |
| --no-ignore --parents $nOpts $qOpts $pOpts" | |
| ;; | |
| auth) | |
| cmdOpts="--remove --show-passwords $pOpts" | |
| ;; | |
| blame|annotate|ann|praise) | |
| cmdOpts="$rOpts $pOpts -v --verbose --incremental --xml \ | |
| -x --extensions --force $gOpts" | |
| ;; | |
| cat) | |
| cmdOpts="$rOpts $pOpts --ignore-keywords" | |
| ;; | |
| changelist|cl) | |
| cmdOpts="--targets $pOpts $qOpts $cOpts \ | |
| -R --recursive --depth --remove" | |
| ;; | |
| checkout|co) | |
| cmdOpts="$rOpts $qOpts $nOpts $pOpts --ignore-externals \ | |
| --force" | |
| ;; | |
| cleanup) | |
| cmdOpts="--diff3-cmd $pOpts --include-externals -q --quiet\ | |
| --remove-ignored --remove-unversioned" | |
| ;; | |
| commit|ci) | |
| cmdOpts="$mOpts $qOpts $nOpts --targets --editor-cmd $pOpts \ | |
| --no-unlock $cOpts --keep-changelists \ | |
| --include-externals" | |
| ;; | |
| copy|cp) | |
| cmdOpts="$mOpts $rOpts $qOpts --editor-cmd $pOpts --parents \ | |
| --ignore-externals --pin-externals" | |
| ;; | |
| delete|del|remove|rm) | |
| cmdOpts="--force $mOpts $qOpts --targets --editor-cmd $pOpts \ | |
| --keep-local" | |
| ;; | |
| diff|di) | |
| cmdOpts="$rOpts -x --extensions --diff-cmd --no-diff-deleted \ | |
| $nOpts $pOpts --force --old --new --notice-ancestry \ | |
| -c --change --summarize $cOpts --xml --git \ | |
| --internal-diff --show-copies-as-adds \ | |
| --ignore-properties --properties-only --no-diff-added \ | |
| --patch-compatible" | |
| ;; | |
| export) | |
| cmdOpts="$rOpts $qOpts $pOpts $nOpts --force --native-eol \ | |
| --ignore-externals --ignore-keywords" | |
| ;; | |
| help|h|\?) | |
| cmdOpts= | |
| ;; | |
| import) | |
| cmdOpts="--auto-props --no-auto-props $mOpts $qOpts $nOpts \ | |
| --no-ignore --editor-cmd $pOpts --force" | |
| ;; | |
| info) | |
| cmdOpts="$pOpts $rOpts --targets -R --recursive --depth \ | |
| --include-externals --incremental --xml \ | |
| --show-item --no-newline $cOpts" | |
| ;; | |
| list|ls) | |
| cmdOpts="$rOpts -v --verbose -R --recursive $pOpts \ | |
| --incremental --xml --depth --include-externals" | |
| ;; | |
| lock) | |
| cmdOpts="-m --message -F --file --encoding --force-log \ | |
| --targets --force $pOpts" | |
| ;; | |
| log) | |
| cmdOpts="$rOpts -v --verbose --targets $pOpts --stop-on-copy \ | |
| --incremental --xml $qOpts -l --limit -c --change \ | |
| $gOpts --with-all-revprops --with-revprop --depth \ | |
| --diff --diff-cmd -x --extensions --internal-diff \ | |
| --with-no-revprops --search --search-and" | |
| ;; | |
| merge) | |
| cmdOpts="$rOpts $nOpts $qOpts --force --dry-run --diff3-cmd \ | |
| $pOpts --ignore-ancestry -c --change -x --extensions \ | |
| --record-only --accept \ | |
| --allow-mixed-revisions -v --verbose" | |
| ;; | |
| mergeinfo) | |
| cmdOpts="$rOpts $pOpts --depth --show-revs -R --recursive \ | |
| $qOpts -v --verbose --incremental --log" | |
| ;; | |
| mkdir) | |
| cmdOpts="$mOpts $qOpts --editor-cmd $pOpts --parents" | |
| ;; | |
| move|mv|rename|ren) | |
| cmdOpts="$mOpts $rOpts $qOpts --force --editor-cmd $pOpts \ | |
| --parents --allow-mixed-revisions" | |
| ;; | |
| patch) | |
| cmdOpts="$qOpts $pOpts --dry-run --ignore-whitespace \ | |
| --reverse-diff --strip" | |
| ;; | |
| propdel|pdel|pd) | |
| cmdOpts="$qOpts -R --recursive $rOpts $pOpts $cOpts \ | |
| --depth" | |
| [[ $isRevProp || ! $prop ]] && cmdOpts="$cmdOpts --revprop" | |
| ;; | |
| propedit|pedit|pe) | |
| cmdOpts="--editor-cmd $pOpts $mOpts --force" | |
| [[ $isRevProp || ! $prop ]] && \ | |
| cmdOpts="$cmdOpts --revprop $rOpts" | |
| ;; | |
| propget|pget|pg) | |
| cmdOpts="-v --verbose -R --recursive $rOpts --no-newline \ | |
| $pOpts $cOpts --depth --xml --show-inherited-props" | |
| [[ $isRevProp || ! $prop ]] && cmdOpts="$cmdOpts --revprop" | |
| ;; | |
| proplist|plist|pl) | |
| cmdOpts="-v --verbose -R --recursive $rOpts --revprop $qOpts \ | |
| $pOpts $cOpts --depth --xml --show-inherited-props" | |
| ;; | |
| propset|pset|ps) | |
| cmdOpts="$qOpts --targets -R --recursive \ | |
| --encoding $pOpts --force $cOpts --depth" | |
| [[ $isRevProp || ! $prop ]] && \ | |
| cmdOpts="$cmdOpts --revprop $rOpts" | |
| [[ $val ]] || cmdOpts="$cmdOpts -F --file" | |
| ;; | |
| relocate) | |
| cmdOpts="--ignore-externals $pOpts" | |
| ;; | |
| resolve) | |
| cmdOpts="--targets -R --recursive $qOpts $pOpts --accept \ | |
| --depth" | |
| ;; | |
| resolved) | |
| cmdOpts="--targets -R --recursive $qOpts $pOpts --depth" | |
| ;; | |
| revert) | |
| cmdOpts="--targets -R --recursive $qOpts $cOpts \ | |
| --depth $pOpts" | |
| ;; | |
| status|stat|st) | |
| cmdOpts="-u --show-updates -v --verbose $nOpts $qOpts $pOpts \ | |
| --no-ignore --ignore-externals --incremental --xml \ | |
| $rOpts $cOpts" | |
| ;; | |
| switch|sw) | |
| cmdOpts="--relocate $rOpts $nOpts $qOpts $pOpts --diff3-cmd \ | |
| --force --accept --ignore-externals --set-depth \ | |
| --ignore-ancestry" | |
| ;; | |
| unlock) | |
| cmdOpts="--targets --force $pOpts" | |
| ;; | |
| update|up) | |
| cmdOpts="$rOpts $nOpts $qOpts $pOpts --diff3-cmd \ | |
| --ignore-externals --force --accept $cOpts \ | |
| --parents --editor-cmd --set-depth" | |
| ;; | |
| upgrade) | |
| cmdOpts="$qOpts $pOpts" | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| # add options that are nearly always available | |
| [[ "$cmd" != "--version" ]] && cmdOpts="$cmdOpts $helpOpts" | |
| cmdOpts="$cmdOpts --config-dir --config-option" | |
| # --accept (edit|launch) incompatible with --non-interactive | |
| if [[ $acceptOpt == @(edit|launch) ]] ; | |
| then | |
| cmdOpts=${cmdOpts/ --non-interactive / } | |
| fi | |
| # take out options already given | |
| for opt in $options | |
| do | |
| local optBase | |
| # remove leading dashes and arguments | |
| case $opt in | |
| --*) optBase=${opt/=*/} ;; | |
| -*) optBase=${opt:0:2} ;; | |
| esac | |
| cmdOpts=" $cmdOpts " | |
| cmdOpts=${cmdOpts/ ${optBase} / } | |
| # take out alternatives and mutually exclusives | |
| case $optBase in | |
| -v) cmdOpts=${cmdOpts/ --verbose / } ;; | |
| --verbose) cmdOpts=${cmdOpts/ -v / } ;; | |
| -N) cmdOpts=${cmdOpts/ --non-recursive / } ;; | |
| --non-recursive) cmdOpts=${cmdOpts/ -N / } ;; | |
| -R) cmdOpts=${cmdOpts/ --recursive / } ;; | |
| --recursive) cmdOpts=${cmdOpts/ -R / } ;; | |
| -x) cmdOpts=${cmdOpts/ --extensions / } ;; | |
| --extensions) cmdOpts=${cmdOpts/ -x / } ;; | |
| -q) cmdOpts=${cmdOpts/ --quiet / } ;; | |
| --quiet) cmdOpts=${cmdOpts/ -q / } ;; | |
| -h) cmdOpts=${cmdOpts/ --help / } ;; | |
| --help) cmdOpts=${cmdOpts/ -h / } ;; | |
| -l) cmdOpts=${cmdOpts/ --limit / } ;; | |
| --limit) cmdOpts=${cmdOpts/ -l / } ;; | |
| -r) cmdOpts=${cmdOpts/ --revision / } ;; | |
| --revision) cmdOpts=${cmdOpts/ -r / } ;; | |
| -c) cmdOpts=${cmdOpts/ --change / } ;; | |
| --change) cmdOpts=${cmdOpts/ -c / } ;; | |
| --auto-props) cmdOpts=${cmdOpts/ --no-auto-props / } ;; | |
| --no-auto-props) cmdOpts=${cmdOpts/ --auto-props / } ;; | |
| -g) cmdOpts=${cmdOpts/ --use-merge-history / } ;; | |
| --use-merge-history) | |
| cmdOpts=${cmdOpts/ -g / } ;; | |
| -m|--message|-F|--file) | |
| cmdOpts=${cmdOpts/ --message / } | |
| cmdOpts=${cmdOpts/ -m / } | |
| cmdOpts=${cmdOpts/ --file / } | |
| cmdOpts=${cmdOpts/ -F / } | |
| ;; | |
| esac | |
| # remove help options within help subcommand | |
| if [ $isHelpCmd ] ; then | |
| cmdOpts=${cmdOpts/ -h / } | |
| cmdOpts=${cmdOpts/ --help / } | |
| fi | |
| done | |
| # provide help about available options | |
| COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) ) | |
| return 0 | |
| } | |
| complete -F _svn -o default -X '@(*/.svn|*/.svn/|.svn|.svn/)' svn | |
| _svnadmin () | |
| { | |
| local cur cmds cmdOpts optsParam opt helpCmds optBase i | |
| COMPREPLY=() | |
| cur=${COMP_WORDS[COMP_CWORD]} | |
| # Possible expansions, without pure-prefix abbreviations such as "h". | |
| cmds='crashtest create delrevprop deltify dump freeze help hotcopy \ | |
| info list-dblogs \ | |
| list-unused-dblogs load lock lslocks lstxns pack recover rmlocks \ | |
| rmtxns setlog setrevprop setuuid unlock upgrade verify --version' | |
| if [[ $COMP_CWORD -eq 1 ]] ; then | |
| COMPREPLY=( $( compgen -W "$cmds" -- $cur ) ) | |
| return 0 | |
| fi | |
| # options that require a parameter | |
| # note: continued lines must end '|' continuing lines must start '|' | |
| optsParam="-r|--revision|--parent-dir|--fs-type|-M|--memory-cache-size" | |
| optsParam="$optsParam|-F|--file" | |
| # if not typing an option, or if the previous option required a | |
| # parameter, then fallback on ordinary filename expansion | |
| helpCmds='help|--help|h|\?' | |
| if [[ ${COMP_WORDS[1]} != @($helpCmds) ]] && \ | |
| [[ "$cur" != -* ]] || \ | |
| [[ ${COMP_WORDS[COMP_CWORD-1]} == @($optsParam) ]] ; then | |
| return 0 | |
| fi | |
| cmdOpts= | |
| case ${COMP_WORDS[1]} in | |
| create) | |
| cmdOpts="--bdb-txn-nosync --bdb-log-keep --config-dir \ | |
| --fs-type --pre-1.4-compatible --pre-1.5-compatible \ | |
| --pre-1.6-compatible --compatible-version" | |
| ;; | |
| deltify) | |
| cmdOpts="-r --revision -q --quiet" | |
| ;; | |
| dump) | |
| cmdOpts="-r --revision --incremental -q --quiet --deltas \ | |
| -M --memory-cache-size" | |
| ;; | |
| freeze) | |
| cmdOpts="-F --file" | |
| ;; | |
| help|h|\?) | |
| cmdOpts="$cmds" | |
| ;; | |
| hotcopy) | |
| cmdOpts="--clean-logs" | |
| ;; | |
| load) | |
| cmdOpts="--ignore-uuid --force-uuid --parent-dir -q --quiet \ | |
| --use-pre-commit-hook --use-post-commit-hook \ | |
| --bypass-prop-validation -M --memory-cache-size" | |
| ;; | |
| lstxns) | |
| cmdOpts="-r --revision" | |
| ;; | |
| lock|unlock) | |
| cmdOpts="--bypass-hooks" | |
| ;; | |
| recover) | |
| cmdOpts="--wait" | |
| ;; | |
| rmtxns) | |
| cmdOpts="-q --quiet" | |
| ;; | |
| setlog) | |
| cmdOpts="-r --revision --bypass-hooks" | |
| ;; | |
| setrevprop|delrevprop) | |
| cmdOpts="-r --revision -t --transaction \ | |
| --use-pre-revprop-change-hook \ | |
| --use-post-revprop-change-hook" | |
| ;; | |
| verify) | |
| cmdOpts="-r --revision -q --quiet" | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| cmdOpts="$cmdOpts --help -h" | |
| # take out options already given | |
| for (( i=2; i<=$COMP_CWORD-1; ++i )) ; do | |
| opt=${COMP_WORDS[$i]} | |
| case $opt in | |
| --*) optBase=${opt/=*/} ;; | |
| -*) optBase=${opt:0:2} ;; | |
| esac | |
| cmdOpts=" $cmdOpts " | |
| cmdOpts=${cmdOpts/ ${optBase} / } | |
| # take out alternatives | |
| case $optBase in | |
| -q) cmdOpts=${cmdOpts/ --quiet / } ;; | |
| --quiet) cmdOpts=${cmdOpts/ -q / } ;; | |
| -h) cmdOpts=${cmdOpts/ --help / } ;; | |
| --help) cmdOpts=${cmdOpts/ -h / } ;; | |
| -r) cmdOpts=${cmdOpts/ --revision / } ;; | |
| --revision) cmdOpts=${cmdOpts/ -r / } ;; | |
| -t) cmdOpts=${cmdOpts/ --transaction / } ;; | |
| --transaction) cmdOpts=${cmdOpts/ -t / } ;; | |
| -F) cmdOpts=${cmdOpts/ --file / } ;; | |
| --file) cmdOpts=${cmdOpts/ -F / } ;; | |
| -M) cmdOpts=${cmdOpts/ --memory-cache-size / } ;; | |
| --memory-cache-size) cmdOpts=${cmdOpts/ --M / } ;; | |
| esac | |
| # skip next option if this one requires a parameter | |
| if [[ $opt == @($optsParam) ]] ; then | |
| ((++i)) | |
| fi | |
| done | |
| COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) ) | |
| return 0 | |
| } | |
| complete -F _svnadmin -o default svnadmin | |
| _svndumpfilter () | |
| { | |
| local cur cmds cmdOpts optsParam opt helpCmds optBase i | |
| COMPREPLY=() | |
| cur=${COMP_WORDS[COMP_CWORD]} | |
| # Possible expansions, without pure-prefix abbreviations such as "h". | |
| cmds='exclude help include --version' | |
| if [[ $COMP_CWORD -eq 1 ]] ; then | |
| COMPREPLY=( $( compgen -W "$cmds" -- $cur ) ) | |
| return 0 | |
| fi | |
| # options that require a parameter | |
| # note: continued lines must end '|' continuing lines must start '|' | |
| optsParam="--targets" | |
| # if not typing an option, or if the previous option required a | |
| # parameter, then fallback on ordinary filename expansion | |
| helpCmds='help|--help|h|\?' | |
| if [[ ${COMP_WORDS[1]} != @($helpCmds) ]] && \ | |
| [[ "$cur" != -* ]] || \ | |
| [[ ${COMP_WORDS[COMP_CWORD-1]} == @($optsParam) ]] ; then | |
| return 0 | |
| fi | |
| cmdOpts= | |
| case ${COMP_WORDS[1]} in | |
| exclude|include) | |
| cmdOpts="--drop-empty-revs --renumber-revs | |
| --skip-missing-merge-sources --targets | |
| --preserve-revprops --quiet" | |
| ;; | |
| help|h|\?) | |
| cmdOpts="$cmds" | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| cmdOpts="$cmdOpts --help -h" | |
| # take out options already given | |
| for (( i=2; i<=$COMP_CWORD-1; ++i )) ; do | |
| opt=${COMP_WORDS[$i]} | |
| case $opt in | |
| --*) optBase=${opt/=*/} ;; | |
| -*) optBase=${opt:0:2} ;; | |
| esac | |
| cmdOpts=" $cmdOpts " | |
| cmdOpts=${cmdOpts/ ${optBase} / } | |
| # take out alternatives | |
| case $optBase in | |
| -h) cmdOpts=${cmdOpts/ --help / } ;; | |
| --help) cmdOpts=${cmdOpts/ -h / } ;; | |
| esac | |
| # skip next option if this one requires a parameter | |
| if [[ $opt == @($optsParam) ]] ; then | |
| ((++i)) | |
| fi | |
| done | |
| COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) ) | |
| return 0 | |
| } | |
| complete -F _svndumpfilter -o default svndumpfilter | |
| _svnlook () | |
| { | |
| local cur cmds cmdOpts optsParam opt helpCmds optBase i | |
| COMPREPLY=() | |
| cur=${COMP_WORDS[COMP_CWORD]} | |
| # Possible expansions, without pure-prefix abbreviations such as "h". | |
| cmds='author cat changed date diff dirs-changed filesize help history \ | |
| info lock log propget proplist tree uuid youngest --version' | |
| if [[ $COMP_CWORD -eq 1 ]] ; then | |
| COMPREPLY=( $( compgen -W "$cmds" -- $cur ) ) | |
| return 0 | |
| fi | |
| # options that require a parameter | |
| # note: continued lines must end '|' continuing lines must start '|' | |
| optsParam="-r|--revision|-t|--transaction|-l|--limit|-x|--extensions" | |
| # if not typing an option, or if the previous option required a | |
| # parameter, then fallback on ordinary filename expansion | |
| helpCmds='help|--help|h|\?' | |
| if [[ ${COMP_WORDS[1]} != @($helpCmds) ]] && \ | |
| [[ "$cur" != -* ]] || \ | |
| [[ ${COMP_WORDS[COMP_CWORD-1]} == @($optsParam) ]] ; then | |
| return 0 | |
| fi | |
| cmdOpts= | |
| case ${COMP_WORDS[1]} in | |
| author) | |
| cmdOpts="-r --revision -t --transaction" | |
| ;; | |
| cat) | |
| cmdOpts="-r --revision -t --transaction" | |
| ;; | |
| changed) | |
| cmdOpts="-r --revision -t --transaction --copy-info" | |
| ;; | |
| date) | |
| cmdOpts="-r --revision -t --transaction" | |
| ;; | |
| diff) | |
| cmdOpts="-r --revision -t --transaction --diff-copy-from \ | |
| --no-diff-added --no-diff-deleted -x --extensions" | |
| ;; | |
| dirs-changed) | |
| cmdOpts="-r --revision -t --transaction" | |
| ;; | |
| filesize) | |
| cmdOpts="-r --revision -t --transaction" | |
| ;; | |
| help|h|\?) | |
| cmdOpts="$cmds" | |
| ;; | |
| history) | |
| cmdOpts="-r --revision -l --limit --show-ids" | |
| ;; | |
| info) | |
| cmdOpts="-r --revision -t --transaction" | |
| ;; | |
| lock) | |
| cmdOpts= | |
| ;; | |
| log) | |
| cmdOpts="-r --revision -t --transaction" | |
| ;; | |
| propget|pget|pg) | |
| cmdOpts="-r --revision -t --transaction --revprop" | |
| ;; | |
| proplist|plist|pl) | |
| cmdOpts="-r --revision -t --transaction --revprop -v --verbose --xml" | |
| ;; | |
| tree) | |
| cmdOpts="-r --revision -t --transaction --full-paths -N --non-recursive --show-ids" | |
| ;; | |
| uuid) | |
| cmdOpts= | |
| ;; | |
| youngest) | |
| cmdOpts= | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| cmdOpts="$cmdOpts --help -h" | |
| # take out options already given | |
| for (( i=2; i<=$COMP_CWORD-1; ++i )) ; do | |
| opt=${COMP_WORDS[$i]} | |
| case $opt in | |
| --*) optBase=${opt/=*/} ;; | |
| -*) optBase=${opt:0:2} ;; | |
| esac | |
| cmdOpts=" $cmdOpts " | |
| cmdOpts=${cmdOpts/ ${optBase} / } | |
| # take out alternatives | |
| case $optBase in | |
| -N) cmdOpts=${cmdOpts/ --non-recursive / } ;; | |
| --non-recursive) cmdOpts=${cmdOpts/ -N / } ;; | |
| -h) cmdOpts=${cmdOpts/ --help / } ;; | |
| --help) cmdOpts=${cmdOpts/ -h / } ;; | |
| -l) cmdOpts=${cmdOpts/ --limit / } ;; | |
| --limit) cmdOpts=${cmdOpts/ -l / } ;; | |
| -r) cmdOpts=${cmdOpts/ --revision / } ;; | |
| --revision) cmdOpts=${cmdOpts/ -r / } ;; | |
| -t) cmdOpts=${cmdOpts/ --transaction / } ;; | |
| --transaction) cmdOpts=${cmdOpts/ -t / } ;; | |
| -v) cmdOpts=${cmdOpts/ --verbose / } ;; | |
| --verbose) cmdOpts=${cmdOpts/ -v / } ;; | |
| -x) cmdOpts=${cmdOpts/ --extensions / } ;; | |
| --extensions) cmdOpts=${cmdOpts/ -x / } ;; | |
| esac | |
| # skip next option if this one requires a parameter | |
| if [[ $opt == @($optsParam) ]] ; then | |
| ((++i)) | |
| fi | |
| done | |
| COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) ) | |
| return 0 | |
| } | |
| complete -F _svnlook -o default svnlook | |
| _svnsync () | |
| { | |
| local cur cmds cmdOpts optsParam opt helpCmds optBase i | |
| COMPREPLY=() | |
| cur=${COMP_WORDS[COMP_CWORD]} | |
| # Possible expansions, without pure-prefix abbreviations such as "h". | |
| cmds='copy-revprops help info initialize synchronize --version' | |
| if [[ $COMP_CWORD -eq 1 ]] ; then | |
| COMPREPLY=( $( compgen -W "$cmds" -- $cur ) ) | |
| return 0 | |
| fi | |
| # options that require a parameter | |
| # note: continued lines must end '|' continuing lines must start '|' | |
| optsParam="--config-dir|--config-option|--source-username|--source-password" | |
| optsParam="$optsParam|--sync-username|--sync-password" | |
| # if not typing an option, or if the previous option required a | |
| # parameter, then fallback on ordinary filename expansion | |
| helpCmds='help|--help|h|\?' | |
| if [[ ${COMP_WORDS[1]} != @($helpCmds) ]] && \ | |
| [[ "$cur" != -* ]] || \ | |
| [[ ${COMP_WORDS[COMP_CWORD-1]} == @($optsParam) ]] ; then | |
| return 0 | |
| fi | |
| cmdOpts= | |
| case ${COMP_WORDS[1]} in | |
| copy-revprops|initialize|init|synchronize|sync) | |
| cmdOpts="--non-interactive --no-auth-cache --trust-server-cert \ | |
| --source-username --source-password --sync-username \ | |
| --sync-password --config-dir --config-option \ | |
| -q --quiet -M --memory-cache-size" | |
| ;; | |
| help|h|\?) | |
| cmdOpts="$cmds" | |
| ;; | |
| info) | |
| cmdOpts="--non-interactive --no-auth-cache --trust-server-cert \ | |
| --source-username --source-password --sync-username \ | |
| --sync-password --config-dir --config-option" | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| cmdOpts="$cmdOpts --help -h" | |
| # take out options already given | |
| for (( i=2; i<=$COMP_CWORD-1; ++i )) ; do | |
| opt=${COMP_WORDS[$i]} | |
| case $opt in | |
| --*) optBase=${opt/=*/} ;; | |
| -*) optBase=${opt:0:2} ;; | |
| esac | |
| cmdOpts=" $cmdOpts " | |
| cmdOpts=${cmdOpts/ ${optBase} / } | |
| # take out alternatives | |
| case $optBase in | |
| -h) cmdOpts=${cmdOpts/ --help / } ;; | |
| --help) cmdOpts=${cmdOpts/ -h / } ;; | |
| -q) cmdOpts=${cmdOpts/ --quiet / } ;; | |
| --quiet) cmdOpts=${cmdOpts/ -q / } ;; | |
| esac | |
| # skip next option if this one requires a parameter | |
| if [[ $opt == @($optsParam) ]] ; then | |
| ((++i)) | |
| fi | |
| done | |
| COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) ) | |
| return 0 | |
| } | |
| complete -F _svnsync -o default svnsync | |
| # reasonable completion for 'svnversion' | |
| _svnversion () | |
| { | |
| local cmdOpts=" -n --no-newline -c --committed -h --help --version " | |
| local cur=${COMP_WORDS[COMP_CWORD]} | |
| COMPREPLY=() | |
| # parse current options | |
| local options= wcpath= trailurl= last='none' stat= opt= i=-1 isCur= | |
| for opt in ${COMP_WORDS[@]} | |
| do | |
| [[ $i -eq $COMP_CWORD ]] && stat=$last | |
| let i++ | |
| # are we processing the current word? | |
| isCur= | |
| [[ $i -eq $COMP_CWORD ]] && isCur=1 | |
| # skip first command, should be 'svnversion' | |
| if [ $last = 'none' ] ; then | |
| last='first' | |
| continue | |
| fi | |
| # get options | |
| if [[ $last != 'arg' && $opt == -* ]] | |
| then | |
| # if '--' is at the current position, it means that we are looking | |
| # for '--*' options, and not the end of option processing. | |
| if [[ $opt = '--' && ! $isCur ]] | |
| then | |
| last='arg' | |
| else | |
| options="$options $opt " | |
| last='opt' | |
| fi | |
| continue | |
| fi | |
| # get arguments | |
| if [[ $opt != -* ]] | |
| then | |
| last='arg' | |
| if [[ ! $wcpath ]] | |
| then | |
| wcpath=$opt | |
| elif [[ ! $trailurl ]] | |
| then | |
| trailurl=$opt | |
| fi | |
| fi | |
| done | |
| [[ $stat ]] || stat=$last | |
| # argument part | |
| if [[ $cur != -* || $stat = 'arg' ]] | |
| then | |
| [[ $wcpath && $trailurl ]] && COMPREPLY=( '' ) | |
| return 0 | |
| fi | |
| # suggest options, and take out already given options | |
| for opt in $options | |
| do | |
| # take out options | |
| cmdOpts=${cmdOpts/ $opt / } | |
| # take out alternatives | |
| case $opt in | |
| -n) cmdOpts=${cmdOpts/ --no-newline / } ;; | |
| --no-newline) cmdOpts=${cmdOpts/ -n / } ;; | |
| -h) cmdOpts=${cmdOpts/ --help / } ;; | |
| --help) cmdOpts=${cmdOpts/ -h / } ;; | |
| -c) cmdOpts=${cmdOpts/ --committed / } ;; | |
| --committed) cmdOpts=${cmdOpts/ -c / } ;; | |
| esac | |
| done | |
| COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) ) | |
| return 0 | |
| } | |
| # -X option does not seem to work? | |
| complete -F _svnversion -o dirnames -X '*.svn*' svnversion |