Re: Bash completion for git aliases containing nested subcommands

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Oct 03, 2022 at 04:24:37PM +0200, SZEDER Gábor wrote:

> > Is there a way to get the completion on the alias behave like on the
> > original command?
> 
> In general: no.  Our Bash completion script is organized as one
> _git_cmd() function for each git supported command.  If a command has
> subcommands, then its completion function looks for any of its
> subcommands amond the words on the command line, and takes the
> appropriate action, which is usually executing a particular arm of a
> case statement.  The two main issues are that in case of such an alias
> there is no subcommand ("show") on the command line, and there is no
> dedicated function to handle only the completion for 'git stash show'.

It feels like this ought to be able to work, for the same reason that
"git stash show <TAB>" works. In the non-aliased case, we call into
_git_stash(), and it sees that "show" is already there on the command
line. But in the aliased case, we know "show" is part of the alias but
throw away that information completely, and never feed it to
_git_stash() at all.

I think we could do something like the patch below, though I suspect
there are some dragons with more complicated aliases. I wonder if
__git_aliased_command() needs to be more careful with distinguishing
pure-git-command aliases from the complexity of "!" aliases. Or maybe
the alias stuff is all best-effort enough that this doesn't make
anything worse.

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ba5c395d2d..f68bfcbf05 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1148,10 +1148,13 @@ __git_aliased_command ()
 		cur=
 
 		for word in $cmdline; do
+			if test -n "$cur"; then
+				expansion_words+=("$word")
+				continue
+			fi
 			case "$word" in
 			\!gitk|gitk)
 				cur="gitk"
-				break
 				;;
 			\!*)	: shell command alias ;;
 			-*)	: option ;;
@@ -1163,14 +1166,13 @@ __git_aliased_command ()
 			\'*)	: skip opening quote after sh -c ;;
 			*)
 				cur="$word"
-				break
 			esac
 		done
 	done
 
 	cur=$last
 	if [[ "$cur" != "$1" ]]; then
-		echo "$cur"
+		expansion=$cur
 	fi
 }
 
@@ -3507,9 +3509,13 @@ __git_main ()
 
 	__git_complete_command "$command" && return
 
-	local expansion=$(__git_aliased_command "$command")
+	# __git_aliased_command now writes to these
+	local expansion
+	local expansion_words
+	__git_aliased_command "$command"
 	if [ -n "$expansion" ]; then
-		words[1]=$expansion
+		words=("${words[0]}" "$expansion" "${expansion_words[@]}" "${words[@]:2}")
+		cword=$((cword + ${#expansion_words[@]}))
 		__git_complete_command "$expansion"
 	fi
 }

By the way, you'll notice that the splice into "words" happens right
at words[1]. That matches the earlier code that just touches words[1].
But I suspect that isn't right. If we're completing "git -p foo", for
example, then the command is at word[2]. I don't know if this causes any
bugs, since we get to the right completion function based on $expansion,
not any value in $words. But presumably it should be __git_cmd_idx?

-Peff



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux