17

This question is quite similar to this one, but I can't understand the solution. I also know this tutorial, but still I am unable to understand what I am doing wrong.

I am trying to autocomplete the list of directories that are placed in /something/:

$ ls /something/

One    Other    Three

in a way that this will happen:

$ hi [TAB]

One Other Three
$ hi O[TAB]

One Other

Only when the first word is hi and not only inside /something/.

This is what I am doing in .profile:

_codeComplete()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $(compgen `ls /something/` -- $cur) )

}
complete -F _codeComplete "hi "
Donovan
  • 293
  • 1
  • 2
  • 4

5 Answers5

16

Try:

_codeComplete()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $(compgen -W "$(ls /something/)" -- $cur) )
}

complete -F _codeComplete hi

You need to specify the -W option in compgen and also quote the command which produces the wordlist.

More information on how to write completion functions on this blog: Writing your own Bash Completion Function

dogbane
  • 29,087
  • 16
  • 80
  • 60
  • 6
    This will fail on file names containing whitespace and other special characters. – Gilles 'SO- stop being evil' Jan 04 '12 at 23:39
  • 2
    It is weirdly difficult to find the name of the `complete` command if you don't already know it and are searching for `autocomplete` or `tab-completion`... This was the first place I found the command name, and what I needed to fix it for `eject` on upgrade to Ubuntu 14.04 (`$ complete -p ls` -> `complete -F _longopt ls`, so the fix was: `complete -F _longopt eject`) (Here's hoping this comment helps others find it!) – Izkata Sep 01 '14 at 20:10
1

Let me try to improve upon the accepted answer.

The original answer will fail with filenames containing whitespace. After some investigation I realize you can change the input separator to end-of-line:

IFS=$'\n'

making the function handle spaces correctly.

_codeComplete()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    IFS=$'\n' tmp=( $(compgen -W "$(ls ~/something/ )" -- $cur))
    COMPREPLY=( "${tmp[@]// /\ }" )
}

complete -F _codeComplete hi
1

Here's a version that not only handles spaces, but escapes them, too:

_codeComplete()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    local AUTO_COMPLETE_DIRS=$(ls /something/)

    IFS=$'\n' COMPREPLY1=( $(compgen -W "$AUTO_COMPLETE_DIRS" -- $cur))
    COMPREPLY2=( "${COMPREPLY1[@]// /\ }" )
    COMPREPLY=($(printf "%q\n" "${COMPREPLY2[@]}"))

}
complete -F _codeComplete "hi "

(Based on dogbane's and Eduardo Almeida dos Santos' answers, but with escaping as provided by antak on SO: https://stackoverflow.com/a/11536437/1536933)

EM0
  • 436
  • 5
  • 15
1

(this could be a comment but I have <50 reputation)

A fix for EM0 answer, his version handle spaces but also escape them. But when you try to autocomplete a word that does not match any directory the word is changed to '' instead of providing no completion. Here is a simple fix.

_codeComplete(){
    local cur=${COMP_WORDS[COMP_CWORD]}

    IFS=$'\n' tmp=( $(compgen -W "$(ls /home/matutu/.templates)" -- $cur))
    COMPREPLY=( "${tmp[@]// /\ }" )
    # check if completion array is not empty
    if [ ${#tmp[@]} -ne 0 ]; then
        COMPREPLY=( $(printf "%q\n" "${tmp[@]}") )
    fi
}
complete -F _codeComplete "hi "
mDeram
  • 11
  • 2
  • Welcome to the site, and thank you for your contribution. While you cannot yet comment, you can make edit suggestions if you see the potential to improve an existing answer. It will even count towards your reputation if it is accepted. – AdminBee Jul 05 '21 at 07:56
0
_hi() {
    COMPREPLY=(cd /something/ && compgen -A directory -S / -- $2)
}

complete -o nospace -F _hi hi
xdch47
  • 1