0

I'm writing a CLI application using the python click library, and I want users of my CLI to have shell autocompletion out of the box. Precisely, I want my users to install my CLI using pip install my-cli and after that they would have autocompletion already without having to source any shell file or install any other package.

I already implemented the autocompletion script as shown in the official docs of the click library and automated the autocompletion installation in setup.py. I did it following these instructions

However, in this case, my users would have to install my-cli and then re-source the shell script file (e.g .bashrc for bash).

Precisely, this is what is happening:

  • open the terminal
  • run pip install my-cli (I automated installing the completion script here)
  • users do not have autocompletion yet. Therefore, they should open a new terminal or run source .bashrc (this is the step that I want to automate, if possible)
  • After that, autocompletion works fine

I don't know if this is possible in my case. I know that I can't source a shell script using python since the python subprocess module will spawn a subprocess and the environment changes will not apply on the current process in this case (correct me if I'm wrong).

On the other way, some packages like git and docker provide autocompletion automatically after installing them. Last time I installed docker and then run docker <Tab> <Tab> I already got a list of the subcommands that I can use. So it would be interesting to know how to achieve this using python.

Interestingly, some other python CLI frameworks like typer provides a way to automatically install autocompletion using a subcommand. However, after running the install command, it shows a message that you should re-source the bash script or open a new terminal in order to get autocompletion, which makes me wonder if it's possible to automate this step, because I'm sure they would have done it if that is the case.

basilisk
  • 1,006
  • 1
  • 11
  • 30

1 Answers1

0

According to man bash:

There is some support for dynamically modifying completions. This is most useful when used in combination with a default completion specified with complete -D. It's possible for shell functions executed as completion handlers to indicate that completion should be retried by returning an exit status of 124. If a shell function returns 124, and changes the compspec associated with the command on which completion is being attempted (supplied as the first argument when the function is executed), programmable completion restarts from the beginning, with an attempt to find a new compspec for that command. This allows a set of completions to be built dynamically as completion is attempted, rather than being loaded all at once.

For instance, assuming that there is a library of compspecs, each kept in a file corresponding to the name of the command, the following default completion function would load completions dynamically:

_completion_loader()
{
     . "/etc/bash_completion.d/$1.sh" >/dev/null 2>&1 && return 124
}
complete -D -F _completion_loader -o bashdefault -o default

So what you're asking for is possible if some package is doing this already. Just put your compspec file somewhere following the package's convention.

I believe the most popular bash completion package is bash-completion and in it's source code it has this:

# set up dynamic completion loading
_completion_loader()
{
    # $1=_EmptycmD_ already for empty cmds in bash 4.3, set to it for earlier
    local cmd=${1:-_EmptycmD_}
    __load_completion "$cmd" && return 124
    # Need to define *something*, otherwise there will be no completion at all.
    complete -F _minimal -- "$cmd" && return 124
} &&
    complete -D -F _completion_loader

So just go check how __load_completion is dynamically finding and loading compspecs for commands.

pynexj
  • 16,531
  • 5
  • 29
  • 48