Peter Moore
Peter Moore

Reputation: 2126

How to configure bash autocomplete for file search and custom search?

I want to have a command autocomplete uploaded scripts that would be run remotely, but the user could also pick a local script to upload. Here is a small example to illustrate the problem I have with the bash complete logic.

_test_complete()
{
    local cur prev opts uploaded_scripts
    uploaded_scripts='proc1.sh proc2.sh'
    
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    if [[ ${prev} == '-s' ]] ; then
        COMPREPLY=( $(compgen -W "${uploaded_scripts}" -- ${cur}) )
        return 0
    fi
}

complete -F _test_complete remote

The example almost works but it does not autocomplete local file searches anymore.

$ remote -s proc<TAB><TAB>
proc1.sh  proc2.sh

$ remote -s proc1.sh ./<TAB><TAB>

Nothing happens when you do the usual file search ./ which should list files in current dir. Any ideas on how you can enable both ?


EDIT: The above example had a problem you could only pick one file with file complete. I hacked a solution which works but if anyone has a better one please leave a comment. Also with the -o default from the accepted answer.

_test_complete()
{
    local cur prev opts uploaded_scripts
    uploaded_scripts='proc1.sh proc2.sh'

    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    
    [[ $COMP_CWORD == '1' ]] && LAST_OPT=''
    [[ ${prev:0:1} == '-' ]] && LAST_OPT=${prev}
    
    if [[ ${LAST_OPT} == '-s' ]]; then
        COMPREPLY=( $(compgen -o default -W "${uploaded_scripts}" -- ${cur}) )
        return 0
    fi
}

complete -F _test_complete remote

Upvotes: 1

Views: 1012

Answers (2)

Socowi
Socowi

Reputation: 27370

You just have to add all files from the local directory to COMPREPLY too. complete -f -- abc generates a list of files starting with abc.

By the way: Instead of "${COMP_WORDS[COMP_CWORD]}" and COMP_CWORD-1 you can also use $2 and $3 which are supplied to any completion function by bash.
But here I completely dropped the if since it seems you want to allow multiple files after -s. Since you don't suggest -s itself, just suggest the files all the time:

_test_complete() { 
  local cur="$2" prev="$3" uploaded_scripts='proc1.sh proc2.sh'
  COMPREPLY=( $(
    compgen -W "${uploaded_scripts}" -- "$cur"
    compgen -f -- "$cur"
  ) )
}

complete -F _test_complete remote

Note: COMPREPLY=( $(...) ) is easy to write but has some flaws. Files with spaces in them will be split into multiple suggestions and special symbols like * will expand and generate even more suggestions. To avoid this, either set IFS=$'\n'; set -o noglob or use mapfile -t COMPREPLY < <(...).
After you have done this, you can use complete -o filenames -F ... such that those problematic suggestions are correctly quoted when being inserted too.

Upvotes: 1

pynexj
pynexj

Reputation: 20797

You can use complete's -o default option (Usually I'd use both -o default and -o bashdefault):

complete -o default -F _test_complete remote

According to man bash:

  • bashdefault

    Perform the rest of the default bash completions if the compspec generates no matches.

  • default

    Use readline's default filename completion if the compspec generates no matches.

Upvotes: 1

Related Questions