Skip to content
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
''',
)