[Bash-completion-devel] scp remote path completion broken?

Freddy Vulto fvulto at gmail.com
Sun Sep 6 08:44:48 UTC 2009


On Fri, Sep 4, 2009 at 11:50 PM, Ville Skyttä<ville.skytta at iki.fi> wrote:
> scp's remote path completion appears broken to me - the ":" to _get_cword does
> not seem to affect anything and thus the hostname always disappears and things
> go south from there.  On a brief look, it seems to me that _get_cword doesn't
> actually do anything with the argument given to it.
>
> This is on Fedora 11, bash 4.0.23.  Did I overlook something?

I can confirm the same problem on Ubuntu, bash-4.0-28.

Steps to reproduce the problem:

1.  Complete foo with _foo:

    _foo() {
        cur=$(_get_cword ':')
        echo; echo "cur: $cur"
    } # foo()
    complete -F _foo foo

2.  On bash-3, output is this:

    $ foo a:b<TAB>
    cur: a:b

    Whereas on bash-4, output is this:

    $ foo a:b<TAB>
    cur: b


It looks like processing argument $1 has been dropped from
_get_cword() in commit: f6497298 "fixed _get_cword()" (2008-06-23),
coming from Ubuntu.  David, can you recall what this fixed?

Using the original _get_cword fixes the problem.

I looks we should move the `WORDBREAKS' code back into _get_cword,
or restore the original?

More info:

An explanation for the problem might be, from
http://taskwarrior.org/issues/show/241:

    "It appears that the real problem may have been with bash 3.x.
    According to the bash man page, the env. variable
    COMP_WORDBREAKS provides a list of characters that are to
    delimit words. In both Fedora 10 and 11 this does contain the
    colon (:) character and Fedora 11 (i.e., bash 4) correctly does
    delimit at the colon, but Fedora 10 (i.e., bash 3) does not.
    Apparently, completion of projects under bash 3 is working only
    because of what appears to be a bug in bash 3."

See also E13, http://tiswww.case.edu/php/chet/bash/FAQ:

    E13) Why does filename completion misbehave if a colon appears
    in the filename?

    Filename completion (and word completion in general) may appear
    to behave improperly if there is a colon in the word to be
    completed.

    The colon is special to readline's word completion code:  it is
    one of the characters that breaks words for the completer.
    Readline uses these characters in sort of the same way that bash
    uses $IFS: they break or separate the words the completion code
    hands to the application-specific or default word completion
    functions.  The original intent was to make it easy to edit
    colon-separated lists (such as $PATH in bash) in various
    applications using readline for input.

    This is complicated by the fact that some versions of the
    popular `bash-completion' programmable completion package have
    problems with the default completion behavior in the presence of
    colons.

    The current set of completion word break characters is available
    in bash as the value of the COMP_WORDBREAKS variable.  Removing
    `:' from that value is enough to make the colon not special to
    completion:

    COMP_WORDBREAKS=${COMP_WORDBREAKS//:}

    You can also quote the colon with a backslash to achieve the
    same result temporarily.

This was the original _get_cword before the fix:

    # Get the word to complete
    # This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it
    # handles cases where the user is completing in the middle of a
    # word.
    # (For example, if the line is "ls foobar",
    # and the cursor is here -------->   ^
    # it will complete just "foo", not "foobar", which is what the
    # user wants.)
    #
    # Accepts an optional parameter indicating which characters out
    # of $COMP_WORDBREAKS should NOT be considered word breaks. This
    # is useful for things like scp where we want to return
    # host:path and not only path.
    _get_cword()
    {
            local i
            local LC_CTYPE=C
            local WORDBREAKS=${COMP_WORDBREAKS}
            if [ -n $1 ]; then
                    for (( i=0; i<${#1}; ++i )); do
                            local char=${1:$i:1}
                            WORDBREAKS=${WORDBREAKS//$char/}
                    done
            fi
            local cur=${COMP_LINE:0:$COMP_POINT}
            local tmp="${cur}"
            local word_start=`expr "$tmp" : '.*['"${WORDBREAKS}"']'`
            while [ "$word_start" -ge 2 ]; do
                    local char=${cur:$(( $word_start - 2 )):1}
                    if [ "$char" != "\\" ]; then
                            break
                    fi
                    tmp=${COMP_LINE:0:$(( $word_start - 2 ))}
                    word_start=`expr "$tmp" : '.*['"${WORDBREAKS}"']'`
            done

            cur=${cur:$word_start}
            echo "$cur"
    }


Regards,

Freddy Vulto
http://fvue.nl



More information about the Bash-completion-devel mailing list