threads / patch / 36869

patchcompletion: Handle '!f() { ... }; f' aliases

Subject: [PATCH] completion: Handle '!f() { ... }; f' aliases

## tl;dr

6 messages between Jun 7, 2014 and Jun 12, 2014. Diffs are folded; open one to read it.

replies: 5people: 3as markdown or json

Steffen Prohaska· Jun 7, 2014, 14:10 UTC · lore

'!f() { ... }; f' is a recommended pattern to declare more complex aliases (see git wiki [1]). This commit teaches the completion to handle them.

When determining which completion to use for an alias, the opening brace is now ignored in order to continue the search for a git command inside the function body. For example, the alias '!f() { git commit ... }' now triggers commit completion. Previously, the search stopped on '{', and the completion tried it to determine how to complete, which obviously was useless.

Furthermore, the null command ':' is now skipped, so that it can be used as a workaround to declare the desired completion style. For example, the alias '!f() { : git commit ; if ... ' now triggers commit completion.

[1] https://git.wiki.kernel.org/index.php/Aliases
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
 contrib/completion/git-completion.bash |  7 +++++++
 t/t9902-completion.sh                  | 20 ++++++++++++++++++++
 2 files changed, 27 insertions(+)
Show changes to 2 files +27 −0

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 2c59a76..aecb975 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -21,6 +21,11 @@
 #        source ~/.git-completion.sh
 #    3) Consider changing your PS1 to also show the current branch,
 #       see git-prompt.sh for details.
+#
+# If you use complex aliases of form '!f() { ... }; f', you can use the null
+# command ':' as the first command in the function body to declare the desired
+# completion style.  For example '!f() { : git commit ; ... }; f' will
+# tell the completion to use commit completion.
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -781,6 +786,8 @@ __git_aliased_command ()
 		-*)	: option ;;
 		*=*)	: setting env ;;
 		git)	: git itself ;;
+		{)	: skip start of shell helper function ;;
+		:)	: skip null command ;;
 		*)
 			echo "$word"
 			return
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 2d4beb5..ea48681 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -550,6 +550,26 @@ test_expect_success 'complete files' '
 	test_completion "git add mom" "momified"
 '
 
+test_expect_success 'completion uses <cmd> completion for alias !f() { VAR=val git <cmd> ... }' '
+	git config alias.co "!f() { VAR=val git checkout ... ; } f" &&
+	test_completion "git co m" <<-\EOF &&
+	master Z
+	mybranch Z
+	mytag Z
+	EOF
+	git config --unset alias.co
+'
+
+test_expect_success 'completion used <cmd> completion for alias !f() { : git <cmd> ; ... }' '
+	git config alias.co "!f() { : git checkout ; if ... } f" &&
+	test_completion "git co m" <<-\EOF &&
+	master Z
+	mybranch Z
+	mytag Z
+	EOF
+	git config --unset alias.co
+'
+
 test_expect_failure 'complete with tilde expansion' '
 	git init tmp && cd tmp &&
 	test_when_finished "cd .. && rm -rf tmp" &&
-- 
2.0.0.244.g4e8e734
Eric Sunshine· Jun 8, 2014, 09:02 UTC · re: Steffen Prohaska · lore

Re: [PATCH] completion: Handle '!f() { ... }; f' aliases

On Sat, Jun 7, 2014 at 10:10 AM, Steffen Prohaska <prohaska@zib.de> wrote:
Show 30 quoted lines
> '!f() { ... }; f' is a recommended pattern to declare more complex
> aliases (see git wiki [1]).  This commit teaches the completion to
> handle them.
>
> When determining which completion to use for an alias, the opening brace
> is now ignored in order to continue the search for a git command inside
> the function body.  For example, the alias '!f() { git commit ... }' now
> triggers commit completion.  Previously, the search stopped on '{', and
> the completion tried it to determine how to complete, which obviously
> was useless.
>
> Furthermore, the null command ':' is now skipped, so that it can be used
> as a workaround to declare the desired completion style.  For example,
> the alias '!f() { : git commit ; if ...  ' now triggers commit
> completion.
>
> [1] https://git.wiki.kernel.org/index.php/Aliases
>
> Signed-off-by: Steffen Prohaska <prohaska@zib.de>
> ---
> diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
> index 2d4beb5..ea48681 100755
> --- a/t/t9902-completion.sh
> +++ b/t/t9902-completion.sh
> @@ -550,6 +550,26 @@ test_expect_success 'complete files' '
>         test_completion "git add mom" "momified"
>  '
>
> +test_expect_success 'completion uses <cmd> completion for alias !f() { VAR=val git <cmd> ... }' '
> +       git config alias.co "!f() { VAR=val git checkout ... ; } f" &&

test_config would be an appropriate replacement for "git config" + "git config --unset".

Show 10 quoted lines
> +       test_completion "git co m" <<-\EOF &&
> +       master Z
> +       mybranch Z
> +       mytag Z
> +       EOF
> +       git config --unset alias.co
> +'
> +
> +test_expect_success 'completion used <cmd> completion for alias !f() { : git <cmd> ; ... }' '
> +       git config alias.co "!f() { : git checkout ; if ... } f" &&
Ditto.
Show 13 quoted lines
> +       test_completion "git co m" <<-\EOF &&
> +       master Z
> +       mybranch Z
> +       mytag Z
> +       EOF
> +       git config --unset alias.co
> +'
> +
>  test_expect_failure 'complete with tilde expansion' '
>         git init tmp && cd tmp &&
>         test_when_finished "cd .. && rm -rf tmp" &&
> --
> 2.0.0.244.g4e8e734
Steffen Prohaska· Jun 9, 2014, 12:54 UTC · re: Eric Sunshine · lore

[PATCH v2] completion: Handle '!f() { ... }; f' aliases

'!f() { ... }; f' is a recommended pattern to declare more complex aliases (see git wiki [1]). This commit teaches the completion to handle them.

When determining which completion to use for an alias, the opening brace is now ignored in order to continue the search for a git command inside the function body. For example, the alias '!f() { git commit ... }' now triggers commit completion. Previously, the search stopped on '{', and the completion tried it to determine how to complete, which obviously was useless.

Furthermore, the null command ':' is now skipped, so that it can be used as a workaround to declare the desired completion style. For example, the alias '!f() { : git commit ; if ... ' now triggers commit completion.

[1] https://git.wiki.kernel.org/index.php/Aliases
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
I changed the tests to use test_config, as Eric suggested.  Thanks.
 contrib/completion/git-completion.bash |  7 +++++++
 t/t9902-completion.sh                  | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+)
Show changes to 2 files +25 −0

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 2c59a76..aecb975 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -21,6 +21,11 @@
 #        source ~/.git-completion.sh
 #    3) Consider changing your PS1 to also show the current branch,
 #       see git-prompt.sh for details.
+#
+# If you use complex aliases of form '!f() { ... }; f', you can use the null
+# command ':' as the first command in the function body to declare the desired
+# completion style.  For example '!f() { : git commit ; ... }; f' will
+# tell the completion to use commit completion.
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -781,6 +786,8 @@ __git_aliased_command ()
 		-*)	: option ;;
 		*=*)	: setting env ;;
 		git)	: git itself ;;
+		{)	: skip start of shell helper function ;;
+		:)	: skip null command ;;
 		*)
 			echo "$word"
 			return
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 2d4beb5..10ceb29 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -550,6 +550,24 @@ test_expect_success 'complete files' '
 	test_completion "git add mom" "momified"
 '
 
+test_expect_success 'completion uses <cmd> completion for alias !f() { VAR=val git <cmd> ... }' '
+	test_config alias.co "!f() { VAR=val git checkout ... ; } f" &&
+	test_completion "git co m" <<-\EOF
+	master Z
+	mybranch Z
+	mytag Z
+	EOF
+'
+
+test_expect_success 'completion used <cmd> completion for alias !f() { : git <cmd> ; ... }' '
+	test_config alias.co "!f() { : git checkout ; if ... } f" &&
+	test_completion "git co m" <<-\EOF
+	master Z
+	mybranch Z
+	mytag Z
+	EOF
+'
+
 test_expect_failure 'complete with tilde expansion' '
 	git init tmp && cd tmp &&
 	test_when_finished "cd .. && rm -rf tmp" &&
-- 
2.0.0.244.g4e8e734
Junio C Hamano· Jun 10, 2014, 05:27 UTC · re: Steffen Prohaska · lore

Re: [PATCH v2] completion: Handle '!f() { ... }; f' aliases

Steffen Prohaska <prohaska@zib.de> writes:
> '!f() { ... }; f' is a recommended pattern to declare more complex
> aliases (see git wiki [1]).  This commit teaches the completion to
> handle them.

Hmm, I've never endorsed nor recommended such a notation myself ;-) I tend to prefer writing it like so instead:

    sh -c '...' -

so that I won't clobber "f" (or any other name). I wonder if you can help users of this other pattern as well.

> When determining which completion to use for an alias, the opening brace
> is now ignored in order to continue the search for a git command inside
> the function body.  For example, the alias '!f() { git commit ... }' now
> triggers commit completion.

I suspect that "scanning" is error-prone. I like this one for its cuteness very much, though:

> Furthermore, the null command ':' is now skipped, so that it can be used
> as a workaround to declare the desired completion style.  For example,
> the alias '!f() { : git commit ; if ...  ' now triggers commit
> completion.
> +test_expect_success 'completion uses <cmd> completion for alias !f() { VAR=val git <cmd> ... }' '
> +	test_config alias.co "!f() { VAR=val git checkout ... ; } f" &&

Is it only "f" that is completed, or can I spell it using another arbitrary token, e.g.

	test_config alias.co "!co () { git checkout ... } co"
Steffen Prohaska· Jun 12, 2014, 18:41 UTC · re: Junio C Hamano · lore

Re: [PATCH v2] completion: Handle '!f() { ... }; f' aliases

On Jun 10, 2014, at 7:27 AM, Junio C Hamano <gitster@pobox.com> wrote:
Show 8 quoted lines
> Steffen Prohaska <prohaska@zib.de> writes:
> 
> I tend to prefer writing it like so instead:
> 
>    sh -c '...' -
> 
> so that I won't clobber "f" (or any other name).  I wonder if you
> can help users of this other pattern as well.
I'll send an updated patch that handles it.
Show 7 quoted lines
>> +test_expect_success 'completion uses <cmd> completion for alias !f() { VAR=val git <cmd> ... }' '
>> +	test_config alias.co "!f() { VAR=val git checkout ... ; } f" &&
> 
> Is it only "f" that is completed, or can I spell it using another
> arbitrary token, e.g.
> 
> 	test_config alias.co "!co () { git checkout ... } co"
Any token that starts with ! already worked before. 
The updated patch will also handle spaces before the parens.
	Steffen
Steffen Prohaska· Jun 12, 2014, 18:49 UTC · re: Steffen Prohaska · lore

[PATCH v2] completion: Handle '!f() { ... }; f' and "!sh -c '...'" aliases

'!f() { ... }; f' and "!sh -c '....'" are recommended patterns for declaring more complex aliases (see git wiki [1]). This commit teaches the completion to handle them.

When determining which completion to use for an alias, an opening brace or single quote is now skipped, and the search for a git command is continued. For example, the aliases '!f() { git commit ... }' or "!sh -c 'git commit ...'" now trigger commit completion. Previously, the search stopped on the opening brace or quote, and the completion tried it to determine how to complete, which obviously was useless.

The null command ':' is now skipped, so that it can be used as a workaround to declare the desired completion style. For example, the aliases '!f() { : git commit ; if ... ' and "!sh -c ': git commit; if ...'" now trigger commit completion.

Shell function declarations now work with or without space before the parens, i.e. '!f() ...' and '!f () ...' both work.

[1] https://git.wiki.kernel.org/index.php/Aliases
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
---
 contrib/completion/git-completion.bash | 10 ++++++++++
 t/t9902-completion.sh                  | 27 +++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)
Show changes to 2 files +37 −0

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 2c59a76..575f8f7 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -21,6 +21,12 @@
 #        source ~/.git-completion.sh
 #    3) Consider changing your PS1 to also show the current branch,
 #       see git-prompt.sh for details.
+#
+# If you use complex aliases of form '!f() { ... }; f', you can use the null
+# command ':' as the first command in the function body to declare the desired
+# completion style.  For example '!f() { : git commit ; ... }; f' will
+# tell the completion to use commit completion.  This also works with aliases
+# of form "!sh -c '...'".  For example, "!sh -c ': git commit ; ... '".
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -781,6 +787,10 @@ __git_aliased_command ()
 		-*)	: option ;;
 		*=*)	: setting env ;;
 		git)	: git itself ;;
+		\(\))   : skip parens of shell function definition ;;
+		{)	: skip start of shell helper function ;;
+		:)	: skip null command ;;
+		\'*)	: skip opening quote after sh -c ;;
 		*)
 			echo "$word"
 			return
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 2d4beb5..1d1c106 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -550,6 +550,33 @@ test_expect_success 'complete files' '
 	test_completion "git add mom" "momified"
 '
 
+test_expect_success "completion uses <cmd> completion for alias: !sh -c 'git <cmd> ...'" '
+	test_config alias.co "!sh -c '"'"'git checkout ...'"'"'" &&
+	test_completion "git co m" <<-\EOF
+	master Z
+	mybranch Z
+	mytag Z
+	EOF
+'
+
+test_expect_success 'completion uses <cmd> completion for alias: !f () { VAR=val git <cmd> ... }' '
+	test_config alias.co "!f () { VAR=val git checkout ... ; } f" &&
+	test_completion "git co m" <<-\EOF
+	master Z
+	mybranch Z
+	mytag Z
+	EOF
+'
+
+test_expect_success 'completion used <cmd> completion for alias: !f() { : git <cmd> ; ... }' '
+	test_config alias.co "!f() { : git checkout ; if ... } f" &&
+	test_completion "git co m" <<-\EOF
+	master Z
+	mybranch Z
+	mytag Z
+	EOF
+'
+
 test_expect_failure 'complete with tilde expansion' '
 	git init tmp && cd tmp &&
 	test_when_finished "cd .. && rm -rf tmp" &&
-- 
2.0.0.244.g4e8e734

← back to recent threads