3

Context

I am creating a shell program which is a command line tool. I want to create my own auto-completion for this tool.

I want to do two different things (maybe should I post two questions):

  • for the options --install and -i, I want to auto-complete on file paths, like the ls command do.
  • for the options --unit-test and -t, I want to auto-complete on file paths from a particular directory which I can get running my_app --directory.

my_app_autocomplete file

__my_app_autocomplete()
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="--help -h --install -i --run -r --rebuild -rb --show-running-containers -ps --stop -s --remove -rm --logs -l --bash -b --sass -css --unit-tests -t"
    containers="nginx php mysql mongo node"
    sass="watch"

    # By default, autocomplete with options
    if [[ ${prev} == my_app ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
    # By default, autocomplete with options
    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
    # For --install and -i options, autocomplete with folder
    if [ ${prev} == --install ] || [ ${prev} == -i ] ; then
        COMPREPLY=( $(compgen -d -- ${cur}) )
        return 0
    fi
    # For --stop --remove --logs and --bash, autocomplete with containers
    if [ ${prev} == --stop ] || [ ${prev} == -s ] || [ ${prev} == --remove ] || [ ${prev} == -rm ] || [ ${prev} == --logs ] || [ ${prev} == -l ] || [ ${prev} == --bash ] || [ ${prev} == -b ] ; then
        COMPREPLY=( $(compgen -W "${containers}" -- ${cur}) )
        return 0
    fi
    # For --sass and -css, complete with sass options
    if [ ${prev} == --sass ] || [ ${prev} == -css ] ; then
        COMPREPLY=( $(compgen -W "${sass}" -- ${cur}) )
        return 0
    fi
    # For --unit-tests and -t, complete with relative to my_app folder paths
    if [ ${prev} == --unit-tests ] || [ ${prev} == -t ] ; then
        COMPREPLY=( $(compgen -d -- ${cur}) )
        return 0
    fi
}
complete -F __my_app_autocomplete my_app

Problem

I struggle on a particular point: auto-complete file paths.

I don't understand compgen options and how to do things with it. Maybe I could try to run a subcommand but I don't know the syntax and I can't find any useful information except man of bash - Programmable completion builtins which does not give much information about compgen.

In this case, when I do:

user@computer:~$ my_app --install D[TAB][TAB]

I would like:

user@computer:~$ my_app --install Documents/

I obtain:

user@computer:~$ myapp --install Documents 

with a blank space at the end of the line, which is a problem because I have to erase it and add a / to be able to redo [TAB][TAB] to auto-complete for sub-directories.

Investigations

-o nospace

With the option -o nospace applied on complete as:

complete -o nospace -F __my_app_autocomplete my_app

the behavior is:

user@computer:~$ myapp --i[TAB][TAB]
user@computer:~$ myapp --install

without space.

user@computer:~$ myapp --install D[TAB][TAB]
user@computer:~$ myapp --install Documents

without space.

Problems:

  • It removes spaces for all options, forcing me to manually add a space after those that aren't file paths (like --install)
  • I have to add / to navigate into sub directories

-o filenames

With the option -o filenames applied on complete as:

complete -o filenames -F __my_app_autocomplete my_app

the behavior is:

user@computer:~$ myapp --i[TAB][TAB]
user@computer:~$ myapp --install

with a space

user@computer:~$ myapp --install D[TAB][TAB]
user@computer:~$ myapp --install Documents/

with a / and without space if it's a directory

user@computer:~$ myapp --install f[TAB][TAB]
user@computer:~$ myapp --install file 

with a space if it's a file

It seems to set paths only for completion not defined in an list of words, so it does not affect other completions, I think it's the first part of what I need.

From a particular directory

I will open another question to avoid mixing things: How to autocomplete a bash commandline with file paths from a specific directory without displaying this directory?

1 Answer 1

1

To auto complete file paths

Substitute

complete -F __my_app_autocomplete my_app

with

complete -o filenames -F __my_app_autocomplete my_app

Here you can find all the compgen options explained:

https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html

Sign up to request clarification or add additional context in comments.

2 Comments

If you read carefully my question, you can see there is a link to this documentation... Thanks, the -o filenames solved the first part of my problem, what about the second part: from a particular folder?
I split my question to avoid mixing things: stackoverflow.com/questions/44453510/… Thank you for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.