git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [completion] Request: Include remote heads as push targets

From
SZEDER Gábor <szeder@ira.uka.de>
Date
Oct 24, 2010, 11:23 UTC
Message-ID
<20101024112325.GB29386@neumann>
In-Reply-To
<20101023200739.28b6eb1e@montecarlo.grandprix.int>
On Sat, Oct 23, 2010 at 08:07:39PM -0400, Peter van der Does wrote:
Show 30 quoted lines
> On Sat, 23 Oct 2010 15:04:34 +0200
> SZEDER Gábor <szeder@ira.uka.de> 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().

Show 214 quoted lines
> 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@vger.kernel.org
>  #
> +# 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@gnu.org/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.
> 
Previous: Peter van der DoesNext: Peter van der Does
Message 9 of 10 in “[completion] Request: Include remote heads as push targets”
  1. Marc BranchaudOct 21, 2010
  2. Marc BranchaudOct 21, 2010
  3. Jonathan NiederOct 21, 2010
  4. Peter van der DoesOct 22, 2010
  5. Kevin BallardOct 22, 2010
  6. Marc BranchaudOct 22, 2010
  7. SZEDER GáborOct 23, 2010
  8. Peter van der DoesOct 24, 2010
  9. SZEDER GáborOct 24, 2010
  10. Peter van der DoesOct 24, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.