Skip to content

Commit

Permalink
rename autocompletion to shell_complete
Browse files Browse the repository at this point in the history
new function takes additional param arg, must return a homogeneous list
of strings or CompletionItem, and must perform matching on results
  • Loading branch information
davidism committed Oct 3, 2020
1 parent cb5c21e commit 3faede8
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 85 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ Unreleased
completions suggestions.
- Groups complete the names commands were registered with, which
can differ from the name they were created with.
- The ``autocompletion`` parameter for options and arguments is
renamed to ``shell_complete``. The function must take four
parameters ``ctx, param, args, incomplete``, must do matching
rather than return all values, and must return a list of strings
or a list of ``ShellComplete``. The old name and behavior is
deprecated and will be removed in 8.1.


Version 7.1.2
Expand Down
7 changes: 4 additions & 3 deletions docs/shell-completion.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,12 @@ Overriding Value Completion
---------------------------

Value completions for a parameter can be customized without a custom
type by providing an ``autocompletion`` function. The function is used
type by providing a ``shell_complete`` function. The function is used
instead of any completion provided by the type. It is passed 3 keyword
arguments:

- ``ctx`` - The current command context.
- ``param`` - The current parameter requesting completion.
- ``args`` - The list of complete args before the incomplete value.
- ``incomplete`` - The partial word that is being completed. May
be an empty string if no characters have been entered yet.
Expand All @@ -165,11 +166,11 @@ start with the incomplete value.

.. code-block:: python
def complete_env_vars(ctx, args, incomplete):
def complete_env_vars(ctx, param, args, incomplete):
return [k for k in os.environ if k.startswith(incomplete)]
@click.command()
@click.argument("name", autocompletion=complete_env_vars)
@click.argument("name", shell_complete=complete_env_vars)
def cli(name):
click.echo(f"Name: {name}")
click.echo(f"Value: {os.environ[name]}")
Expand Down
12 changes: 0 additions & 12 deletions examples/bashcompletion/README

This file was deleted.

45 changes: 0 additions & 45 deletions examples/bashcompletion/bashcompletion.py

This file was deleted.

28 changes: 28 additions & 0 deletions examples/completion/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
$ completion
============

Demonstrates Click's shell completion support.

.. code-block:: bash

pip install --editable .

For Bash:

.. code-block:: bash

eval "$(_COMPLETION_COMPLETE=source_bash completion)"

For Zsh:

.. code-block:: zsh

eval "$(_COMPLETION_COMPLETE=source_zsh completion)"

For Fish:

.. code-block:: fish

eval (env _COMPLETION_COMPLETE=source_fish completion)

Now press tab (maybe twice) after typing something to see completions.
53 changes: 53 additions & 0 deletions examples/completion/completion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import os

import click
from click.shell_completion import CompletionItem


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


@cli.command()
@click.option("--dir", type=click.Path(file_okay=False))
def ls(dir):
click.echo("\n".join(os.listdir(dir)))


def get_env_vars(ctx, param, args, incomplete):
# Returning a list of values is a shortcut to returning a list of
# CompletionItem(value).
return [k for k in os.environ if incomplete in k]


@cli.command(help="A command to print environment variables")
@click.argument("envvar", shell_complete=get_env_vars)
def show_env(envvar):
click.echo(f"Environment variable: {envvar}")
click.echo(f"Value: {os.environ[envvar]}")


@cli.group(help="A group that holds a subcommand")
def group():
pass


def list_users(ctx, args, incomplete):
# You can generate completions with help strings by returning a list
# of CompletionItem. You can match on whatever you want, including
# the help.
items = [("bob", "butcher"), ("alice", "baker"), ("jerry", "candlestick maker")]

for value, help in items:
if incomplete in value or incomplete in help:
yield CompletionItem(value, help=help)


@group.command(help="Choose a user")
@click.argument("user", type=click.STRING, autocompletion=list_users)
def select_user(user):
click.echo(f"Chosen user is {user}")


cli.add_command(group)
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from setuptools import setup

setup(
name="click-example-bashcompletion",
name="click-example-completion",
version="1.0",
py_modules=["bashcompletion"],
py_modules=["completion"],
include_package_data=True,
install_requires=["click"],
entry_points="""
[console_scripts]
bashcompletion=bashcompletion:cli
completion=completion:cli
""",
)
65 changes: 49 additions & 16 deletions src/click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1781,9 +1781,17 @@ class Parameter:
order of processing.
:param envvar: a string or list of strings that are environment variables
that should be checked.
:param autocompletion: A function that returns custom shell
:param shell_complete: A function that returns custom shell
completions. Used instead of the param's type completion if
given.
given. Takes ``ctx, param, args, incomplete`` and returns a list
of :class:`~click.shell_completion.CompletionItem` or a list of
strings.
.. versionchanged:: 8.0
``autocompletion`` is renamed to ``shell_complete`` and has new
semantics described in the docs above. The old name is
deprecated and will be removed in 8.1, until then it will be
wrapped to match the new requirements.
.. versionchanged:: 7.1
Empty environment variables are ignored rather than taking the
Expand All @@ -1795,6 +1803,7 @@ class Parameter:
parameter. The old callback format will still work, but it will
raise a warning to give you a chance to migrate the code easier.
"""

param_type_name = "parameter"

def __init__(
Expand All @@ -1809,6 +1818,7 @@ def __init__(
expose_value=True,
is_eager=False,
envvar=None,
shell_complete=None,
autocompletion=None,
):
self.name, self.opts, self.secondary_opts = self._parse_decls(
Expand All @@ -1834,7 +1844,35 @@ def __init__(
self.is_eager = is_eager
self.metavar = metavar
self.envvar = envvar
self.autocompletion = autocompletion

if autocompletion is not None:
import warnings

warnings.warn(
"'autocompletion' is renamed to 'shell_complete'. The old name is"
" deprecated and will be removed in Click 8.1. See the docs about"
" 'Parameter' for information about new behavior.",
DeprecationWarning,
stacklevel=2,
)

def shell_complete(ctx, param, args, incomplete):
from click.shell_completion import CompletionItem

out = []

for c in autocompletion(ctx, args, incomplete):
if isinstance(c, tuple):
c = CompletionItem(c[0], help=c[1])
elif isinstance(c, str):
c = CompletionItem(c)

if c.value.startswith(incomplete):
out.append(c)

return out

self._custom_shell_complete = shell_complete

def to_info_dict(self):
"""Gather information that could be useful for a tool generating
Expand Down Expand Up @@ -2025,8 +2063,8 @@ def get_error_hint(self, ctx):
return " / ".join(repr(x) for x in hint_list)

def shell_complete(self, ctx, args, incomplete):
"""Return a list of completions for the incomplete value. If an
:attr:`autocompletion` function was given, it is used.
"""Return a list of completions for the incomplete value. If a
``shell_complete`` function was given during init, it is used.
Otherwise, the :attr:`type`
:meth:`~click.types.ParamType.shell_complete` function is used.
Expand All @@ -2036,22 +2074,17 @@ def shell_complete(self, ctx, args, incomplete):
.. versionadded:: 8.0
"""
from click.shell_completion import CompletionItem
if self._custom_shell_complete is not None:
results = self._custom_shell_complete(ctx, self, args, incomplete)

if self.autocompletion is not None:
results = []
if results and isinstance(results[0], str):
from click.shell_completion import CompletionItem

for c in self.autocompletion(ctx=ctx, args=args, incomplete=incomplete):
if isinstance(c, CompletionItem):
results.append(c)
elif isinstance(c, tuple):
results.append(CompletionItem(c[0], help=c[1]))
else:
results.append(CompletionItem(c))
results = [CompletionItem(c) for c in results]

return results

return self.type.shell_complete(ctx, args, incomplete)
return self.type.shell_complete(ctx, self, args, incomplete)


class Option(Parameter):
Expand Down
12 changes: 8 additions & 4 deletions src/click/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,15 @@ def fail(self, message, param=None, ctx=None):
"""Helper method to fail with an invalid value message."""
raise BadParameter(message, ctx=ctx, param=param)

def shell_complete(self, ctx, args, incomplete):
def shell_complete(self, ctx, param, args, incomplete):
"""Return a list of
:class:`~click.shell_completion.CompletionItem` objects for the
incomplete value. Most types do not provide completions, but
some do, and this allows custom types to provide custom
completions as well.
:param ctx: Invocation context for this command.
:param param: The parameter that is requesting completion.
:param args: List of complete args before the incomplete value.
:param incomplete: Value being completed. May be empty.
Expand Down Expand Up @@ -264,10 +265,11 @@ def convert(self, value, param, ctx):
def __repr__(self):
return f"Choice({list(self.choices)})"

def shell_complete(self, ctx, args, incomplete):
def shell_complete(self, ctx, param, args, incomplete):
"""Complete choices that start with the incomplete value.
:param ctx: Invocation context for this command.
:param param: The parameter that is requesting completion.
:param args: List of complete args before the incomplete value.
:param incomplete: Value being completed. May be empty.
Expand Down Expand Up @@ -612,11 +614,12 @@ def convert(self, value, param, ctx):
ctx,
)

def shell_complete(self, ctx, args, incomplete):
def shell_complete(self, ctx, param, args, incomplete):
"""Return a special completion marker that tells the completion
system to use the shell to provide file path completions.
:param ctx: Invocation context for this command.
:param param: The parameter that is requesting completion.
:param args: List of complete args before the incomplete value.
:param incomplete: Value being completed. May be empty.
Expand Down Expand Up @@ -757,12 +760,13 @@ def convert(self, value, param, ctx):

return self.coerce_path_result(rv)

def shell_complete(self, ctx, args, incomplete):
def shell_complete(self, ctx, param, args, incomplete):
"""Return a special completion marker that tells the completion
system to use the shell to provide path completions for only
directories or any paths.
:param ctx: Invocation context for this command.
:param param: The parameter that is requesting completion.
:param args: List of complete args before the incomplete value.
:param incomplete: Value being completed. May be empty.
Expand Down
Loading

0 comments on commit 3faede8

Please sign in to comment.