Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony based autocomplete breaks SCP autocomplete

I am using the PHP tools http://robo.li and n98-magerun.phar - both are based on Sympfony's CLI components.

When I use such a autocomplete script:

https://gist.github.com/caseyfw/51bdbcb37e5dfb91b74e

#!/bin/sh
function __robo_list_cmds ()
{
      robo list --raw | awk '{print $1}' | sort
}

function __robo_list_opts ()
{
    robo list --no-ansi | sed -e '1,/Options:/d' -e '/^$/,$d' -e 's/^ *//' -e 's/ .*//' | sort
}

_robo()
{
    local cur="${COMP_WORDS[COMP_CWORD]}"
    COMPREPLY=($(compgen -W "$(__robo_list_opts) $(__robo_list_cmds)" -- ${cur}))
    return 0;
}

complete -o default -F _robo robo
COMP_WORDBREAKS=${COMP_WORDBREAKS//:}

It breaks the autocomplete of the scp command (which usually completes files on a remote server - but with this - unrelated - robo completion in place, scp removes the host name from the command)

Why is that? How to fix?

EDIT

based on the answer, the fixed version is here:

https://gist.github.com/amenk/d68f1fe54b156952ced621f771ff48ba

like image 262
Alex Avatar asked Aug 26 '16 08:08

Alex


1 Answers

This has probably nothing to do with your robo compspec. Nor with the _scp completion function associated with scp.

It is probably due to your COMP_WORDBREAKS=${COMP_WORDBREAKS//:}.

You removed : from the list of separators. Apparently _scp is robust enough to behave the same with or without : as a word separator. It returns the same list of candidate completions. But the token that gets substituted when _scp returns only one candidate for the completion of, e.g. scp host:public_ht, is host:public_ht, instead of just public_ht. Proof:

$ _foobar () { COMPREPLY=bazcux; return 0; }
$ complete -o default -F _foobar foobar
$ echo $COMP_WORDBREAKS
"'><=;|&(:

If you try to complete foobar host:public_ht, you get foobar host:bazcux because the substituted token is just public_ht. While with:

$ COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
$ echo $COMP_WORDBREAKS
"'><=;|&(

if you try to complete foobar host:public_ht, you get foobar bazcux because it is the complete host:public_ht that is replaced by bazcux.

The solution to your problem is probably to adapt your _robo completion function such that it does not require that : is not a word separator. Something like:

_stem () {
    local lcur lprev
    lcur="$cur"
    stem="$lcur"
    for (( i = cword - 1; i >= 0; i -= 1 )); do
        lprev="${words[i]}"
        [[ $lcur == ":" ]] && [[ $lprev == ":" ]] && break
        [[ $lcur != ":" ]] && [[ $lprev != ":" ]] && break
        stem="$lprev$stem"
        lcur="$lprev"
    done
}

_robo () {
    local cur prev words cword
    _init_completion || return
    local stem options
    options=($(__robo_list_opts) $(__robo_list_cmds))
    COMPREPLY=()
    _stem
    COMPREPLY=($(compgen -W '${options[@]}' -- "$stem"))
    [[ $stem =~ : ]] && stem=${stem%:*}: && COMPREPLY=(${COMPREPLY[@]#"$stem"})
    return 0
}

complete -o default -F _robo robo

A much (apparently) simpler solution consists in replacing the _stem function above by the existing __reassemble_comp_words_by_ref function of the bash_completion library:

_robo () {
    local cur prev words cword
    _init_completion || return
    __reassemble_comp_words_by_ref ":" words cword
    options=($(__robo_list_opts) $(__robo_list_cmds))
    COMPREPLY=($(compgen -W '${options[@]}' -- "$cur"))
    return 0
}

complete -o default -F _robo robo

All this is probably not exactly what you want. I do not know robo.il and there are probably many improvements that would take more context into account to propose specific completions. But it may be a starting point.

like image 78
Renaud Pacalet Avatar answered Oct 25 '22 05:10

Renaud Pacalet