Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for autocompletion of arguments #428

Closed
18 changes: 16 additions & 2 deletions click/_bashcomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import re
from .utils import echo
from .parser import split_arg_string
from .core import MultiCommand, Option

from .core import MultiCommand, Option, Argument

COMPLETION_SCRIPT = '''
%(complete_func)s() {
Expand Down Expand Up @@ -61,6 +60,21 @@ def do_complete(cli, prog_name):
choices.extend(param.secondary_opts)
elif isinstance(ctx.command, MultiCommand):
choices.extend(ctx.command.list_commands(ctx))
else:
for param in ctx.command.params:
if isinstance(param, Argument):
arguments = [k for k in args if k != ctx.command.name]
if len(arguments) <= param.nargs or param.nargs == -1:
try:
if callable(param.autocompletion):
choices.extend(param.autocompletion(ctx=ctx,
incomplete=incomplete,
cwords=cwords,
cword=cword))
else:
choices.extend(param.autocompletion)
except AttributeError:
pass

for item in choices:
if item.startswith(incomplete):
Expand Down
2 changes: 2 additions & 0 deletions click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,8 @@ def __init__(self, param_decls, required=None, **attrs):
required = False
else:
required = attrs.get('nargs', 1) > 0
if attrs.get('autocompletion') is not None:
self.autocompletion = attrs.pop('autocompletion')
Parameter.__init__(self, param_decls, required=required, **attrs)
if self.default is not None and self.nargs < 0:
raise TypeError('nargs=-1 in combination with a default value '
Expand Down
40 changes: 39 additions & 1 deletion docs/bashcomplete.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,52 @@ This might be relaxed in future versions.
What it Completes
-----------------

Generally, the Bash completion support will complete subcommands and
By default, the Bash completion support will complete subcommands and
parameters. Subcommands are always listed whereas parameters only if at
least a dash has been provided. Example::

$ repo <TAB><TAB>
clone commit copy delete setuser
$ repo clone -<TAB><TAB>
--deep --help --rev --shallow -r

Additionally, custom suggestions can be provided for arguments with the
``autocompletion`` parameter. ``autocompletion`` may be a list of strings, as
in the following example:

.. click:example::

@click.command()
@click.argument("name", type=click.STRING, autocompletion=["John", "Simon", "Doe"])
def cmd1(name):
click.echo('Name: %s' % name)

Alternatively, ``autocompletion`` may be a callback function that returns a list
of strings. This is useful when the suggestions need to be dynamically generated
at bash completion time. The callback function will be passed 4 keyword
arguments:

- ``ctx`` - The current click context.
- ``incomplete`` - The partial word that is being completed, as a string. May
be an empty string ``''`` if no characters have been entered yet.
- ``cwords`` - The bash `COMP_WORDS <https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html#Programmable-Completion>`_ array, as a list of strings.
- ``cword`` - The bash `COMP_CWORD <https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html#Programmable-Completion>`_ variable, as an integer.

Here is an example of using a callback function to generate dynamic suggestions:

.. click:example::

import os

def get_env_vars(ctx, incomplete, cwords, cword):
return os.environ.keys()

@click.command()
@click.argument("envvar", type=click.STRING, autocompletion=get_env_vars)
def cmd1(envvar):
click.echo('Environment variable: %s' % envvar)
click.echo('Value: %s' % os.environ[envvar])


Activation
----------
Expand Down
12 changes: 12 additions & 0 deletions examples/bashcompletion/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
$ bashcompletion

bashcompletion is a simple example of an application that
tries to autocomplete commands, arguments and options.

This example requires Click 2.0 or higher.

Usage:

$ pip install --editable .
$ eval "$(_BASHCOMPLETION_COMPLETE=source bashcompletion)"
$ bashcompletion --help
25 changes: 25 additions & 0 deletions examples/bashcompletion/bashcompletion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import click
import os

@click.group()
def cli():
pass

@cli.command()
@click.argument("name", type=click.STRING, autocompletion=["John", "Simon", "Doe"])
def cmd1(name):
click.echo('Name: %s' % name)

def get_env_vars(ctx, incomplete, cwords, cword):
return os.environ.keys()

@cli.command()
@click.argument("envvar", type=click.STRING, autocompletion=get_env_vars)
def cmd2(envvar):
click.echo('Environment variable: %s' % envvar)
click.echo('Value: %s' % os.environ[envvar])

@cli.command()
def cmd3():
pass

15 changes: 15 additions & 0 deletions examples/bashcompletion/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from setuptools import setup

setup(
name='click-example-bashcompletion',
version='1.0',
py_modules=['bashcompletion'],
include_package_data=True,
install_requires=[
'click',
],
entry_points='''
[console_scripts]
bashcompletion=bashcompletion:cli
''',
)