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?

  • can you show us expected input and their expected output?? – Hackaholic Nov 9 '14 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 '14 at 9:58
  • I have edited my post to better describe the issue. – phimath Nov 9 '14 at 19:09
up vote 4 down vote accepted

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.

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

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.