覆盖git clone的bash完成

Ant*_*ile 15 git bash bash-completion

内置完成

git clone的默认完成(在下面重现)为选项提供了标签完成--*:

_git_clone ()
{
    case "$cur" in
    --*)
        __gitcomp_builtin clone
        return
        ;;
    esac
}
Run Code Online (Sandbox Code Playgroud)

bash-completion 1.x(old bash)

(具体的例子,macos high sierra + brew安装了bash-completion/git)

在bash-completion 1.x世界中,要覆盖它,我会(在.bashrc/中.bash_profile)定义我自己的_git_clone完成函数:

# https://github.com/scop/bash-completion/blob/d2f14a7/bash_completion#L498
__ltrim_colon_completions() {
    if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
        # Remove colon-word prefix from COMPREPLY items
        local colon_word=${1%"${1##*:}"}
        local i=${#COMPREPLY[*]}
        while [[ $((--i)) -ge 0 ]]; do
            COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
        done
    fi
}


_git_clone() {
    case "$cur" in
    --*)
        __gitcomp_builtin clone
        return
        ;;
    *)
        argc=0
        for word in "${words[@]}"; do
            case "$word" in
            git|clone|--*)
                continue
                ;;
            *)
                argc=$((argc + 1))
                ;;
            esac
        done

        if [ $argc -le 1 ]; then
            __gitcomp "https://github.com/git/git https://github.com/python/cpython"
            __ltrim_colon_completions "$cur"
        fi
        ;;
    esac
}
Run Code Online (Sandbox Code Playgroud)

这非常有效:

(我输入的序列是git clone h<tab><tab>g<tab>)

$ git clone https://github.com/
//github.com/git/git          //github.com/python/cpython 
$ git clone https://github.com/git/git 
Run Code Online (Sandbox Code Playgroud)

bash-completion 2.x

(具体实例:股票ubuntu仿生(18.04))

在bash-completion 2.x中,模型被翻转为动态加载的配置.这意味着当gittab完成时,__load_completion触发,在它安装的路径上找到git完成并获取它.

_git_clone.bashrc/中定义我自己的完成函数.bash_profile现在是无用的,因为它被动态源完成文件破坏了.

我可以git这个目录中定义自己的完成:

local -a dirs=( ${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions )
Run Code Online (Sandbox Code Playgroud)

(例如~/.local/share/bash-completion/completions/git.bash).然而,这关闭了所有其他git完成!

如何clone在此模型下使自定义选项卡完成工作(并且默认完成继续工作)?

不可接受的解决方案:

  • 修改系统打包文件:/usr/share/bash-completion/completions/git.此文件由apt.管理.

Bsq*_* ℬℬ 11

bash-completion 的官方FAQ包含非常有趣的信息.

首先,如果你是100%肯定你$BASH_COMPLETION_USER_DIR$XDG_DATA_HOME环境变量都是空的,你在你原来的问题指定什么是一个好地方,添加自己的bash完成脚本:

~/.local/share/bash-completion/completions/git
Run Code Online (Sandbox Code Playgroud)

需要注意的是.bash扩展没有必要.

事实是,由于/etc/profile.d/bash_completion.sh文件,加载了bash-completion脚本.

如果你在你的.bashrc文件中执行某些操作,你会以某种方式破坏加载链中的某些东西.

但是,如果覆盖现有的完成功能,仍需要确保加载顺序正确.因此,必须加载第一个bash-completion脚本以确保一切都成功结束.您可以轻松执行它,在~/.local/share/bash-completion/completions/git文件开头添加此初始指令:

# Ensures git bash-completion is loaded before overriding any function (be careful to avoid endless loop).
! complete -p git &> /dev/null && [ ${ENDLESS_LOOP_SAFEGUARD:-0} -eq 0 ] && ENDLESS_LOOP_SAFEGUARD=1 BASH_COMPLETION_USER_DIR=/dev/null  _completion_loader git
Run Code Online (Sandbox Code Playgroud)

首先,它检查是否已经加载了git bash-completion,然后如果不是这种情况,则加载所有bash-completion git定义.编辑:ENDLESS_LOOP_SAFEGUARD当这是第一次bash完成加载git部分时,该技巧允许避免无限循环.

如果需要,您可以获得以下用途:

complete --help
Run Code Online (Sandbox Code Playgroud)

完成:完成[-abcdefgjksuv] [-pr] [-DE] [-o选项] [-A动作] [-G globpat] [-W wordlist] [-F功能] [-C命令] [-X filterpat] [-P prefix] [-S suffix] [name ...]指定Readline如何完成参数.

对于每个NAME,指定参数的完成方式.如果未提供选项,则以允许将其重新用作输入的方式打印现有完成规范.

选项:

-p以可重用格式打印现有完成规范-r删除每个NAME的完成规范,或者,如果没有提供NAME,则所有完成规范-D将完成和操作应用为命令的默认值,而不定义任何特定完成-E将完成和操作应用于"空"命令 - 在空白行上尝试完成

尝试完成时,将按照上面列出的大写字母选项的顺序应用操作.-D选项优先于-E.

退出状态:除非提供了无效选项或发生错误,否则返回成功.

然后,只有这样,您才能定义您想要的任何内容,包括重写git clone bash完成的旧方法:

# Ensures git bash-completion is loaded before overriding any function (be careful to avoid endless loop).
! complete -p git &> /dev/null && [ ${ENDLESS_LOOP_SAFEGUARD:-0} -eq 0 ] && ENDLESS_LOOP_SAFEGUARD=1 BASH_COMPLETION_USER_DIR=/dev/null  _completion_loader git

# https://github.com/scop/bash-completion/blob/d2f14a7/bash_completion#L498
__ltrim_colon_completions() {
    if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
        # Remove colon-word prefix from COMPREPLY items
        local colon_word=${1%"${1##*:}"}
        local i=${#COMPREPLY[*]}
        while [[ $((--i)) -ge 0 ]]; do
            COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
        done
    fi
}


_git_clone() {
    case "$cur" in
    --*)
        __gitcomp_builtin clone
        return
        ;;
    *)
        argc=0
        for word in "${words[@]}"; do
            case "$word" in
            git|clone|--*)
                continue
                ;;
            *)
                argc=$((argc + 1))
                ;;
            esac
        done

        if [ $argc -le 1 ]; then
            __gitcomp "https://github.com/git/git https://github.com/python/cpython"
            __ltrim_colon_completions "$cur"
        fi
        ;;
    esac
}
Run Code Online (Sandbox Code Playgroud)

每次执行更改并想要检查结果时,您只需要为git请求bash-completion reload:

_completion_loader git
Run Code Online (Sandbox Code Playgroud)

这样一来,你永远不会丢失你的改变,因为你让包文件不受影响; 并且仍然可以使用您自己的功能增强任何现有的bash-completion.

编辑:

关于你对_completion_loaderfunction =>的恐惧,但是在检查了源代码之后,这个函数自提交cad3abfc7以来就存在了,2015-07-15 20:53:05所以我想它应该保持向后兼容,但是没有保证就是真的.我会编辑我的答案以提出一些替代方案

作为替代方案,这应该是获得自己的git完成定义的另一种方法(放在你自己的脚本的开头):

# Ensures git bash-completion is loaded before overriding any function
# Be careful to avoid endless loop with dedicated $ENDLESS_LOOP_SAFEGUARD environment variable.
if ! complete -p git &> /dev/null && [ ${ENDLESS_LOOP_SAFEGUARD:-0} -eq 0 ]; then
    # Trick: define $BASH_COMPLETION_USER_DIR environment variable here to ensure bash-completion rule are loaded once.
    export BASH_COMPLETION_USER_DIR=/usr/share
    complete -D git

    unset BASH_COMPLETION_USER_DIR
    ENDLESS_LOOP_SAFEGUARD=1 complete -D git
fi
Run Code Online (Sandbox Code Playgroud)