Bash – nyway to get COMPREPLY to be output as a vertical list of words instead in a single line

autocompletebash

COMPREPLY by default returns a space separated list of words, but I'd like to have it return a single word per line. I've tried putting newlines at the ends of the words and have looked through the docs for both compgen and complete but can't find anything.

Is this possible?

EDIT:

Sorry I really explained that poorly. I have a script that is bound to an autocomplete function via complete -F. When the user runs the script, hitting tab twice will show a list of possible options via compgen. Right now the function has lines of code like this:

COMPREPLY=( $(compgen -W '$( ls ~/work/dev/jobs/ | cat )' -- $curword ) )

When the user hits tab though, these directories are displayed like:

directory0 directory1 directory2 directory3

but i would like them displayed like:

directory0
directory1
directory2
directory3

I posted a similar thread to /r/bash and someone suggested doing

bind 'set completion-display-width 0'

which works, and then I can unset it with

bind 'set completion-display-width -1'

The issue now is that if I unset it before the complete function returns, it has no effect, so I unset it in the script after the user has pressed enter. This works fine, but if the user starts using the autocomplete, and then changes their mind and delets what they had entered and were to return to the shell, completion-display-width would still be set to 0.

Is there another way to go about this?

Best Answer

I'm the one that suggested changing the completion-display-width readline variable at /r/bash, but then you didn't specify you only wanted it to work on this one completion function.

Anyway, in a completion function, you can detect whether it's triggered by TAB (COMP_TYPE == 9) or by TABTAB (COMP_TYPE == 63), and if the latter is the case, you could pad the results with spaces so they fill the entire width of the terminal. It's the least hackish thing I can think of. It would look something like this:

_foo_complete() {
    local i file files
    files=( ~/work/dev/jobs/"$2"* )
    [[ -e ${files[0]} || -L ${files[0]} ]] || return 0
    if (( COMP_TYPE == 63 )); then
        for file in "${files[@]}"; do
            printf -v 'COMPREPLY[i++]' '%*s' "-$COLUMNS" "${file##*/}"
        done
    else
        COMPREPLY=( "${files[@]##*/}" )
    fi
}
complete -F _foo_complete foo

On a side note, you really shouldn't parse ls output.

Related Question