Skip to content

Shell completion

Generate a completion script, or compute the candidates directly. See the Shell completion guide.

generate_completion

generate_completion(
    doc: str, prog: str, shell: str = "bash"
) -> str

Return a context-aware shell completion script for the CLI described by doc.

The script is a thin callback carrying no grammar of its own. At each Tab it re-invokes the program with a completion request in the environment, and that program's docopt call resolves the tokens legal at the cursor from the usage grammar. Suggestions therefore narrow to the matched subcommand's options and arguments, rather than a flat global list.

A docopt program answers those requests by default. A program that does not want this passes docopt(..., complete=False) to opt out.

Parameters:

Name Type Description Default
doc str

The usage message (the same string given to docopt).

required
prog str

The command name the script completes for. Must be a plain command name (letters, digits, ., _, -), and must be on PATH under that name.

required
shell str

One of "bash", "zsh", "fish", "powershell" or "nushell".

'bash'

Returns:

Type Description
str

The completion script as text. It depends only on prog and shell, never on the usage,

str

since the grammar stays in the program.

Raises:

Type Description
ValueError

shell is not supported, or prog is not a plain command name.

DocoptLanguageError

The usage message is malformed. It fails here rather than at Tab time.

Source code in src/docopt2/_completion.py
def generate_completion(doc: str, prog: str, shell: str = "bash") -> str:
    """Return a context-aware shell completion script for the CLI described by ``doc``.

    The script is a thin callback carrying no grammar of its own. At each Tab it re-invokes the program with
    a completion request in the environment, and that program's [`docopt`][docopt2.docopt] call resolves the
    tokens legal at the cursor from the usage grammar. Suggestions therefore narrow to the matched subcommand's options
    and arguments, rather than a flat global list.

    A docopt program answers those requests by default. A program that does not want this passes
    ``docopt(..., complete=False)`` to opt out.

    Args:
        doc: The usage message (the same string given to [`docopt`][docopt2.docopt]).
        prog: The command name the script completes for. Must be a plain command name
            (letters, digits, ``.``, ``_``, ``-``), and must be on ``PATH`` under that name.
        shell: One of ``"bash"``, ``"zsh"``, ``"fish"``, ``"powershell"`` or ``"nushell"``.

    Returns:
        The completion script as text. It depends only on ``prog`` and ``shell``, never on the usage,
        since the grammar stays in the program.

    Raises:
        ValueError: ``shell`` is not supported, or ``prog`` is not a plain command name.
        DocoptLanguageError: The usage message is malformed. It fails here rather than at Tab time.
    """
    if shell not in _RENDERERS:
        supported = ", ".join(sorted(_RENDERERS))
        raise ValueError(f"unsupported shell: {shell!r}; expected one of {supported}")
    # The script interpolates `prog` into shell/PowerShell source that is sourced or eval'd, so a
    # name with metacharacters (`;`, `$()`, spaces, quotes) would inject or corrupt it. Require a
    # plain command name.
    if not re.fullmatch(r"[A-Za-z0-9._-]+", prog):
        raise ValueError(f"prog {prog!r} must be a plain command name (letters, digits, . _ -)")
    # Validate the docstring up front so a malformed usage fails loudly here, not silently at Tab.
    parse_pattern(formal_usage(single_usage_section(doc)), parse_defaults(doc))  # as a Tab press reads it
    return _RENDERERS[shell](prog, _function_name(prog))

complete

complete(
    doc: str,
    words: Sequence[str],
    schema: type[Any] | None = None,
) -> list[str]

Return the completion candidates for the last (cursor) word of words.

Earlier tokens are consumed against the usage pattern. The command literals and option names that could legally come next are returned, filtered to the partial word. A malformed doc yields no candidates, never raises.

A value is a candidate only with schema, and only for a field that takes a closed set, a Literal or an Enum. Such a field completes as the next positional, as the argument the last option is waiting for, and as --option=value beside the option's own name. Without it, a prefix that ends on an option waiting for its argument yields no candidates.

The next positional is the one docopt would give the next word to: with [<name>] [<mode>] a word typed first is a <name>, so no <mode> is offered before it.

A schema other than a pydantic model reads the typed words too: after a value that its field does not take there are no candidates, since no argv that starts that way can be bound.

Source code in src/docopt2/_completion.py
def complete(doc: str, words: Sequence[str], schema: type[Any] | None = None) -> list[str]:
    """Return the completion candidates for the last (cursor) word of ``words``.

    Earlier tokens are consumed against the usage pattern. The command literals and option names
    that could legally come next are returned, filtered to the partial word. A malformed doc yields
    no candidates, never raises.

    A value is a candidate only with ``schema``, and only for a field that takes a closed set, a
    ``Literal`` or an ``Enum``. Such a field completes as the next positional, as the argument the
    last option is waiting for, and as ``--option=value`` beside the option's own name. Without it,
    a prefix that ends on an option waiting for its argument yields no candidates.

    The next positional is the one [`docopt`][docopt2.docopt] would give the next word to: with
    ``[<name>] [<mode>]`` a word typed first is a ``<name>``, so no ``<mode>`` is offered before it.

    A schema other than a pydantic model reads the typed words too: after a value that its field does
    not take there are no candidates, since no argv that starts that way can be bound.
    """
    return _complete(doc, words, [] if schema is None else [schema])[0]