当我的单词包含冒号时,如何给标签提供正确的建议

时间:2015-02-12 13:52:42

标签: bash bash-completion

我正在为实用程序编写bash选项卡完成文件,有时需要在表单上使用完整的URL:protocol://host:port。这包含两个冒号,已证明对标签完成有问题。这是因为冒号被视为分词。我已经读过,我不应该直接更改COMP_WORDBREAKS,因此我想按照此处的建议使用_get_comp_words_by_ref__ltrim_colon_completionsHow to reset COMP_WORDBREAKS without effecting other completion script?

这适用于单个冒号,但第二个冒号会导致一个小问题,如最小例子中所示:

此示例显示了该问题。它出现在建议中的任意数量的冒号中。

[root@2e3e8853cc0c /]# cat /etc/bash_completion.d/foo 
_foo()
{
    local cur
    COMPREPLY=()
    _get_comp_words_by_ref -n : -c cur

    COMPREPLY=( $(compgen -W "http://host:1234/aaa http://host:1234/bbb http://host:1234/ccc" -- ${cur}) )
    __ltrim_colon_completions "$cur"
    return 0
}
complete -F _foo foo

foo成功完成公共部分后点击标签。之后两次点击标签,产生以下建议:

[root@2e3e8853cc0c /]# foo http://host:1234/
1234/aaa  1234/bbb  1234/ccc

理想的结果是:

[root@2e3e8853cc0c /]# foo http://host:1234/
http://host:1234/aaa  http://host:1234/bbb  http://host:1234/ccc

之后,按a,b或c plus标签按预期工作,它会完成完整的URL。

有关如何生成正确输出的任何建议?我是否需要手动更改COMPREPLY变量,或者我只是使用错误的函数?

1 个答案:

答案 0 :(得分:1)

我想出了一个基于我一直使用的技巧的解决方案。希望它会有所帮助。

_common_prefix()
{   
    local vname=$1
    local first prefix v

    shift
    if [[ $# -eq 0 ]]; then
        local "$vname" && _upvar "$vname" ""
        return 0
    fi

    first=$1
    shift
    for ((i = 0; i < ${#first}; ++i)); do
        prefix=${first:0:i+1}
        for v; do
            if [[ ${v:0:i+1} != "$prefix" ]]; then
                local "$vname" && _upvar "$vname" "${first:0:i}"
                return 0
            fi
        done
    done

    local "$vname" && _upvar "$vname" "$first"
    return 0
}

_bar()      
{           
    local CUR=$2
    local cur
    local -a compreply=()
    local -a urls=(ftp://gnu.org \
                   http://host1:1234/aaa \
                   http://host2:1234/bbb \
                   http://host2:1234/ccc)

    _get_comp_words_by_ref -n : -c cur

    compreply=( $(compgen -W "${urls[*]}" -- "$cur") )
    COMPREPLY=( "${compreply[@]}" )
    __ltrim_colon_completions "$cur"

    if [[ ${#COMPREPLY[@]} -gt 1 ]]; then
        local common_prefix
        _common_prefix common_prefix "${COMPREPLY[@]}"
        if [[ $common_prefix == "$CUR" ]]; then
            COMPREPLY=( "${compreply[@]}" " " )
        fi
    fi

    return 0
}

complete -F _bar bar

以下是它的样子(使用Bash 4.3.33测试):

[STEP 101] $ bar <TAB><TAB>
                       http://host1:1234/aaa  http://host2:1234/ccc
ftp://gnu.org          http://host2:1234/bbb
[STEP 101] $ bar f<TAB>
[STEP 101] $ bar ftp://gnu.org␣
[STEP 101] $ bar ftp://gnu.org <ENTER>
bash: bar: command not found
[STEP 102] $ bar h<TAB>
[STEP 102] $ bar http://host
[STEP 102] $ bar http://host<TAB><TAB>
                       http://host2:1234/bbb
http://host1:1234/aaa  http://host2:1234/ccc
[STEP 102] $ bar http://host2<TAB>
[STEP 102] $ bar http://host2:1234/
[STEP 102] $ bar http://host2:1234/<TAB><TAB>
                       http://host2:1234/bbb  http://host2:1234/ccc
[STEP 102] $ bar http://host2:1234/b<TAB>
[STEP 102] $ bar http://host2:1234/bbb␣
[STEP 102] $ bar http://host2:1234/bbb <ENTER>
bash: bar: command not found
[STEP 103] $

实际上问题并不是两个或更多冒号的具体问题。一个冒号也有类似的问题。