File: shell-completion.md

package info (click to toggle)
python-asyncclick 8.3.0.5%2Basync-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,664 kB
  • sloc: python: 14,154; makefile: 12; sh: 10
file content (249 lines) | stat: -rw-r--r-- 9,387 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
(shell-completion)=

# Shell Completion

```{currentmodule} click.shell_completion
```

Click provides tab completion support for Bash (version 4.4 and up), Zsh, and Fish. It is possible to add support for
other shells too, and suggestions can be customized at multiple levels.

Shell completion suggests command names, option names, and values for choice, file, and path parameter types. Options
are only listed if at least a dash has been entered. Hidden commands and options are not shown.

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

## Enabling Completion

Completion is only available if a script is installed and invoked through an entry point, not through the `python`
command. See {doc}`entry-points`. Once the executable is installed, calling it with a special environment variable will
put Click in completion mode.

To enable shell completion, the user needs to register a special function with their shell. The exact script varies
depending on the shell you are using. Click will output it when called with `_{FOO_BAR}_COMPLETE` set to
`{shell}_source`. `{FOO_BAR}` is the executable name in uppercase with dashes replaced by underscores. It is
conventional but not strictly required for environment variable names to be in upper case. This convention helps
distinguish environment variables from regular shell variables and commands, making scripts and configuration files more
readable and easier to maintain. The built-in shells are `bash`, `zsh`, and `fish`.

Provide your users with the following instructions customized to your program name. This uses `foo-bar` as an example.

```{eval-rst}
.. tabs::

    .. group-tab:: Bash

        Add this to ``~/.bashrc``:

        .. code-block:: bash

            eval "$(_FOO_BAR_COMPLETE=bash_source foo-bar)"

    .. group-tab:: Zsh

        Add this to ``~/.zshrc``:

        .. code-block:: zsh

            eval "$(_FOO_BAR_COMPLETE=zsh_source foo-bar)"

    .. group-tab:: Fish

        Add this to ``~/.config/fish/completions/foo-bar.fish``:

        .. code-block:: fish

            _FOO_BAR_COMPLETE=fish_source foo-bar | source

        This is the same file used for the activation script method
        below. For Fish it's probably always easier to use that method.
```

Using `eval` means that the command is invoked and evaluated every time a shell is started, which can delay shell
responsiveness. To speed it up, write the generated script to a file, then source that. You can generate the files ahead
of time and distribute them with your program to save your users a step.

```{eval-rst}
.. tabs::

    .. group-tab:: Bash

        Save the script somewhere.

        .. code-block:: bash

            _FOO_BAR_COMPLETE=bash_source foo-bar > ~/.foo-bar-complete.bash

        Source the file in ``~/.bashrc``.

        .. code-block:: bash

            . ~/.foo-bar-complete.bash

    .. group-tab:: Zsh

        Save the script somewhere.

        .. code-block:: bash

            _FOO_BAR_COMPLETE=zsh_source foo-bar > ~/.foo-bar-complete.zsh

        Source the file in ``~/.zshrc``.

        .. code-block:: bash

            . ~/.foo-bar-complete.zsh

    .. group-tab:: Fish

        Save the script to ``~/.config/fish/completions/foo-bar.fish``:

        .. code-block:: fish

            _FOO_BAR_COMPLETE=fish_source foo-bar > ~/.config/fish/completions/foo-bar.fish
```

After modifying the shell config, you need to start a new shell in order for the changes to be loaded.

## Custom Type Completion

When creating a custom {class}`~click.ParamType`, override its {meth}`~click.ParamType.shell_complete` method to provide
shell completion for parameters with the type. The method must return a list of {class}`~CompletionItem` objects.
Besides the value, these objects hold metadata that shell support might use. The built-in implementations use `type` to
indicate special handling for paths, and `help` for shells that support showing a help string next to a suggestion.

In this example, the type will suggest environment variables that start with the incomplete value.

```python
class EnvVarType(ParamType):
    name = "envvar"

    def shell_complete(self, ctx, param, incomplete):
        return [
            CompletionItem(name)
            for name in os.environ if name.startswith(incomplete)
        ]

@click.command()
@click.option("--ev", type=EnvVarType())
def cli(ev):
    click.echo(os.environ[ev])
```

## Overriding Value Completion

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

- `ctx` - The current command context.
- `param` - The current parameter requesting completion.
- `incomplete` - The partial word that is being completed. May be an empty string if no characters have been entered
  yet.

It must return a list of {class}`CompletionItem` objects, or as a shortcut it can return a list of strings.

In this example, the command will suggest environment variables that start with the incomplete value.

```python
def complete_env_vars(ctx, param, incomplete):
    return [k for k in os.environ if k.startswith(incomplete)]

@click.command()
@click.argument("name", shell_complete=complete_env_vars)
def cli(name):
    click.echo(f"Name: {name}")
    click.echo(f"Value: {os.environ[name]}")
```

## Adding Support for a Shell

Support can be added for shells that do not come built in. Be sure to check PyPI to see if there's already a package
that adds support for your shell. This topic is very technical, you'll want to look at Click's source to study the
built-in implementations.

Shell support is provided by subclasses of {class}`ShellComplete` registered with {func}`add_completion_class`. When
Click is invoked in completion mode, it calls {meth}`~ShellComplete.source` to output the completion script, or
{meth}`~ShellComplete.complete` to output completions. The base class provides default implementations that require
implementing some smaller parts.

First, you'll need to figure out how your shell's completion system works and write a script to integrate it with Click.
It must invoke your program with the environment variable `_{FOO_BAR}_COMPLETE` set to `{shell}_complete` and pass the
complete args and incomplete value. How it passes those values, and the format of the completion response from Click is
up to you.

In your subclass, set {attr}`ShellComplete.source_template` to the completion script. The default implementation will
perform `%` formatting with the following variables:

- `complete_func` - A safe name for the completion function defined in the script.
- `complete_var` - The environment variable name for passing the `{shell}_complete` instruction.
- `foo_bar` - The name of the executable being completed.

The example code is for a made up shell "My Shell" or "mysh" for short.

```python
from click.shell_completion import add_completion_class
from click.shell_completion import ShellComplete

_mysh_source = """\
%(complete_func)s {
    response=$(%(complete_var)s=mysh_complete %(foo_bar)s)
    # parse response and set completions somehow
}
call-on-complete %(foo_bar)s %(complete_func)s
"""

@add_completion_class
class MyshComplete(ShellComplete):
    name = "mysh"
    source_template = _mysh_source
```

Next, implement {meth}`~ShellComplete.get_completion_args`. This must get, parse, and return the complete args and
incomplete value from the completion script. For example, for the Bash implementation the `COMP_WORDS` env var contains
the command line args as a string, and the `COMP_CWORD` env var contains the index of the incomplete arg. The method
must return a `(args, incomplete)` tuple.

```python
import os
from click.parser import split_arg_string

class MyshComplete(ShellComplete):
    ...

    def get_completion_args(self):
        args = split_arg_string(os.environ["COMP_WORDS"])

        if os.environ["COMP_PARTIAL"] == "1":
            incomplete = args.pop()
            return args, incomplete

        return args, ""
```

Finally, implement {meth}`~ShellComplete.format_completion`. This is called to format each {class}`CompletionItem` into a string. For example, the Bash implementation returns `f"{item.type},{item.value}` (it doesn't support help strings), and the Zsh implementation returns each part separated by a newline, replacing empty help with a `_` placeholder. This format is entirely up to what you parse with your completion script.

The `type` value is usually `plain`, but it can be another value that the completion script can switch on. For example,
`file` or `dir` can tell the shell to handle path completion, since the shell is better at that than Click.

```python
class MyshComplete(ShellComplete):
    ...

    def format_completion(self, item):
        return f"{item.type}\t{item.value}"
```

With those three things implemented, the new shell support is ready. In case those weren't sufficient, there are more
parts that can be overridden, but that probably isn't necessary.

The activation instructions will again depend on how your shell works. Use the following to generate the completion
script, then load it into the shell somehow.

```console
_FOO_BAR_COMPLETE=mysh_source foo-bar
```