Search code examples
bashautocompletebash-completioncompgen

Simulate Bash's COMPREPLY response without actually completing it


Steps to reproduce

  • Create directory on tmp, add 1 file inside.

    mkdir /tmp/testdir && touch /tmp/testdir/examplefile
    
  • Paste below script on /tmp/completion.sh

    # BEGIN AUTOCOMPLETE
    function _foo_complete() {
    local comnum cur opts
    [[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    opts="--help --restart -h -r"
    if (( COMP_CWORD > comnum )); then
     COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
     return
    fi
    if [[ ${cur} == -* ]]; then
     COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
     return 0
    else
     COMPREPLY=( $(for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done) )
    fi
    }
    complete -F _foo_complete foo.sh
    # END AUTOCOMPLETE
    
  • Source it then.

    . /tmp/completion.sh
    

Expected result

$ foo.sh --restart examplefile <tab><tab>
examplefile           
$ foo.sh --restart examplefile <tab><tab>
examplefile        
$ foo.sh --restart examplefile <tab><tab>
examplefile     
$ foo.sh --restart examplefile <tab><tab>

What happen instead

$ foo.sh --restart examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile

I want the suggestion to appear as possible completion, but without actually completing it (for display purposes). This question has been asked before, but to this date no answer is given.

Regarding -o nosort

I look into that option and it's only available at Bash 4.4+, I tried on my 16.04 machine and it fail. Looking for more globalish solution


Solution

  • Try the following compspec.sh (based on OP's code):

    function _foo_complete()
    {
        local comnum cur opts
    
        [[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
    
        COMPREPLY=()
        cur="${COMP_WORDS[COMP_CWORD]}"
        opts="--help --restart -h -r"
    
        if (( COMP_CWORD > comnum )); then
            COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
            if [[ ${#COMPREPLY[@]} -gt 0 ]]; then
                #
                # you can try COMPREPLY+=( zzz ) and see what's happening
                #
                COMPREPLY+=( ' ' )
            fi
            return
        fi
    
        if [[ ${cur} == -* ]]; then
            COMPREPLY=( $( compgen -W "${opts}" -- ${cur} ) )
            return 0
        else
            COMPREPLY=( $( for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done ) )
        fi
    }
    
    complete -F _foo_complete foo.sh
    

    enter image description here


    UPDATE:

    is it possible to move the empty string to end of completion, so it doesn't look like there are empty space?

    You can use complete -o nosort (requires Bash 4.4+) if you can sort the completion candidates all by yourself.