bash - 覆盖 git clone 的 bash 补全

标签 bash git bash-completion

内置补全

默认completion for git clone (转载于下方)为 --* 提供制表符补全选项:

_git_clone ()
{
    case "$cur" in
    --*)
        __gitcomp_builtin clone
        return
        ;;
    esac
}

bash-completion 1.x(旧 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
}

效果很好:

(我在这里输入的序列是 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 

bash-completion 2.x

(具体实例:stock ubuntu bionic (18.04))

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

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

我可以自己定义git完成 this directory :

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

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

如何定制 clone此模型下的选项卡完成工作(并让默认完成继续工作)?

Not Acceptable 解决方案:

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

最佳答案

official FAQ bash-completion 包含非常有趣的信息。

首先,如果您 100% 确定您的 $BASH_COMPLETION_USER_DIR$XDG_DATA_HOME 环境变量是空的,那么您在原始问题中指定的是添加您的代码的好地方自己的 bash 完成脚本:

~/.local/share/bash-completion/completions/git

要注意 .bash 扩展名不是必需的。

事实上,由于 /etc/profile.d/bash_completion.sh 文件加载了 bash 完成脚本。

如果您在 .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 定义。 编辑:ENDLESS_LOOP_SAFEGUARD 技巧允许在 bash 完成第一次加载 git 部分时避免无限循环。

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

complete --help

complete: complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...] Specify how arguments are to be completed by Readline.

For each NAME, specify how arguments are to be completed. If no options are supplied, existing completion specifications are printed in a way that allows them to be reused as input.

Options:

-p print existing completion specifications in a reusable format -r remove a completion specification for each NAME, or, if no NAMEs are supplied, all completion specifications -D apply the completions and actions as the default for commands without any specific completion defined -E apply the completions and actions to "empty" commands -- completion attempted on a blank line

When completion is attempted, the actions are applied in the order the uppercase-letter options are listed above. The -D option takes precedence over -E.

Exit Status: Returns success unless an invalid option is supplied or an error occurs.

然后,也只有那时,您可以定义任何您想要的,包括您覆盖 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
}

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

_completion_loader git

这样,您将永远不会丢失您的零钱,因为您让包文件保持原样;并且仍然可以使用您自己的函数增强任何现有的 bash-completion。

编辑:

关于你对 _completion_loader function => 的恐惧,但是在检查了源代码之后,这个函数自提交以来就存在 cad3abfc7 , of 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

关于bash - 覆盖 git clone 的 bash 补全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51972474/

相关文章:

xml - 用 bash 解析 HTML 表格列

git - 指定包含访问 token 的分页的 git API 调用示例

git - Mercurial相当于git的HEAD~1

autocomplete - zsh 函数 : forward completion to subfunction

git - Bash 完成 : Honor repository-specific Git alias in alias completion

python - 带 shell 完成的 pip install

regex - 如何修复此 SED 命令以查找和替换字符串

mysql - 如何 grep 多行模式

node.js - n( Node 版本管理器)安装后不工作 - "bash: n: command not found"

git - git-receive-pack 是如何工作的?