Git 别名的完成就像 Git 本身一样
Git completion for alias as if for Git itself
背景
我已成功配置 Bash 完成各种 Git 别名。例如:
$ git config alias.subject
!git --no-pager show --quiet --pretty='%s'
$ function _git_subject() { _git_show; }
$ git subject my<TAB>
$ git subject my-branch
挑战
但是,我有一个 Git 别名,我不知道如何设置 Bash 完成。问题是我希望别名像顶级 Git 命令本身一样完成。别名是这样的:
$ git config alias.alias
alias = !"f() { if [[ \"$#\" != 1 ]]; then >&2 echo \"Usage: git alias COMMAND\"; return 1; fi; git config alias.\"\"; }; f"
# Example
$ git alias s
status
我试过使用 _git
、__git_main
和 __git_wrap__git_main
,但其中 none 有效(我认为这会导致无限循环,因为它从不 returns 在我按下 tab 之后)。
有没有一种方法可以为 Git 别名添加完成,就像它是顶级 Git 命令一样完成?或者具体如何完成这个别名?
试过但没用
function _git_alias() { _git; }
function _git_alias() { __git_main; }
function _git_alias() { __git_wrap__git_main; }
期望的行为
$ git alias su<TAB>
subject submodule
$ git alias sub
或者,如果有一种简单的方法来仅完成别名,那也很酷。不过,出于好奇,我也想知道如何完成顶级 Git 命令。
我终于能够通过围绕“神奇”Bash 完成变量的一些技巧创建一个可行的解决方案。我将这些变量更改为“假装”我们正在完成给定 git
本身的给定命令。
如果有人有任何简化这个的建议,我会完全接受建议。
# This is complex because we want to delegate to the completion for Git
# itself without ending up with an infinite loop (which happens if you try
# to just delegate to _git).
_git_alias() {
if [[ "$COMP_CWORD" -lt 2 ]]; then
return
fi
local old_comp_line_length new_comp_line_length
COMP_WORDS=(git "${COMP_WORDS[@]:2}")
((COMP_CWORD -= 1))
old_comp_line_length=${#COMP_LINE}
if [[ "$COMP_LINE" =~ ^[^[:blank:]]+[[:blank:]]+[^[:blank:]]+[[:blank:]]+(.*)$ ]]; then
COMP_LINE="git ${BASH_REMATCH[1]}"
fi
new_comp_line_length=${#COMP_LINE}
(( COMP_POINT += new_comp_line_length - old_comp_line_length ))
_git "$@"
# git alias blah
# ^
# 01234567890123
# 0 1
# point: 11
# length: 13
#
# git blah
# ^
# 01234567
# point: 5
# length: 7
#
# point = point - (old length) + (new length)
# point = 11 - 13 + 7
# point = -2 + 7
# point = 5
}
背景
我已成功配置 Bash 完成各种 Git 别名。例如:
$ git config alias.subject
!git --no-pager show --quiet --pretty='%s'
$ function _git_subject() { _git_show; }
$ git subject my<TAB>
$ git subject my-branch
挑战
但是,我有一个 Git 别名,我不知道如何设置 Bash 完成。问题是我希望别名像顶级 Git 命令本身一样完成。别名是这样的:
$ git config alias.alias
alias = !"f() { if [[ \"$#\" != 1 ]]; then >&2 echo \"Usage: git alias COMMAND\"; return 1; fi; git config alias.\"\"; }; f"
# Example
$ git alias s
status
我试过使用 _git
、__git_main
和 __git_wrap__git_main
,但其中 none 有效(我认为这会导致无限循环,因为它从不 returns 在我按下 tab 之后)。
有没有一种方法可以为 Git 别名添加完成,就像它是顶级 Git 命令一样完成?或者具体如何完成这个别名?
试过但没用
function _git_alias() { _git; }
function _git_alias() { __git_main; }
function _git_alias() { __git_wrap__git_main; }
期望的行为
$ git alias su<TAB>
subject submodule
$ git alias sub
或者,如果有一种简单的方法来仅完成别名,那也很酷。不过,出于好奇,我也想知道如何完成顶级 Git 命令。
我终于能够通过围绕“神奇”Bash 完成变量的一些技巧创建一个可行的解决方案。我将这些变量更改为“假装”我们正在完成给定 git
本身的给定命令。
如果有人有任何简化这个的建议,我会完全接受建议。
# This is complex because we want to delegate to the completion for Git
# itself without ending up with an infinite loop (which happens if you try
# to just delegate to _git).
_git_alias() {
if [[ "$COMP_CWORD" -lt 2 ]]; then
return
fi
local old_comp_line_length new_comp_line_length
COMP_WORDS=(git "${COMP_WORDS[@]:2}")
((COMP_CWORD -= 1))
old_comp_line_length=${#COMP_LINE}
if [[ "$COMP_LINE" =~ ^[^[:blank:]]+[[:blank:]]+[^[:blank:]]+[[:blank:]]+(.*)$ ]]; then
COMP_LINE="git ${BASH_REMATCH[1]}"
fi
new_comp_line_length=${#COMP_LINE}
(( COMP_POINT += new_comp_line_length - old_comp_line_length ))
_git "$@"
# git alias blah
# ^
# 01234567890123
# 0 1
# point: 11
# length: 13
#
# git blah
# ^
# 01234567
# point: 5
# length: 7
#
# point = point - (old length) + (new length)
# point = 11 - 13 + 7
# point = -2 + 7
# point = 5
}