]> crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/click/shell_completion.py
ActualizaciĆ³n de Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / click / shell_completion.py
1 import os
2 import re
3 import typing as t
4 from gettext import gettext as _
5
6 from .core import Argument
7 from .core import BaseCommand
8 from .core import Context
9 from .core import MultiCommand
10 from .core import Option
11 from .core import Parameter
12 from .core import ParameterSource
13 from .parser import split_arg_string
14 from .utils import echo
15
16
17 def shell_complete(
18 cli: BaseCommand,
19 ctx_args: t.MutableMapping[str, t.Any],
20 prog_name: str,
21 complete_var: str,
22 instruction: str,
23 ) -> int:
24 """Perform shell completion for the given CLI program.
25
26 :param cli: Command being called.
27 :param ctx_args: Extra arguments to pass to
28 ``cli.make_context``.
29 :param prog_name: Name of the executable in the shell.
30 :param complete_var: Name of the environment variable that holds
31 the completion instruction.
32 :param instruction: Value of ``complete_var`` with the completion
33 instruction and shell, in the form ``instruction_shell``.
34 :return: Status code to exit with.
35 """
36 shell, _, instruction = instruction.partition("_")
37 comp_cls = get_completion_class(shell)
38
39 if comp_cls is None:
40 return 1
41
42 comp = comp_cls(cli, ctx_args, prog_name, complete_var)
43
44 if instruction == "source":
45 echo(comp.source())
46 return 0
47
48 if instruction == "complete":
49 echo(comp.complete())
50 return 0
51
52 return 1
53
54
55 class CompletionItem:
56 """Represents a completion value and metadata about the value. The
57 default metadata is ``type`` to indicate special shell handling,
58 and ``help`` if a shell supports showing a help string next to the
59 value.
60
61 Arbitrary parameters can be passed when creating the object, and
62 accessed using ``item.attr``. If an attribute wasn't passed,
63 accessing it returns ``None``.
64
65 :param value: The completion suggestion.
66 :param type: Tells the shell script to provide special completion
67 support for the type. Click uses ``"dir"`` and ``"file"``.
68 :param help: String shown next to the value if supported.
69 :param kwargs: Arbitrary metadata. The built-in implementations
70 don't use this, but custom type completions paired with custom
71 shell support could use it.
72 """
73
74 __slots__ = ("value", "type", "help", "_info")
75
76 def __init__(
77 self,
78 value: t.Any,
79 type: str = "plain",
80 help: t.Optional[str] = None,
81 **kwargs: t.Any,
82 ) -> None:
83 self.value: t.Any = value
84 self.type: str = type
85 self.help: t.Optional[str] = help
86 self._info = kwargs
87
88 def __getattr__(self, name: str) -> t.Any:
89 return self._info.get(name)
90
91
92 # Only Bash >= 4.4 has the nosort option.
93 _SOURCE_BASH = """\
94 %(complete_func)s() {
95 local IFS=$'\\n'
96 local response
97
98 response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \
99 %(complete_var)s=bash_complete $1)
100
101 for completion in $response; do
102 IFS=',' read type value <<< "$completion"
103
104 if [[ $type == 'dir' ]]; then
105 COMPREPLY=()
106 compopt -o dirnames
107 elif [[ $type == 'file' ]]; then
108 COMPREPLY=()
109 compopt -o default
110 elif [[ $type == 'plain' ]]; then
111 COMPREPLY+=($value)
112 fi
113 done
114
115 return 0
116 }
117
118 %(complete_func)s_setup() {
119 complete -o nosort -F %(complete_func)s %(prog_name)s
120 }
121
122 %(complete_func)s_setup;
123 """
124
125 _SOURCE_ZSH = """\
126 #compdef %(prog_name)s
127
128 %(complete_func)s() {
129 local -a completions
130 local -a completions_with_descriptions
131 local -a response
132 (( ! $+commands[%(prog_name)s] )) && return 1
133
134 response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \
135 %(complete_var)s=zsh_complete %(prog_name)s)}")
136
137 for type key descr in ${response}; do
138 if [[ "$type" == "plain" ]]; then
139 if [[ "$descr" == "_" ]]; then
140 completions+=("$key")
141 else
142 completions_with_descriptions+=("$key":"$descr")
143 fi
144 elif [[ "$type" == "dir" ]]; then
145 _path_files -/
146 elif [[ "$type" == "file" ]]; then
147 _path_files -f
148 fi
149 done
150
151 if [ -n "$completions_with_descriptions" ]; then
152 _describe -V unsorted completions_with_descriptions -U
153 fi
154
155 if [ -n "$completions" ]; then
156 compadd -U -V unsorted -a completions
157 fi
158 }
159
160 if [[ $zsh_eval_context[-1] == loadautofunc ]]; then
161 # autoload from fpath, call function directly
162 %(complete_func)s "$@"
163 else
164 # eval/source/. command, register function for later
165 compdef %(complete_func)s %(prog_name)s
166 fi
167 """
168
169 _SOURCE_FISH = """\
170 function %(complete_func)s;
171 set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \
172 COMP_CWORD=(commandline -t) %(prog_name)s);
173
174 for completion in $response;
175 set -l metadata (string split "," $completion);
176
177 if test $metadata[1] = "dir";
178 __fish_complete_directories $metadata[2];
179 else if test $metadata[1] = "file";
180 __fish_complete_path $metadata[2];
181 else if test $metadata[1] = "plain";
182 echo $metadata[2];
183 end;
184 end;
185 end;
186
187 complete --no-files --command %(prog_name)s --arguments \
188 "(%(complete_func)s)";
189 """
190
191
192 class ShellComplete:
193 """Base class for providing shell completion support. A subclass for
194 a given shell will override attributes and methods to implement the
195 completion instructions (``source`` and ``complete``).
196
197 :param cli: Command being called.
198 :param prog_name: Name of the executable in the shell.
199 :param complete_var: Name of the environment variable that holds
200 the completion instruction.
201
202 .. versionadded:: 8.0
203 """
204
205 name: t.ClassVar[str]
206 """Name to register the shell as with :func:`add_completion_class`.
207 This is used in completion instructions (``{name}_source`` and
208 ``{name}_complete``).
209 """
210
211 source_template: t.ClassVar[str]
212 """Completion script template formatted by :meth:`source`. This must
213 be provided by subclasses.
214 """
215
216 def __init__(
217 self,
218 cli: BaseCommand,
219 ctx_args: t.MutableMapping[str, t.Any],
220 prog_name: str,
221 complete_var: str,
222 ) -> None:
223 self.cli = cli
224 self.ctx_args = ctx_args
225 self.prog_name = prog_name
226 self.complete_var = complete_var
227
228 @property
229 def func_name(self) -> str:
230 """The name of the shell function defined by the completion
231 script.
232 """
233 safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII)
234 return f"_{safe_name}_completion"
235
236 def source_vars(self) -> t.Dict[str, t.Any]:
237 """Vars for formatting :attr:`source_template`.
238
239 By default this provides ``complete_func``, ``complete_var``,
240 and ``prog_name``.
241 """
242 return {
243 "complete_func": self.func_name,
244 "complete_var": self.complete_var,
245 "prog_name": self.prog_name,
246 }
247
248 def source(self) -> str:
249 """Produce the shell script that defines the completion
250 function. By default this ``%``-style formats
251 :attr:`source_template` with the dict returned by
252 :meth:`source_vars`.
253 """
254 return self.source_template % self.source_vars()
255
256 def get_completion_args(self) -> t.Tuple[t.List[str], str]:
257 """Use the env vars defined by the shell script to return a
258 tuple of ``args, incomplete``. This must be implemented by
259 subclasses.
260 """
261 raise NotImplementedError
262
263 def get_completions(
264 self, args: t.List[str], incomplete: str
265 ) -> t.List[CompletionItem]:
266 """Determine the context and last complete command or parameter
267 from the complete args. Call that object's ``shell_complete``
268 method to get the completions for the incomplete value.
269
270 :param args: List of complete args before the incomplete value.
271 :param incomplete: Value being completed. May be empty.
272 """
273 ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args)
274 obj, incomplete = _resolve_incomplete(ctx, args, incomplete)
275 return obj.shell_complete(ctx, incomplete)
276
277 def format_completion(self, item: CompletionItem) -> str:
278 """Format a completion item into the form recognized by the
279 shell script. This must be implemented by subclasses.
280
281 :param item: Completion item to format.
282 """
283 raise NotImplementedError
284
285 def complete(self) -> str:
286 """Produce the completion data to send back to the shell.
287
288 By default this calls :meth:`get_completion_args`, gets the
289 completions, then calls :meth:`format_completion` for each
290 completion.
291 """
292 args, incomplete = self.get_completion_args()
293 completions = self.get_completions(args, incomplete)
294 out = [self.format_completion(item) for item in completions]
295 return "\n".join(out)
296
297
298 class BashComplete(ShellComplete):
299 """Shell completion for Bash."""
300
301 name = "bash"
302 source_template = _SOURCE_BASH
303
304 @staticmethod
305 def _check_version() -> None:
306 import subprocess
307
308 output = subprocess.run(
309 ["bash", "-c", 'echo "${BASH_VERSION}"'], stdout=subprocess.PIPE
310 )
311 match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode())
312
313 if match is not None:
314 major, minor = match.groups()
315
316 if major < "4" or major == "4" and minor < "4":
317 echo(
318 _(
319 "Shell completion is not supported for Bash"
320 " versions older than 4.4."
321 ),
322 err=True,
323 )
324 else:
325 echo(
326 _("Couldn't detect Bash version, shell completion is not supported."),
327 err=True,
328 )
329
330 def source(self) -> str:
331 self._check_version()
332 return super().source()
333
334 def get_completion_args(self) -> t.Tuple[t.List[str], str]:
335 cwords = split_arg_string(os.environ["COMP_WORDS"])
336 cword = int(os.environ["COMP_CWORD"])
337 args = cwords[1:cword]
338
339 try:
340 incomplete = cwords[cword]
341 except IndexError:
342 incomplete = ""
343
344 return args, incomplete
345
346 def format_completion(self, item: CompletionItem) -> str:
347 return f"{item.type},{item.value}"
348
349
350 class ZshComplete(ShellComplete):
351 """Shell completion for Zsh."""
352
353 name = "zsh"
354 source_template = _SOURCE_ZSH
355
356 def get_completion_args(self) -> t.Tuple[t.List[str], str]:
357 cwords = split_arg_string(os.environ["COMP_WORDS"])
358 cword = int(os.environ["COMP_CWORD"])
359 args = cwords[1:cword]
360
361 try:
362 incomplete = cwords[cword]
363 except IndexError:
364 incomplete = ""
365
366 return args, incomplete
367
368 def format_completion(self, item: CompletionItem) -> str:
369 return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}"
370
371
372 class FishComplete(ShellComplete):
373 """Shell completion for Fish."""
374
375 name = "fish"
376 source_template = _SOURCE_FISH
377
378 def get_completion_args(self) -> t.Tuple[t.List[str], str]:
379 cwords = split_arg_string(os.environ["COMP_WORDS"])
380 incomplete = os.environ["COMP_CWORD"]
381 args = cwords[1:]
382
383 # Fish stores the partial word in both COMP_WORDS and
384 # COMP_CWORD, remove it from complete args.
385 if incomplete and args and args[-1] == incomplete:
386 args.pop()
387
388 return args, incomplete
389
390 def format_completion(self, item: CompletionItem) -> str:
391 if item.help:
392 return f"{item.type},{item.value}\t{item.help}"
393
394 return f"{item.type},{item.value}"
395
396
397 ShellCompleteType = t.TypeVar("ShellCompleteType", bound=t.Type[ShellComplete])
398
399
400 _available_shells: t.Dict[str, t.Type[ShellComplete]] = {
401 "bash": BashComplete,
402 "fish": FishComplete,
403 "zsh": ZshComplete,
404 }
405
406
407 def add_completion_class(
408 cls: ShellCompleteType, name: t.Optional[str] = None
409 ) -> ShellCompleteType:
410 """Register a :class:`ShellComplete` subclass under the given name.
411 The name will be provided by the completion instruction environment
412 variable during completion.
413
414 :param cls: The completion class that will handle completion for the
415 shell.
416 :param name: Name to register the class under. Defaults to the
417 class's ``name`` attribute.
418 """
419 if name is None:
420 name = cls.name
421
422 _available_shells[name] = cls
423
424 return cls
425
426
427 def get_completion_class(shell: str) -> t.Optional[t.Type[ShellComplete]]:
428 """Look up a registered :class:`ShellComplete` subclass by the name
429 provided by the completion instruction environment variable. If the
430 name isn't registered, returns ``None``.
431
432 :param shell: Name the class is registered under.
433 """
434 return _available_shells.get(shell)
435
436
437 def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool:
438 """Determine if the given parameter is an argument that can still
439 accept values.
440
441 :param ctx: Invocation context for the command represented by the
442 parsed complete args.
443 :param param: Argument object being checked.
444 """
445 if not isinstance(param, Argument):
446 return False
447
448 assert param.name is not None
449 # Will be None if expose_value is False.
450 value = ctx.params.get(param.name)
451 return (
452 param.nargs == -1
453 or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE
454 or (
455 param.nargs > 1
456 and isinstance(value, (tuple, list))
457 and len(value) < param.nargs
458 )
459 )
460
461
462 def _start_of_option(ctx: Context, value: str) -> bool:
463 """Check if the value looks like the start of an option."""
464 if not value:
465 return False
466
467 c = value[0]
468 return c in ctx._opt_prefixes
469
470
471 def _is_incomplete_option(ctx: Context, args: t.List[str], param: Parameter) -> bool:
472 """Determine if the given parameter is an option that needs a value.
473
474 :param args: List of complete args before the incomplete value.
475 :param param: Option object being checked.
476 """
477 if not isinstance(param, Option):
478 return False
479
480 if param.is_flag or param.count:
481 return False
482
483 last_option = None
484
485 for index, arg in enumerate(reversed(args)):
486 if index + 1 > param.nargs:
487 break
488
489 if _start_of_option(ctx, arg):
490 last_option = arg
491
492 return last_option is not None and last_option in param.opts
493
494
495 def _resolve_context(
496 cli: BaseCommand,
497 ctx_args: t.MutableMapping[str, t.Any],
498 prog_name: str,
499 args: t.List[str],
500 ) -> Context:
501 """Produce the context hierarchy starting with the command and
502 traversing the complete arguments. This only follows the commands,
503 it doesn't trigger input prompts or callbacks.
504
505 :param cli: Command being called.
506 :param prog_name: Name of the executable in the shell.
507 :param args: List of complete args before the incomplete value.
508 """
509 ctx_args["resilient_parsing"] = True
510 ctx = cli.make_context(prog_name, args.copy(), **ctx_args)
511 args = ctx.protected_args + ctx.args
512
513 while args:
514 command = ctx.command
515
516 if isinstance(command, MultiCommand):
517 if not command.chain:
518 name, cmd, args = command.resolve_command(ctx, args)
519
520 if cmd is None:
521 return ctx
522
523 ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True)
524 args = ctx.protected_args + ctx.args
525 else:
526 sub_ctx = ctx
527
528 while args:
529 name, cmd, args = command.resolve_command(ctx, args)
530
531 if cmd is None:
532 return ctx
533
534 sub_ctx = cmd.make_context(
535 name,
536 args,
537 parent=ctx,
538 allow_extra_args=True,
539 allow_interspersed_args=False,
540 resilient_parsing=True,
541 )
542 args = sub_ctx.args
543
544 ctx = sub_ctx
545 args = [*sub_ctx.protected_args, *sub_ctx.args]
546 else:
547 break
548
549 return ctx
550
551
552 def _resolve_incomplete(
553 ctx: Context, args: t.List[str], incomplete: str
554 ) -> t.Tuple[t.Union[BaseCommand, Parameter], str]:
555 """Find the Click object that will handle the completion of the
556 incomplete value. Return the object and the incomplete value.
557
558 :param ctx: Invocation context for the command represented by
559 the parsed complete args.
560 :param args: List of complete args before the incomplete value.
561 :param incomplete: Value being completed. May be empty.
562 """
563 # Different shells treat an "=" between a long option name and
564 # value differently. Might keep the value joined, return the "="
565 # as a separate item, or return the split name and value. Always
566 # split and discard the "=" to make completion easier.
567 if incomplete == "=":
568 incomplete = ""
569 elif "=" in incomplete and _start_of_option(ctx, incomplete):
570 name, _, incomplete = incomplete.partition("=")
571 args.append(name)
572
573 # The "--" marker tells Click to stop treating values as options
574 # even if they start with the option character. If it hasn't been
575 # given and the incomplete arg looks like an option, the current
576 # command will provide option name completions.
577 if "--" not in args and _start_of_option(ctx, incomplete):
578 return ctx.command, incomplete
579
580 params = ctx.command.get_params(ctx)
581
582 # If the last complete arg is an option name with an incomplete
583 # value, the option will provide value completions.
584 for param in params:
585 if _is_incomplete_option(ctx, args, param):
586 return param, incomplete
587
588 # It's not an option name or value. The first argument without a
589 # parsed value will provide value completions.
590 for param in params:
591 if _is_incomplete_argument(ctx, param):
592 return param, incomplete
593
594 # There were no unparsed arguments, the command may be a group that
595 # will provide command name completions.
596 return ctx.command, incomplete