From c63437cbd79e4c11ddcd06cc59f81401ae393794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Tue, 23 Feb 2010 22:02:57 +0100 Subject: [PATCH 1/4] bash: improve aliased command recognition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index fe93747c93..78c4983983 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -625,10 +625,15 @@ __git_aliased_command () local word cmdline=$(git --git-dir="$(__gitdir)" \ config --get "alias.$1") for word in $cmdline; do - if [ "${word##-*}" ]; then - echo $word + case "$word" in + \!*) : shell command alias ;; + -*) : option ;; + *=*) : setting env ;; + git) : git itself ;; + *) + echo "$word" return - fi + esac done } From 424cce832d180843ab9b54eec3a7643948fc1afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Tue, 23 Feb 2010 22:02:58 +0100 Subject: [PATCH 2/4] bash: support user-supplied completion scripts for user's git commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 67 +++++--------------------- 1 file changed, 12 insertions(+), 55 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 78c4983983..2ac356705b 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1439,6 +1439,11 @@ _git_send_email () COMPREPLY=() } +_git_stage () +{ + _git_add +} + __git_config_get_set_variables () { local prevword word config_file= c=$COMP_CWORD @@ -2170,6 +2175,11 @@ _git_tag () esac } +_git_whatchanged () +{ + _git_log +} + _git () { local i c=1 command __git_dir @@ -2209,61 +2219,8 @@ _git () local expansion=$(__git_aliased_command "$command") [ "$expansion" ] && command="$expansion" - case "$command" in - am) _git_am ;; - add) _git_add ;; - apply) _git_apply ;; - archive) _git_archive ;; - bisect) _git_bisect ;; - bundle) _git_bundle ;; - branch) _git_branch ;; - checkout) _git_checkout ;; - cherry) _git_cherry ;; - cherry-pick) _git_cherry_pick ;; - clean) _git_clean ;; - clone) _git_clone ;; - commit) _git_commit ;; - config) _git_config ;; - describe) _git_describe ;; - diff) _git_diff ;; - difftool) _git_difftool ;; - fetch) _git_fetch ;; - format-patch) _git_format_patch ;; - fsck) _git_fsck ;; - gc) _git_gc ;; - grep) _git_grep ;; - help) _git_help ;; - init) _git_init ;; - log) _git_log ;; - ls-files) _git_ls_files ;; - ls-remote) _git_ls_remote ;; - ls-tree) _git_ls_tree ;; - merge) _git_merge;; - mergetool) _git_mergetool;; - merge-base) _git_merge_base ;; - mv) _git_mv ;; - name-rev) _git_name_rev ;; - notes) _git_notes ;; - pull) _git_pull ;; - push) _git_push ;; - rebase) _git_rebase ;; - remote) _git_remote ;; - replace) _git_replace ;; - reset) _git_reset ;; - revert) _git_revert ;; - rm) _git_rm ;; - send-email) _git_send_email ;; - shortlog) _git_shortlog ;; - show) _git_show ;; - show-branch) _git_show_branch ;; - stash) _git_stash ;; - stage) _git_add ;; - submodule) _git_submodule ;; - svn) _git_svn ;; - tag) _git_tag ;; - whatchanged) _git_log ;; - *) COMPREPLY=() ;; - esac + local completion_func="_git_${command//-/_}" + declare -F $completion_func >/dev/null && $completion_func } _gitk () From 8024ea60db290dd64db294e1019a0ada64ce1770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Tue, 23 Feb 2010 22:02:59 +0100 Subject: [PATCH 3/4] bash: support user-supplied completion scripts for aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 2ac356705b..8593fd707b 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2216,11 +2216,14 @@ _git () return fi - local expansion=$(__git_aliased_command "$command") - [ "$expansion" ] && command="$expansion" - local completion_func="_git_${command//-/_}" - declare -F $completion_func >/dev/null && $completion_func + declare -F $completion_func >/dev/null && $completion_func && return + + local expansion=$(__git_aliased_command "$command") + if [ -n "$expansion" ]; then + completion_func="_git_${expansion//-/_}" + declare -F $completion_func >/dev/null && $completion_func + fi } _gitk () From 66729509457f11b15216c3cdfdbb2f34eddfbe89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Tue, 23 Feb 2010 22:03:00 +0100 Subject: [PATCH 4/4] bash: completion for gitk aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 8593fd707b..3029f160b0 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -626,6 +626,10 @@ __git_aliased_command () config --get "alias.$1") for word in $cmdline; do case "$word" in + \!gitk|gitk) + echo "gitk" + return + ;; \!*) : shell command alias ;; -*) : option ;; *=*) : setting env ;; @@ -1087,6 +1091,11 @@ _git_gc () COMPREPLY=() } +_git_gitk () +{ + _gitk +} + _git_grep () { __git_has_doubledash && return