Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to give correct suggestions to tab complete when my words contains colons

I am writing a bash tab completion file for a utility that some times requires full URLs on the form: protocol://host:port. This contains two colons, which have proven to be problematic for tab completion. This is because the colons are treated as word breaks. I have read that I should not change COMP_WORDBREAKS directly, so I want to use the _get_comp_words_by_ref and __ltrim_colon_completions as suggested here: How to reset COMP_WORDBREAKS without effecting other completion script?

This works for a single colon, but the second colon causes a small problem as demonstrated in this minimal example:

This example shows the problem. It occurs for any number of colons in the suggestions.

[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

Hitting tab after foo successfully completes the common part. Hitting tab twice after that, yields the following suggestions:

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

The desired result is ofcourse:

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

After that, hitting a, b, or c plus tab works as expected, it completes the full URL.

Any suggestions to how I can produce the right output? Do I need to manually change the COMPREPLY variable, or am I just using the functions wrong?

like image 302
toftis Avatar asked Oct 31 '22 10:10

toftis


1 Answers

I came up with a solution based on one trick I'm always using. Hope it would help.

_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=$( printf '%s\n' "${COMPREPLY[@]}" \
                         | sed '$q;N;s/^\(.*\).*\n\1.*$/\1/;h;G;D' )
        if [[ $common_prefix == "$CUR" ]]; then
            COMPREPLY=( "${compreply[@]}" " " )
        fi
    fi

    return 0
}

complete -F _bar bar

Following is what it would look like (tested with 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] $

And actually the problem is not specific about two or more colons. One colon has the similar problem too.

like image 150
pynexj Avatar answered Nov 04 '22 12:11

pynexj