覆盖git克隆的bash完成 内置完成

覆盖git克隆的bash完成 内置完成,bash,git,bash-completion,Bash,Git,Bash Completion,默认设置(如下所示)为-*选项提供选项卡完成: _git_clone () { case "$cur" in --*) __gitcomp_builtin clone return ;; esac } bash完成1.x(旧bash) (对于具体实例,macos high sierra+brew安装了bash completion/git) 在bash completion 1.x世界中,要覆盖此功能,我将(在.bashr

默认设置(如下所示)为
-*
选项提供选项卡完成:

_git_clone ()
{
    case "$cur" in
    --*)
        __gitcomp_builtin clone
        return
        ;;
    esac
}
bash完成1.x(旧bash) (对于具体实例,macos high sierra+brew安装了bash completion/git)

在bash completion 1.x世界中,要覆盖此功能,我将(在
.bashrc
/
.bash\u profile
中)定义自己的
\u git\u 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
}
这非常有效:

(我在这里输入的序列是git clone hg)

bash完成2.x (举一个具体的例子:股票ubuntu bionic(18.04))

在bash completion 2.x中,模型被转换为动态加载的配置。这意味着当“
git
已完成”选项卡时,激发,在其安装的路径上查找git完成并将其来源

.bashrc
/
.bash\u profile
中定义我自己的
\u git\u clone
完成函数现在是无用的,因为它会被动态来源的完成文件破坏

我可以在以下位置定义自己的
git
完成:

(例如
~/.local/share/bash completion/completions/git.bash
)。但是,这会关闭所有其他的
git
completion

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

不可接受的解决方案:

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

在您的
.bashrc
/
.bash\u配置文件中,您可以在重新定义
git克隆的完成之前,强制加载
git
的默认完成:

if ! complete -p git &> /dev/null
then
    # Instead of hardcoding the name of the dynamic completion loader
    # function, you can obtain it by parsing the output of 'complete -p -D'
    _completion_loader git
fi

_git_clone() {
    COMPREPLY=("My own completion for 'git clone'")
}
编辑

上述方法的一个可延迟加载版本(不急于加载
git
的默认bash完成)如下所示:

bash完成过程包含非常有趣的信息

首先,如果您100%确定您的
$BASH\u COMPLETION\u USER\u DIR
$XDG\u DATA\u HOME
环境变量为空,那么您在原始问题中指定的是添加自己的BASH完成脚本的好地方:

~/.local/share/bash-completion/completions/git
需要注意的是,
.bash
不需要扩展

事实上,bash完成脚本是通过
/etc/profile.d/bash_completion.sh
文件加载的

如果在
.bashrc
文件中执行某些操作,可能会破坏加载链中的某些内容

尽管如此,如果覆盖现有的完成函数,仍然需要确保加载顺序正确。 因此,加载第一个bash完成脚本是必需的,以确保一切顺利结束。 您可以轻松地执行此操作,在
~/.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
首先检查是否已经加载git bash completion,如果不是这样,则加载所有bash completion git定义。 编辑:当bash completion第一次加载git部分时,
无止境循环保护
技巧允许避免无止境循环

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

complete --help
完成:完成[-abcdefgjksuv][-pr][-DE][-o 选项][A操作][G globpat][W单词列表][F函数][C 命令][X filterpat][P前缀][S后缀][名称…] 指定Readline如何完成参数

对于每个名称,指定如何完成参数。如果没有选择 现有竣工规范的打印方式如下: 允许将它们重新用作输入

选项:

-p以可重复使用的格式打印现有的完成规范 -r删除每个名称的完成规范,如果没有,则删除 提供名称,所有完工规范 -D将完成和操作应用为命令的默认值 没有定义任何特定的完成 -E将完成和操作应用于“空”命令-- 试图在空行上完成

尝试完成时,将按照 上面列出了大写字母选项。-D选项需要 优先于-E

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

然后,也只有这样,您才能定义您想要的任何内容,包括覆盖git clone bash completion的旧方法:

# 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
}
每次执行更改并希望检查结果时,只需请求git的bash completion重载:

_completion_loader git
这样,你就永远不会失去你的改变,因为你让包文件原封不动;并且仍然可以使用您自己的函数增强任何现有的bash完成

编辑:

关于你对
\u completion\u loader
function=>的恐惧,但是在检查了源代码之后,这个函数自提交后就存在了,日期是
2015-07-15 20:53:05
,所以我想它应该保持向后兼容,但不保证是真的。我将编辑我的答案,提出一些备选方案

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


自己调用
\uuuu load\u completion
,然后像以前一样重写?@o11c调用双下划线函数感觉非常脆弱这感觉像是一种黑客行为——我想新的延迟加载系统是为了防止像这样潜在的昂贵的急加载?但是它确实可以工作(在shell启动时有一个明显的停顿)。您还没有真正解释它的工作原理,或者如何“解析
complete-p-D
”的输出@AnthonySottile*如何“解析
complete-p-D
”的输出*该注释是为了防止您在
complete --help
# 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
}
_completion_loader 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