如何通过最近的 bash-completion 重用现有的完成?

如何通过最近的 bash-completion 重用现有的完成?

我用别名它向某些程序添加一些参数。

例如:

alias git.home='git --git-dir=$HOME/.git.home/'

complete -o bashdefault -o default -o nospace -F _git git.home \
  2>/dev/null || complete -o default -o nospace -F _git git.home

它适用于bash-completion v.1:2.0-1(“debian 7 wheezy”):
tab完成参数和选项别名 git.home以及“原始” git

但在输入并按下bash-completion v.1:2.1-4("debian 8 jessie") 后,我收到此错误:git.hometab

bash:完成:找不到函数“_git”

git如何通过最新版本的 package重用现有的完成(例如 for ) bash-completion


更新

找到部分解决方案:source /usr/share/bash-completion/completions/git之前做complete ...

但我收到另一个错误 - git.home log+ space+tab结果:

致命:不是 git 存储库(或任何父目录):.git HEAD

答案1

如何通过最新版本的 bash-completion 包重用现有的补全(例如 git)

将以下行添加到您的~/.bashrc

_completion_loader git
eval $(complete -p git | perl -pe 's/(\s)git$/$1git.home/')

解释:

bash-completion使用动态加载完成,因为1.90。因此,git在您输入git, Space,之前,compspec 不可用Tab

尝试:

bash
complete -p git # bash: complete: git: no completion specification
git<space><tab>
complete -p git # complete -o bashdefault -o default -o nospace -F __git_wrap__git_main git

_completion_loader git模仿git, Space, Tab(即加载 的 compspec git

complete -p git | perl -pe 's/(\s)git$/$1git.home/'构建一个 compspec for git.home(替换gitgit.homeagit的 compspec)

eval执行生成的 compspec。

类型git.homeSpacepTab。你应该看到:

popt   pull   push

git.home log,,Space产生Tab

致命:不是 git 存储库(或任何父目录):.git HEAD

此消息是 git 完成错误的结果。上游有一个修复:完成:沉默“致命:不是 git 存储库”错误

看起来像是另一个问题:)

_githome(){ 
   GIT_DIR=$HOME/.git.home
   complete -o default -o nospace -F _git git.home
 }

没有按预期工作。您GIT_DIR为当前会话设置。尝试使用您的解决方案:

bash
git clone git://git.debian.org/git/bash-completion/bash-completion.git ~/bash-completion
cd ~/bash-completion
git log<space><tab> # completion for current repo
git.home log<space><tab> # completion for GIT_DIR
git log<space><tab> # completion for GIT_DIR

答案2

更新

解决方案别名 git.home,它与 repo 一起运行~/.git.home

部分基于这个答案

添加~/.bashrc

alias git.home='git --git-dir=$HOME/.git.home/'

_completion_loader git
eval "$(complete -p git | sed -r 's/(\s)git$/\1git.home/')"

eval "$(type __gitdir | 
  sed '1d;1,/if/s|if|if [[ "$COMP_LINE" == "git.home "* ]]; then\necho "$HOME/.git.home"\nelif|')"

最后的解释eval(其他线路参见回答):

我们正在修补该函数__gitdir(),该函数返回 git repo 目录的路径。从:

$ type __gitdir | head -n 4
__gitdir is a function
__gitdir () 
{ 
    if [ -z "${1-}" ]; then

到:

$ type __gitdir | head -n 7
__gitdir is a function
__gitdir () 
{ 
    if [[ "$COMP_LINE" == "git.home "* ]]; then
        echo "$HOME/.git.home";
    else
        if [ -z "${1-}" ]; then

即,如果命令以 a 开头"git.home ",则函数返回$HOME/.git.home

答案3

这是一个适用于任何完成功能的通用答案。我担心其他答案的不安全性,假设单行输出由sedor解析,perl并且我可以在没有外部调用的情况下实现它。

# Usage: complete_as TARGET COMMAND [COMMAND...]
# Tab-complete one or more COMMANDs like TARGET
complete_as() {
  _completion_loader "$1"
  local completion="$(complete -p "$1")"
  completion="${completion%[[:space:]]$1}"
  shift
  eval "$completion $@"
}
complete_as git git.home

就像旧答案中的sed和代码一样,这用新命令 ( ) 替换了目标命令 ( ) 的最后一个实例,但我正在使用perl$1$2参数替换,它查看整个内容而不是在输出的每一行上运行。这很重要,因为完成函数的输出末尾有时会有换行符(如 的情况complete -W "$(_parse_help foo)" foo)。删除外部调用也会使速度更快,如果您经常这样做,您可能会注意到这一点。

您可以类似地构建这样的安全性(并使用 bash 替换)来修复__gitdir类似的功能亚历山大·巴拉金的回答做。

也可以看看这个 zsh 解决方案对于同样的问题。

相关内容