{"thread":{"id":"25550","subject":"[PATCH/RFC] Make git-completion Bash 4 compatible.","startedAt":"2010-10-26T13:53:19Z","lastAt":"2010-10-26T14:14:33Z","messageCount":2,"participants":["Peter van der Does","Marc Branchaud"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"154447","messageId":"20101026095319.669c0d69@montecarlo.grandprix.int","threadId":"25550","inReplyTo":null,"subject":"[PATCH/RFC] Make git-completion Bash 4 compatible.","fromName":"Peter van der Does","fromEmail":"peter@avirtualhome.com","sentAt":"2010-10-26T13:53:19Z","receivedAt":"2010-10-26T13:53:19Z","isPatch":true,"sender":{"key":"peter@avirtualhome.com","avatar":"https://avatars.githubusercontent.com/u/380071?v=4"},"body":"\nThe completion script does not work as expected under Bash 4.\nBash: 3\noutput:\n$ git log --pretty=<tab><tab>\nemail     full      medium    raw\nformat:   fuller    oneline   short\n\nBash: 4\noutput:\n$ git log --pretty=<tab><tab>\n.bash_logout         .local/\n.bash_profile        Music/\n--More--\n\nSigned-off-by: Peter van der Does <peter@avirtualhome.com>\n---\n contrib/completion/git-completion.bash |  419 +++++++++++++++++++++++++++-----\n 1 files changed, 357 insertions(+), 62 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex f83f019..becabd0 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -71,12 +71,251 @@\n #\n #       git@vger.kernel.org\n #\n+# Updated for Bash 4.0\n \n case \"$COMP_WORDBREAKS\" in\n *:*) : great ;;\n *)   COMP_WORDBREAKS=\"$COMP_WORDBREAKS:\"\n esac\n \n+# If the function _get_comp_words_by_ref does not exists, we can assume the\n+# bash_completion 1.2 script isn't loaded and therefor we're defining the\n+# necessary functions ourselves.\n+if ! type _get_comp_words_by_ref &> /dev/null ; then\n+\t# Assign variable one scope above the caller\n+\t# Usage: local \"$1\" && _upvar $1 \"value(s)\"\n+\t# Param: $1  Variable name to assign value to\n+\t# Param: $*  Value(s) to assign.  If multiple values, an array is\n+\t#            assigned, otherwise a single value is assigned.\n+\t# NOTE: For assigning multiple variables, use '_upvars'.  Do NOT\n+\t#       use multiple '_upvar' calls, since one '_upvar' call might\n+\t#       reassign a variable to be used by another '_upvar' call.\n+\t# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference\n+\t_upvar() {\n+\t\tif unset -v \"$1\"; then           # Unset & validate varname\n+\t        if (( $# == 2 )); then\n+\t            eval $1=\\\"\\$2\\\"          # Return single value\n+\t        else\n+\t            eval $1=\\(\\\"\\${@:2}\\\"\\)  # Return array\n+\t        fi\n+\t    fi\n+\t}\n+\n+\n+\t# Assign variables one scope above the caller\n+\t# Usage: local varname [varname ...] &&\n+\t#        _upvars [-v varname value] | [-aN varname [value ...]] ...\n+\t# Available OPTIONS:\n+\t#     -aN  Assign next N values to varname as array\n+\t#     -v   Assign single value to varname\n+\t# Return: 1 if error occurs\n+\t# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference\n+\t_upvars() {\n+\t    if ! (( $# )); then\n+\t        echo \"${FUNCNAME[0]}: usage: ${FUNCNAME[0]} [-v varname\"\\\n+\t            \"value] | [-aN varname [value ...]] ...\" 1>&2\n+\t        return 2\n+\t    fi\n+\t    while (( $# )); do\n+\t        case $1 in\n+\t            -a*)\n+\t                # Error checking\n+\t                [[ ${1#-a} ]] || { echo \"bash: ${FUNCNAME[0]}: \\`$1': missing\"\\\n+\t                    \"number specifier\" 1>&2; return 1; }\n+\t                printf %d \"${1#-a}\" &> /dev/null || { echo \"bash:\"\\\n+\t                    \"${FUNCNAME[0]}: \\`$1': invalid number specifier\" 1>&2\n+\t                    return 1; }\n+\t                # Assign array of -aN elements\n+\t                [[ \"$2\" ]] && unset -v \"$2\" && eval $2=\\(\\\"\\${@:3:${1#-a}}\\\"\\) &&\n+\t                shift $((${1#-a} + 2)) || { echo \"bash: ${FUNCNAME[0]}:\"\\\n+\t                    \"\\`$1${2+ }$2': missing argument(s)\" 1>&2; return 1; }\n+\t                ;;\n+\t            -v)\n+\t                # Assign single value\n+\t                [[ \"$2\" ]] && unset -v \"$2\" && eval $2=\\\"\\$3\\\" &&\n+\t                shift 3 || { echo \"bash: ${FUNCNAME[0]}: $1: missing\"\\\n+\t                \"argument(s)\" 1>&2; return 1; }\n+\t                ;;\n+\t            *)\n+\t                echo \"bash: ${FUNCNAME[0]}: $1: invalid option\" 1>&2\n+\t                return 1 ;;\n+\t        esac\n+\t    done\n+\t}\n+\n+\n+\t# Reassemble command line words, excluding specified characters from the\n+\t# list of word completion separators (COMP_WORDBREAKS).\n+\t# @param $1 chars  Characters out of $COMP_WORDBREAKS which should\n+\t#     NOT be considered word breaks. This is useful for things like scp where\n+\t#     we want to return host:path and not only path, so we would pass the\n+\t#     colon (:) as $1 here.\n+\t# @param $2 words  Name of variable to return words to\n+\t# @param $3 cword  Name of variable to return cword to\n+\t#\n+\t__reassemble_comp_words_by_ref() {\n+\t    local exclude i j ref\n+\t    # Exclude word separator characters?\n+\t    if [[ $1 ]]; then\n+\t        # Yes, exclude word separator characters;\n+\t        # Exclude only those characters, which were really included\n+\t        exclude=\"${1//[^$COMP_WORDBREAKS]}\"\n+\t    fi\n+\n+\t    # Default to cword unchanged\n+\t    eval $3=$COMP_CWORD\n+\t    # Are characters excluded which were former included?\n+\t    if [[ $exclude ]]; then\n+\t        # Yes, list of word completion separators has shrunk;\n+\t        # Re-assemble words to complete\n+\t        for (( i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do\n+\t            # Is current word not word 0 (the command itself) and is word not\n+\t            # empty and is word made up of just word separator characters to be\n+\t            # excluded?\n+\t            while [[ $i -gt 0 && ${COMP_WORDS[$i]} &&\n+\t                ${COMP_WORDS[$i]//[^$exclude]} == ${COMP_WORDS[$i]}\n+\t            ]]; do\n+\t                [ $j -ge 2 ] && ((j--))\n+\t                # Append word separator to current word\n+\t                ref=\"$2[$j]\"\n+\t                eval $2[$j]=\\${!ref}\\${COMP_WORDS[i]}\n+\t                # Indicate new cword\n+\t                [ $i = $COMP_CWORD ] && eval $3=$j\n+\t                # Indicate next word if available, else end *both* while and for loop\n+\t                (( $i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2\n+\t            done\n+\t            # Append word to current word\n+\t            ref=\"$2[$j]\"\n+\t            eval $2[$j]=\\${!ref}\\${COMP_WORDS[i]}\n+\t            # Indicate new cword\n+\t            [ $i = $COMP_CWORD ] && [[ ${COMP_WORDS[i]} ]] && eval $3=$j\n+\t        done\n+\t    else\n+\t        # No, list of word completions separators hasn't changed;\n+\t        eval $2=\\( \\\"\\${COMP_WORDS[@]}\\\" \\)\n+\t    fi\n+\t} # __reassemble_comp_words_by_ref()\n+\n+\t# @param $1 exclude  Characters out of $COMP_WORDBREAKS which should NOT be\n+\t#     considered word breaks. This is useful for things like scp where\n+\t#     we want to return host:path and not only path, so we would pass the\n+\t#     colon (:) as $1 in this case.  Bash-3 doesn't do word splitting, so this\n+\t#     ensures we get the same word on both bash-3 and bash-4.\n+\t# @param $2 words  Name of variable to return words to\n+\t# @param $3 cword  Name of variable to return cword to\n+\t# @param $4 cur  Name of variable to return current word to complete to\n+\t# @see ___get_cword_at_cursor_by_ref()\n+\t__get_cword_at_cursor_by_ref() {\n+\t    local cword words=()\n+\t    __reassemble_comp_words_by_ref \"$1\" words cword\n+\n+\t    local i cur2\n+\t    local cur=\"$COMP_LINE\"\n+\t    local index=\"$COMP_POINT\"\n+\t    for (( i = 0; i <= cword; ++i )); do\n+\t        while [[\n+\t            # Current word fits in $cur?\n+\t            \"${#cur}\" -ge ${#words[i]} &&\n+\t            # $cur doesn't match cword?\n+\t            \"${cur:0:${#words[i]}}\" != \"${words[i]}\"\n+\t        ]]; do\n+\t            # Strip first character\n+\t            cur=\"${cur:1}\"\n+\t            # Decrease cursor position\n+\t            ((index--))\n+\t        done\n+\n+\t        # Does found word matches cword?\n+\t        if [[ \"$i\" -lt \"$cword\" ]]; then\n+\t            # No, cword lies further;\n+\t            local old_size=\"${#cur}\"\n+\t            cur=\"${cur#${words[i]}}\"\n+\t            local new_size=\"${#cur}\"\n+\t            index=$(( index - old_size + new_size ))\n+\t        fi\n+\t    done\n+\n+\t    if [[ \"${words[cword]:0:${#cur}}\" != \"$cur\" ]]; then\n+\t        # We messed up. At least return the whole word so things keep working\n+\t        cur2=${words[cword]}\n+\t    else\n+\t        cur2=${cur:0:$index}\n+\t    fi\n+\n+\t    local \"$2\" \"$3\" \"$4\" &&\n+\t        _upvars -a${#words[@]} $2 \"${words[@]}\" -v $3 \"$cword\" -v $4 \"$cur2\"\n+\t}\n+\n+\n+\t# Get the word to complete and optional previous words.\n+\t# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases\n+\t# where the user is completing in the middle of a word.\n+\t# (For example, if the line is \"ls foobar\",\n+\t# and the cursor is here -------->   ^\n+\t# Also one is able to cross over possible wordbreak characters.\n+\t# Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES]\n+\t# Available VARNAMES:\n+\t#     cur         Return cur via $cur\n+\t#     prev        Return prev via $prev\n+\t#     words       Return words via $words\n+\t#     cword       Return cword via $cword\n+\t#\n+\t# Available OPTIONS:\n+\t#     -n EXCLUDE  Characters out of $COMP_WORDBREAKS which should NOT be\n+\t#                 considered word breaks. This is useful for things like scp\n+\t#                 where we want to return host:path and not only path, so we\n+\t#                 would pass the colon (:) as -n option in this case.  Bash-3\n+\t#                 doesn't do word splitting, so this ensures we get the same\n+\t#                 word on both bash-3 and bash-4.\n+\t#     -c VARNAME  Return cur via $VARNAME\n+\t#     -p VARNAME  Return prev via $VARNAME\n+\t#     -w VARNAME  Return words via $VARNAME\n+\t#     -i VARNAME  Return cword via $VARNAME\n+\t#\n+\t# Example usage:\n+\t#\n+\t#    $ _get_comp_words_by_ref -n : cur prev\n+\t#\n+\t_get_comp_words_by_ref()\n+\t{\n+\t    local exclude flag i OPTIND=1\n+\t    local cur cword words=()\n+\t    local upargs=() upvars=() vcur vcword vprev vwords\n+\n+\t    while getopts \"c:i:n:p:w:\" flag \"$@\"; do\n+\t        case $flag in\n+\t            c) vcur=$OPTARG ;;\n+\t            i) vcword=$OPTARG ;;\n+\t            n) exclude=$OPTARG ;;\n+\t            p) vprev=$OPTARG ;;\n+\t            w) vwords=$OPTARG ;;\n+\t        esac\n+\t    done\n+\t    while [[ $# -ge $OPTIND ]]; do\n+\t        case ${!OPTIND} in\n+\t            cur)   vcur=cur ;;\n+\t            prev)  vprev=prev ;;\n+\t            cword) vcword=cword ;;\n+\t            words) vwords=words ;;\n+\t            *) echo \"bash: $FUNCNAME(): \\`${!OPTIND}': unknown argument\" \\\n+\t                1>&2; return 1\n+\t        esac\n+\t        let \"OPTIND += 1\"\n+\t    done\n+\n+\t    __get_cword_at_cursor_by_ref \"$exclude\" words cword cur\n+\n+\t    [[ $vcur   ]] && { upvars+=(\"$vcur\"  ); upargs+=(-v $vcur   \"$cur\"  ); }\n+\t    [[ $vcword ]] && { upvars+=(\"$vcword\"); upargs+=(-v $vcword \"$cword\"); }\n+\t    [[ $vprev  ]] && { upvars+=(\"$vprev\" ); upargs+=(-v $vprev\n+\t        \"${words[cword - 1]}\"); }\n+\t    [[ $vwords ]] && { upvars+=(\"$vwords\"); upargs+=(-a${#words[@]} $vwords\n+\t        \"${words[@]}\"); }\n+\n+\t    (( ${#upvars[@]} )) && local \"${upvars[@]}\" && _upvars \"${upargs[@]}\"\n+\t}\n+fi\n+\n # __gitdir accepts 0 or 1 arguments (i.e., location)\n # returns location of .git repo\n __gitdir ()\n@@ -325,7 +564,8 @@ __gitcomp_1 ()\n # generates completion reply with compgen\n __gitcomp ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tif [ $# -gt 2 ]; then\n \t\tcur=\"$3\"\n \tfi\n@@ -384,7 +624,8 @@ __git_tags ()\n __git_refs ()\n {\n \tlocal i is_hash=y dir=\"$(__gitdir \"${1-}\")\"\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\" format refs\n+\tlocal cur format refs\n+\t_get_comp_words_by_ref cur\n \tif [ -d \"$dir\" ]; then\n \t\tcase \"$cur\" in\n \t\trefs|refs/*)\n@@ -482,7 +723,8 @@ __git_compute_merge_strategies ()\n \n __git_complete_file ()\n {\n-\tlocal pfx ls ref cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal pfx ls ref cur\n+\t_get_comp_words_by_ref -n \":\" cur\n \tcase \"$cur\" in\n \t?*:*)\n \t\tref=\"${cur%%:*}\"\n@@ -530,7 +772,8 @@ __git_complete_file ()\n \n __git_complete_revlist ()\n {\n-\tlocal pfx cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal pfx cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t*...*)\n \t\tpfx=\"${cur%...*}...\"\n@@ -550,11 +793,14 @@ __git_complete_revlist ()\n \n __git_complete_remote_or_refspec ()\n {\n-\tlocal cmd=\"${COMP_WORDS[1]}\"\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal git_comp_words git_comp_cword\n+\t__reassemble_comp_words_by_ref : git_comp_words git_comp_cword\n+\tlocal cmd=\"${git_comp_words[1]}\"\n+\tlocal cur\n \tlocal i c=2 remote=\"\" pfx=\"\" lhs=1 no_complete_refspec=0\n-\twhile [ $c -lt $COMP_CWORD ]; do\n-\t\ti=\"${COMP_WORDS[c]}\"\n+\t_get_comp_words_by_ref -n \":\" cur\n+\twhile [ $c -lt $git_comp_cword ]; do\n+\t\ti=\"${git_comp_words[c]}\"\n \t\tcase \"$i\" in\n \t\t--mirror) [ \"$cmd\" = \"push\" ] && no_complete_refspec=1 ;;\n \t\t--all)\n@@ -622,13 +868,15 @@ __git_complete_remote_or_refspec ()\n \n __git_complete_strategy ()\n {\n+\tlocal cur prev\n+\t_get_comp_words_by_ref -n \"=\" cur prev\n \t__git_compute_merge_strategies\n-\tcase \"${COMP_WORDS[COMP_CWORD-1]}\" in\n+\tcase \"${prev}\" in\n \t-s|--strategy)\n \t\t__gitcomp \"$__git_merge_strategies\"\n \t\treturn 0\n \tesac\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\n \tcase \"$cur\" in\n \t--strategy=*)\n \t\t__gitcomp \"$__git_merge_strategies\" \"\" \"${cur##--strategy=}\"\n@@ -818,7 +1066,12 @@ __git_whitespacelist=\"nowarn warn error error-all fix\"\n \n _git_am ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\" dir=\"$(__gitdir)\"\n+\tlocal cur\n+\tlocal dir=\"$(__gitdir)\"\n+\n+\t_get_comp_words_by_ref -n \"=\" cur\n+\techo \"$cur\"\n+\techo \"$prev\"\n \tif [ -d \"$dir\"/rebase-apply ]; then\n \t\t__gitcomp \"--skip --continue --resolved --abort\"\n \t\treturn\n@@ -842,7 +1095,8 @@ _git_am ()\n \n _git_apply ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--whitespace=*)\n \t\t__gitcomp \"$__git_whitespacelist\" \"\" \"${cur##--whitespace=}\"\n@@ -865,7 +1119,8 @@ _git_add ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n@@ -879,7 +1134,8 @@ _git_add ()\n \n _git_archive ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--format=*)\n \t\t__gitcomp \"$(git archive --list)\" \"\" \"${cur##--format=}\"\n@@ -923,7 +1179,8 @@ _git_bisect ()\n \n _git_branch ()\n {\n-\tlocal i c=1 only_local_ref=\"n\" has_r=\"n\"\n+\tlocal i c=1 only_local_ref=\"n\" has_r=\"n\", cur\n+\t_get_comp_words_by_ref cur\n \n \twhile [ $c -lt $COMP_CWORD ]; do\n \t\ti=\"${COMP_WORDS[c]}\"\n@@ -934,7 +1191,7 @@ _git_branch ()\n \t\tc=$((++c))\n \tdone\n \n-\tcase \"${COMP_WORDS[COMP_CWORD]}\" in\n+\tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n \t\t\t--color --no-color --verbose --abbrev= --no-abbrev\n@@ -976,7 +1233,8 @@ _git_checkout ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--conflict=*)\n \t\t__gitcomp \"diff3 merge\" \"\" \"${cur##--conflict=}\"\n@@ -1000,7 +1258,8 @@ _git_cherry ()\n \n _git_cherry_pick ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--edit --no-commit\"\n@@ -1015,7 +1274,8 @@ _git_clean ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--dry-run --quiet\"\n@@ -1027,7 +1287,8 @@ _git_clean ()\n \n _git_clone ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n@@ -1054,7 +1315,8 @@ _git_commit ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--cleanup=*)\n \t\t__gitcomp \"default strip verbatim whitespace\n@@ -1089,7 +1351,8 @@ _git_commit ()\n \n _git_describe ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n@@ -1121,7 +1384,8 @@ _git_diff ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--cached --staged --pickaxe-all --pickaxe-regex\n@@ -1142,7 +1406,8 @@ _git_difftool ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--tool=*)\n \t\t__gitcomp \"$__git_mergetools_common kompare\" \"\" \"${cur##--tool=}\"\n@@ -1167,7 +1432,8 @@ __git_fetch_options=\"\n \n _git_fetch ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"$__git_fetch_options\"\n@@ -1179,7 +1445,8 @@ _git_fetch ()\n \n _git_format_patch ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--thread=*)\n \t\t__gitcomp \"\n@@ -1211,7 +1478,8 @@ _git_format_patch ()\n \n _git_fsck ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n@@ -1226,7 +1494,8 @@ _git_fsck ()\n \n _git_gc ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--prune --aggressive\"\n@@ -1245,7 +1514,8 @@ _git_grep ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n@@ -1268,7 +1538,8 @@ _git_grep ()\n \n _git_help ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--all --info --man --web\"\n@@ -1286,7 +1557,8 @@ _git_help ()\n \n _git_init ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--shared=*)\n \t\t__gitcomp \"\n@@ -1306,7 +1578,8 @@ _git_ls_files ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--cached --deleted --modified --others --ignored\n@@ -1360,7 +1633,8 @@ _git_log ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tlocal g=\"$(git rev-parse --git-dir 2>/dev/null)\"\n \tlocal merge=\"\"\n \tif [ -f \"$g/MERGE_HEAD\" ]; then\n@@ -1419,7 +1693,8 @@ _git_merge ()\n {\n \t__git_complete_strategy && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"$__git_merge_options\"\n@@ -1430,7 +1705,8 @@ _git_merge ()\n \n _git_mergetool ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--tool=*)\n \t\t__gitcomp \"$__git_mergetools_common tortoisemerge\" \"\" \"${cur##--tool=}\"\n@@ -1451,7 +1727,8 @@ _git_merge_base ()\n \n _git_mv ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--dry-run\"\n@@ -1488,7 +1765,8 @@ _git_pull ()\n {\n \t__git_complete_strategy && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n@@ -1504,8 +1782,9 @@ _git_pull ()\n \n _git_push ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n-\tcase \"${COMP_WORDS[COMP_CWORD-1]}\" in\n+\tlocal cur prev\n+\t_get_comp_words_by_ref -n \"=\" cur prev\n+\tcase \"$prev\" in\n \t--repo)\n \t\t__gitcomp \"$(__git_remotes)\"\n \t\treturn\n@@ -1528,7 +1807,9 @@ _git_push ()\n \n _git_rebase ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\" dir=\"$(__gitdir)\"\n+\tlocal cur\n+\tlocal dir=\"$(__gitdir)\"\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tif [ -d \"$dir\"/rebase-apply ] || [ -d \"$dir\"/rebase-merge ]; then\n \t\t__gitcomp \"--continue --skip --abort\"\n \t\treturn\n@@ -1558,7 +1839,8 @@ __git_send_email_suppresscc_options=\"author self cc bodycc sob cccmd body all\"\n \n _git_send_email ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--confirm=*)\n \t\t__gitcomp \"\n@@ -1600,9 +1882,11 @@ _git_stage ()\n \n __git_config_get_set_variables ()\n {\n-\tlocal prevword word config_file= c=$COMP_CWORD\n+\tlocal prevword word config_file= c\n+\tlocal git_comp_words\n+\t__reassemble_comp_words_by_ref = git_comp_words c\n \twhile [ $c -gt 1 ]; do\n-\t\tword=\"${COMP_WORDS[c]}\"\n+\t\tword=\"${git_comp_words[c]}\"\n \t\tcase \"$word\" in\n \t\t--global|--system|--file=*)\n \t\t\tconfig_file=\"$word\"\n@@ -1630,9 +1914,9 @@ __git_config_get_set_variables ()\n \n _git_config ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n-\tlocal prv=\"${COMP_WORDS[COMP_CWORD-1]}\"\n-\tcase \"$prv\" in\n+\tlocal cur prev\n+\t_get_comp_words_by_ref cur prev\n+\tcase \"$prev\" in\n \tbranch.*.remote)\n \t\t__gitcomp \"$(__git_remotes)\"\n \t\treturn\n@@ -1642,13 +1926,13 @@ _git_config ()\n \t\treturn\n \t\t;;\n \tremote.*.fetch)\n-\t\tlocal remote=\"${prv#remote.}\"\n+\t\tlocal remote=\"${prev#remote.}\"\n \t\tremote=\"${remote%.fetch}\"\n \t\t__gitcomp \"$(__git_refs_remotes \"$remote\")\"\n \t\treturn\n \t\t;;\n \tremote.*.push)\n-\t\tlocal remote=\"${prv#remote.}\"\n+\t\tlocal remote=\"${prev#remote.}\"\n \t\tremote=\"${remote%.push}\"\n \t\t__gitcomp \"$(git --git-dir=\"$(__gitdir)\" \\\n \t\t\tfor-each-ref --format='%(refname):%(refname)' \\\n@@ -2039,7 +2323,8 @@ _git_reset ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--merge --mixed --hard --soft --patch\"\n@@ -2051,7 +2336,8 @@ _git_reset ()\n \n _git_revert ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--edit --mainline --no-edit --no-commit --signoff\"\n@@ -2065,7 +2351,8 @@ _git_rm ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur=\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"--cached --dry-run --ignore-unmatch --quiet\"\n@@ -2079,7 +2366,8 @@ _git_shortlog ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n@@ -2097,7 +2385,8 @@ _git_show ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref -n \"=\" cur\n \tcase \"$cur\" in\n \t--pretty=*)\n \t\t__gitcomp \"$__git_log_pretty_formats\n@@ -2121,7 +2410,8 @@ _git_show ()\n \n _git_show_branch ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n@@ -2138,10 +2428,11 @@ _git_show_branch ()\n \n _git_stash ()\n {\n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n \tlocal save_opts='--keep-index --no-keep-index --quiet --patch'\n \tlocal subcommands='save list show apply clear drop pop create branch'\n \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n+\t_get_comp_words_by_ref cur\n \tif [ -z \"$subcommand\" ]; then\n \t\tcase \"$cur\" in\n \t\t--*)\n@@ -2183,7 +2474,8 @@ _git_submodule ()\n \n \tlocal subcommands=\"add status init update summary foreach sync\"\n \tif [ -z \"$(__git_find_on_cmdline \"$subcommands\")\" ]; then\n-\t\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\t\tlocal cur\n+\t\t_get_comp_words_by_ref cur\n \t\tcase \"$cur\" in\n \t\t--*)\n \t\t\t__gitcomp \"--quiet --cached\"\n@@ -2227,7 +2519,8 @@ _git_svn ()\n \t\t\t--edit --rmdir --find-copies-harder --copy-similarity=\n \t\t\t\"\n \n-\t\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\t\tlocal cur\n+\t\t_get_comp_words_by_ref cur\n \t\tcase \"$subcommand,$cur\" in\n \t\tfetch,--*)\n \t\t\t__gitcomp \"--revision= --fetch-all $fc_opts\"\n@@ -2337,10 +2630,11 @@ _git_whatchanged ()\n \n _git ()\n {\n-\tlocal i c=1 command __git_dir\n+\tlocal i c=1 command __git_dir git_comp_words git_comp_cword\n \n-\twhile [ $c -lt $COMP_CWORD ]; do\n-\t\ti=\"${COMP_WORDS[c]}\"\n+\t__reassemble_comp_words_by_ref = git_comp_words git_comp_cword\n+\twhile [ $c -lt $git_comp_cword ]; do\n+\t\ti=\"${git_comp_words[c]}\"\n \t\tcase \"$i\" in\n \t\t--git-dir=*) __git_dir=\"${i#--git-dir=}\" ;;\n \t\t--bare)      __git_dir=\".\" ;;\n@@ -2352,7 +2646,7 @@ _git ()\n \tdone\n \n \tif [ -z \"$command\" ]; then\n-\t\tcase \"${COMP_WORDS[COMP_CWORD]}\" in\n+\t\tcase \"${git_comp_words[git_comp_cword]}\" in\n \t\t--*)   __gitcomp \"\n \t\t\t--paginate\n \t\t\t--no-pager\n@@ -2385,12 +2679,13 @@ _gitk ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal cur\n \tlocal g=\"$(__gitdir)\"\n \tlocal merge=\"\"\n \tif [ -f \"$g/MERGE_HEAD\" ]; then\n \t\tmerge=\"--merge\"\n \tfi\n+\t_get_comp_words_by_ref cur\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n-- \n1.7.3.1\n\n\n-- \nPeter van der Does\n\nGPG key: E77E8E98\n\nIRC: Ganseki on irc.freenode.net\nTwitter: @petervanderdoes\n"},{"id":"154448","messageId":"4CC6E249.7040204@xiplink.com","threadId":"25550","inReplyTo":"20101026095319.669c0d69@montecarlo.grandprix.int","subject":"Re: [PATCH/RFC] Make git-completion Bash 4 compatible.","fromName":"Marc Branchaud","fromEmail":"marcnarc@xiplink.com","sentAt":"2010-10-26T14:14:33Z","receivedAt":"2010-10-26T14:14:33Z","isPatch":true,"sender":{"key":"marcnarc@xiplink.com","avatar":"https://avatars.githubusercontent.com/u/14980203?v=4"},"body":"On 10-10-26 09:53 AM, Peter van der Does wrote:\n> \n> The completion script does not work as expected under Bash 4.\n> Bash: 3\n> output:\n> $ git log --pretty=<tab><tab>\n> email     full      medium    raw\n> format:   fuller    oneline   short\n> \n> Bash: 4\n> output:\n> $ git log --pretty=<tab><tab>\n> .bash_logout         .local/\n> .bash_profile        Music/\n> --More--\n\nThis patch also fixes my remote-refs issue.\n\n\"git push origin HEAD:ba<tab><tab>\" does the Right Thing (with bash 3 & 4).\n\nThanks!\n\n\t\tM.\n"}]}