git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v4 0/2] *** SUBJECT HERE ***
@ 2010-12-01 20:49 Peter van der Does
  2010-12-01 20:49 ` [PATCH v4 1/2] Introduce functions from bash-completion project Peter van der Does
                   ` (4 more replies)
  0 siblings, 5 replies; 22+ messages in thread
From: Peter van der Does @ 2010-12-01 20:49 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Peter van der Does, git, Jonathan Nieder

*** BLURB HERE ***
Make git-completion Bash 4 compatible.

I've made the following changes since v3:
- Patch is based upon the next branch.
- Grammatical error in commit message

Peter van der Does (2):
  Introduce functions from bash-completion project.
  Use the new functions to get the current cword.

 contrib/completion/git-completion.bash |  446 ++++++++++++++++++++++++++------
 1 files changed, 363 insertions(+), 83 deletions(-)

-- 
1.7.3.2

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v4 1/2] Introduce functions from bash-completion project.
  2010-12-01 20:49 [PATCH v4 0/2] *** SUBJECT HERE *** Peter van der Does
@ 2010-12-01 20:49 ` Peter van der Does
  2010-12-01 20:49 ` [PATCH v4 2/2] Use the new functions to get the current cword Peter van der Does
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 22+ messages in thread
From: Peter van der Does @ 2010-12-01 20:49 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Peter van der Does, git, Jonathan Nieder

The completion script does not work as expected under Bash 4.
Bash: 3
output:
$ git log --pretty=<tab><tab>
email     full      medium    raw
format:   fuller    oneline   short

Bash: 4
output:
$ git log --pretty=<tab><tab>
.bash_logout         .local/
.bash_profile        Music/
--More--

With Bash 4 the way word breaking is done in the programmable completion
code has changed. The documentation at the bash project is not very
clear what was changed, the only reference found is in the NEWS section:

i.  The programmable completion code now uses the same set of characters
as readline when breaking the command line into a list of words.

The word breaking problem occurs with certain characters, like colon and
equal sign.

The bash-completion project (http://bash-completion.alioth.debian.org/)
has written several functions to overcome this problem. By using these
functions within the git-completion.bash script the word breaking
problem is solved.

Signed-off-by: Peter van der Does <peter@avirtualhome.com>
---
 contrib/completion/git-completion.bash |  223 ++++++++++++++++++++++++++++++++
 1 files changed, 223 insertions(+), 0 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index f710469..0036e8b 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -82,6 +82,229 @@ case "$COMP_WORDBREAKS" in
 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
 esac
 
+# If the function _get_comp_words_by_ref does not exists, we can assume the
+# bash_completion 1.2 script isn't loaded and therefor we're defining the
+# necessary functions ourselves.
+# The functions come from the bash_completion 1.2 script.
+# See: http://bash-completion.alioth.debian.org/
+if ! type _get_comp_words_by_ref &> /dev/null ; then
+	# The bash_completion 1.2 library wasn't loaded,
+	# we have to define some functions from it ourselves.
+
+	# Assign variables one scope above the caller
+	# Usage: local varname [varname ...] &&
+	#        _upvars [-v varname value] | [-aN varname [value ...]] ...
+	# Available OPTIONS:
+	#     -aN  Assign next N values to varname as array
+	#     -v   Assign single value to varname
+	# Return: 1 if error occurs
+	# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
+	_upvars() {
+	    if ! (( $# )); then
+	        echo "${FUNCNAME[0]}: usage: ${FUNCNAME[0]} [-v varname"\
+	            "value] | [-aN varname [value ...]] ..." 1>&2
+	        return 2
+	    fi
+	    while (( $# )); do
+	        case $1 in
+	            -a*)
+	                # Error checking
+	                [[ ${1#-a} ]] || { echo "bash: ${FUNCNAME[0]}: \`$1': missing"\
+	                    "number specifier" 1>&2; return 1; }
+	                printf %d "${1#-a}" &> /dev/null || { echo "bash:"\
+	                    "${FUNCNAME[0]}: \`$1': invalid number specifier" 1>&2
+	                    return 1; }
+	                # Assign array of -aN elements
+	                [[ "$2" ]] && unset -v "$2" && eval $2=\(\"\${@:3:${1#-a}}\"\) &&
+	                shift $((${1#-a} + 2)) || { echo "bash: ${FUNCNAME[0]}:"\
+	                    "\`$1${2+ }$2': missing argument(s)" 1>&2; return 1; }
+	                ;;
+	            -v)
+	                # Assign single value
+	                [[ "$2" ]] && unset -v "$2" && eval $2=\"\$3\" &&
+	                shift 3 || { echo "bash: ${FUNCNAME[0]}: $1: missing"\
+	                "argument(s)" 1>&2; return 1; }
+	                ;;
+	            *)
+	                echo "bash: ${FUNCNAME[0]}: $1: invalid option" 1>&2
+	                return 1 ;;
+	        esac
+	    done
+	}
+
+
+	# Reassemble command line words, excluding specified characters from the
+	# list of word completion separators (COMP_WORDBREAKS).
+	# @param $1 chars  Characters out of $COMP_WORDBREAKS which should
+	#     NOT be considered word breaks. This is useful for things like scp where
+	#     we want to return host:path and not only path, so we would pass the
+	#     colon (:) as $1 here.
+	# @param $2 words  Name of variable to return words to
+	# @param $3 cword  Name of variable to return cword to
+	#
+	__reassemble_comp_words_by_ref() {
+	    local exclude i j ref
+	    # Exclude word separator characters?
+	    if [[ $1 ]]; then
+	        # Yes, exclude word separator characters;
+	        # Exclude only those characters, which were really included
+	        exclude="${1//[^$COMP_WORDBREAKS]}"
+	    fi
+
+	    # Default to cword unchanged
+	    eval $3=$COMP_CWORD
+	    # Are characters excluded which were former included?
+	    if [[ $exclude ]]; then
+	        # Yes, list of word completion separators has shrunk;
+	        # Re-assemble words to complete
+	        for (( i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
+	            # Is current word not word 0 (the command itself) and is word not
+	            # empty and is word made up of just word separator characters to be
+	            # excluded?
+	            while [[ $i -gt 0 && ${COMP_WORDS[$i]} &&
+	                ${COMP_WORDS[$i]//[^$exclude]} == ${COMP_WORDS[$i]}
+	            ]]; do
+	                [ $j -ge 2 ] && ((j--))
+	                # Append word separator to current word
+	                ref="$2[$j]"
+	                eval $2[$j]=\${!ref}\${COMP_WORDS[i]}
+	                # Indicate new cword
+	                [ $i = $COMP_CWORD ] && eval $3=$j
+	                # Indicate next word if available, else end *both* while and for loop
+	                (( $i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2
+	            done
+	            # Append word to current word
+	            ref="$2[$j]"
+	            eval $2[$j]=\${!ref}\${COMP_WORDS[i]}
+	            # Indicate new cword
+	            [ $i = $COMP_CWORD ] && [[ ${COMP_WORDS[i]} ]] && eval $3=$j
+	        done
+	    else
+	        # No, list of word completions separators hasn't changed;
+	        eval $2=\( \"\${COMP_WORDS[@]}\" \)
+	    fi
+	} # __reassemble_comp_words_by_ref()
+
+	# @param $1 exclude  Characters out of $COMP_WORDBREAKS which should NOT be
+	#     considered word breaks. This is useful for things like scp where
+	#     we want to return host:path and not only path, so we would pass the
+	#     colon (:) as $1 in this case.  Bash-3 doesn't do word splitting, so this
+	#     ensures we get the same word on both bash-3 and bash-4.
+	# @param $2 words  Name of variable to return words to
+	# @param $3 cword  Name of variable to return cword to
+	# @param $4 cur  Name of variable to return current word to complete to
+	# @see ___get_cword_at_cursor_by_ref()
+	__get_cword_at_cursor_by_ref() {
+	    local cword words=()
+	    __reassemble_comp_words_by_ref "$1" words cword
+
+	    local i cur2
+	    local cur="$COMP_LINE"
+	    local index="$COMP_POINT"
+	    for (( i = 0; i <= cword; ++i )); do
+	        while [[
+	            # Current word fits in $cur?
+	            "${#cur}" -ge ${#words[i]} &&
+	            # $cur doesn't match cword?
+	            "${cur:0:${#words[i]}}" != "${words[i]}"
+	        ]]; do
+	            # Strip first character
+	            cur="${cur:1}"
+	            # Decrease cursor position
+	            ((index--))
+	        done
+
+	        # Does found word matches cword?
+	        if [[ "$i" -lt "$cword" ]]; then
+	            # No, cword lies further;
+	            local old_size="${#cur}"
+	            cur="${cur#${words[i]}}"
+	            local new_size="${#cur}"
+	            index=$(( index - old_size + new_size ))
+	        fi
+	    done
+
+	    if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then
+	        # We messed up. At least return the whole word so things keep working
+	        cur2=${words[cword]}
+	    else
+	        cur2=${cur:0:$index}
+	    fi
+
+	    local "$2" "$3" "$4" &&
+	        _upvars -a${#words[@]} $2 "${words[@]}" -v $3 "$cword" -v $4 "$cur2"
+	}
+
+
+	# Get the word to complete and optional previous words.
+	# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases
+	# where the user is completing in the middle of a word.
+	# (For example, if the line is "ls foobar",
+	# and the cursor is here -------->   ^
+	# Also one is able to cross over possible wordbreak characters.
+	# Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES]
+	# Available VARNAMES:
+	#     cur         Return cur via $cur
+	#     prev        Return prev via $prev
+	#     words       Return words via $words
+	#     cword       Return cword via $cword
+	#
+	# Available OPTIONS:
+	#     -n EXCLUDE  Characters out of $COMP_WORDBREAKS which should NOT be
+	#                 considered word breaks. This is useful for things like scp
+	#                 where we want to return host:path and not only path, so we
+	#                 would pass the colon (:) as -n option in this case.  Bash-3
+	#                 doesn't do word splitting, so this ensures we get the same
+	#                 word on both bash-3 and bash-4.
+	#     -c VARNAME  Return cur via $VARNAME
+	#     -p VARNAME  Return prev via $VARNAME
+	#     -w VARNAME  Return words via $VARNAME
+	#     -i VARNAME  Return cword via $VARNAME
+	#
+	# Example usage:
+	#
+	#    $ _get_comp_words_by_ref -n : cur prev
+	#
+	_get_comp_words_by_ref()
+	{
+	    local exclude flag i OPTIND=1
+	    local cur cword words=()
+	    local upargs=() upvars=() vcur vcword vprev vwords
+
+	    while getopts "c:i:n:p:w:" flag "$@"; do
+	        case $flag in
+	            c) vcur=$OPTARG ;;
+	            i) vcword=$OPTARG ;;
+	            n) exclude=$OPTARG ;;
+	            p) vprev=$OPTARG ;;
+	            w) vwords=$OPTARG ;;
+	        esac
+	    done
+	    while [[ $# -ge $OPTIND ]]; do
+	        case ${!OPTIND} in
+	            cur)   vcur=cur ;;
+	            prev)  vprev=prev ;;
+	            cword) vcword=cword ;;
+	            words) vwords=words ;;
+	            *) echo "bash: $FUNCNAME(): \`${!OPTIND}': unknown argument" \
+	                1>&2; return 1
+	        esac
+	        let "OPTIND += 1"
+	    done
+
+	    __get_cword_at_cursor_by_ref "$exclude" words cword cur
+
+	    [[ $vcur   ]] && { upvars+=("$vcur"  ); upargs+=(-v $vcur   "$cur"  ); }
+	    [[ $vcword ]] && { upvars+=("$vcword"); upargs+=(-v $vcword "$cword"); }
+	    [[ $vprev  ]] && { upvars+=("$vprev" ); upargs+=(-v $vprev
+	        "${words[cword - 1]}"); }
+	    [[ $vwords ]] && { upvars+=("$vwords"); upargs+=(-a${#words[@]} $vwords
+	        "${words[@]}"); }
+
+	    (( ${#upvars[@]} )) && local "${upvars[@]}" && _upvars "${upargs[@]}"
+	}
+fi
+
 # __gitdir accepts 0 or 1 arguments (i.e., location)
 # returns location of .git repo
 __gitdir ()
-- 
1.7.3.2

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 2/2] Use the new functions to get the current cword.
  2010-12-01 20:49 [PATCH v4 0/2] *** SUBJECT HERE *** Peter van der Does
  2010-12-01 20:49 ` [PATCH v4 1/2] Introduce functions from bash-completion project Peter van der Does
@ 2010-12-01 20:49 ` Peter van der Does
  2010-12-02  7:45   ` Jonathan Nieder
  2010-12-02 22:36   ` SZEDER Gábor
  2010-12-01 21:09 ` [PATCH v4 0/2] Make git-completion Bash 4 compatible Jonathan Nieder
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 22+ messages in thread
From: Peter van der Does @ 2010-12-01 20:49 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Peter van der Does, git, Jonathan Nieder

Change the completion functions to use the newly introduced functions to
get the current and/or previous cword and to reassemble the COMP_CWORDS,
making sure the options are correctly split.

Signed-off-by: Peter van der Does <peter@avirtualhome.com>
---
 contrib/completion/git-completion.bash |  223 ++++++++++++++++++++------------
 1 files changed, 140 insertions(+), 83 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 0036e8b..f915e1f 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -554,7 +554,8 @@ __gitcomp_1 ()
 # generates completion reply with compgen
 __gitcomp ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	if [ $# -gt 2 ]; then
 		cur="$3"
 	fi
@@ -615,7 +616,8 @@ __git_tags ()
 __git_refs ()
 {
 	local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}"
-	local cur="${COMP_WORDS[COMP_CWORD]}" format refs
+	local cur format refs
+	_get_comp_words_by_ref cur
 	if [ -d "$dir" ]; then
 		case "$cur" in
 		refs|refs/*)
@@ -729,7 +731,8 @@ __git_compute_merge_strategies ()
 
 __git_complete_file ()
 {
-	local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
+	local pfx ls ref cur
+	_get_comp_words_by_ref -n ":" cur
 	case "$cur" in
 	?*:*)
 		ref="${cur%%:*}"
@@ -777,7 +780,8 @@ __git_complete_file ()
 
 __git_complete_revlist ()
 {
-	local pfx cur="${COMP_WORDS[COMP_CWORD]}"
+	local pfx cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	*...*)
 		pfx="${cur%...*}..."
@@ -797,11 +801,13 @@ __git_complete_revlist ()
 
 __git_complete_remote_or_refspec ()
 {
-	local cmd="${COMP_WORDS[1]}"
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur words cword
+	_get_comp_words_by_ref -n ":" cur words cword
+	local cmd="${words[1]}"
 	local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
 		--all)
@@ -869,13 +875,15 @@ __git_complete_remote_or_refspec ()
 
 __git_complete_strategy ()
 {
+	local cur prev
+	_get_comp_words_by_ref -n "=" cur prev
 	__git_compute_merge_strategies
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	case "${prev}" in
 	-s|--strategy)
 		__gitcomp "$__git_merge_strategies"
 		return 0
 	esac
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+
 	case "$cur" in
 	--strategy=*)
 		__gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}"
@@ -1048,10 +1056,11 @@ __git_aliased_command ()
 # __git_find_on_cmdline requires 1 argument
 __git_find_on_cmdline ()
 {
-	local word subcommand c=1
+	local word subcommand c=1 words cword
 
-	while [ $c -lt $COMP_CWORD ]; do
-		word="${COMP_WORDS[c]}"
+	_get_comp_words_by_ref words cword
+	while [ $c -lt $cword ]; do
+		word="${words[c]}"
 		for subcommand in $1; do
 			if [ "$subcommand" = "$word" ]; then
 				echo "$subcommand"
@@ -1064,9 +1073,10 @@ __git_find_on_cmdline ()
 
 __git_has_doubledash ()
 {
-	local c=1
-	while [ $c -lt $COMP_CWORD ]; do
-		if [ "--" = "${COMP_WORDS[c]}" ]; then
+	local c=1, words cword
+	_get_comp_words_by_ref words cword
+	while [ $c -lt $cwords ]; do
+		if [ "--" = "${words[c]}" ]; then
 			return 0
 		fi
 		c=$((++c))
@@ -1078,7 +1088,9 @@ __git_whitespacelist="nowarn warn error error-all fix"
 
 _git_am ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+	local cur dir="$(__gitdir)"
+
+	_get_comp_words_by_ref -n "=" cur
 	if [ -d "$dir"/rebase-apply ]; then
 		__gitcomp "--skip --continue --resolved --abort"
 		return
@@ -1102,7 +1114,8 @@ _git_am ()
 
 _git_apply ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--whitespace=*)
 		__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
@@ -1125,7 +1138,8 @@ _git_add ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1139,7 +1153,8 @@ _git_add ()
 
 _git_archive ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--format=*)
 		__gitcomp "$(git archive --list)" "" "${cur##--format=}"
@@ -1187,10 +1202,11 @@ _git_bisect ()
 
 _git_branch ()
 {
-	local i c=1 only_local_ref="n" has_r="n"
+	local i c=1 only_local_ref="n" has_r="n" cur words cword
+	_get_comp_words_by_ref cur words cword
 
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		-d|-m)	only_local_ref="y" ;;
 		-r)	has_r="y" ;;
@@ -1198,7 +1214,7 @@ _git_branch ()
 		c=$((++c))
 	done
 
-	case "${COMP_WORDS[COMP_CWORD]}" in
+	case "$cur" in
 	--*)
 		__gitcomp "
 			--color --no-color --verbose --abbrev= --no-abbrev
@@ -1218,8 +1234,10 @@ _git_branch ()
 
 _git_bundle ()
 {
-	local cmd="${COMP_WORDS[2]}"
-	case "$COMP_CWORD" in
+	local words cword
+	_get_comp_words_by_ref words cword
+	local cmd="${words[2]}"
+	case "$cword" in
 	2)
 		__gitcomp "create list-heads verify unbundle"
 		;;
@@ -1240,7 +1258,8 @@ _git_checkout ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--conflict=*)
 		__gitcomp "diff3 merge" "" "${cur##--conflict=}"
@@ -1270,7 +1289,8 @@ _git_cherry ()
 
 _git_cherry_pick ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--edit --no-commit"
@@ -1285,7 +1305,8 @@ _git_clean ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--dry-run --quiet"
@@ -1297,7 +1318,8 @@ _git_clean ()
 
 _git_clone ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1324,7 +1346,8 @@ _git_commit ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--cleanup=*)
 		__gitcomp "default strip verbatim whitespace
@@ -1359,7 +1382,8 @@ _git_commit ()
 
 _git_describe ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1391,7 +1415,8 @@ _git_diff ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
@@ -1412,7 +1437,8 @@ _git_difftool ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--tool=*)
 		__gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
@@ -1437,7 +1463,8 @@ __git_fetch_options="
 
 _git_fetch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "$__git_fetch_options"
@@ -1449,7 +1476,8 @@ _git_fetch ()
 
 _git_format_patch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--thread=*)
 		__gitcomp "
@@ -1481,7 +1509,8 @@ _git_format_patch ()
 
 _git_fsck ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1496,7 +1525,8 @@ _git_fsck ()
 
 _git_gc ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--prune --aggressive"
@@ -1515,7 +1545,8 @@ _git_grep ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1538,7 +1569,8 @@ _git_grep ()
 
 _git_help ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--all --info --man --web"
@@ -1556,7 +1588,8 @@ _git_help ()
 
 _git_init ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--shared=*)
 		__gitcomp "
@@ -1576,7 +1609,8 @@ _git_ls_files ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --deleted --modified --others --ignored
@@ -1630,7 +1664,8 @@ _git_log ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	local g="$(git rev-parse --git-dir 2>/dev/null)"
 	local merge=""
 	if [ -f "$g/MERGE_HEAD" ]; then
@@ -1689,7 +1724,8 @@ _git_merge ()
 {
 	__git_complete_strategy && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "$__git_merge_options"
@@ -1700,7 +1736,8 @@ _git_merge ()
 
 _git_mergetool ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--tool=*)
 		__gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
@@ -1721,7 +1758,8 @@ _git_merge_base ()
 
 _git_mv ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--dry-run"
@@ -1740,7 +1778,8 @@ _git_notes ()
 {
 	local subcommands='add append copy edit list prune remove show'
 	local subcommand="$(__git_find_on_cmdline "$subcommands")"
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur prev
+	_get_comp_words_by_ref -n "=" cur prev
 
 	case "$subcommand,$cur" in
 	,--*)
@@ -1775,7 +1814,7 @@ _git_notes ()
 	prune,*)
 		;;
 	*)
-		case "${COMP_WORDS[COMP_CWORD-1]}" in
+		case "${prev}" in
 		-m|-F)
 			;;
 		*)
@@ -1790,7 +1829,8 @@ _git_pull ()
 {
 	__git_complete_strategy && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1806,8 +1846,9 @@ _git_pull ()
 
 _git_push ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	local cur prev
+	_get_comp_words_by_ref -n "=" cur prev
+	case "$prev" in
 	--repo)
 		__gitcomp "$(__git_remotes)"
 		return
@@ -1830,7 +1871,9 @@ _git_push ()
 
 _git_rebase ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+	local cur
+	local dir="$(__gitdir)"
+	_get_comp_words_by_ref -n "=" cur
 	if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
 		__gitcomp "--continue --skip --abort"
 		return
@@ -1860,7 +1903,8 @@ __git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
 
 _git_send_email ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--confirm=*)
 		__gitcomp "
@@ -1902,9 +1946,10 @@ _git_stage ()
 
 __git_config_get_set_variables ()
 {
-	local prevword word config_file= c=$COMP_CWORD
-	while [ $c -gt 1 ]; do
-		word="${COMP_WORDS[c]}"
+	local prevword word config_file= words cword
+	_get_comp_words_by_ref -n "=" words cword
+	while [ $cword -gt 1 ]; do
+		word="${words[cword]}"
 		case "$word" in
 		--global|--system|--file=*)
 			config_file="$word"
@@ -1916,7 +1961,7 @@ __git_config_get_set_variables ()
 			;;
 		esac
 		prevword=$word
-		c=$((--c))
+		cword=$((--cword))
 	done
 
 	git --git-dir="$(__gitdir)" config $config_file --list 2>/dev/null |
@@ -1932,9 +1977,9 @@ __git_config_get_set_variables ()
 
 _git_config ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
-	local prv="${COMP_WORDS[COMP_CWORD-1]}"
-	case "$prv" in
+	local cur prev
+	_get_comp_words_by_ref cur prev
+	case "$prev" in
 	branch.*.remote)
 		__gitcomp "$(__git_remotes)"
 		return
@@ -1944,13 +1989,13 @@ _git_config ()
 		return
 		;;
 	remote.*.fetch)
-		local remote="${prv#remote.}"
+		local remote="${prev#remote.}"
 		remote="${remote%.fetch}"
 		__gitcomp "$(__git_refs_remotes "$remote")"
 		return
 		;;
 	remote.*.push)
-		local remote="${prv#remote.}"
+		local remote="${prev#remote.}"
 		remote="${remote%.push}"
 		__gitcomp "$(git --git-dir="$(__gitdir)" \
 			for-each-ref --format='%(refname):%(refname)' \
@@ -2341,7 +2386,8 @@ _git_reset ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--merge --mixed --hard --soft --patch"
@@ -2353,7 +2399,8 @@ _git_reset ()
 
 _git_revert ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--edit --mainline --no-edit --no-commit --signoff"
@@ -2367,7 +2414,8 @@ _git_rm ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur=
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --dry-run --ignore-unmatch --quiet"
@@ -2381,7 +2429,8 @@ _git_shortlog ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -2399,7 +2448,8 @@ _git_show ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n "=" cur
 	case "$cur" in
 	--pretty=*)
 		__gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
@@ -2423,7 +2473,8 @@ _git_show ()
 
 _git_show_branch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -2440,10 +2491,11 @@ _git_show_branch ()
 
 _git_stash ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
 	local save_opts='--keep-index --no-keep-index --quiet --patch'
 	local subcommands='save list show apply clear drop pop create branch'
 	local subcommand="$(__git_find_on_cmdline "$subcommands")"
+	_get_comp_words_by_ref cur
 	if [ -z "$subcommand" ]; then
 		case "$cur" in
 		--*)
@@ -2485,7 +2537,8 @@ _git_submodule ()
 
 	local subcommands="add status init update summary foreach sync"
 	if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
-		local cur="${COMP_WORDS[COMP_CWORD]}"
+		local cur
+		_get_comp_words_by_ref cur
 		case "$cur" in
 		--*)
 			__gitcomp "--quiet --cached"
@@ -2529,7 +2582,8 @@ _git_svn ()
 			--edit --rmdir --find-copies-harder --copy-similarity=
 			"
 
-		local cur="${COMP_WORDS[COMP_CWORD]}"
+		local cur
+		_get_comp_words_by_ref cur
 		case "$subcommand,$cur" in
 		fetch,--*)
 			__gitcomp "--revision= --fetch-all $fc_opts"
@@ -2600,9 +2654,10 @@ _git_svn ()
 
 _git_tag ()
 {
-	local i c=1 f=0
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	local i c=1 f=0 words cword prev
+	_get_comp_words_by_ref prev words cword
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		-d|-v)
 			__gitcomp "$(__git_tags)"
@@ -2615,7 +2670,7 @@ _git_tag ()
 		c=$((++c))
 	done
 
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	case "${prev}" in
 	-m|-F)
 		COMPREPLY=()
 		;;
@@ -2639,15 +2694,16 @@ _git_whatchanged ()
 
 _git ()
 {
-	local i c=1 command __git_dir
+	local i c=1 command __git_dir words cword
 
-	if [[ -n ${ZSH_VERSION-} ]]; then
+	if [[ -n $ZSH_VERSION ]]; then
 		emulate -L bash
 		setopt KSH_TYPESET
 	fi
 
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	_get_comp_words_by_ref -n "=" words cword
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		--git-dir=*) __git_dir="${i#--git-dir=}" ;;
 		--bare)      __git_dir="." ;;
@@ -2659,7 +2715,7 @@ _git ()
 	done
 
 	if [ -z "$command" ]; then
-		case "${COMP_WORDS[COMP_CWORD]}" in
+		case "${words[cword]}" in
 		--*)   __gitcomp "
 			--paginate
 			--no-pager
@@ -2690,19 +2746,20 @@ _git ()
 
 _gitk ()
 {
-	if [[ -n ${ZSH_VERSION-} ]]; then
+	if [[ -n $ZSH_VERSION ]]; then
 		emulate -L bash
 		setopt KSH_TYPESET
 	fi
 
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
 	local g="$(__gitdir)"
 	local merge=""
 	if [ -f "$g/MERGE_HEAD" ]; then
 		merge="--merge"
 	fi
+	_get_comp_words_by_ref cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -2730,7 +2787,7 @@ complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
 	|| complete -o default -o nospace -F _git git.exe
 fi
 
-if [[ -n ${ZSH_VERSION-} ]]; then
+if [[ -n $ZSH_VERSION ]]; then
 	shopt () {
 		local option
 		if [ $# -ne 2 ]; then
-- 
1.7.3.2

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 0/2] Make git-completion Bash 4 compatible
  2010-12-01 20:49 [PATCH v4 0/2] *** SUBJECT HERE *** Peter van der Does
  2010-12-01 20:49 ` [PATCH v4 1/2] Introduce functions from bash-completion project Peter van der Does
  2010-12-01 20:49 ` [PATCH v4 2/2] Use the new functions to get the current cword Peter van der Does
@ 2010-12-01 21:09 ` Jonathan Nieder
  2010-12-02  1:10 ` SZEDER Gábor
  2010-12-02  9:16 ` Jonathan Nieder
  4 siblings, 0 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-01 21:09 UTC (permalink / raw)
  To: Peter van der Does; +Cc: Shawn O. Pearce, git

Peter van der Does wrote:

> - Patch is based upon the next branch.

Please don't do that.  Documentation/SubmittingPatches explains
(section "(0) Decide what to base your work on").

> - Grammatical error in commit message

Thanks, I'll look over this version then.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 0/2] Make git-completion Bash 4 compatible.
  2010-12-01 20:49 [PATCH v4 0/2] *** SUBJECT HERE *** Peter van der Does
                   ` (2 preceding siblings ...)
  2010-12-01 21:09 ` [PATCH v4 0/2] Make git-completion Bash 4 compatible Jonathan Nieder
@ 2010-12-02  1:10 ` SZEDER Gábor
  2010-12-02  9:16 ` Jonathan Nieder
  4 siblings, 0 replies; 22+ messages in thread
From: SZEDER Gábor @ 2010-12-02  1:10 UTC (permalink / raw)
  To: Peter van der Does; +Cc: Shawn O. Pearce, git, Jonathan Nieder

Hi,

On Wed, Dec 01, 2010 at 03:49:40PM -0500, Peter van der Does wrote:
> *** BLURB HERE ***
> Make git-completion Bash 4 compatible.
> 
> I've made the following changes since v3:
> - Patch is based upon the next branch.
> - Grammatical error in commit message

I have a few little changes to fix some minor nits and bugs.  Will try
to find some time tomorrow to dig them up and send them to the list.


Best,
Gábor

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 2/2] Use the new functions to get the current cword.
  2010-12-01 20:49 ` [PATCH v4 2/2] Use the new functions to get the current cword Peter van der Does
@ 2010-12-02  7:45   ` Jonathan Nieder
  2010-12-02 22:36   ` SZEDER Gábor
  1 sibling, 0 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-02  7:45 UTC (permalink / raw)
  To: Peter van der Does; +Cc: Shawn O. Pearce, git, SZEDER Gábor

Hi Peter,

Peter van der Does wrote:

> Change the completion functions to use the newly introduced functions to
> get the current and/or previous cword and to reassemble the COMP_CWORDS,
> making sure the options are correctly split.

Some comments.  Please don't reroll until discussion has quieted down
(though thoughts and incremental patches would always be welcome, of
course).

> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -554,7 +554,8 @@ __gitcomp_1 ()
>  # generates completion reply with compgen
>  __gitcomp ()
>  {
> -	local cur="${COMP_WORDS[COMP_CWORD]}"
> +	local cur
> +	_get_comp_words_by_ref -n "=" cur

To save the reader some time: this excludes '=' from word-breaking
characters, so $cur will include an = when appropriate.  IIUC that is
precisely the behavior that bash 4 changed.

Perhaps that is worth explaining in the commit message in the next
round?

> @@ -615,7 +616,8 @@ __git_tags ()
>  __git_refs ()
>  {
>  	local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}"
> -	local cur="${COMP_WORDS[COMP_CWORD]}" format refs
> +	local cur format refs
> +	_get_comp_words_by_ref cur

This does not exclude '=' from word-breaking characters.  Would that
break completion of

	git update-ref refs/topics/foo=bar HEAD
	git checkout refs/topics/foo=<tab><tab>

?

> @@ -729,7 +731,8 @@ __git_compute_merge_strategies ()
>  
>  __git_complete_file ()
>  {
> -	local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
> +	local pfx ls ref cur
> +	_get_comp_words_by_ref -n ":" cur

This treats '=' as a word-breaking character but not ':'.  Is that
the right behavior?

> @@ -777,7 +780,8 @@ __git_complete_file ()
>  
>  __git_complete_revlist ()
>  {
> -	local pfx cur="${COMP_WORDS[COMP_CWORD]}"
> +	local pfx cur
> +	_get_comp_words_by_ref cur

'=' and ':' are word-breakers.

> @@ -797,11 +801,13 @@ __git_complete_revlist ()
>  
>  __git_complete_remote_or_refspec ()
>  {
> -	local cmd="${COMP_WORDS[1]}"
> -	local cur="${COMP_WORDS[COMP_CWORD]}"
> +	local cur words cword
> +	_get_comp_words_by_ref -n ":" cur words cword
> +	local cmd="${words[1]}"

'=' is a word-breaker, ':' not.

> @@ -869,13 +875,15 @@ __git_complete_remote_or_refspec ()
>  
>  __git_complete_strategy ()
>  {
> +	local cur prev
> +	_get_comp_words_by_ref -n "=" cur prev

'=' is not a wordbreaker, so --strategy= can be completed correctly.

> @@ -1048,10 +1056,11 @@ __git_aliased_command ()
>  # __git_find_on_cmdline requires 1 argument
>  __git_find_on_cmdline ()
>  {
> -	local word subcommand c=1
> +	local word subcommand c=1 words cword
>  
> -	while [ $c -lt $COMP_CWORD ]; do
> -		word="${COMP_WORDS[c]}"
> +	_get_comp_words_by_ref words cword

':' and '=' are word-breakers when completing subcommand names.

> @@ -1064,9 +1073,10 @@ __git_find_on_cmdline ()
>  
>  __git_has_doubledash ()
>  {
> -	local c=1
> -	while [ $c -lt $COMP_CWORD ]; do
> -		if [ "--" = "${COMP_WORDS[c]}" ]; then
> +	local c=1, words cword

Extra comma.

> +	_get_comp_words_by_ref words cword

':' and '=' are word-breakers when looking for "--".

[etc]

So in general, it seems that : and = are treated as word-breakers
after this change much more often than git itself would treat them
as such.  Is that intentional?  What rule is used to choose -n
arguments?

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 0/2] Make git-completion Bash 4 compatible
  2010-12-01 20:49 [PATCH v4 0/2] *** SUBJECT HERE *** Peter van der Does
                   ` (3 preceding siblings ...)
  2010-12-02  1:10 ` SZEDER Gábor
@ 2010-12-02  9:16 ` Jonathan Nieder
  2010-12-02 14:16   ` Peter van der Does
  4 siblings, 1 reply; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-02  9:16 UTC (permalink / raw)
  To: Peter van der Does
  Cc: Shawn O. Pearce, git, SZEDER Gábor, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

Hi again,

Peter van der Does wrote:

> Make git-completion Bash 4 compatible.

Thanks again for this work and sorry for all the fuss.

> Peter van der Does (2):
>   Introduce functions from bash-completion project.

This patch introduces a minor regression in that it breaks the
(already somewhat incomplete) zsh support.  Should be fixable by
falling back to using COMP_WORDS on zsh.

>   Use the new functions to get the current cword.

This one introduces some subtle differences between commands and imho
does more than it set out to do, by differentiating word splitting
behavior between commands.  bash 3 was not splitting COMP_WORDS at
equal signs or colons, ever.  Maybe we can start with that and then
make refinements on top later.

While trying that out, I had an idea.  The patch depends on
understanding the bash-completion library function introduced by patch
1, but I think we can avoid that by rearranging the patch series like
this:

 1. If _get_comp_words_by_ref is already defined, use it to fetch
    completion words.  Otherwise, just use COMP_WORDS (using a stub
    _get_comp_words_by_ref), maintaining the current behavior.
    [shown below]

 2. Import the definition of _get_comp_words_by_ref from the
    bash-completion lib and use it if ZSH_VERSION is unset.

 3. Further refinements, if needed.

What do you think?

-- 8< --
From: Peter van der Does <peter@avirtualhome.com>
Subject: bash: work around bash 4.0 change in COMP_WORDS semantics

Before bash 4, running

	$ git log --pretty=m <tab><tab>

would give a list of pretty formats starting with 'm', but now it
completes on ordinary files instead.  It seems that as part of a
rework of completion word splitting, bash 4.0 changed the semantics of
the COMP_WORDS array: previously, --pretty=m was treated as one word,
but now it breaks on '=' if COMP_WORDBREAKS contains an equal sign.

It would be possible to work around that by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), doing
so is likely to break *other* completion scripts.  Luckily, the
bash-completion library includes a better workaround --- a
_get_comp_words_by_ref function to retrieve an array somewhat like
COMP_WORDS but:

 * excluding some word break characters of your choice
 * returning correct results even when the cursor is in the middle of
   a word.

Use it.  To avoid breaking setups where the bash-completion library is
not already loaded, if that function is not defined then a shim
replacement that just reads COMP_WORDS will be used instead.

Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 contrib/completion/git-completion.bash |  236 +++++++++++++++++++++----------
 1 files changed, 160 insertions(+), 76 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index feab651..0b0eb45 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -327,11 +327,39 @@ __gitcomp_1 ()
 	done
 }
 
+if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
+_get_comp_words_by_ref ()
+{
+	while [ $# -gt 0 ]; do
+		case "$1" in
+		cur)
+			cur=${COMP_WORDS[COMP_CWORD]}
+			;;
+		prev)
+			prev=${COMP_WORDS[COMP_CWORD-1]}
+			;;
+		words)
+			words=("${COMP_WORDS[@]}")
+			;;
+		cword)
+			cword=$COMP_CWORD
+			;;
+		-n)
+			# assume COMP_WORDBREAKS is already set sanely
+			shift
+			;;
+		esac
+		shift
+	done
+}
+fi
+
 # __gitcomp accepts 1, 2, 3, or 4 arguments
 # generates completion reply with compgen
 __gitcomp ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	if [ $# -gt 2 ]; then
 		cur="$3"
 	fi
@@ -390,7 +418,8 @@ __git_tags ()
 __git_refs ()
 {
 	local i is_hash=y dir="$(__gitdir "${1-}")"
-	local cur="${COMP_WORDS[COMP_CWORD]}" format refs
+	local cur format refs
+	_get_comp_words_by_ref -n =: cur
 	if [ -d "$dir" ]; then
 		case "$cur" in
 		refs|refs/*)
@@ -488,7 +517,8 @@ __git_compute_merge_strategies ()
 
 __git_complete_file ()
 {
-	local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
+	local pfx ls ref cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	?*:*)
 		ref="${cur%%:*}"
@@ -536,7 +566,8 @@ __git_complete_file ()
 
 __git_complete_revlist ()
 {
-	local pfx cur="${COMP_WORDS[COMP_CWORD]}"
+	local pfx cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	*...*)
 		pfx="${cur%...*}..."
@@ -556,11 +587,12 @@ __git_complete_revlist ()
 
 __git_complete_remote_or_refspec ()
 {
-	local cmd="${COMP_WORDS[1]}"
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur words cword
+	_get_comp_words_by_ref -n =: cur words cword
+	local cmd="${words[1]}"
 	local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
 		--all)
@@ -628,13 +660,14 @@ __git_complete_remote_or_refspec ()
 
 __git_complete_strategy ()
 {
+	local cur prev
+	_get_comp_words_by_ref -n =: cur prev
 	__git_compute_merge_strategies
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	case "$prev" in
 	-s|--strategy)
 		__gitcomp "$__git_merge_strategies"
 		return 0
 	esac
-	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--strategy=*)
 		__gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}"
@@ -794,10 +827,10 @@ __git_aliased_command ()
 # __git_find_on_cmdline requires 1 argument
 __git_find_on_cmdline ()
 {
-	local word subcommand c=1
-
-	while [ $c -lt $COMP_CWORD ]; do
-		word="${COMP_WORDS[c]}"
+	local word subcommand c=1 words cword
+	_get_comp_words_by_ref -n =: words cword
+	while [ $c -lt $cword ]; do
+		word="${words[c]}"
 		for subcommand in $1; do
 			if [ "$subcommand" = "$word" ]; then
 				echo "$subcommand"
@@ -810,9 +843,10 @@ __git_find_on_cmdline ()
 
 __git_has_doubledash ()
 {
-	local c=1
-	while [ $c -lt $COMP_CWORD ]; do
-		if [ "--" = "${COMP_WORDS[c]}" ]; then
+	local c=1 words cword
+	_get_comp_words_by_ref -n =: words cword
+	while [ $c -lt $cword ]; do
+		if [ "--" = "${words[c]}" ]; then
 			return 0
 		fi
 		c=$((++c))
@@ -824,7 +858,8 @@ __git_whitespacelist="nowarn warn error error-all fix"
 
 _git_am ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+	local cur dir="$(__gitdir)"
+	_get_comp_words_by_ref -n =: cur
 	if [ -d "$dir"/rebase-apply ]; then
 		__gitcomp "--skip --continue --resolved --abort"
 		return
@@ -848,7 +883,8 @@ _git_am ()
 
 _git_apply ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--whitespace=*)
 		__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
@@ -871,7 +907,8 @@ _git_add ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -885,7 +922,8 @@ _git_add ()
 
 _git_archive ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--format=*)
 		__gitcomp "$(git archive --list)" "" "${cur##--format=}"
@@ -929,10 +967,11 @@ _git_bisect ()
 
 _git_branch ()
 {
-	local i c=1 only_local_ref="n" has_r="n"
+	local i c=1 only_local_ref="n" has_r="n" cur words cword
 
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	_get_comp_words_by_ref -n =: cur words cword
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		-d|-m)	only_local_ref="y" ;;
 		-r)	has_r="y" ;;
@@ -940,7 +979,7 @@ _git_branch ()
 		c=$((++c))
 	done
 
-	case "${COMP_WORDS[COMP_CWORD]}" in
+	case "$cur" in
 	--*)
 		__gitcomp "
 			--color --no-color --verbose --abbrev= --no-abbrev
@@ -960,8 +999,10 @@ _git_branch ()
 
 _git_bundle ()
 {
-	local cmd="${COMP_WORDS[2]}"
-	case "$COMP_CWORD" in
+	local words cword
+	_get_comp_words_by_ref -n =: words cword
+	local cmd="${words[2]}"
+	case "$cword" in
 	2)
 		__gitcomp "create list-heads verify unbundle"
 		;;
@@ -982,7 +1023,8 @@ _git_checkout ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--conflict=*)
 		__gitcomp "diff3 merge" "" "${cur##--conflict=}"
@@ -1006,7 +1048,8 @@ _git_cherry ()
 
 _git_cherry_pick ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--edit --no-commit"
@@ -1021,7 +1064,8 @@ _git_clean ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--dry-run --quiet"
@@ -1033,7 +1077,8 @@ _git_clean ()
 
 _git_clone ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1060,7 +1105,8 @@ _git_commit ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--cleanup=*)
 		__gitcomp "default strip verbatim whitespace
@@ -1095,7 +1141,8 @@ _git_commit ()
 
 _git_describe ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1127,7 +1174,8 @@ _git_diff ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
@@ -1148,7 +1196,8 @@ _git_difftool ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--tool=*)
 		__gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
@@ -1173,7 +1222,8 @@ __git_fetch_options="
 
 _git_fetch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "$__git_fetch_options"
@@ -1185,7 +1235,8 @@ _git_fetch ()
 
 _git_format_patch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--thread=*)
 		__gitcomp "
@@ -1217,7 +1268,8 @@ _git_format_patch ()
 
 _git_fsck ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1232,7 +1284,8 @@ _git_fsck ()
 
 _git_gc ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--prune --aggressive"
@@ -1251,7 +1304,8 @@ _git_grep ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1274,7 +1328,8 @@ _git_grep ()
 
 _git_help ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--all --info --man --web"
@@ -1292,7 +1347,8 @@ _git_help ()
 
 _git_init ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--shared=*)
 		__gitcomp "
@@ -1312,7 +1368,8 @@ _git_ls_files ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --deleted --modified --others --ignored
@@ -1366,12 +1423,13 @@ _git_log ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
 	local g="$(git rev-parse --git-dir 2>/dev/null)"
 	local merge=""
 	if [ -f "$g/MERGE_HEAD" ]; then
 		merge="--merge"
 	fi
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--pretty=*)
 		__gitcomp "$__git_log_pretty_formats
@@ -1425,7 +1483,8 @@ _git_merge ()
 {
 	__git_complete_strategy && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "$__git_merge_options"
@@ -1436,7 +1495,8 @@ _git_merge ()
 
 _git_mergetool ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--tool=*)
 		__gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
@@ -1457,7 +1517,8 @@ _git_merge_base ()
 
 _git_mv ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--dry-run"
@@ -1475,12 +1536,14 @@ _git_name_rev ()
 _git_notes ()
 {
 	local subcommands="edit show"
+	local words cword
+	_get_comp_words_by_ref -n =: words cword
 	if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
 		__gitcomp "$subcommands"
 		return
 	fi
 
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	case "${words[cword-1]}" in
 	-m|-F)
 		COMPREPLY=()
 		;;
@@ -1494,7 +1557,8 @@ _git_pull ()
 {
 	__git_complete_strategy && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1510,8 +1574,9 @@ _git_pull ()
 
 _git_push ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	local cur prev
+	_get_comp_words_by_ref -n =: cur prev
+	case "$prev" in
 	--repo)
 		__gitcomp "$(__git_remotes)"
 		return
@@ -1534,7 +1599,9 @@ _git_push ()
 
 _git_rebase ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+	local dir="$(__gitdir)"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
 		__gitcomp "--continue --skip --abort"
 		return
@@ -1564,7 +1631,8 @@ __git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
 
 _git_send_email ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--confirm=*)
 		__gitcomp "
@@ -1606,9 +1674,11 @@ _git_stage ()
 
 __git_config_get_set_variables ()
 {
-	local prevword word config_file= c=$COMP_CWORD
+	local words cword
+	_get_comp_words_by_ref -n =: words cword
+	local prevword word config_file= c=$cword
 	while [ $c -gt 1 ]; do
-		word="${COMP_WORDS[c]}"
+		word="${words[c]}"
 		case "$word" in
 		--global|--system|--file=*)
 			config_file="$word"
@@ -1636,9 +1706,9 @@ __git_config_get_set_variables ()
 
 _git_config ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
-	local prv="${COMP_WORDS[COMP_CWORD-1]}"
-	case "$prv" in
+	local cur prev
+	_get_comp_words_by_ref -n =: cur prev
+	case "$prev" in
 	branch.*.remote)
 		__gitcomp "$(__git_remotes)"
 		return
@@ -1648,13 +1718,13 @@ _git_config ()
 		return
 		;;
 	remote.*.fetch)
-		local remote="${prv#remote.}"
+		local remote="${prev#remote.}"
 		remote="${remote%.fetch}"
 		__gitcomp "$(__git_refs_remotes "$remote")"
 		return
 		;;
 	remote.*.push)
-		local remote="${prv#remote.}"
+		local remote="${prev#remote.}"
 		remote="${remote%.push}"
 		__gitcomp "$(git --git-dir="$(__gitdir)" \
 			for-each-ref --format='%(refname):%(refname)' \
@@ -2045,7 +2115,8 @@ _git_reset ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--merge --mixed --hard --soft --patch"
@@ -2057,7 +2128,8 @@ _git_reset ()
 
 _git_revert ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--edit --mainline --no-edit --no-commit --signoff"
@@ -2071,7 +2143,8 @@ _git_rm ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --dry-run --ignore-unmatch --quiet"
@@ -2085,7 +2158,8 @@ _git_shortlog ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -2103,7 +2177,8 @@ _git_show ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--pretty=*)
 		__gitcomp "$__git_log_pretty_formats
@@ -2127,7 +2202,8 @@ _git_show ()
 
 _git_show_branch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -2144,7 +2220,8 @@ _git_show_branch ()
 
 _git_stash ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	local save_opts='--keep-index --no-keep-index --quiet --patch'
 	local subcommands='save list show apply clear drop pop create branch'
 	local subcommand="$(__git_find_on_cmdline "$subcommands")"
@@ -2189,7 +2266,8 @@ _git_submodule ()
 
 	local subcommands="add status init update summary foreach sync"
 	if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
-		local cur="${COMP_WORDS[COMP_CWORD]}"
+		local cur
+		_get_comp_words_by_ref -n =: cur
 		case "$cur" in
 		--*)
 			__gitcomp "--quiet --cached"
@@ -2233,7 +2311,8 @@ _git_svn ()
 			--edit --rmdir --find-copies-harder --copy-similarity=
 			"
 
-		local cur="${COMP_WORDS[COMP_CWORD]}"
+		local cur
+		_get_comp_words_by_ref -n =: cur
 		case "$subcommand,$cur" in
 		fetch,--*)
 			__gitcomp "--revision= --fetch-all $fc_opts"
@@ -2305,8 +2384,10 @@ _git_svn ()
 _git_tag ()
 {
 	local i c=1 f=0
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	local words cword prev
+	_get_comp_words_by_ref -n =: words cword prev
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		-d|-v)
 			__gitcomp "$(__git_tags)"
@@ -2319,7 +2400,7 @@ _git_tag ()
 		c=$((++c))
 	done
 
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	case "$prev" in
 	-m|-F)
 		COMPREPLY=()
 		;;
@@ -2350,8 +2431,10 @@ _git ()
 		setopt KSH_TYPESET
 	fi
 
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	local cur words cword
+	_get_comp_words_by_ref -n =: cur words cword
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		--git-dir=*) __git_dir="${i#--git-dir=}" ;;
 		--bare)      __git_dir="." ;;
@@ -2363,7 +2446,7 @@ _git ()
 	done
 
 	if [ -z "$command" ]; then
-		case "${COMP_WORDS[COMP_CWORD]}" in
+		case "$cur" in
 		--*)   __gitcomp "
 			--paginate
 			--no-pager
@@ -2401,12 +2484,13 @@ _gitk ()
 
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
 	local g="$(__gitdir)"
 	local merge=""
 	if [ -f "$g/MERGE_HEAD" ]; then
 		merge="--merge"
 	fi
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 0/2] Make git-completion Bash 4 compatible
  2010-12-02  9:16 ` Jonathan Nieder
@ 2010-12-02 14:16   ` Peter van der Does
  2010-12-02 21:02     ` [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib Jonathan Nieder
  0 siblings, 1 reply; 22+ messages in thread
From: Peter van der Does @ 2010-12-02 14:16 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Shawn O. Pearce, git, SZEDER Gábor, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

On Thu, 2 Dec 2010 03:16:24 -0600
Jonathan Nieder <jrnieder@gmail.com> wrote:

> Hi again,
> 
> Peter van der Does wrote:
> 
> > Make git-completion Bash 4 compatible.
> 
> Thanks again for this work and sorry for all the fuss.
> 
> > Peter van der Does (2):
> >   Introduce functions from bash-completion project.
> 
> This patch introduces a minor regression in that it breaks the
> (already somewhat incomplete) zsh support.  Should be fixable by
> falling back to using COMP_WORDS on zsh.
> 
> >   Use the new functions to get the current cword.
> 
> This one introduces some subtle differences between commands and imho
> does more than it set out to do, by differentiating word splitting
> behavior between commands.  bash 3 was not splitting COMP_WORDS at
> equal signs or colons, ever.  Maybe we can start with that and then
> make refinements on top later.
> 
> While trying that out, I had an idea.  The patch depends on
> understanding the bash-completion library function introduced by patch
> 1, but I think we can avoid that by rearranging the patch series like
> this:
> 
>  1. If _get_comp_words_by_ref is already defined, use it to fetch
>     completion words.  Otherwise, just use COMP_WORDS (using a stub
>     _get_comp_words_by_ref), maintaining the current behavior.
>     [shown below]
> 
>  2. Import the definition of _get_comp_words_by_ref from the
>     bash-completion lib and use it if ZSH_VERSION is unset.
> 
>  3. Further refinements, if needed.
> 
> What do you think?
> 

I like the idea and we should go with this solution.

If by importing you mean using :
[CODE]. /git_bash_completion-functions[/CODE] in the
contrib/completion/git-completion.bash script, which would be the best
solution imho. The question is where to place that the function file.

This would also means changing the documentation inside the
git-completion.bash script, currently the instructions are:
[QUOTE]
# 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
[/QUOTE]

It would have to include copying the functions file somewhere as well.

Or we could use the method used now and include the functions in the
git-completion.bash script.

I'll be waiting for further feedback from Gábor, as he mentioned on the
list of he had some little changes to fix some minor nits and bugs
before completely implementing this solution.

-- 
Peter van der Does

GPG key: E77E8E98

IRC: Ganseki on irc.freenode.net
Twitter: @petervanderdoes

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-02 14:16   ` Peter van der Does
@ 2010-12-02 21:02     ` Jonathan Nieder
  2010-12-02 23:40       ` SZEDER Gábor
  2010-12-07 16:07       ` SZEDER Gábor
  0 siblings, 2 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-02 21:02 UTC (permalink / raw)
  To: Peter van der Does
  Cc: Shawn O. Pearce, git, SZEDER Gábor, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

Add a minimal implementation of _get_comp_words_by_ref,
the routine used to work around bash 4.0's COMP_WORDS semantics.

Based on bash-completion 2.x (commit bf763033, 2010-10-26) but
tweaked for simplicity and to allow zsh to at least parse the
code.

Based-on-patch-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Peter van der Does wrote:
> Jonathan Nieder <jrnieder@gmail.com> wrote:

>>  2. Import the definition of _get_comp_words_by_ref from the
>>     bash-completion lib and use it if ZSH_VERSION is unset.
>> 
>>  3. Further refinements, if needed.
>> 
>> What do you think?
>
> I like the idea and we should go with this solution.
> 
> If by importing you mean using :
> [CODE]. /git_bash_completion-functions[/CODE] in the
> contrib/completion/git-completion.bash script, which would be the best
> solution imho. The question is where to place that the function file.
[...]
> It would have to include copying the functions file somewhere as well.
> 
> Or we could use the method used now and include the functions in the
> git-completion.bash script.

Sorry for the lack of clarity.  Here's what I meant.

 contrib/completion/git-completion.bash |  125 ++++++++++++++++++++++++++++++++
 1 files changed, 125 insertions(+), 0 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 0b0eb45..1743319 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -327,7 +327,102 @@ __gitcomp_1 ()
 	done
 }
 
+# The following function is based on code from:
+#
+#   bash_completion - programmable completion functions for bash 3.2+
+#
+#   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
+#             © 2009-2010, Bash Completion Maintainers
+#                     <bash-completion-devel@lists.alioth.debian.org>
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2, or (at your option)
+#   any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#   The latest version of this software can be obtained here:
+#
+#   http://bash-completion.alioth.debian.org/
+#
+#   RELEASE: 2.x
+
+# This function can be used to access a tokenized list of words
+# on the command line:
+#
+#	__reassemble_comp_words_by_ref '=:'
+#	if test "${words_[cword_-1]}" = -w
+#	then
+#		...
+#	fi
+#
+# The argument should be a collection of characters from the list of
+# word completion separators (COMP_WORDBREAKS) to treat as ordinary
+# characters.
+#
+# This is roughly equivalent to locally setting COMP_WORDBREAKS to
+# exclude those characters, but it does not clobber COMP_WORDBREAKS.
+# The intent is for it to be used by commands like ssh that want to
+# treat host:path as one token.
+#
+# Output: words_, cword_, cur_.
+
+__git_reassemble_comp_words_by_ref()
+{
+	local exclude i j first
+	# Which word separators to exclude?
+	exclude="${1//[^$COMP_WORDBREAKS]}"
+	cword_=$COMP_CWORD
+	if [ -z "$exclude" ]; then
+		words_=("${COMP_WORDS[@]}")
+		return
+	fi
+	# List of word completion separators has shrunk;
+	# re-assemble words to complete.
+	for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
+		# Append each nonempty word consisting of just
+		# word separator characters to the current word.
+		first=t
+		while
+			[ $i -gt 0 ] &&
+			[ -n "${COMP_WORDS[$i]}" ] &&
+			# word consists of excluded word separators
+			[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
+		do
+			# Attach to the previous token,
+			# unless the previous token is the command name.
+			if [ $j -ge 2 ] && [ -n "$first" ]; then
+				((j--))
+			fi
+			first=
+			words_[$j]=${words_[j]}${COMP_WORDS[i]}
+			if [ $i = $COMP_CWORD ]; then
+				cword_=$j
+			fi
+			if (($i < ${#COMP_WORDS[@]} - 1)); then
+				((i++))
+			else
+				# Done.
+				return
+			fi
+		done
+		words_[$j]=${words_[j]}${COMP_WORDS[i]}
+		if [ $i = $COMP_CWORD ]; then
+			cword_=$j
+		fi
+	done
+}
+
 if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
+if [[ -n $ZSH_VERSION ]]; then
 _get_comp_words_by_ref ()
 {
 	while [ $# -gt 0 ]; do
@@ -352,6 +447,36 @@ _get_comp_words_by_ref ()
 		shift
 	done
 }
+else
+_get_comp_words_by_ref ()
+{
+	local exclude cur_ cword_
+	local words_=()
+	if [ "$1" = "-n" ]; then
+		exclude=$2
+		shift 2
+	fi
+	__git_reassemble_comp_words_by_ref "$exclude"
+	cur_=${words_[cword_]}
+	while [ $# -gt 0 ]; do
+		case "$1" in
+		cur)
+			cur=$cur_
+			;;
+		prev)
+			prev=${words_[$cword_-1]}
+			;;
+		words)
+			words=("${words_[@]}")
+			;;
+		cword)
+			cword=$cword_
+			;;
+		esac
+		shift
+	done
+}
+fi
 fi
 
 # __gitcomp accepts 1, 2, 3, or 4 arguments
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 2/2] Use the new functions to get the current cword.
  2010-12-01 20:49 ` [PATCH v4 2/2] Use the new functions to get the current cword Peter van der Does
  2010-12-02  7:45   ` Jonathan Nieder
@ 2010-12-02 22:36   ` SZEDER Gábor
  1 sibling, 0 replies; 22+ messages in thread
From: SZEDER Gábor @ 2010-12-02 22:36 UTC (permalink / raw)
  To: Peter van der Does; +Cc: Shawn O. Pearce, git, Jonathan Nieder

Hi,


Here are my nits I mentioned yesterday.

On Wed, Dec 01, 2010 at 03:49:42PM -0500, Peter van der Does wrote:
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index 0036e8b..f915e1f 100755
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash

> @@ -1064,9 +1073,10 @@ __git_find_on_cmdline ()
>  
>  __git_has_doubledash ()
>  {
> -	local c=1
> -	while [ $c -lt $COMP_CWORD ]; do
> -		if [ "--" = "${COMP_WORDS[c]}" ]; then
> +	local c=1, words cword

No comma, and ...

> +	_get_comp_words_by_ref words cword
> +	while [ $c -lt $cwords ]; do

... that should be $cword in the condition, without the s at the end.
These two typos caused some weird behaviors when completing long
options for commands understanding the '--' option-path separator,
e.g. git diff --<TAB<TAB>.


> @@ -1775,7 +1814,7 @@ _git_notes ()
>  	prune,*)
>  		;;
>  	*)
> -		case "${COMP_WORDS[COMP_CWORD-1]}" in
> +		case "${prev}" in

> @@ -2615,7 +2670,7 @@ _git_tag ()
>  		c=$((++c))
>  	done
>  
> -	case "${COMP_WORDS[COMP_CWORD-1]}" in
> +	case "${prev}" in

No {} are needed around prev.


> @@ -2639,15 +2694,16 @@ _git_whatchanged ()
>  
>  _git ()
>  {
> -	local i c=1 command __git_dir
> +	local i c=1 command __git_dir words cword
>  
> -	if [[ -n ${ZSH_VERSION-} ]]; then
> +	if [[ -n $ZSH_VERSION ]]; then

> @@ -2690,19 +2746,20 @@ _git ()
>  
>  _gitk ()
>  {
> -	if [[ -n ${ZSH_VERSION-} ]]; then
> +	if [[ -n $ZSH_VERSION ]]; then

> @@ -2730,7 +2787,7 @@ complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
>  	|| complete -o default -o nospace -F _git git.exe
>  fi
>  
> -if [[ -n ${ZSH_VERSION-} ]]; then
> +if [[ -n $ZSH_VERSION ]]; then

These three changes have nothing to do with bash4 issues, and they
break in 'set -u' environments, because $ZSH_VERSION is, of course,
undefined in bash.


Best,
Gábor

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-02 21:02     ` [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib Jonathan Nieder
@ 2010-12-02 23:40       ` SZEDER Gábor
  2010-12-03  0:07         ` Jonathan Nieder
  2010-12-03  8:02         ` Stephen Boyd
  2010-12-07 16:07       ` SZEDER Gábor
  1 sibling, 2 replies; 22+ messages in thread
From: SZEDER Gábor @ 2010-12-02 23:40 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Peter van der Does, Shawn O. Pearce, git, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

Hi,


On Thu, Dec 02, 2010 at 03:02:07PM -0600, Jonathan Nieder wrote:
> Add a minimal implementation of _get_comp_words_by_ref,
> the routine used to work around bash 4.0's COMP_WORDS semantics.

Some extension:

Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line.  In Bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page).  This behavior has changed with Bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).

Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in Bash also affects git's completion script.  For
example, when using Bash v4 the completion script can't provide
possible options for a command line argument (e.g. git log
--pretty=<TAB><TAB> lists files, but it should list possible log
formats).


I would really, _really_ like to have the above text in the commit
message (either in yours or in Peter's), because it took me weeks to
figure this out ;)  Not that it was that difficult, but when I
discovered this issue more than a month ago, "unfortunately" I
remembered a similar issue (db8a9ff, bash completion: Resolve git show
ref:path<tab> losing ref: portion, 2008-07-15), and it got me
sidetracked really really  badly.

(I'm still wondering what Bash v3.x was doing with COMP_WORDBREAKS,
though...)

> Based on bash-completion 2.x (commit bf763033, 2010-10-26) but
> tweaked for simplicity and to allow zsh to at least parse the
> code.
> 
> Based-on-patch-by: Peter van der Does <peter@avirtualhome.com>
> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
> ---
> Peter van der Does wrote:
> > Jonathan Nieder <jrnieder@gmail.com> wrote:
> 
> >>  2. Import the definition of _get_comp_words_by_ref from the
> >>     bash-completion lib and use it if ZSH_VERSION is unset.
> >> 
> >>  3. Further refinements, if needed.
> >> 
> >> What do you think?
> >
> > I like the idea and we should go with this solution.
> > 
> > If by importing you mean using :
> > [CODE]. /git_bash_completion-functions[/CODE] in the
> > contrib/completion/git-completion.bash script, which would be the best
> > solution imho. The question is where to place that the function file.
> [...]
> > It would have to include copying the functions file somewhere as well.
> > 
> > Or we could use the method used now and include the functions in the
> > git-completion.bash script.
> 
> Sorry for the lack of clarity.  Here's what I meant.
> 
>  contrib/completion/git-completion.bash |  125 ++++++++++++++++++++++++++++++++
>  1 files changed, 125 insertions(+), 0 deletions(-)

I haven't tried to understand the code yet, but noticed the following
two nits while glancing it over.

> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index 0b0eb45..1743319 100755
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -327,7 +327,102 @@ __gitcomp_1 ()
>  	done
>  }
>  
> +# The following function is based on code from:
> +#
> +#   bash_completion - programmable completion functions for bash 3.2+
> +#
> +#   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
> +#             © 2009-2010, Bash Completion Maintainers
> +#                     <bash-completion-devel@lists.alioth.debian.org>
> +#
> +#   This program is free software; you can redistribute it and/or modify
> +#   it under the terms of the GNU General Public License as published by
> +#   the Free Software Foundation; either version 2, or (at your option)
> +#   any later version.
> +#
> +#   This program is distributed in the hope that it will be useful,
> +#   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +#   GNU General Public License for more details.
> +#
> +#   You should have received a copy of the GNU General Public License
> +#   along with this program; if not, write to the Free Software Foundation,
> +#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> +#
> +#   The latest version of this software can be obtained here:
> +#
> +#   http://bash-completion.alioth.debian.org/
> +#
> +#   RELEASE: 2.x
> +
> +# This function can be used to access a tokenized list of words
> +# on the command line:
> +#
> +#	__reassemble_comp_words_by_ref '=:'

__git_reassemble_comp_words_by_ref?

> +#	if test "${words_[cword_-1]}" = -w
> +#	then
> +#		...
> +#	fi
> +#
> +# The argument should be a collection of characters from the list of
> +# word completion separators (COMP_WORDBREAKS) to treat as ordinary
> +# characters.
> +#
> +# This is roughly equivalent to locally setting COMP_WORDBREAKS to
> +# exclude those characters, but it does not clobber COMP_WORDBREAKS.
> +# The intent is for it to be used by commands like ssh that want to
> +# treat host:path as one token.
> +#
> +# Output: words_, cword_, cur_.
> +
> +__git_reassemble_comp_words_by_ref()
> +{
> +	local exclude i j first
> +	# Which word separators to exclude?
> +	exclude="${1//[^$COMP_WORDBREAKS]}"
> +	cword_=$COMP_CWORD
> +	if [ -z "$exclude" ]; then
> +		words_=("${COMP_WORDS[@]}")
> +		return
> +	fi
> +	# List of word completion separators has shrunk;
> +	# re-assemble words to complete.
> +	for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
> +		# Append each nonempty word consisting of just
> +		# word separator characters to the current word.
> +		first=t
> +		while
> +			[ $i -gt 0 ] &&
> +			[ -n "${COMP_WORDS[$i]}" ] &&
> +			# word consists of excluded word separators
> +			[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
> +		do
> +			# Attach to the previous token,
> +			# unless the previous token is the command name.
> +			if [ $j -ge 2 ] && [ -n "$first" ]; then
> +				((j--))
> +			fi
> +			first=
> +			words_[$j]=${words_[j]}${COMP_WORDS[i]}
> +			if [ $i = $COMP_CWORD ]; then
> +				cword_=$j
> +			fi
> +			if (($i < ${#COMP_WORDS[@]} - 1)); then
> +				((i++))
> +			else
> +				# Done.
> +				return
> +			fi
> +		done
> +		words_[$j]=${words_[j]}${COMP_WORDS[i]}
> +		if [ $i = $COMP_CWORD ]; then
> +			cword_=$j
> +		fi
> +	done
> +}
> +
>  if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
> +if [[ -n $ZSH_VERSION ]]; then

This should be ${ZSH_VERSION-} to keep 'set -u' environments happy.

 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-02 23:40       ` SZEDER Gábor
@ 2010-12-03  0:07         ` Jonathan Nieder
  2010-12-03  8:02         ` Stephen Boyd
  1 sibling, 0 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-03  0:07 UTC (permalink / raw)
  To: SZEDER Gábor
  Cc: Peter van der Does, Shawn O. Pearce, git, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

SZEDER Gábor wrote:

> Bash's programmable completion provides the COMP_WORDS array variable,
> which holds the individual words in the current command line.  In Bash
> versions prior to v4 "words are split on shell metacharacters as the
> shell parser would separate them" (quote from bash v3.2.48's man
> page).  This behavior has changed with Bash v4, and the command line
> "is split into words as readline would split it, using COMP_WORDBREAKS
> as" "the set of characters that the readline library treats as word
> separators" (quote from bash v4's man page).
>
> Since COMP_WORDBREAKS contains the characters : and = by default, this
> behavior change in Bash also affects git's completion script.  For
> example, when using Bash v4 the completion script can't provide
> possible options for a command line argument (e.g. git log
> --pretty=<TAB><TAB> lists files, but it should list possible log
> formats).
> 
> 
> I would really, _really_ like to have the above text in the commit
> message (either in yours or in Peter's), because it took me weeks to
> figure this out ;)

Sounds good.

> (I'm still wondering what Bash v3.x was doing with COMP_WORDBREAKS,
> though...)

Based on v1.5.6.4~9^2 (bash completion: Resolve git show ref:path<tab>
losing ref: portion, 2008-07-15) it seems COMP_WORDBREAKS determined
the interpretation of COMPREPLY (result of completion).  Of course it
also governed standard filename completion.

> On Thu, Dec 02, 2010 at 03:02:07PM -0600, Jonathan Nieder wrote:

>> +++ b/contrib/completion/git-completion.bash
>> @@ -327,7 +327,102 @@ __gitcomp_1 ()
[...]
>> +# This function can be used to access a tokenized list of words
>> +# on the command line:
>> +#
>> +#	__reassemble_comp_words_by_ref '=:'
>
> __git_reassemble_comp_words_by_ref?
[...]
>>  if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
>> +if [[ -n $ZSH_VERSION ]]; then
>
> This should be ${ZSH_VERSION-} to keep 'set -u' environments happy.

Nice catches; thanks.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-02 23:40       ` SZEDER Gábor
  2010-12-03  0:07         ` Jonathan Nieder
@ 2010-12-03  8:02         ` Stephen Boyd
  1 sibling, 0 replies; 22+ messages in thread
From: Stephen Boyd @ 2010-12-03  8:02 UTC (permalink / raw)
  To: SZEDER Gábor
  Cc: Jonathan Nieder, Peter van der Does, Shawn O. Pearce, git,
	Marc Branchaud, Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

On 12/02/10 15:40, SZEDER Gábor wrote:
>
> I would really, _really_ like to have the above text in the commit
> message (either in yours or in Peter's), because it took me weeks to
> figure this out ;)  Not that it was that difficult, but when I
> discovered this issue more than a month ago, "unfortunately" I
> remembered a similar issue (db8a9ff, bash completion: Resolve git show
> ref:path<tab> losing ref: portion, 2008-07-15), and it got me
> sidetracked really really  badly.
> 

I reported this issue over a year ago!

http://article.gmane.org/gmane.comp.version-control.git/133067

I'll be glad to see it fixed (but I haven't had time to look over these
patches and try them out yet).

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-02 21:02     ` [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib Jonathan Nieder
  2010-12-02 23:40       ` SZEDER Gábor
@ 2010-12-07 16:07       ` SZEDER Gábor
  2010-12-07 19:49         ` Jonathan Nieder
  1 sibling, 1 reply; 22+ messages in thread
From: SZEDER Gábor @ 2010-12-07 16:07 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Peter van der Does, Shawn O. Pearce, git, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

Hi Jonathan,

What is this patch based on?


Thanks,
Gábor


On Thu, Dec 02, 2010 at 03:02:07PM -0600, Jonathan Nieder wrote:
> Add a minimal implementation of _get_comp_words_by_ref,
> the routine used to work around bash 4.0's COMP_WORDS semantics.
> 
> Based on bash-completion 2.x (commit bf763033, 2010-10-26) but
> tweaked for simplicity and to allow zsh to at least parse the
> code.
> 
> Based-on-patch-by: Peter van der Does <peter@avirtualhome.com>
> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
> ---
> Peter van der Does wrote:
> > Jonathan Nieder <jrnieder@gmail.com> wrote:
> 
> >>  2. Import the definition of _get_comp_words_by_ref from the
> >>     bash-completion lib and use it if ZSH_VERSION is unset.
> >> 
> >>  3. Further refinements, if needed.
> >> 
> >> What do you think?
> >
> > I like the idea and we should go with this solution.
> > 
> > If by importing you mean using :
> > [CODE]. /git_bash_completion-functions[/CODE] in the
> > contrib/completion/git-completion.bash script, which would be the best
> > solution imho. The question is where to place that the function file.
> [...]
> > It would have to include copying the functions file somewhere as well.
> > 
> > Or we could use the method used now and include the functions in the
> > git-completion.bash script.
> 
> Sorry for the lack of clarity.  Here's what I meant.
> 
>  contrib/completion/git-completion.bash |  125 ++++++++++++++++++++++++++++++++
>  1 files changed, 125 insertions(+), 0 deletions(-)
> 
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index 0b0eb45..1743319 100755
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -327,7 +327,102 @@ __gitcomp_1 ()
>  	done
>  }
>  
> +# The following function is based on code from:
> +#
> +#   bash_completion - programmable completion functions for bash 3.2+
> +#
> +#   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
> +#             © 2009-2010, Bash Completion Maintainers
> +#                     <bash-completion-devel@lists.alioth.debian.org>
> +#
> +#   This program is free software; you can redistribute it and/or modify
> +#   it under the terms of the GNU General Public License as published by
> +#   the Free Software Foundation; either version 2, or (at your option)
> +#   any later version.
> +#
> +#   This program is distributed in the hope that it will be useful,
> +#   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +#   GNU General Public License for more details.
> +#
> +#   You should have received a copy of the GNU General Public License
> +#   along with this program; if not, write to the Free Software Foundation,
> +#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> +#
> +#   The latest version of this software can be obtained here:
> +#
> +#   http://bash-completion.alioth.debian.org/
> +#
> +#   RELEASE: 2.x
> +
> +# This function can be used to access a tokenized list of words
> +# on the command line:
> +#
> +#	__reassemble_comp_words_by_ref '=:'
> +#	if test "${words_[cword_-1]}" = -w
> +#	then
> +#		...
> +#	fi
> +#
> +# The argument should be a collection of characters from the list of
> +# word completion separators (COMP_WORDBREAKS) to treat as ordinary
> +# characters.
> +#
> +# This is roughly equivalent to locally setting COMP_WORDBREAKS to
> +# exclude those characters, but it does not clobber COMP_WORDBREAKS.
> +# The intent is for it to be used by commands like ssh that want to
> +# treat host:path as one token.
> +#
> +# Output: words_, cword_, cur_.
> +
> +__git_reassemble_comp_words_by_ref()
> +{
> +	local exclude i j first
> +	# Which word separators to exclude?
> +	exclude="${1//[^$COMP_WORDBREAKS]}"
> +	cword_=$COMP_CWORD
> +	if [ -z "$exclude" ]; then
> +		words_=("${COMP_WORDS[@]}")
> +		return
> +	fi
> +	# List of word completion separators has shrunk;
> +	# re-assemble words to complete.
> +	for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
> +		# Append each nonempty word consisting of just
> +		# word separator characters to the current word.
> +		first=t
> +		while
> +			[ $i -gt 0 ] &&
> +			[ -n "${COMP_WORDS[$i]}" ] &&
> +			# word consists of excluded word separators
> +			[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
> +		do
> +			# Attach to the previous token,
> +			# unless the previous token is the command name.
> +			if [ $j -ge 2 ] && [ -n "$first" ]; then
> +				((j--))
> +			fi
> +			first=
> +			words_[$j]=${words_[j]}${COMP_WORDS[i]}
> +			if [ $i = $COMP_CWORD ]; then
> +				cword_=$j
> +			fi
> +			if (($i < ${#COMP_WORDS[@]} - 1)); then
> +				((i++))
> +			else
> +				# Done.
> +				return
> +			fi
> +		done
> +		words_[$j]=${words_[j]}${COMP_WORDS[i]}
> +		if [ $i = $COMP_CWORD ]; then
> +			cword_=$j
> +		fi
> +	done
> +}
> +
>  if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
> +if [[ -n $ZSH_VERSION ]]; then
>  _get_comp_words_by_ref ()
>  {
>  	while [ $# -gt 0 ]; do
> @@ -352,6 +447,36 @@ _get_comp_words_by_ref ()
>  		shift
>  	done
>  }
> +else
> +_get_comp_words_by_ref ()
> +{
> +	local exclude cur_ cword_
> +	local words_=()
> +	if [ "$1" = "-n" ]; then
> +		exclude=$2
> +		shift 2
> +	fi
> +	__git_reassemble_comp_words_by_ref "$exclude"
> +	cur_=${words_[cword_]}
> +	while [ $# -gt 0 ]; do
> +		case "$1" in
> +		cur)
> +			cur=$cur_
> +			;;
> +		prev)
> +			prev=${words_[$cword_-1]}
> +			;;
> +		words)
> +			words=("${words_[@]}")
> +			;;
> +		cword)
> +			cword=$cword_
> +			;;
> +		esac
> +		shift
> +	done
> +}
> +fi
>  fi
>  
>  # __gitcomp accepts 1, 2, 3, or 4 arguments
> -- 
> 1.7.2.3
> 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-07 16:07       ` SZEDER Gábor
@ 2010-12-07 19:49         ` Jonathan Nieder
  2010-12-07 20:41           ` SZEDER Gábor
  2010-12-07 21:03           ` Junio C Hamano
  0 siblings, 2 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-07 19:49 UTC (permalink / raw)
  To: SZEDER Gábor
  Cc: Peter van der Does, Shawn O. Pearce, git, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

SZEDER Gábor wrote:
> On Thu, Dec 02, 2010 at 03:02:07PM -0600, Jonathan Nieder wrote:

>> Add a minimal implementation of _get_comp_words_by_ref,
>> the routine used to work around bash 4.0's COMP_WORDS semantics.
>> 
>> Based on bash-completion 2.x (commit bf763033, 2010-10-26) but
>> tweaked for simplicity and to allow zsh to at least parse the
>> code.
>
> What is this patch based on?

Ah, sorry, applies to d93f4a297 (bash: work around bash 4.0 change in
COMP_WORDS semantics, 2010-12-02).

Can re-send in a few moments based on maint if you'd like.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-07 19:49         ` Jonathan Nieder
@ 2010-12-07 20:41           ` SZEDER Gábor
  2010-12-07 20:59             ` Jonathan Nieder
  2010-12-07 21:03           ` Junio C Hamano
  1 sibling, 1 reply; 22+ messages in thread
From: SZEDER Gábor @ 2010-12-07 20:41 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Peter van der Does, Shawn O. Pearce, git, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

Hi Jonathan,


On Tue, Dec 07, 2010 at 01:49:23PM -0600, Jonathan Nieder wrote:
> SZEDER Gábor wrote:
> > On Thu, Dec 02, 2010 at 03:02:07PM -0600, Jonathan Nieder wrote:
> 
> >> Add a minimal implementation of _get_comp_words_by_ref,
> >> the routine used to work around bash 4.0's COMP_WORDS semantics.
> >> 
> >> Based on bash-completion 2.x (commit bf763033, 2010-10-26) but
> >> tweaked for simplicity and to allow zsh to at least parse the
> >> code.
> >
> > What is this patch based on?
> 
> Ah, sorry, applies to d93f4a297 (bash: work around bash 4.0 change in
> COMP_WORDS semantics, 2010-12-02).

In which repo? ;)

I don't have d93f4a297, but I have e0a9590 (Introduce functions from
bash-completion project., 2010-12-01) and c7e75bb (Use the new
functions to get the current cword., 2010-12-01) instead, which were
merged into pu at 0c30752 (Merge branch 'pd/bash-4-completion' into
pu, 2010-12-03).

Hm, waittaminit...  Ah, OK, nevermind, got it.  There was a patch in

  http://article.gmane.org/gmane.comp.version-control.git/162686

I forgot to apply first...  Now I have it all, seems to work so far.


Thanks,
Gábor

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-07 20:41           ` SZEDER Gábor
@ 2010-12-07 20:59             ` Jonathan Nieder
  0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-07 20:59 UTC (permalink / raw)
  To: SZEDER Gábor
  Cc: Peter van der Does, Shawn O. Pearce, git, Marc Branchaud,
	Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

SZEDER Gábor wrote:
> On Tue, Dec 07, 2010 at 01:49:23PM -0600, Jonathan Nieder wrote:

>> Ah, sorry, applies to d93f4a297 (bash: work around bash 4.0 change in
>> COMP_WORDS semantics, 2010-12-02).
>
> In which repo? ;)

Thanks.  I had meant to say that patch 1 applies to 06f44c3c
(completion: make compatible with zsh, 2010-09-06) and that the bash 4
support could be rebased to work without that if there is demand.

*goes off to get some coffee*

Sorry for the confusion.
Jonathan

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib
  2010-12-07 19:49         ` Jonathan Nieder
  2010-12-07 20:41           ` SZEDER Gábor
@ 2010-12-07 21:03           ` Junio C Hamano
  2010-12-15  6:24             ` [PATCH v5.1 0/3] Make git-completion Bash 4 compatible Jonathan Nieder
  1 sibling, 1 reply; 22+ messages in thread
From: Junio C Hamano @ 2010-12-07 21:03 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: SZEDER Gábor, Peter van der Does, Shawn O. Pearce, git,
	Marc Branchaud, Brian Gernhardt, Kevin Ballard, Mathias Lafeldt

Jonathan Nieder <jrnieder@gmail.com> writes:

> SZEDER Gábor wrote:
>> On Thu, Dec 02, 2010 at 03:02:07PM -0600, Jonathan Nieder wrote:
>
>>> Add a minimal implementation of _get_comp_words_by_ref,
>>> the routine used to work around bash 4.0's COMP_WORDS semantics.
>>> 
>>> Based on bash-completion 2.x (commit bf763033, 2010-10-26) but
>>> tweaked for simplicity and to allow zsh to at least parse the
>>> code.
>>
>> What is this patch based on?
>
> Ah, sorry, applies to d93f4a297 (bash: work around bash 4.0 change in
> COMP_WORDS semantics, 2010-12-02).

Sorry, but whose repository does that object live in?

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v5.1 0/3] Make git-completion Bash 4 compatible
  2010-12-07 21:03           ` Junio C Hamano
@ 2010-12-15  6:24             ` Jonathan Nieder
  2010-12-15  6:26               ` [PATCH 1/3] bash: get --pretty=m<tab> completion to work with bash v4 Jonathan Nieder
                                 ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-15  6:24 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: SZEDER Gábor, Peter van der Does, Shawn O. Pearce, git,
	Marc Branchaud, Brian Gernhardt, Kevin Ballard, Mathias Lafeldt,
	Stephen Boyd

Junio C Hamano wrote:
>>> On Thu, Dec 02, 2010 at 03:02:07PM -0600, Jonathan Nieder wrote:

>>>> Add a minimal implementation of _get_comp_words_by_ref,
>>>> the routine used to work around bash 4.0's COMP_WORDS semantics.
>>>>
>>>> Based on bash-completion 2.x (commit bf763033, 2010-10-26) but
>>>> tweaked for simplicity and to allow zsh to at least parse the
>>>> code.
[...]
> Sorry, but whose repository does that object live in?

Agh, sorry for the mess.  Please fetch

  git://repo.or.cz/git/jrn.git pd/bash-4-completion 

to receive the following history:

  o [maint-1.7.2] --- A --- B --- M [FETCH_HEAD]
                                 /
                                o [master (early part)]

[A] bash: get --pretty=m<tab> completion to work with bash v4
(by Peter)

[B] bash: simple reimplementation of _get_comp_words_by_ref
(discussed above)

[M] Merge branch 'master' (early part) into pd/bash-4-completion
(zsh compatibility)

[master (early part)] completion: fix zsh check under bash with 'set -u'
(2010-10-28 11:45:00 -0700).

A and B are the patches sent previously in this thread, rebased on an
older code base to avoid the zsh support.  A combined diff for the
merge 'M' will follow.  Thoughts, suggestions, acks, test reports
would be welcome.

Thanks for your patience.
Jonathan

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 1/3] bash: get --pretty=m<tab> completion to work with bash v4
  2010-12-15  6:24             ` [PATCH v5.1 0/3] Make git-completion Bash 4 compatible Jonathan Nieder
@ 2010-12-15  6:26               ` Jonathan Nieder
  2010-12-15  6:27               ` [PATCH 2/3] bash: simple reimplementation of _get_comp_words_by_ref Jonathan Nieder
  2010-12-15  6:42               ` [MERGE PATCH 3/3] Merge branch 'master' (early part) into pd/bash-4-completion Jonathan Nieder
  2 siblings, 0 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-15  6:26 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: SZEDER Gábor, Peter van der Does, Shawn O. Pearce, git,
	Marc Branchaud, Brian Gernhardt, Kevin Ballard, Mathias Lafeldt,
	Stephen Boyd

From: Peter van der Does <peter@avirtualhome.com>

Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line.  In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page).  This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).

Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script.  For example,
before bash 4, running

	$ git log --pretty=m <tab><tab>

would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.

It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts.  The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice.  Use it.

As a bonus, this improves behavior when tab is pressed with the cursor
in the middle of a word if the bash-completion lib is loaded.

To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then use
a shim that just reads COMP_WORDS instead (no change from the current
behavior in that case).

Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
---
 contrib/completion/git-completion.bash |  236 +++++++++++++++++++++----------
 1 files changed, 160 insertions(+), 76 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 82e6609..68b68d0 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -321,11 +321,39 @@ __gitcomp_1 ()
 	done
 }
 
+if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
+_get_comp_words_by_ref ()
+{
+	while [ $# -gt 0 ]; do
+		case "$1" in
+		cur)
+			cur=${COMP_WORDS[COMP_CWORD]}
+			;;
+		prev)
+			prev=${COMP_WORDS[COMP_CWORD-1]}
+			;;
+		words)
+			words=("${COMP_WORDS[@]}")
+			;;
+		cword)
+			cword=$COMP_CWORD
+			;;
+		-n)
+			# assume COMP_WORDBREAKS is already set sanely
+			shift
+			;;
+		esac
+		shift
+	done
+}
+fi
+
 # __gitcomp accepts 1, 2, 3, or 4 arguments
 # generates completion reply with compgen
 __gitcomp ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	if [ $# -gt 2 ]; then
 		cur="$3"
 	fi
@@ -384,7 +412,8 @@ __git_tags ()
 __git_refs ()
 {
 	local i is_hash=y dir="$(__gitdir "${1-}")"
-	local cur="${COMP_WORDS[COMP_CWORD]}" format refs
+	local cur format refs
+	_get_comp_words_by_ref -n =: cur
 	if [ -d "$dir" ]; then
 		case "$cur" in
 		refs|refs/*)
@@ -482,7 +511,8 @@ __git_compute_merge_strategies ()
 
 __git_complete_file ()
 {
-	local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
+	local pfx ls ref cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	?*:*)
 		ref="${cur%%:*}"
@@ -530,7 +560,8 @@ __git_complete_file ()
 
 __git_complete_revlist ()
 {
-	local pfx cur="${COMP_WORDS[COMP_CWORD]}"
+	local pfx cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	*...*)
 		pfx="${cur%...*}..."
@@ -550,11 +581,12 @@ __git_complete_revlist ()
 
 __git_complete_remote_or_refspec ()
 {
-	local cmd="${COMP_WORDS[1]}"
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur words cword
+	_get_comp_words_by_ref -n =: cur words cword
+	local cmd="${words[1]}"
 	local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
 		--all)
@@ -622,13 +654,14 @@ __git_complete_remote_or_refspec ()
 
 __git_complete_strategy ()
 {
+	local cur prev
+	_get_comp_words_by_ref -n =: cur prev
 	__git_compute_merge_strategies
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	case "$prev" in
 	-s|--strategy)
 		__gitcomp "$__git_merge_strategies"
 		return 0
 	esac
-	local cur="${COMP_WORDS[COMP_CWORD]}"
 	case "$cur" in
 	--strategy=*)
 		__gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}"
@@ -788,10 +821,10 @@ __git_aliased_command ()
 # __git_find_on_cmdline requires 1 argument
 __git_find_on_cmdline ()
 {
-	local word subcommand c=1
-
-	while [ $c -lt $COMP_CWORD ]; do
-		word="${COMP_WORDS[c]}"
+	local word subcommand c=1 words cword
+	_get_comp_words_by_ref -n =: words cword
+	while [ $c -lt $cword ]; do
+		word="${words[c]}"
 		for subcommand in $1; do
 			if [ "$subcommand" = "$word" ]; then
 				echo "$subcommand"
@@ -804,9 +837,10 @@ __git_find_on_cmdline ()
 
 __git_has_doubledash ()
 {
-	local c=1
-	while [ $c -lt $COMP_CWORD ]; do
-		if [ "--" = "${COMP_WORDS[c]}" ]; then
+	local c=1 words cword
+	_get_comp_words_by_ref -n =: words cword
+	while [ $c -lt $cword ]; do
+		if [ "--" = "${words[c]}" ]; then
 			return 0
 		fi
 		c=$((++c))
@@ -818,7 +852,8 @@ __git_whitespacelist="nowarn warn error error-all fix"
 
 _git_am ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+	local cur dir="$(__gitdir)"
+	_get_comp_words_by_ref -n =: cur
 	if [ -d "$dir"/rebase-apply ]; then
 		__gitcomp "--skip --continue --resolved --abort"
 		return
@@ -842,7 +877,8 @@ _git_am ()
 
 _git_apply ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--whitespace=*)
 		__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
@@ -865,7 +901,8 @@ _git_add ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -879,7 +916,8 @@ _git_add ()
 
 _git_archive ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--format=*)
 		__gitcomp "$(git archive --list)" "" "${cur##--format=}"
@@ -923,10 +961,11 @@ _git_bisect ()
 
 _git_branch ()
 {
-	local i c=1 only_local_ref="n" has_r="n"
+	local i c=1 only_local_ref="n" has_r="n" cur words cword
 
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	_get_comp_words_by_ref -n =: cur words cword
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		-d|-m)	only_local_ref="y" ;;
 		-r)	has_r="y" ;;
@@ -934,7 +973,7 @@ _git_branch ()
 		c=$((++c))
 	done
 
-	case "${COMP_WORDS[COMP_CWORD]}" in
+	case "$cur" in
 	--*)
 		__gitcomp "
 			--color --no-color --verbose --abbrev= --no-abbrev
@@ -954,8 +993,10 @@ _git_branch ()
 
 _git_bundle ()
 {
-	local cmd="${COMP_WORDS[2]}"
-	case "$COMP_CWORD" in
+	local words cword
+	_get_comp_words_by_ref -n =: words cword
+	local cmd="${words[2]}"
+	case "$cword" in
 	2)
 		__gitcomp "create list-heads verify unbundle"
 		;;
@@ -976,7 +1017,8 @@ _git_checkout ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--conflict=*)
 		__gitcomp "diff3 merge" "" "${cur##--conflict=}"
@@ -1000,7 +1042,8 @@ _git_cherry ()
 
 _git_cherry_pick ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--edit --no-commit"
@@ -1015,7 +1058,8 @@ _git_clean ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--dry-run --quiet"
@@ -1027,7 +1071,8 @@ _git_clean ()
 
 _git_clone ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1054,7 +1099,8 @@ _git_commit ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--cleanup=*)
 		__gitcomp "default strip verbatim whitespace
@@ -1089,7 +1135,8 @@ _git_commit ()
 
 _git_describe ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1121,7 +1168,8 @@ _git_diff ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
@@ -1142,7 +1190,8 @@ _git_difftool ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--tool=*)
 		__gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
@@ -1167,7 +1216,8 @@ __git_fetch_options="
 
 _git_fetch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "$__git_fetch_options"
@@ -1179,7 +1229,8 @@ _git_fetch ()
 
 _git_format_patch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--thread=*)
 		__gitcomp "
@@ -1211,7 +1262,8 @@ _git_format_patch ()
 
 _git_fsck ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1226,7 +1278,8 @@ _git_fsck ()
 
 _git_gc ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--prune --aggressive"
@@ -1245,7 +1298,8 @@ _git_grep ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1268,7 +1322,8 @@ _git_grep ()
 
 _git_help ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--all --info --man --web"
@@ -1286,7 +1341,8 @@ _git_help ()
 
 _git_init ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--shared=*)
 		__gitcomp "
@@ -1306,7 +1362,8 @@ _git_ls_files ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --deleted --modified --others --ignored
@@ -1360,12 +1417,13 @@ _git_log ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
 	local g="$(git rev-parse --git-dir 2>/dev/null)"
 	local merge=""
 	if [ -f "$g/MERGE_HEAD" ]; then
 		merge="--merge"
 	fi
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--pretty=*)
 		__gitcomp "$__git_log_pretty_formats
@@ -1419,7 +1477,8 @@ _git_merge ()
 {
 	__git_complete_strategy && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "$__git_merge_options"
@@ -1430,7 +1489,8 @@ _git_merge ()
 
 _git_mergetool ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--tool=*)
 		__gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
@@ -1451,7 +1511,8 @@ _git_merge_base ()
 
 _git_mv ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--dry-run"
@@ -1469,12 +1530,14 @@ _git_name_rev ()
 _git_notes ()
 {
 	local subcommands="edit show"
+	local words cword
+	_get_comp_words_by_ref -n =: words cword
 	if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
 		__gitcomp "$subcommands"
 		return
 	fi
 
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	case "${words[cword-1]}" in
 	-m|-F)
 		COMPREPLY=()
 		;;
@@ -1488,7 +1551,8 @@ _git_pull ()
 {
 	__git_complete_strategy && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -1504,8 +1568,9 @@ _git_pull ()
 
 _git_push ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	local cur prev
+	_get_comp_words_by_ref -n =: cur prev
+	case "$prev" in
 	--repo)
 		__gitcomp "$(__git_remotes)"
 		return
@@ -1528,7 +1593,9 @@ _git_push ()
 
 _git_rebase ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+	local dir="$(__gitdir)"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
 		__gitcomp "--continue --skip --abort"
 		return
@@ -1558,7 +1625,8 @@ __git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
 
 _git_send_email ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--confirm=*)
 		__gitcomp "
@@ -1600,9 +1668,11 @@ _git_stage ()
 
 __git_config_get_set_variables ()
 {
-	local prevword word config_file= c=$COMP_CWORD
+	local words cword
+	_get_comp_words_by_ref -n =: words cword
+	local prevword word config_file= c=$cword
 	while [ $c -gt 1 ]; do
-		word="${COMP_WORDS[c]}"
+		word="${words[c]}"
 		case "$word" in
 		--global|--system|--file=*)
 			config_file="$word"
@@ -1630,9 +1700,9 @@ __git_config_get_set_variables ()
 
 _git_config ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
-	local prv="${COMP_WORDS[COMP_CWORD-1]}"
-	case "$prv" in
+	local cur prev
+	_get_comp_words_by_ref -n =: cur prev
+	case "$prev" in
 	branch.*.remote)
 		__gitcomp "$(__git_remotes)"
 		return
@@ -1642,13 +1712,13 @@ _git_config ()
 		return
 		;;
 	remote.*.fetch)
-		local remote="${prv#remote.}"
+		local remote="${prev#remote.}"
 		remote="${remote%.fetch}"
 		__gitcomp "$(__git_refs_remotes "$remote")"
 		return
 		;;
 	remote.*.push)
-		local remote="${prv#remote.}"
+		local remote="${prev#remote.}"
 		remote="${remote%.push}"
 		__gitcomp "$(git --git-dir="$(__gitdir)" \
 			for-each-ref --format='%(refname):%(refname)' \
@@ -2039,7 +2109,8 @@ _git_reset ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--merge --mixed --hard --soft --patch"
@@ -2051,7 +2122,8 @@ _git_reset ()
 
 _git_revert ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--edit --mainline --no-edit --no-commit --signoff"
@@ -2065,7 +2137,8 @@ _git_rm ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "--cached --dry-run --ignore-unmatch --quiet"
@@ -2079,7 +2152,8 @@ _git_shortlog ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -2097,7 +2171,8 @@ _git_show ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--pretty=*)
 		__gitcomp "$__git_log_pretty_formats
@@ -2121,7 +2196,8 @@ _git_show ()
 
 _git_show_branch ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
@@ -2138,7 +2214,8 @@ _git_show_branch ()
 
 _git_stash ()
 {
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
+	_get_comp_words_by_ref -n =: cur
 	local save_opts='--keep-index --no-keep-index --quiet --patch'
 	local subcommands='save list show apply clear drop pop create branch'
 	local subcommand="$(__git_find_on_cmdline "$subcommands")"
@@ -2183,7 +2260,8 @@ _git_submodule ()
 
 	local subcommands="add status init update summary foreach sync"
 	if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
-		local cur="${COMP_WORDS[COMP_CWORD]}"
+		local cur
+		_get_comp_words_by_ref -n =: cur
 		case "$cur" in
 		--*)
 			__gitcomp "--quiet --cached"
@@ -2227,7 +2305,8 @@ _git_svn ()
 			--edit --rmdir --find-copies-harder --copy-similarity=
 			"
 
-		local cur="${COMP_WORDS[COMP_CWORD]}"
+		local cur
+		_get_comp_words_by_ref -n =: cur
 		case "$subcommand,$cur" in
 		fetch,--*)
 			__gitcomp "--revision= --fetch-all $fc_opts"
@@ -2299,8 +2378,10 @@ _git_svn ()
 _git_tag ()
 {
 	local i c=1 f=0
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	local words cword prev
+	_get_comp_words_by_ref -n =: words cword prev
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		-d|-v)
 			__gitcomp "$(__git_tags)"
@@ -2313,7 +2394,7 @@ _git_tag ()
 		c=$((++c))
 	done
 
-	case "${COMP_WORDS[COMP_CWORD-1]}" in
+	case "$prev" in
 	-m|-F)
 		COMPREPLY=()
 		;;
@@ -2339,8 +2420,10 @@ _git ()
 {
 	local i c=1 command __git_dir
 
-	while [ $c -lt $COMP_CWORD ]; do
-		i="${COMP_WORDS[c]}"
+	local cur words cword
+	_get_comp_words_by_ref -n =: cur words cword
+	while [ $c -lt $cword ]; do
+		i="${words[c]}"
 		case "$i" in
 		--git-dir=*) __git_dir="${i#--git-dir=}" ;;
 		--bare)      __git_dir="." ;;
@@ -2352,7 +2435,7 @@ _git ()
 	done
 
 	if [ -z "$command" ]; then
-		case "${COMP_WORDS[COMP_CWORD]}" in
+		case "$cur" in
 		--*)   __gitcomp "
 			--paginate
 			--no-pager
@@ -2385,12 +2468,13 @@ _gitk ()
 {
 	__git_has_doubledash && return
 
-	local cur="${COMP_WORDS[COMP_CWORD]}"
+	local cur
 	local g="$(__gitdir)"
 	local merge=""
 	if [ -f "$g/MERGE_HEAD" ]; then
 		merge="--merge"
 	fi
+	_get_comp_words_by_ref -n =: cur
 	case "$cur" in
 	--*)
 		__gitcomp "
-- 
1.7.3.3.573.g0bcfc

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 2/3] bash: simple reimplementation of _get_comp_words_by_ref
  2010-12-15  6:24             ` [PATCH v5.1 0/3] Make git-completion Bash 4 compatible Jonathan Nieder
  2010-12-15  6:26               ` [PATCH 1/3] bash: get --pretty=m<tab> completion to work with bash v4 Jonathan Nieder
@ 2010-12-15  6:27               ` Jonathan Nieder
  2010-12-15  6:42               ` [MERGE PATCH 3/3] Merge branch 'master' (early part) into pd/bash-4-completion Jonathan Nieder
  2 siblings, 0 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-15  6:27 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: SZEDER Gábor, Peter van der Does, Shawn O. Pearce, git,
	Marc Branchaud, Brian Gernhardt, Kevin Ballard, Mathias Lafeldt,
	Stephen Boyd

Add a minimal implementation of _get_comp_words_by_ref so

	$ git show head:g <tab><tab>

on bash 4 can complete paths within the head commit without requiring
the bash_completion functions to be loaded.  This is a follow-up to
the previous patch (bash: get --pretty=m<tab> completion to work with
bash v4).

Based on bash-completion 2.x (commit bf763033, 2010-10-26) but tweaked
for simplicity and to allow zsh to parse the code.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Improved-by: SZEDER Gábor <szeder@ira.uka.de>
---
 contrib/completion/git-completion.bash |  118 +++++++++++++++++++++++++++++--
 1 files changed, 110 insertions(+), 8 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 68b68d0..1747091 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -321,26 +321,128 @@ __gitcomp_1 ()
 	done
 }
 
+# The following function is based on code from:
+#
+#   bash_completion - programmable completion functions for bash 3.2+
+#
+#   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
+#             © 2009-2010, Bash Completion Maintainers
+#                     <bash-completion-devel@lists.alioth.debian.org>
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2, or (at your option)
+#   any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#   The latest version of this software can be obtained here:
+#
+#   http://bash-completion.alioth.debian.org/
+#
+#   RELEASE: 2.x
+
+# This function can be used to access a tokenized list of words
+# on the command line:
+#
+#	__git_reassemble_comp_words_by_ref '=:'
+#	if test "${words_[cword_-1]}" = -w
+#	then
+#		...
+#	fi
+#
+# The argument should be a collection of characters from the list of
+# word completion separators (COMP_WORDBREAKS) to treat as ordinary
+# characters.
+#
+# This is roughly equivalent to going back in time and setting
+# COMP_WORDBREAKS to exclude those characters.  The intent is to
+# make option types like --date=<type> and <rev>:<path> easy to
+# recognize by treating each shell word as a single token.
+#
+# It is best not to set COMP_WORDBREAKS directly because the value is
+# shared with other completion scripts.  By the time the completion
+# function gets called, COMP_WORDS has already been populated so local
+# changes to COMP_WORDBREAKS have no effect.
+#
+# Output: words_, cword_, cur_.
+
+__git_reassemble_comp_words_by_ref()
+{
+	local exclude i j first
+	# Which word separators to exclude?
+	exclude="${1//[^$COMP_WORDBREAKS]}"
+	cword_=$COMP_CWORD
+	if [ -z "$exclude" ]; then
+		words_=("${COMP_WORDS[@]}")
+		return
+	fi
+	# List of word completion separators has shrunk;
+	# re-assemble words to complete.
+	for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
+		# Append each nonempty word consisting of just
+		# word separator characters to the current word.
+		first=t
+		while
+			[ $i -gt 0 ] &&
+			[ -n "${COMP_WORDS[$i]}" ] &&
+			# word consists of excluded word separators
+			[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
+		do
+			# Attach to the previous token,
+			# unless the previous token is the command name.
+			if [ $j -ge 2 ] && [ -n "$first" ]; then
+				((j--))
+			fi
+			first=
+			words_[$j]=${words_[j]}${COMP_WORDS[i]}
+			if [ $i = $COMP_CWORD ]; then
+				cword_=$j
+			fi
+			if (($i < ${#COMP_WORDS[@]} - 1)); then
+				((i++))
+			else
+				# Done.
+				return
+			fi
+		done
+		words_[$j]=${words_[j]}${COMP_WORDS[i]}
+		if [ $i = $COMP_CWORD ]; then
+			cword_=$j
+		fi
+	done
+}
+
 if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
 _get_comp_words_by_ref ()
 {
+	local exclude cur_ words_ cword_
+	if [ "$1" = "-n" ]; then
+		exclude=$2
+		shift 2
+	fi
+	__git_reassemble_comp_words_by_ref "$exclude"
+	cur_=${words_[cword_]}
 	while [ $# -gt 0 ]; do
 		case "$1" in
 		cur)
-			cur=${COMP_WORDS[COMP_CWORD]}
+			cur=$cur_
 			;;
 		prev)
-			prev=${COMP_WORDS[COMP_CWORD-1]}
+			prev=${words_[$cword_-1]}
 			;;
 		words)
-			words=("${COMP_WORDS[@]}")
+			words=("${words_[@]}")
 			;;
 		cword)
-			cword=$COMP_CWORD
-			;;
-		-n)
-			# assume COMP_WORDBREAKS is already set sanely
-			shift
+			cword=$cword_
 			;;
 		esac
 		shift
-- 
1.7.3.3.573.g0bcfc

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [MERGE PATCH 3/3] Merge branch 'master' (early part) into pd/bash-4-completion
  2010-12-15  6:24             ` [PATCH v5.1 0/3] Make git-completion Bash 4 compatible Jonathan Nieder
  2010-12-15  6:26               ` [PATCH 1/3] bash: get --pretty=m<tab> completion to work with bash v4 Jonathan Nieder
  2010-12-15  6:27               ` [PATCH 2/3] bash: simple reimplementation of _get_comp_words_by_ref Jonathan Nieder
@ 2010-12-15  6:42               ` Jonathan Nieder
  2 siblings, 0 replies; 22+ messages in thread
From: Jonathan Nieder @ 2010-12-15  6:42 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: SZEDER Gábor, Peter van der Does, Shawn O. Pearce, git,
	Marc Branchaud, Brian Gernhardt, Kevin Ballard, Mathias Lafeldt,
	Stephen Boyd

* 'master' (early part): (529 commits)
  completion: fix zsh check under bash with 'set -u'
  Fix copy-pasted comments related to tree diff handling.
  Git 1.7.3.2
  {cvs,svn}import: use the new 'git read-tree --empty'
  t/t9001-send-email.sh: fix stderr redirection in 'Invalid In-Reply-To'
  Clarify and extend the "git diff" format documentation
  git-show-ref.txt: clarify the pattern matching
  documentation: git-config minor cleanups
  Update test script annotate-tests.sh to handle missing/extra authors
  ...

Conflicts:
	GIT-VERSION-GEN
	RelNotes
	contrib/completion/git-completion.bash
---
Suggestions for further work:

 - check edge cases:

	git log --pretty m<tab><tab>		should complete formats
	git log --pretty =<tab><tab>		should complain
	git log --pretty= m<tab><tab>		should complete commits

 - use a custom function to avoid repeating

	_get_comp_words_by_ref -n =:

   As an application, consider teaching git to complete

	git show HEAD@{<tab><tab>		completes to numbers and "upstream"

   Would the argument to -n need an @ for that?

 - get the zsh completion to actually work. :)  Even without this
   series, it seems it is willing to complete subcommand names and
   switches for git but nothing more.

 - adopt the rest of bash_completion's _get_comp_words_by_ref logic,
   so

	git log --pretty=m<cursor>master <tab><tab>

   completes formats starting with 'm', not formats starting with 'mmaster'.

If something turned out buggy, I'd be glad to fix it, but aside from
that I probably will not be working much more on this topic.  (Perhaps
an actual tab completion user would have a better sense of which
aspects are worth working on.)  Please feel free to pick it up and run
in whatever direction you please.

Good night,
Jonathan

diff --cc contrib/completion/git-completion.bash
index 1747091,168669b..d117055
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@@ -321,135 -327,6 +327,162 @@@ __gitcomp_1 (
  	done
  }
  
 +# The following function is based on code from:
 +#
 +#   bash_completion - programmable completion functions for bash 3.2+
 +#
 +#   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
 +#             © 2009-2010, Bash Completion Maintainers
 +#                     <bash-completion-devel@lists.alioth.debian.org>
 +#
 +#   This program is free software; you can redistribute it and/or modify
 +#   it under the terms of the GNU General Public License as published by
 +#   the Free Software Foundation; either version 2, or (at your option)
 +#   any later version.
 +#
 +#   This program is distributed in the hope that it will be useful,
 +#   but WITHOUT ANY WARRANTY; without even the implied warranty of
 +#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +#   GNU General Public License for more details.
 +#
 +#   You should have received a copy of the GNU General Public License
 +#   along with this program; if not, write to the Free Software Foundation,
 +#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 +#
 +#   The latest version of this software can be obtained here:
 +#
 +#   http://bash-completion.alioth.debian.org/
 +#
 +#   RELEASE: 2.x
 +
 +# This function can be used to access a tokenized list of words
 +# on the command line:
 +#
 +#	__git_reassemble_comp_words_by_ref '=:'
 +#	if test "${words_[cword_-1]}" = -w
 +#	then
 +#		...
 +#	fi
 +#
 +# The argument should be a collection of characters from the list of
 +# word completion separators (COMP_WORDBREAKS) to treat as ordinary
 +# characters.
 +#
 +# This is roughly equivalent to going back in time and setting
 +# COMP_WORDBREAKS to exclude those characters.  The intent is to
 +# make option types like --date=<type> and <rev>:<path> easy to
 +# recognize by treating each shell word as a single token.
 +#
 +# It is best not to set COMP_WORDBREAKS directly because the value is
 +# shared with other completion scripts.  By the time the completion
 +# function gets called, COMP_WORDS has already been populated so local
 +# changes to COMP_WORDBREAKS have no effect.
 +#
 +# Output: words_, cword_, cur_.
 +
 +__git_reassemble_comp_words_by_ref()
 +{
 +	local exclude i j first
 +	# Which word separators to exclude?
 +	exclude="${1//[^$COMP_WORDBREAKS]}"
 +	cword_=$COMP_CWORD
 +	if [ -z "$exclude" ]; then
 +		words_=("${COMP_WORDS[@]}")
 +		return
 +	fi
 +	# List of word completion separators has shrunk;
 +	# re-assemble words to complete.
 +	for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
 +		# Append each nonempty word consisting of just
 +		# word separator characters to the current word.
 +		first=t
 +		while
 +			[ $i -gt 0 ] &&
 +			[ -n "${COMP_WORDS[$i]}" ] &&
 +			# word consists of excluded word separators
 +			[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
 +		do
 +			# Attach to the previous token,
 +			# unless the previous token is the command name.
 +			if [ $j -ge 2 ] && [ -n "$first" ]; then
 +				((j--))
 +			fi
 +			first=
 +			words_[$j]=${words_[j]}${COMP_WORDS[i]}
 +			if [ $i = $COMP_CWORD ]; then
 +				cword_=$j
 +			fi
 +			if (($i < ${#COMP_WORDS[@]} - 1)); then
 +				((i++))
 +			else
 +				# Done.
 +				return
 +			fi
 +		done
 +		words_[$j]=${words_[j]}${COMP_WORDS[i]}
 +		if [ $i = $COMP_CWORD ]; then
 +			cword_=$j
 +		fi
 +	done
 +}
 +
 +if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
++if [[ -z ${ZSH_VERSION:+set} ]]; then
 +_get_comp_words_by_ref ()
 +{
 +	local exclude cur_ words_ cword_
 +	if [ "$1" = "-n" ]; then
 +		exclude=$2
 +		shift 2
 +	fi
 +	__git_reassemble_comp_words_by_ref "$exclude"
 +	cur_=${words_[cword_]}
 +	while [ $# -gt 0 ]; do
 +		case "$1" in
 +		cur)
 +			cur=$cur_
 +			;;
 +		prev)
 +			prev=${words_[$cword_-1]}
 +			;;
 +		words)
 +			words=("${words_[@]}")
 +			;;
 +		cword)
 +			cword=$cword_
 +			;;
 +		esac
 +		shift
 +	done
 +}
++else
++_get_comp_words_by_ref ()
++{
++	while [ $# -gt 0 ]; do
++		case "$1" in
++		cur)
++			cur=${COMP_WORDS[COMP_CWORD]}
++			;;
++		prev)
++			prev=${COMP_WORDS[COMP_CWORD-1]}
++			;;
++		words)
++			words=("${COMP_WORDS[@]}")
++			;;
++		cword)
++			cword=$COMP_CWORD
++			;;
++		-n)
++			# assume COMP_WORDBREAKS is already set sanely
++			shift
++			;;
++		esac
++		shift
++	done
++}
++fi
 +fi
 +
  # __gitcomp accepts 1, 2, 3, or 4 arguments
  # generates completion reply with compgen
  __gitcomp ()
@@@ -2522,10 -2345,13 +2555,15 @@@ _git (
  {
  	local i c=1 command __git_dir
  
+ 	if [[ -n ${ZSH_VERSION-} ]]; then
+ 		emulate -L bash
+ 		setopt KSH_TYPESET
+ 	fi
+ 
 -	while [ $c -lt $COMP_CWORD ]; do
 -		i="${COMP_WORDS[c]}"
 +	local cur words cword
 +	_get_comp_words_by_ref -n =: cur words cword
 +	while [ $c -lt $cword ]; do
 +		i="${words[c]}"
  		case "$i" in
  		--git-dir=*) __git_dir="${i#--git-dir=}" ;;
  		--bare)      __git_dir="." ;;
@@@ -2568,9 -2394,14 +2606,14 @@@
  
  _gitk ()
  {
+ 	if [[ -n ${ZSH_VERSION-} ]]; then
+ 		emulate -L bash
+ 		setopt KSH_TYPESET
+ 	fi
+ 
  	__git_has_doubledash && return
  
 -	local cur="${COMP_WORDS[COMP_CWORD]}"
 +	local cur
  	local g="$(__gitdir)"
  	local merge=""
  	if [ -f "$g/MERGE_HEAD" ]; then

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2010-12-15  6:43 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-12-01 20:49 [PATCH v4 0/2] *** SUBJECT HERE *** Peter van der Does
2010-12-01 20:49 ` [PATCH v4 1/2] Introduce functions from bash-completion project Peter van der Does
2010-12-01 20:49 ` [PATCH v4 2/2] Use the new functions to get the current cword Peter van der Does
2010-12-02  7:45   ` Jonathan Nieder
2010-12-02 22:36   ` SZEDER Gábor
2010-12-01 21:09 ` [PATCH v4 0/2] Make git-completion Bash 4 compatible Jonathan Nieder
2010-12-02  1:10 ` SZEDER Gábor
2010-12-02  9:16 ` Jonathan Nieder
2010-12-02 14:16   ` Peter van der Does
2010-12-02 21:02     ` [RFC/PATCH 2/1] bash: eliminate dependency on bash_completion lib Jonathan Nieder
2010-12-02 23:40       ` SZEDER Gábor
2010-12-03  0:07         ` Jonathan Nieder
2010-12-03  8:02         ` Stephen Boyd
2010-12-07 16:07       ` SZEDER Gábor
2010-12-07 19:49         ` Jonathan Nieder
2010-12-07 20:41           ` SZEDER Gábor
2010-12-07 20:59             ` Jonathan Nieder
2010-12-07 21:03           ` Junio C Hamano
2010-12-15  6:24             ` [PATCH v5.1 0/3] Make git-completion Bash 4 compatible Jonathan Nieder
2010-12-15  6:26               ` [PATCH 1/3] bash: get --pretty=m<tab> completion to work with bash v4 Jonathan Nieder
2010-12-15  6:27               ` [PATCH 2/3] bash: simple reimplementation of _get_comp_words_by_ref Jonathan Nieder
2010-12-15  6:42               ` [MERGE PATCH 3/3] Merge branch 'master' (early part) into pd/bash-4-completion Jonathan Nieder

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).