On Sat, Oct 23, 2010 at 08:07:39PM -0400, Peter van der Does wrote: > On Sat, 23 Oct 2010 15:04:34 +0200 > SZEDER Gábor <szeder@xxxxxxxxxx> wrote: > > > This patch assumes that you use fairly recent bash-completion, because > > _get_comp_words_by_ref() was first included in bash-completion v1.2, > > which was released just this summer. > > > > However, git completion is currently a standalone completion script, > > i.e. to use it you need only bash, git-completion.bash, and nothing > > else. If we start to use _get_comp_words_by_ref() directly, as in the > > PoC patch above, then git completion will inherently depend on > > bash-completion, too. This could be considered as a regression. > > > > Alternatively, we could just copy the necessary functions from > > bash-completion to git-completion.bash (with the name changed, of > > course, e.g. to __git_get_comp_words_by_ref()), keeping git completion > > standalone but still getting the benefits of this function, and > > getting these bash 4 vs. 3 issues fixed. > > > > Thoughts? > > > > Instead of using [code]_get_comp_words_by_ref -n '=' cur[/code] you can > use [code]local cur=`_get_cword "="`[/code]. > > To keep git completion standalone we need to, like Gábor mentioned, add > the necessary functions, but we don't have to rename them. There is > an option to check if a function exists. I've changed the entire git > completion script and hopefully covered all options. From my tests it > works on bash 4. Checking for the function first, and declaring it if it doesn't exists could be a viewable alternative, but not with _get_cword(). The _get_cword() implementation you are adding below is outdated. It is from bash-completion 1.1, changed quite a bit after that, and in the end became deprecated in 1.2 in favor of _get_comp_words_by_ref(). > To give an idea of what the change is, here's part of the entire diff. > > diff --git a/contrib/completion/git-completion.bash > b/contrib/completion/git-completion.bash index f83f019..a2c0589 100755 > --- a/contrib/completion/git-completion.bash > +++ b/contrib/completion/git-completion.bash > @@ -71,12 +71,159 @@ > # > # git@xxxxxxxxxxxxxxx > # > +# Updated for Bash 4.0 > > case "$COMP_WORDBREAKS" in > *:*) : great ;; > *) COMP_WORDBREAKS="$COMP_WORDBREAKS:" > esac > > +# If the function _get_cword does not exists, we can assume the > +# bash_completion script isn't loaded and therefor we're defining the > +# necessary functions ourselves. > +if ! type _get_cword &> /dev/null ; then > + # features supported by bash 4.0 and higher > + if [ ${BASH_VERSINFO[0]} -gt 3 ]; then > + declare -r git_bash4=$BASH_VERSION 2>/dev/null || : > + fi > + > + # Get the word to complete. > + # 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 --------> ^ > + # it will complete just "foo", not "foobar", which is what the > user wants.) > + # @param $1 string (optional) 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. > + # NOTE: This parameter only applies to bash-4. > + _get_cword() > + { > + if [ -n "$git_bash4" ] ; then > + __get_cword4 "$@" > + else > + __get_cword3 > + fi > + } # _get_cword() > + > + > + # Get the word to complete on bash-3, where words are not > broken by > + # COMP_WORDBREAKS characters and the COMP_CWORD variables look > like this, for > + # example: > + # > + # $ a b:c<TAB> > + # COMP_CWORD: 1 > + # COMP_CWORDS: > + # 0: a > + # 1: b:c > + # > + # See also: > + # _get_cword, main routine > + # __get_cword4, bash-4 variant > + # > + __get_cword3() > + { > + if [[ "${#COMP_WORDS[COMP_CWORD]}" -eq 0 ]] || > [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then > + printf "%s" "${COMP_WORDS[COMP_CWORD]}" > + else > + local i > + local cur="$COMP_LINE" > + local index="$COMP_POINT" > + for (( i = 0; i <= COMP_CWORD; ++i )); do > + while [[ > + # Current COMP_WORD fits in $cur? > + "${#cur}" -ge ${#COMP_WORDS[i]} && > + # $cur doesn't match COMP_WORD? > + "${cur:0:${#COMP_WORDS[i]}}" != > "${COMP_WORDS[i]}" > + ]]; do > + # Strip first character > + cur="${cur:1}" > + # Decrease cursor position > + index="$(( index - 1 ))" > + done > + > + # Does found COMP_WORD matches COMP_CWORD? > + if [[ "$i" -lt "$COMP_CWORD" ]]; then > + # No, COMP_CWORD lies further; > + local old_size="${#cur}" > + cur="${cur#${COMP_WORDS[i]}}" > + local new_size="${#cur}" > + index="$(( index - old_size + new_size ))" > + fi > + done > + > + if [[ "${COMP_WORDS[COMP_CWORD]:0:${#cur}}" != > "$cur" ]]; then > + # We messed up! At least return the whole word so > things > + # keep working > + printf "%s" "${COMP_WORDS[COMP_CWORD]}" > + else > + printf "%s" "${cur:0:$index}" > + fi > + fi > + } # __get_cword3() > + > + > + # Get the word to complete on bash-4, where words are splitted > by > + # COMP_WORDBREAKS characters (default is " \t\n\"'><=;|&(:") > and the COMP_CWORD > + # variables look like this, for example: > + # > + # $ a b:c<TAB> > + # COMP_CWORD: 3 > + # COMP_CWORDS: > + # 0: a > + # 1: b > + # 2: : > + # 3: c > + # > + # @oaram $1 string > + # $1 string (optional) 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. > + # See also: > + # _get_cword, main routine > + # __get_cword3, bash-3 variant > + # > + __get_cword4() > + { > + local i > + local LC_CTYPE=C > + local WORDBREAKS=$COMP_WORDBREAKS > + # Strip single quote (') and double quote (") from > WORDBREAKS to > + # workaround a bug in bash-4.0, where quoted words are > split > + # unintended, see: > + # > http://www.mail-archive.com/bug-bash@xxxxxxx/msg06095.html > + # This fixes simple quoting (e.g. $ a "b<TAB> returns "b > instead of b) > + # but still fails quoted spaces (e.g. $ a "b c<TAB> > returns c instead > + # of "b c). > + WORDBREAKS=${WORDBREAKS//\"/} > + WORDBREAKS=${WORDBREAKS//\'/} > + if [ -n "$1" ]; then > + for (( i=0; i<${#1}; ++i )); do > + local char=${1:$i:1} > + WORDBREAKS=${WORDBREAKS//$char/} > + done > + fi > + local cur=${COMP_LINE:0:$COMP_POINT} > + local tmp=$cur > + local word_start=`expr "$tmp" : '.*['"$WORDBREAKS"']'` > + while [ "$word_start" -ge 2 ]; do > + # Get character before $word_start > + local char=${cur:$(( $word_start - 2 )):1} > + # If the WORDBREAK character isn't escaped, exit loop > + if [ "$char" != "\\" ]; then > + break > + fi > + # The WORDBREAK character is escaped; > + # Recalculate $word_start > + tmp=${COMP_LINE:0:$(( $word_start - 2 ))} > + word_start=`expr "$tmp" : '.*['"$WORDBREAKS"']'` > + done > + > + cur=${cur:$word_start} > + printf "%s" "$cur" > + } # __get_cword4() > +fi > + > @@ -551,7 +698,7 @@ __git_complete_revlist () > __git_complete_remote_or_refspec () > { > local cmd="${COMP_WORDS[1]}" > - local cur="${COMP_WORDS[COMP_CWORD]}" > + local cur=`_get_cword ":"` > local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0 > while [ $c -lt $COMP_CWORD ]; do > i="${COMP_WORDS[c]}" > @@ -1360,7 +1508,7 @@ _git_log () > { > __git_has_doubledash && return > > - local cur="${COMP_WORDS[COMP_CWORD]}" > + local cur=`_get_cword "="` > local g="$(git rev-parse --git-dir 2>/dev/null)" > local merge="" > if [ -f "$g/MERGE_HEAD" ]; then > @@ -1419,7 +1567,7 @@ _git_merge () > { > __git_complete_strategy && return > > - local cur="${COMP_WORDS[COMP_CWORD]}" > + local cur=`_get_cword` > case "$cur" in > --*) > __gitcomp "$__git_merge_options" > > > I just need someone to test the new script on Bash 3. If somebody is > willing to test, drop me an private email and I can send the new script. > -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html