From: Junio C Hamano <hidden> Date: 2016-06-15 22:48:07
"Shawn O. Pearce" [off-list ref] writes:
quoted
An alias that uses another git subcommand (i.e. the ones that do not start
with a bang "!") seems to be handled correctly, but one of my aliases is
this:
[alias]
lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -"
Doing this is difficult, because its hard to parse that string and
do completion on it.
That is why I said it is unfair to expect completion code to do that.
[completion]
lgm = log
and have `git lgm` complete using the same rules as `git log`.
I actually like that. It matches _my_ expectation as a user to be able to
say "this subcommand has args that look like those given to 'log'".
From: SZEDER Gábor <hidden> Date: 2016-06-15 22:48:07
The bash completion script already provides support to complete
aliases, options and refs for aliases (if the alias can be traced back
to a supported git command by __git_aliased_command()), and the user's
custom git commands, but it does not support the options of the user's
custom git commands (of course; how could it know about the options of
a custom git command?). Users of such custom git commands could
extend git's bash completion script by writing functions to support
their commands, but they might have issues with it: they might not
have the rights to modify a system-wide git completion script, and
they will need to track and merge upstream changes in the future.
This patch addresses this by providing means for users to supply
custom completion scriplets for their custom git commands without
modifying the main git bash completion script.
Instead of having a huge hard-coded list of command-completion
function pairs (in _git()), the completion script will figure out
which completion function to call based on the command's name. That
is, when completing the options of 'git foo', the main completion
script will check whether the function '_git_foo' is declared, and if
declared, it will invoke that function to perform the completion. If
such a function is not declared, it will fall back to complete file
names. So, users will only need to provide this '_git_foo' completion
function in a separate file, source that file, and it will be used the
next time they press TAB after 'git foo '.
There are two git commands (stage and whatchanged), for which the
completion functions of other commands were used, therefore they
got their own completion function.
Signed-off-by: SZEDER Gábor <redacted>
---
How about something like this for subcommands (not aliases)? It's a
good code size reduction anyway.
contrib/completion/git-completion.bash | 67 ++++++--------------------------
1 files changed, 12 insertions(+), 55 deletions(-)
From: Shawn O. Pearce <hidden> Date: 2016-06-15 22:48:07
SZEDER G?bor [off-list ref] wrote:
The bash completion script already provides support to complete
aliases, options and refs for aliases (if the alias can be traced back
to a supported git command by __git_aliased_command()), and the user's
custom git commands, but it does not support the options of the user's
custom git commands (of course; how could it know about the options of
a custom git command?). Users of such custom git commands could
extend git's bash completion script by writing functions to support
their commands, but they might have issues with it: they might not
have the rights to modify a system-wide git completion script, and
they will need to track and merge upstream changes in the future.
This patch addresses this by providing means for users to supply
custom completion scriplets for their custom git commands without
modifying the main git bash completion script.
Instead of having a huge hard-coded list of command-completion
function pairs (in _git()), the completion script will figure out
which completion function to call based on the command's name. That
is, when completing the options of 'git foo', the main completion
script will check whether the function '_git_foo' is declared, and if
declared, it will invoke that function to perform the completion. If
such a function is not declared, it will fall back to complete file
names. So, users will only need to provide this '_git_foo' completion
function in a separate file, source that file, and it will be used the
next time they press TAB after 'git foo '.
There are two git commands (stage and whatchanged), for which the
completion functions of other commands were used, therefore they
got their own completion function.
Signed-off-by: SZEDER G?bor <redacted>
---
How about something like this for subcommands (not aliases)? It's a
good code size reduction anyway.
Hmm, I like this. I just didn't know how to implement it... :-)
Acked-by: Shawn O. Pearce <redacted>
+ local completion_func="_git_${command//-/_}"
+ declare -F $completion_func >/dev/null && $completion_func
From: SZEDER Gábor <hidden> Date: 2016-06-15 22:48:07
Hi Shawn,
On Fri, Jan 29, 2010 at 11:13:26AM -0800, Shawn O. Pearce wrote:
SZEDER G?bor [off-list ref] wrote:
quoted
How about something like this for subcommands (not aliases)? It's a
good code size reduction anyway.
Hmm, I like this. I just didn't know how to implement it... :-)
Acked-by: Shawn O. Pearce <redacted>
quoted
+ local completion_func="_git_${command//-/_}"
+ declare -F $completion_func >/dev/null && $completion_func
Yay for knowing bash. :-)
Heh. I've found out about this 'declare -F' thing about two hours ago
(;
However.
I thought this should actually "Just Work" for aliases, too. e.g.
Junio could use the following completion function to get 'git log's
options for his lgm alias:
_git_lgm () {
_git_log
}
Unfortunately, it doesn't work at all.
In _git() first we have 'lgm' in $command, which is ok, but then comes
this alias handling thing
local expansion=$(__git_aliased_command "$command")
[ "$expansion" ] && command="$expansion"
which writes '!sh' into $command, and that doesn't look quite right
for me, although I admit that I can't seem to figure out how this
__git_aliased_command() is supposed to work (so much about knowing
bash ;). Any insight?
Best,
Gábor
From: Shawn O. Pearce <hidden> Date: 2016-06-15 22:48:07
SZEDER G?bor [off-list ref] wrote:
_git_lgm () {
_git_log
}
Unfortunately, it doesn't work at all.
In _git() first we have 'lgm' in $command, which is ok, but then comes
this alias handling thing
local expansion=$(__git_aliased_command "$command")
[ "$expansion" ] && command="$expansion"
which writes '!sh' into $command, and that doesn't look quite right
__git_aliased_command is returning the first word out of the alias.
I think we need to change this block here to:
case "$expansion" of
\!*) : leave command as alias ;;
'') : leave command alone ;;
*) command="$expansion" ;;
esac
Or something like that. Because an alias whose value starts with
! is a shell command to be executed, so we want to use _git_$command
for completion, but other aliases are builtin commands and we should
use their first word token (what __git_aliased_command returns)
as the name of the completion function.
I think. :-)
--
Shawn.
From: David Rhodes Clymer <hidden> Date: 2016-06-15 22:48:08
2010/1/29 SZEDER Gábor [off-list ref]:
The bash completion script already provides support to complete
aliases, options and refs for aliases (if the alias can be traced back
to a supported git command by __git_aliased_command()), and the user's
custom git commands, but it does not support the options of the user's
custom git commands (of course; how could it know about the options of
a custom git command?). Users of such custom git commands could
extend git's bash completion script by writing functions to support
their commands, but they might have issues with it: they might not
have the rights to modify a system-wide git completion script, and
they will need to track and merge upstream changes in the future.
This patch addresses this by providing means for users to supply
custom completion scriplets for their custom git commands without
modifying the main git bash completion script.
Instead of having a huge hard-coded list of command-completion
function pairs (in _git()), the completion script will figure out
which completion function to call based on the command's name. That
is, when completing the options of 'git foo', the main completion
script will check whether the function '_git_foo' is declared, and if
declared, it will invoke that function to perform the completion. If
such a function is not declared, it will fall back to complete file
names. So, users will only need to provide this '_git_foo' completion
function in a separate file, source that file, and it will be used the
next time they press TAB after 'git foo '.
There are two git commands (stage and whatchanged), for which the
completion functions of other commands were used, therefore they
got their own completion function.
Excellent! This looks just like what I was after. Among other things,
this is much better than my use of awk. ;o)
-davidc
From: SZEDER Gábor <hidden> Date: 2016-06-15 22:48:08
On Fri, Jan 29, 2010 at 12:04:31PM -0800, Shawn O. Pearce wrote:
SZEDER G?bor [off-list ref] wrote:
quoted
_git_lgm () {
_git_log
}
Unfortunately, it doesn't work at all.
In _git() first we have 'lgm' in $command, which is ok, but then comes
this alias handling thing
local expansion=$(__git_aliased_command "$command")
[ "$expansion" ] && command="$expansion"
which writes '!sh' into $command, and that doesn't look quite right
__git_aliased_command is returning the first word out of the alias.
Actually, it returns the first word from the alias which does not
start with a dash. It behaves this way since its introduction in
367dce2a (Bash completion support for aliases, 2006-10-28). I'm not
sure what the original intent was behind ignoring words starting with
a dash, but it gave me some ideas.
I think we need to change this block here to:
case "$expansion" of
\!*) : leave command as alias ;;
'') : leave command alone ;;
*) command="$expansion" ;;
esac
Or something like that. Because an alias whose value starts with
! is a shell command to be executed, so we want to use _git_$command
for completion, but other aliases are builtin commands and we should
use their first word token (what __git_aliased_command returns)
as the name of the completion function.
After pondering about it for a while, I think that in this case the
real issue is not _git() not handling __git_aliased_command()'s return
value corretly, but rather __git_aliased_command() returning junk in
case of a more advanced alias. And while fixing it up, we can also
improve on it to return the right command in some more cases, too.
Let's have an other look at Junio's alias:
[alias]
lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -"
While it's clear that full parsing of something like that in the
completion code is unfeasible, we can easily get rid of stuff that is
definitely not a git command: !sh shell commands, options, and
environment variables.
and this way it would correctly return 'log' for Junio's 'lgm' alias.
With a bit tweaking we could also extend it to handle !gitk aliases,
too.
Of course, it isn't perfect either, and could be fooled easily. It's
not hard to construct an alias, in which a word does not match any of
these filter patterns, but is still not a git command (e.g. by
setting an environment variable to a value which contains spaces). It
may even return false positives, when the output of a git command is
piped into an other git command, and the second gets the command line
options via $@, but the first command will be returned. However, such
problematic cases could be handled by a custom completion function
provided by the user.
What do you think?
Best,
Gábor
From: SZEDER Gábor <hidden> Date: 2016-06-15 22:48:20
Hi,
here is the full series, extended for aliases.
I didn't want to push an obviously post-v1.7.0 change during the -rc
period, and then forgot about it until Teemu (on CC) sent similar
patches today[*]. His two patches do basically the same as my 2/4 (with
minor differences).
Junio was concerned about possible namespace issues. This series does
not addresses his concern, but I have some thoughts about it, and I will
try to discuss it after dinner.
Best,
Gábor
[*] gmane: http://thread.gmane.org/gmane.comp.version-control.git/140804
message id: [off-list ref]
SZEDER Gábor (4):
bash: improve aliased command recognition
bash: support user-supplied completion scripts for user's git
commands
bash: support user-supplied completion scripts for aliases
bash: completion for gitk aliases
contrib/completion/git-completion.bash | 94 ++++++++++++--------------------
1 files changed, 34 insertions(+), 60 deletions(-)
From: SZEDER Gábor <hidden> Date: 2016-06-15 22:48:20
To support completion for aliases, the completion script tries to
figure out which git command is invoked by an alias. Its
implementation in __git_aliased_command() is rather straightforward:
it returns the first word from the alias. For simple aliases starting
with the git command (e.g. alias.last = cat-file commit HEAD) this
gives the right results. Unfortunately, it does not work with shell
command aliases, which can get rather complex, as illustrated by one
of Junio's aliases:
[alias]
lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -"
In this case the current implementation returns "!sh" as the aliased
git command, which is obviosly wrong.
The full parsing of a shell command alias like that in the completion
code is clearly unfeasible. However, we can easily improve on aliased
command recognition by eleminating stuff that is definitely not a git
command: shell commands (anything starting with '!'), command line
options (anything starting with '-'), environment variables (anything
with a '=' in it), and git itself. This way the above alias would be
handled correctly, and the completion script would correctly recognize
"log" as the aliased git command.
Of course, this solution is not perfect either, and could be fooled
easily. It's not hard to construct an alias, in which a word does not
match any of these filter patterns, but is still not a git command
(e.g. by setting an environment variable to a value which contains
spaces). It may even return false positives, when the output of a git
command is piped into an other git command, and the second gets the
command line options via $@, but options for the first one are
offered. However, the following patches will enable the user to
supply custom completion scripts for aliases, which can be used to
remedy these problematic cases.
Signed-off-by: SZEDER Gábor <redacted>
---
contrib/completion/git-completion.bash | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
From: SZEDER Gábor <hidden> Date: 2016-06-15 22:48:20
Shell command aliases can get rather complex, and the completion
script can not always determine correctly the git command invoked by
such an alias. For such cases users might want to provide custom
completion scripts the same way like for their custom commands made
possible by the previous patch.
The current completion script does not allow this, because if it
encounters an alias, then it will unconditionally perform completion
for the aliased git command (in case it can determine the aliased git
command, of course). With this patch the completion script will first
search for a completion function for the command given on the command
line, be it a git command, a custom git command of the user, or an
alias, and invoke that function to perform the completion. This has
no effect on git commands, because they can not be aliased anyway. If
it is an alias and there is a completion function for that alias (e.g.
_git_foo() for the alias 'foo'), then it will be invoked to perform
completion, allowing users to provide custom completion functions for
aliases. If such a completion function can not be found, only then
will the completion script check whether the command given on the
command line is an alias or not, and proceed as usual (i.e. find out
the aliased git command and provide completion for it).
Signed-off-by: SZEDER Gábor <redacted>
---
contrib/completion/git-completion.bash | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
From: SZEDER Gábor <hidden> Date: 2016-06-15 22:48:20
The bash completion script already provides support to complete
aliases, options and refs for aliases (if the alias can be traced back
to a supported git command by __git_aliased_command()), and the user's
custom git commands, but it does not support the options of the user's
custom git commands (of course; how could it know about the options of
a custom git command?). Users of such custom git commands could
extend git's bash completion script by writing functions to support
their commands, but they might have issues with it: they might not
have the rights to modify a system-wide git completion script, and
they will need to track and merge upstream changes in the future.
This patch addresses this by providing means for users to supply
custom completion scriplets for their custom git commands without
modifying the main git bash completion script.
Instead of having a huge hard-coded list of command-completion
function pairs (in _git()), the completion script will figure out
which completion function to call based on the command's name. That
is, when completing the options of 'git foo', the main completion
script will check whether the function '_git_foo' is declared, and if
declared, it will invoke that function to perform the completion. If
such a function is not declared, it will fall back to complete file
names. So, users will only need to provide this '_git_foo' completion
function in a separate file, source that file, and it will be used the
next time they press TAB after 'git foo '.
There are two git commands (stage and whatchanged), for which the
completion functions of other commands were used, therefore they
got their own completion function.
Signed-off-by: SZEDER Gábor <redacted>
---
contrib/completion/git-completion.bash | 67 ++++++--------------------------
1 files changed, 12 insertions(+), 55 deletions(-)
From: SZEDER Gábor <hidden> Date: 2016-06-15 22:48:20
gitk aliases either start with "!gitk", or look something like "!sh -c
FOO=bar gitk", IOW they contain the "gitk" word. With this patch the
completion script will recognize these cases and will offer gitk's
options.
Just like the earlier change improving on aliased command recognition,
this change can also be fooled easily by some complex aliases, but
users of such aliases could remedy it with custom completion
functions.
Signed-off-by: SZEDER Gábor <redacted>
---
contrib/completion/git-completion.bash | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)