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 ofbash,zshandfish) - 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 ispython3.8, you will need to specifypython3.8. In this case, your program name has to be the path tomyscript.py, for example. - Argument
module: Whether the program is running as a python module.pythonwill 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
$ 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,fileanddir. In most cases, it'splain. But if you want to completefileordir, 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 (thecurrentargument). -
type: eitherfileordir -
prefix: theprefixargument, 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)
Enabling completion in your script
Make sure you call params.parse(...) after all parameters/commands defined to make those shell code work.