Skip to content

Shell completion

pyparam supports shell completions for bash, zsh and fish. It also supports the script to be ran as a python script (in the format of python myscript.py) and as a python module (in the format of python -m myscript).

To enable the completions, you will have to print the code generated by params.shellcode(...), and let the user save it at required locations for the shell to initiate the completion.

params.shellcode has 3 arguments that generates codes for direct executables, python scripts and python modules.

  • Argument shell: Specifies the shell (One of bash, zsh and fish)
  • Argument python: Once specified, program will be ran as a python script or a module. It specifies the path or name to the python you used to run your script or your module. For example, if your python executable is python3.8, you will need to specify python3.8. In this case, your program name has to be the path to myscript.py, for example.
  • Argument module: Whether the program is running as a python module. python will be used if specified and your program name need to be the name of the module (myscript, for example).

Let's say you have $ myscript shellcode calling params.shellcode(...) and printing the code:

Completions for bash

$ myscript shellcode >> ~/.bashrc

Completions for fish

For direct executable:

$ myscript shellcode >> ~/.config/fish/completions/myscript.fish
For python script or module:
$ myscript shellcode >> ~/.config/fish/completions/python.fish
$ #     corresponding to your python executable:   ^^^^^^

Completions for zsh

$ myscript shellcode >> ~/.zshrc

If you encounter command not found: compdef, make sure you have this before the inserted code:

autoload -Uz compinit
compinit

Completion value callback

When define a parameter, you can also specify a callback to modify how the completion works for the values. For example, to add some description for a choice parameter:

def complete_callback(current, prefix):
    completes = []
    for value in ['xsmall', 'small', 'medium', 'large', 'xlarge']:
        # only show the value matches user's incomplete input
        if value.startswith(current):
            # prefix makes it works with `--choice=...`
            # Add some description for each value
            completes.append((f'{prefix}{value}', f'Cup size: {value}'))
    return completes

params.add_param('choice', type='choice',
                 choices=['xsmall', 'small', 'medium', 'large', 'xlarge'],
                 complete_callback=complete_callback)

This is how it looks like in fish:

> python -m pyparam complete --choice <tab>
large    (Cup size: large)  small    (Cup size: small)
xsmall  (Cup size: xsmall)  medium  (Cup size: medium)
xlarge  (Cup size: xlarge)

> python -m pyparam complete --choice x<tab>
xlarge  (Cup size: xlarge)  xsmall  (Cup size: xsmall)

Without the callback:

> python -m pyparam complete --choice <tab>
large  medium  small  xlarge  xsmall

> python -m pyparam complete --choice x<tab>
xlarge  xsmall

The callback should return:

  • None: no completion candidates given, meaning it's requiring user to input a value
  • '': An empty string, meaning we are done with the this parameter, go ahead to next available ones.
  • A list of tuple of:

    • 1-element: Shows just the value, without description
    • 2-element: Shows both the value and the description
    • 3-element: Shows the value, type and the description

    There are 3 types of completion candidates. plain, file and dir. In most cases, it's plain. But if you want to complete file or dir, you should return a list of 3-element tuples. Those 3 elements should be:

    • current: the current incomplete user-input, used to filter the paths (the current argument).

    • type: either file or dir

    • prefix: the prefix argument, used to do completion for --path=...

Note

file type of completions will also show directories.

Note

When a command has required parameters uncompleted, no subcommands will show in the candidates.

For example, in your script:

params.add_param('i', required=True)
params.add_command('command')

Then:

> script <tab>
-i  (No description)
will only show the required parameter, command will not show until the required parameters are filled.

Enabling completion in your script

Make sure you call params.parse(...) after all parameters/commands defined to make those shell code work.