9

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?

3
  • can you show us expected input and their expected output??
    – Hackaholic
    Nov 9, 2014 at 4:13
  • There are many methods to do so but ismuch better to see the examples what you have and what you want to receive. printf "%s\n" space separated list, tr ' ' '\n', sed 's/\s/\n/g', etc.
    – Costas
    Nov 9, 2014 at 9:58
  • I have edited my post to better describe the issue.
    – phimath
    Nov 9, 2014 at 19:09

2 Answers 2

9

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.

4

To modify a readline variable for just a particular completion function, you can set the readline variable during function execution and then have $PROMPT_COMMAND change it back.

_foo_complete() {
    # retrieve the original value
    local width=$(bind -v | sed -n 's/^set completion-display-width //p')

    if [[ $width -ne 0 ]]; then
        # change the readline variable
        bind "set completion-display-width 0"

        # set up PROMPT_COMMAND to reset itself to its current value
        PROMPT_COMMAND="PROMPT_COMMAND=$(printf %q "$PROMPT_COMMAND")"

        # set up PROMPT_COMMAND to reset the readline variable
        PROMPT_COMMAND+="; bind 'set completion-display-width $width'"
    fi

    # whatever the function normally does follows
    COMPREPLY=(aa bb)
}
complete -F _foo_complete foo

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .