Merge branch 'sg/complete-refs'
authorJunio C Hamano <gitster@pobox.com>
Fri, 9 Dec 2011 21:37:18 +0000 (13:37 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 9 Dec 2011 21:37:18 +0000 (13:37 -0800)
* sg/complete-refs:
completion: remove broken dead code from __git_heads() and __git_tags()
completion: fast initial completion for config 'remote.*.fetch' value
completion: improve ls-remote output filtering in __git_refs_remotes()
completion: query only refs/heads/ in __git_refs_remotes()
completion: support full refs from remote repositories
completion: improve ls-remote output filtering in __git_refs()
completion: make refs completion consistent for local and remote repos
completion: optimize refs completion
completion: document __gitcomp()

Conflicts:
contrib/completion/git-completion.bash

1  2 
contrib/completion/git-completion.bash
index b7c1edf1cc763199d41a490b212a3b65ea581a86,16623d7c3f001201819949fdf9c006e968e42369..cc1bdf960949cfeb977d8a188a2324b48bf5c6df
@@@ -110,7 -110,6 +110,7 @@@ __git_ps1_show_upstream (
        local upstream=git legacy="" verbose=""
  
        # get some config options from git-config
 +      local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
        while read key value; do
                case "$key" in
                bash.showupstream)
                        upstream=svn+git # default upstream is SVN if available, else git
                        ;;
                esac
 -      done < <(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')
 +      done <<< "$output"
  
        # parse configuration values
        for option in ${GIT_PS1_SHOWUPSTREAM}; do
@@@ -486,8 -485,13 +486,13 @@@ _get_comp_words_by_ref (
  fi
  fi
  
- # __gitcomp accepts 1, 2, 3, or 4 arguments
- # generates completion reply with compgen
+ # Generates completion reply with compgen, appending a space to possible
+ # completion words, if necessary.
+ # It accepts 1 to 4 arguments:
+ # 1: List of possible completion words.
+ # 2: A prefix to be added to each possible completion word (optional).
+ # 3: Generate possible completion matches for this word (optional).
+ # 4: A suffix to be appended to each possible completion word (optional).
  __gitcomp ()
  {
        local cur_="$cur"
        esac
  }
  
- # __git_heads accepts 0 or 1 arguments (to pass to __gitdir)
+ # Generates completion reply with compgen from newline-separated possible
+ # completion words by appending a space to all of them.
+ # It accepts 1 to 4 arguments:
+ # 1: List of possible completion words, separated by a single newline.
+ # 2: A prefix to be added to each possible completion word (optional).
+ # 3: Generate possible completion matches for this word (optional).
+ # 4: A suffix to be appended to each possible completion word instead of
+ #    the default space (optional).  If specified but empty, nothing is
+ #    appended.
+ __gitcomp_nl ()
+ {
+       local s=$'\n' IFS=' '$'\t'$'\n'
+       local cur_="$cur" suffix=" "
+       if [ $# -gt 2 ]; then
+               cur_="$3"
+               if [ $# -gt 3 ]; then
+                       suffix="$4"
+               fi
+       fi
+       IFS=$s
+       COMPREPLY=($(compgen -P "${2-}" -S "$suffix" -W "$1" -- "$cur_"))
+ }
  __git_heads ()
  {
-       local cmd i is_hash=y dir="$(__gitdir "${1-}")"
+       local dir="$(__gitdir)"
        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
  }
  
- # __git_tags accepts 0 or 1 arguments (to pass to __gitdir)
  __git_tags ()
  {
-       local cmd i is_hash=y dir="$(__gitdir "${1-}")"
+       local dir="$(__gitdir)"
        if [ -d "$dir" ]; then
                git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
                        refs/tags
                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/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
-               n,*) is_hash=y; echo "$i" ;;
-               esac
-       done
  }
  
  # __git_refs accepts 0, 1 (to pass to __gitdir), or 2 arguments
  # by checkout for tracking branches
  __git_refs ()
  {
-       local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}"
+       local i hash dir="$(__gitdir "${1-}")" track="${2-}"
        local format refs
        if [ -d "$dir" ]; then
                case "$cur" in
                fi
                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
+       case "$cur" in
+       refs|refs/*)
+               git ls-remote "$dir" "$cur*" 2>/dev/null | \
+               while read hash i; do
+                       case "$i" in
+                       *^{}) ;;
+                       *) echo "$i" ;;
+                       esac
+               done
+               ;;
+       *)
+               git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \
+               while read hash i; do
+                       case "$i" in
+                       *^{}) ;;
+                       refs/*) echo "${i#refs/*/}" ;;
+                       *) echo "$i" ;;
+                       esac
+               done
+               ;;
+       esac
  }
  
  # __git_refs2 requires 1 argument (to pass to __git_refs)
@@@ -611,18 -633,10 +634,10 @@@ __git_refs2 (
  # __git_refs_remotes requires 1 argument (to pass to ls-remote)
  __git_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
+       local i hash
+       git ls-remote "$1" 'refs/heads/*' 2>/dev/null | \
+       while read hash i; do
+               echo "$i:refs/remotes/$1/${i#refs/heads/}"
        done
  }
  
@@@ -712,15 -726,15 +727,15 @@@ __git_complete_revlist_file (
        *...*)
                pfx="${cur_%...*}..."
                cur_="${cur_#*...}"
-               __gitcomp "$(__git_refs)" "$pfx" "$cur_"
+               __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
                ;;
        *..*)
                pfx="${cur_%..*}.."
                cur_="${cur_#*..}"
-               __gitcomp "$(__git_refs)" "$pfx" "$cur_"
+               __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
                ;;
        *)
-               __gitcomp "$(__git_refs)"
+               __gitcomp_nl "$(__git_refs)"
                ;;
        esac
  }
@@@ -760,7 -774,7 +775,7 @@@ __git_complete_remote_or_refspec (
                c=$((++c))
        done
        if [ -z "$remote" ]; then
-               __gitcomp "$(__git_remotes)"
+               __gitcomp_nl "$(__git_remotes)"
                return
        fi
        if [ $no_complete_refspec = 1 ]; then
        case "$cmd" in
        fetch)
                if [ $lhs = 1 ]; then
-                       __gitcomp "$(__git_refs2 "$remote")" "$pfx" "$cur_"
+                       __gitcomp_nl "$(__git_refs2 "$remote")" "$pfx" "$cur_"
                else
-                       __gitcomp "$(__git_refs)" "$pfx" "$cur_"
+                       __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
                fi
                ;;
        pull)
                if [ $lhs = 1 ]; then
-                       __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur_"
+                       __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_"
                else
-                       __gitcomp "$(__git_refs)" "$pfx" "$cur_"
+                       __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
                fi
                ;;
        push)
                if [ $lhs = 1 ]; then
-                       __gitcomp "$(__git_refs)" "$pfx" "$cur_"
+                       __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
                else
-                       __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur_"
+                       __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_"
                fi
                ;;
        esac
@@@ -1080,7 -1094,7 +1095,7 @@@ _git_archive (
                return
                ;;
        --remote=*)
-               __gitcomp "$(__git_remotes)" "" "${cur##--remote=}"
+               __gitcomp_nl "$(__git_remotes)" "" "${cur##--remote=}"
                return
                ;;
        --*)
@@@ -1111,7 -1125,7 +1126,7 @@@ _git_bisect (
  
        case "$subcommand" in
        bad|good|reset|skip|start)
-               __gitcomp "$(__git_refs)"
+               __gitcomp_nl "$(__git_refs)"
                ;;
        *)
                COMPREPLY=()
@@@ -1142,9 -1156,9 +1157,9 @@@ _git_branch (
                ;;
        *)
                if [ $only_local_ref = "y" -a $has_r = "n" ]; then
-                       __gitcomp "$(__git_heads)"
+                       __gitcomp_nl "$(__git_heads)"
                else
-                       __gitcomp "$(__git_refs)"
+                       __gitcomp_nl "$(__git_refs)"
                fi
                ;;
        esac
@@@ -1191,7 -1205,7 +1206,7 @@@ _git_checkout (
                if [ -n "$(__git_find_on_cmdline "$flags")" ]; then
                        track=''
                fi
-               __gitcomp "$(__git_refs '' $track)"
+               __gitcomp_nl "$(__git_refs '' $track)"
                ;;
        esac
  }
@@@ -1208,7 -1222,7 +1223,7 @@@ _git_cherry_pick (
                __gitcomp "--edit --no-commit"
                ;;
        *)
-               __gitcomp "$(__git_refs)"
+               __gitcomp_nl "$(__git_refs)"
                ;;
        esac
  }
@@@ -1262,7 -1276,7 +1277,7 @@@ _git_commit (
                ;;
        --reuse-message=*|--reedit-message=*|\
        --fixup=*|--squash=*)
-               __gitcomp "$(__git_refs)" "" "${cur#*=}"
+               __gitcomp_nl "$(__git_refs)" "" "${cur#*=}"
                return
                ;;
        --untracked-files=*)
@@@ -1293,7 -1307,7 +1308,7 @@@ _git_describe (
                        "
                return
        esac
-       __gitcomp "$(__git_refs)"
+       __gitcomp_nl "$(__git_refs)"
  }
  
  __git_diff_common_options="--stat --numstat --shortstat --summary
@@@ -1430,10 -1444,6 +1445,10 @@@ _git_gitk (
        _gitk
  }
  
 +__git_match_ctag() {
 +      awk "/^${1////\\/}/ { print \$1 }" "$2"
 +}
 +
  _git_grep ()
  {
        __git_has_doubledash && return
                ;;
        esac
  
-                       __gitcomp "$(__git_match_ctag "$cur" tags)"
 +      case "$cword,$prev" in
 +      2,*|*,-*)
 +              if test -r tags; then
-       __gitcomp "$(__git_refs)"
++                      __gitcomp_nl "$(__git_match_ctag "$cur" tags)"
 +                      return
 +              fi
 +              ;;
 +      esac
 +
+       __gitcomp_nl "$(__git_refs)"
  }
  
  _git_help ()
@@@ -1523,7 -1524,7 +1538,7 @@@ _git_ls_files (
  
  _git_ls_remote ()
  {
-       __gitcomp "$(__git_remotes)"
+       __gitcomp_nl "$(__git_remotes)"
  }
  
  _git_ls_tree ()
@@@ -1619,7 -1620,7 +1634,7 @@@ _git_merge (
                __gitcomp "$__git_merge_options"
                return
        esac
-       __gitcomp "$(__git_refs)"
+       __gitcomp_nl "$(__git_refs)"
  }
  
  _git_mergetool ()
  
  _git_merge_base ()
  {
-       __gitcomp "$(__git_refs)"
+       __gitcomp_nl "$(__git_refs)"
  }
  
  _git_mv ()
@@@ -1670,7 -1671,7 +1685,7 @@@ _git_notes (
        ,*)
                case "${words[cword-1]}" in
                --ref)
-                       __gitcomp "$(__git_refs)"
+                       __gitcomp_nl "$(__git_refs)"
                        ;;
                *)
                        __gitcomp "$subcommands --ref"
                ;;
        add,--reuse-message=*|append,--reuse-message=*|\
        add,--reedit-message=*|append,--reedit-message=*)
-               __gitcomp "$(__git_refs)" "" "${cur#*=}"
+               __gitcomp_nl "$(__git_refs)" "" "${cur#*=}"
                ;;
        add,--*|append,--*)
                __gitcomp '--file= --message= --reedit-message=
                -m|-F)
                        ;;
                *)
-                       __gitcomp "$(__git_refs)"
+                       __gitcomp_nl "$(__git_refs)"
                        ;;
                esac
                ;;
@@@ -1726,12 -1727,12 +1741,12 @@@ _git_push (
  {
        case "$prev" in
        --repo)
-               __gitcomp "$(__git_remotes)"
+               __gitcomp_nl "$(__git_remotes)"
                return
        esac
        case "$cur" in
        --repo=*)
-               __gitcomp "$(__git_remotes)" "" "${cur##--repo=}"
+               __gitcomp_nl "$(__git_remotes)" "" "${cur##--repo=}"
                return
                ;;
        --*)
@@@ -1769,7 -1770,7 +1784,7 @@@ _git_rebase (
  
                return
        esac
-       __gitcomp "$(__git_refs)"
+       __gitcomp_nl "$(__git_refs)"
  }
  
  _git_reflog ()
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
        else
-               __gitcomp "$(__git_refs)"
+               __gitcomp_nl "$(__git_refs)"
        fi
  }
  
@@@ -1862,23 -1863,27 +1877,27 @@@ _git_config (
  {
        case "$prev" in
        branch.*.remote)
-               __gitcomp "$(__git_remotes)"
+               __gitcomp_nl "$(__git_remotes)"
                return
                ;;
        branch.*.merge)
-               __gitcomp "$(__git_refs)"
+               __gitcomp_nl "$(__git_refs)"
                return
                ;;
        remote.*.fetch)
                local remote="${prev#remote.}"
                remote="${remote%.fetch}"
-               __gitcomp "$(__git_refs_remotes "$remote")"
+               if [ -z "$cur" ]; then
+                       COMPREPLY=("refs/heads/")
+                       return
+               fi
+               __gitcomp_nl "$(__git_refs_remotes "$remote")"
                return
                ;;
        remote.*.push)
                local remote="${prev#remote.}"
                remote="${remote%.push}"
-               __gitcomp "$(git --git-dir="$(__gitdir)" \
+               __gitcomp_nl "$(git --git-dir="$(__gitdir)" \
                        for-each-ref --format='%(refname):%(refname)' \
                        refs/heads)"
                return
                return
                ;;
        --get|--get-all|--unset|--unset-all)
-               __gitcomp "$(__git_config_get_set_variables)"
+               __gitcomp_nl "$(__git_config_get_set_variables)"
                return
                ;;
        *.*)
                ;;
        branch.*)
                local pfx="${cur%.*}." cur_="${cur#*.}"
-               __gitcomp "$(__git_heads)" "$pfx" "$cur_" "."
+               __gitcomp_nl "$(__git_heads)" "$pfx" "$cur_" "."
                return
                ;;
        guitool.*.*)
        pager.*)
                local pfx="${cur%.*}." cur_="${cur#*.}"
                __git_compute_all_commands
-               __gitcomp "$__git_all_commands" "$pfx" "$cur_"
+               __gitcomp_nl "$__git_all_commands" "$pfx" "$cur_"
                return
                ;;
        remote.*.*)
                ;;
        remote.*)
                local pfx="${cur%.*}." cur_="${cur#*.}"
-               __gitcomp "$(__git_remotes)" "$pfx" "$cur_" "."
+               __gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
                return
                ;;
        url.*.*)
@@@ -2294,7 -2299,7 +2313,7 @@@ _git_remote (
  
        case "$subcommand" in
        rename|rm|show|prune)
-               __gitcomp "$(__git_remotes)"
+               __gitcomp_nl "$(__git_remotes)"
                ;;
        update)
                local i c='' IFS=$'\n'
  
  _git_replace ()
  {
-       __gitcomp "$(__git_refs)"
+       __gitcomp_nl "$(__git_refs)"
  }
  
  _git_reset ()
                return
                ;;
        esac
-       __gitcomp "$(__git_refs)"
+       __gitcomp_nl "$(__git_refs)"
  }
  
  _git_revert ()
                return
                ;;
        esac
-       __gitcomp "$(__git_refs)"
+       __gitcomp_nl "$(__git_refs)"
  }
  
  _git_rm ()
@@@ -2435,7 -2440,7 +2454,7 @@@ _git_stash (
                        COMPREPLY=()
                        ;;
                show,*|apply,*|drop,*|pop,*|branch,*)
-                       __gitcomp "$(git --git-dir="$(__gitdir)" stash list \
+                       __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \
                                        | sed -n -e 's/:.*//p')"
                        ;;
                *)
@@@ -2569,7 -2574,7 +2588,7 @@@ _git_tag (
                i="${words[c]}"
                case "$i" in
                -d|-v)
-                       __gitcomp "$(__git_tags)"
+                       __gitcomp_nl "$(__git_tags)"
                        return
                        ;;
                -f)
                ;;
        -*|tag)
                if [ $f = 1 ]; then
-                       __gitcomp "$(__git_tags)"
+                       __gitcomp_nl "$(__git_tags)"
                else
                        COMPREPLY=()
                fi
                ;;
        *)
-               __gitcomp "$(__git_refs)"
+               __gitcomp_nl "$(__git_refs)"
                ;;
        esac
  }