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

Re: Bash completion for git aliases containing nested subcommands

From
Jeff King <peff@peff.net>
Date
Oct 3, 2022, 22:24 UTC
Message-ID
<YzthDLdqeQx6bEcj@coredump.intra.peff.net>
In-Reply-To
<20221003142437.GB7659@szeder.dev>
On Mon, Oct 03, 2022 at 04:24:37PM +0200, SZEDER Gábor wrote:
Show 11 quoted lines
> > 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
Previous: SZEDER GáborNext: Tim Jaacks
Message 3 of 7 in “Bash completion for git aliases containing nested subcommands”
  1. Tim JaacksOct 3, 2022
  2. SZEDER GáborOct 3, 2022
  3. Jeff KingOct 3, 2022
  4. Tim JaacksOct 4, 2022
  5. SZEDER GáborOct 5, 2022
  6. Tim JaacksOct 3, 2022
  7. SZEDER GáborOct 3, 2022

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.