Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

645 linhas
19 KiB

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