The script is based on git's bash completion script. Signed-off-by: Jonas Fonseca <fonseca@xxxxxxx> --- contrib/tg-completion.bash | 438 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 438 insertions(+), 0 deletions(-) create mode 100755 contrib/tg-completion.bash I have RFC'd this because I am still a topgit noob. diff --git a/contrib/tg-completion.bash b/contrib/tg-completion.bash new file mode 100755 index 0000000..35eabe9 --- /dev/null +++ b/contrib/tg-completion.bash @@ -0,0 +1,438 @@ +# +# bash completion support for TopGit. +# +# Copyright (C) 2008 Jonas Fonseca <fonseca@xxxxxxx> +# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@xxxxxxxxxxx> +# Based git's git-completion.sh: http://repo.or.cz/w/git/fastimport.git +# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/). +# Distributed under the GNU General Public License, version 2.0. +# +# The contained completion routines provide support for completing: +# +# *) local and remote branch names +# *) local and remote tag names +# *) .git/remotes file names +# *) git 'subcommands' +# *) tree paths within 'ref:path/to/file' expressions +# *) common --long-options +# +# To use these routines: +# +# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh). +# 2) Added the following line to your .bashrc: +# source ~/.git-completion.sh +# +# 3) You may want to make sure the git executable is available +# in your PATH before this script is sourced, as some caching +# is performed while the script loads. If git isn't found +# at source time then all lookups will be done on demand, +# which may be slightly slower. +# +# 4) Consider changing your PS1 to also show the current branch: +# PS1='[\u@\h \W$(__tg_ps1 " (%s)")]\$ ' +# +# The argument to __tg_ps1 will be displayed only if you +# are currently in a git repository. The %s token will be + +case "$COMP_WORDBREAKS" in +*:*) : great ;; +*) COMP_WORDBREAKS="$COMP_WORDBREAKS:" +esac + +### {{{ Utilities + +__tgdir () +{ + if [ -z "$1" ]; then + if [ -n "$__tg_dir" ]; then + echo "$__tg_dir" + elif [ -d .git ]; then + echo .git + else + git rev-parse --git-dir 2>/dev/null + fi + elif [ -d "$1/.git" ]; then + echo "$1/.git" + else + echo "$1" + fi +} + +__tgcomp_1 () +{ + local c IFS=' '$'\t'$'\n' + for c in $1; do + case "$c$2" in + --*=*) printf %s$'\n' "$c$2" ;; + *.) printf %s$'\n' "$c$2" ;; + *) printf %s$'\n' "$c$2 " ;; + esac + done +} + +__tgcomp () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + if [ $# -gt 2 ]; then + cur="$3" + fi + case "$cur" in + --*=) + COMPREPLY=() + ;; + *) + local IFS=$'\n' + COMPREPLY=($(compgen -P "$2" \ + -W "$(__tgcomp_1 "$1" "$4")" \ + -- "$cur")) + ;; + esac +} + +__tg_heads () +{ + local cmd i is_hash=y dir="$(__tgdir "$1")" + if [ -d "$dir" ]; then + git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + refs/heads + return + fi + for i in $(git ls-remote "$1" 2>/dev/null); do + case "$is_hash,$i" in + y,*) is_hash=n ;; + n,*^{}) is_hash=y ;; + n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;; + n,*) is_hash=y; echo "$i" ;; + esac + done +} + +__tg_refs () +{ + local cmd i is_hash=y dir="$(__tgdir "$1")" + if [ -d "$dir" ]; then + if [ -e "$dir/HEAD" ]; then echo HEAD; fi + git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + refs/tags refs/heads refs/remotes + return + fi + for i in $(git ls-remote "$dir" 2>/dev/null); do + case "$is_hash,$i" in + y,*) is_hash=n ;; + n,*^{}) is_hash=y ;; + n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;; + n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;; + n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;; + n,*) is_hash=y; echo "$i" ;; + esac + done +} + +__tg_refs2 () +{ + local i + for i in $(__tg_refs "$1"); do + echo "$i:$i" + done +} + +__tg_refs_remotes () +{ + local cmd i is_hash=y + for i in $(git ls-remote "$1" 2>/dev/null); do + case "$is_hash,$i" in + n,refs/heads/*) + is_hash=y + echo "$i:refs/remotes/$1/${i#refs/heads/}" + ;; + y,*) is_hash=n ;; + n,*^{}) is_hash=y ;; + n,refs/tags/*) is_hash=y;; + n,*) is_hash=y; ;; + esac + done +} + +__tg_remotes () +{ + local i ngoff IFS=$'\n' d="$(__tgdir)" + shopt -q nullglob || ngoff=1 + shopt -s nullglob + for i in "$d/remotes"/*; do + echo ${i#$d/remotes/} + done + [ "$ngoff" ] && shopt -u nullglob + for i in $(git --git-dir="$d" config --list); do + case "$i" in + remote.*.url=*) + i="${i#remote.}" + echo "${i/.url=*/}" + ;; + esac + done +} + +__tg_complete_revlist () +{ + local pfx cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + *...*) + pfx="${cur%...*}..." + cur="${cur#*...}" + __tgcomp "$(__tg_refs)" "$pfx" "$cur" + ;; + *..*) + pfx="${cur%..*}.." + cur="${cur#*..}" + __tgcomp "$(__tg_refs)" "$pfx" "$cur" + ;; + *) + __tgcomp "$(__tg_refs)" + ;; + esac +} + +__tg_topics () +{ + tg summary | cut -f 2 +} + +__tg_commands () +{ + if [ -n "$__tg_all_commandlist" ]; then + echo "$__tg_all_commandlist" + return + fi + local i IFS=" "$'\n' + for i in $(tg help | sed -n 's/^Usage:.*(\(.*\)).*/\1/p' | tr '|' ' ') + do + case $i in + *--*) : helper pattern;; + *) echo $i;; + esac + done +} +__tg_all_commandlist= +__tg_all_commandlist="$(__tg_commands 2>/dev/null)" + +__tg_complete_arg () +{ + if [ $COMP_CWORD -gt 2 ] && [ "${COMP_WORDS[$COMP_CWORD - 1]}" = "$1" ]; then + return 0 + fi + return 1 +} + +### }}} +### {{{ Commands + +_tg_create () +{ + local cmd="$1" + local cur="${COMP_WORDS[COMP_CWORD]}" + + # Name must be the first arg after the create command + if [ $((cmd + 1)) = $COMP_CWORD ]; then + __tgcomp "$(__tg_topics)" + return + fi + + __tg_complete_arg "-r" && { + __tgcomp "$(__tg_remotes)" + return + } + + case "$cur" in + -*) + __tgcomp " + -r + " + ;; + *) + __tgcomp "$(__tg_refs)" + esac +} + +_tg_delete () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + case "$cur" in + -*) + __tgcomp " + -f + " + ;; + *) + __tgcomp "$(__tg_topics)" + esac +} + +_tg_export () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + __tg_complete_arg "--collapse" && { + __tgcomp "$(__tg_heads)" + return + } + + __tg_complete_arg "--quilt" && { + return + } + + case "$cur" in + *) + __tgcomp " + --collapse + --quilt + " + esac +} + +_tg_help () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + -*) + COMPREPLY=() + return + ;; + esac + __tgcomp "$(__tg_commands)" +} + +_tg_import () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + __tg_complete_arg "-p" && { + COMPREPLY=() + return + } + + case "$cur" in + -*) + __tgcomp " + -p + " + ;; + *) + __tg_complete_revlist + esac +} + +_tg_info () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + case "$cur" in + *) + __tgcomp "$(__tg_topics)" + esac +} + +_tg_mail () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + case "$cur" in + *) + __tgcomp "$(__tg_topics)" + esac +} + +_tg_patch () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + case "$cur" in + *) + __tgcomp "$(__tg_topics)" + esac +} + +_tg_remote () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + + case "$cur" in + *) + __tgcomp "$(__tg_remotes)" + esac +} + +_tg_summary () +{ + COMPREPLY=() +} + +_tg_update () +{ + COMPREPLY=() +} + +### }}} +### {{{ tg completion + +_tg () +{ + local i c=1 command __tg_dir + + while [ $c -lt $COMP_CWORD ]; do + i="${COMP_WORDS[c]}" + case "$i" in + -r) + c=$((++c)) + if [ $c -lt $COMP_CWORD ]; then + __tgcomp "$(__tg_remotes)" + return + fi + ;; + -h|--help) command="help"; break ;; + *) command="$i"; break ;; + esac + c=$((++c)) + done + + if [ -z "$command" ]; then + case "${COMP_WORDS[COMP_CWORD]}" in + -*) __tgcomp " + -r + -h + --help + " + ;; + *) __tgcomp "$(__tg_commands)" ;; + esac + return + fi + + case "$command" in + create) _tg_create "$c" ;; + delete) _tg_delete ;; + export) _tg_export ;; + help) _tg_help ;; + import) _tg_import ;; + info) _tg_info ;; + mail) _tg_mail ;; + patch) _tg_patch ;; + remote) _tg_remote ;; + summary) _tg_summary ;; + update) _tg_update ;; + *) COMPREPLY=() ;; + esac +} + +### }}} + + __tgcomp "$(__tg_refs top-bases)" +complete -o default -o nospace -F _tg tg + +# The following are necessary only for Cygwin, and only are needed +# when the user has tab-completed the executable name and consequently +# included the '.exe' suffix. +# +if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then +complete -o default -o nospace -F _tg tg.exe +fi -- 1.6.0.2.471.g47a76.dirty -- Jonas Fonseca -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html