shell_completion.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  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. ) -> t.Literal[0, 1]:
  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. # Write bytes, otherwise Windows text stdout translates LF to CRLF and breaks.
  39. if instruction == "source":
  40. echo(comp.source().encode(), nl=False)
  41. return 0
  42. if instruction == "complete":
  43. echo(comp.complete().encode())
  44. return 0
  45. return 1
  46. if t.TYPE_CHECKING:
  47. from typing_extensions import TypeVar
  48. # `Any` is used as default for backwards compatibility (instead of e.g. `str`)
  49. _ValueT_co = TypeVar("_ValueT_co", covariant=True, default=t.Any)
  50. else:
  51. _ValueT_co = t.TypeVar("_ValueT_co", covariant=True)
  52. class CompletionItem(t.Generic[_ValueT_co]):
  53. """Represents a completion value and metadata about the value. The
  54. default metadata is ``type`` to indicate special shell handling,
  55. and ``help`` if a shell supports showing a help string next to the
  56. value.
  57. Arbitrary parameters can be passed when creating the object, and
  58. accessed using ``item.attr``. If an attribute wasn't passed,
  59. accessing it returns ``None``.
  60. :param value: The completion suggestion.
  61. :param type: Tells the shell script to provide special completion
  62. support for the type. Click uses ``"dir"`` and ``"file"``.
  63. :param help: String shown next to the value if supported.
  64. :param kwargs: Arbitrary metadata. The built-in implementations
  65. don't use this, but custom type completions paired with custom
  66. shell support could use it.
  67. """
  68. __slots__ = ("value", "type", "help", "_info")
  69. def __init__(
  70. self,
  71. value: _ValueT_co,
  72. type: str = "plain",
  73. help: str | None = None,
  74. **kwargs: t.Any,
  75. ) -> None:
  76. self.value: _ValueT_co = value
  77. self.type: str = type
  78. self.help: str | None = help
  79. self._info = kwargs
  80. def __getattr__(self, name: str) -> t.Any:
  81. return self._info.get(name)
  82. # Only Bash >= 4.4 has the nosort option.
  83. _SOURCE_BASH = """\
  84. %(complete_func)s() {
  85. local IFS=$'\\n'
  86. local response
  87. response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \
  88. %(complete_var)s=bash_complete $1)
  89. for completion in $response; do
  90. IFS=',' read type value <<< "$completion"
  91. if [[ $type == 'dir' ]]; then
  92. COMPREPLY=()
  93. compopt -o dirnames
  94. elif [[ $type == 'file' ]]; then
  95. COMPREPLY=()
  96. compopt -o default
  97. elif [[ $type == 'plain' ]]; then
  98. COMPREPLY+=($value)
  99. fi
  100. done
  101. return 0
  102. }
  103. %(complete_func)s_setup() {
  104. complete -o nosort -F %(complete_func)s %(prog_name)s
  105. }
  106. %(complete_func)s_setup;
  107. """
  108. # See ZshComplete.format_completion below, and issue #2703, before
  109. # changing this script.
  110. #
  111. # (TL;DR: _describe is picky about the format, but this Zsh script snippet
  112. # is already widely deployed. So freeze this script, and use clever-ish
  113. # handling of colons in ZshComplet.format_completion.)
  114. _SOURCE_ZSH = """\
  115. #compdef %(prog_name)s
  116. %(complete_func)s() {
  117. local -a completions
  118. local -a completions_with_descriptions
  119. local -a response
  120. (( ! $+commands[%(prog_name)s] )) && return 1
  121. response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \
  122. %(complete_var)s=zsh_complete %(prog_name)s)}")
  123. for type key descr in ${response}; do
  124. if [[ "$type" == "plain" ]]; then
  125. if [[ "$descr" == "_" ]]; then
  126. completions+=("$key")
  127. else
  128. completions_with_descriptions+=("$key":"$descr")
  129. fi
  130. elif [[ "$type" == "dir" ]]; then
  131. _path_files -/
  132. elif [[ "$type" == "file" ]]; then
  133. _path_files -f
  134. fi
  135. done
  136. if [ -n "$completions_with_descriptions" ]; then
  137. _describe -V unsorted completions_with_descriptions -U
  138. fi
  139. if [ -n "$completions" ]; then
  140. compadd -U -V unsorted -a completions
  141. fi
  142. }
  143. if [[ $zsh_eval_context[-1] == loadautofunc ]]; then
  144. # autoload from fpath, call function directly
  145. %(complete_func)s "$@"
  146. else
  147. # eval/source/. command, register function for later
  148. compdef %(complete_func)s %(prog_name)s
  149. fi
  150. """
  151. _SOURCE_FISH = """\
  152. function %(complete_func)s;
  153. set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \
  154. COMP_CWORD=(commandline -t) %(prog_name)s);
  155. for completion in $response;
  156. set -l metadata (string split "," $completion);
  157. if test $metadata[1] = "dir";
  158. __fish_complete_directories $metadata[2];
  159. else if test $metadata[1] = "file";
  160. __fish_complete_path $metadata[2];
  161. else if test $metadata[1] = "plain";
  162. echo $metadata[2];
  163. end;
  164. end;
  165. end;
  166. complete --no-files --command %(prog_name)s --arguments \
  167. "(%(complete_func)s)";
  168. """
  169. # Compatible with Windows PowerShell 5.1+ and PowerShell (pwsh) 7+.
  170. # Uses Register-ArgumentCompleter -Native, which receives the command AST
  171. # as parsed by PowerShell. The command text is forwarded verbatim through
  172. # COMP_WORDS so the Python side can reuse the same shlex-based splitting
  173. # used by the bash/zsh completers.
  174. _SOURCE_POWERSHELL = """\
  175. Register-ArgumentCompleter -Native -CommandName %(prog_name)s -ScriptBlock {
  176. param($wordToComplete, $commandAst, $cursorPosition)
  177. $prev_complete = $env:%(complete_var)s
  178. $prev_words = $env:COMP_WORDS
  179. $prev_cword = $env:COMP_CWORD
  180. $env:%(complete_var)s = 'powershell_complete'
  181. $env:COMP_WORDS = $commandAst.ToString()
  182. if ($wordToComplete) {
  183. $env:COMP_CWORD = $commandAst.CommandElements.Count - 1
  184. } else {
  185. $env:COMP_CWORD = $commandAst.CommandElements.Count
  186. }
  187. try {
  188. $response = & %(prog_name)s 2>$null
  189. } finally {
  190. $env:%(complete_var)s = $prev_complete
  191. $env:COMP_WORDS = $prev_words
  192. $env:COMP_CWORD = $prev_cword
  193. }
  194. if (-not $response) { return }
  195. $prefix = "$wordToComplete*"
  196. $lines = $response -split "`n"
  197. for ($i = 0; $i + 2 -lt $lines.Count; $i += 3) {
  198. $type = $lines[$i]
  199. $value = $lines[$i + 1]
  200. $descr = $lines[$i + 2]
  201. if (-not $type) { continue }
  202. if ($type -eq 'plain') {
  203. $tip = if ($descr -and $descr -ne '_') { $descr } else { $value }
  204. [System.Management.Automation.CompletionResult]::new(
  205. $value, $value, 'ParameterValue', $tip)
  206. } elseif ($type -eq 'dir') {
  207. Get-ChildItem -Directory -Path $prefix -ErrorAction SilentlyContinue |
  208. ForEach-Object {
  209. [System.Management.Automation.CompletionResult]::new(
  210. $_.FullName, $_.Name, 'ProviderContainer', $_.FullName)
  211. }
  212. } elseif ($type -eq 'file') {
  213. Get-ChildItem -Path $prefix -ErrorAction SilentlyContinue |
  214. ForEach-Object {
  215. $kind = 'ProviderItem'
  216. if ($_.PSIsContainer) { $kind = 'ProviderContainer' }
  217. [System.Management.Automation.CompletionResult]::new(
  218. $_.FullName, $_.Name, $kind, $_.FullName)
  219. }
  220. }
  221. }
  222. }
  223. """
  224. class _SourceVarsDict(t.TypedDict):
  225. complete_func: str
  226. complete_var: str
  227. prog_name: str
  228. class ShellComplete:
  229. """Base class for providing shell completion support. A subclass for
  230. a given shell will override attributes and methods to implement the
  231. completion instructions (``source`` and ``complete``).
  232. :param cli: Command being called.
  233. :param prog_name: Name of the executable in the shell.
  234. :param complete_var: Name of the environment variable that holds
  235. the completion instruction.
  236. .. versionadded:: 8.0
  237. """
  238. name: t.ClassVar[str]
  239. """Name to register the shell as with :func:`add_completion_class`.
  240. This is used in completion instructions (``{name}_source`` and
  241. ``{name}_complete``).
  242. """
  243. source_template: t.ClassVar[str]
  244. """Completion script template formatted by :meth:`source`. This must
  245. be provided by subclasses.
  246. """
  247. cli: Command
  248. ctx_args: cabc.MutableMapping[str, t.Any]
  249. prog_name: str
  250. complete_var: str
  251. def __init__(
  252. self,
  253. cli: Command,
  254. ctx_args: cabc.MutableMapping[str, t.Any],
  255. prog_name: str,
  256. complete_var: str,
  257. ) -> None:
  258. self.cli = cli
  259. self.ctx_args = ctx_args
  260. self.prog_name = prog_name
  261. self.complete_var = complete_var
  262. @property
  263. def func_name(self) -> str:
  264. """The name of the shell function defined by the completion
  265. script.
  266. """
  267. safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII)
  268. return f"_{safe_name}_completion"
  269. def source_vars(self) -> _SourceVarsDict:
  270. """Vars for formatting :attr:`source_template`.
  271. By default this provides ``complete_func``, ``complete_var``,
  272. and ``prog_name``.
  273. """
  274. return {
  275. "complete_func": self.func_name,
  276. "complete_var": self.complete_var,
  277. "prog_name": self.prog_name,
  278. }
  279. def source(self) -> str:
  280. """Produce the shell script that defines the completion
  281. function. By default this ``%``-style formats
  282. :attr:`source_template` with the dict returned by
  283. :meth:`source_vars`.
  284. """
  285. return self.source_template % self.source_vars()
  286. def get_completion_args(self) -> tuple[list[str], str]:
  287. """Use the env vars defined by the shell script to return a
  288. tuple of ``args, incomplete``. This must be implemented by
  289. subclasses.
  290. """
  291. raise NotImplementedError
  292. def get_completions(
  293. self, args: list[str], incomplete: str
  294. ) -> list[CompletionItem[str]]:
  295. """Determine the context and last complete command or parameter
  296. from the complete args. Call that object's ``shell_complete``
  297. method to get the completions for the incomplete value.
  298. :param args: List of complete args before the incomplete value.
  299. :param incomplete: Value being completed. May be empty.
  300. """
  301. ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args)
  302. obj, incomplete = _resolve_incomplete(ctx, args, incomplete)
  303. return obj.shell_complete(ctx, incomplete)
  304. def format_completion(self, item: CompletionItem[str]) -> str:
  305. """Format a completion item into the form recognized by the
  306. shell script. This must be implemented by subclasses.
  307. :param item: Completion item to format.
  308. """
  309. raise NotImplementedError
  310. def complete(self) -> str:
  311. """Produce the completion data to send back to the shell.
  312. By default this calls :meth:`get_completion_args`, gets the
  313. completions, then calls :meth:`format_completion` for each
  314. completion.
  315. """
  316. args, incomplete = self.get_completion_args()
  317. completions = self.get_completions(args, incomplete)
  318. out = [self.format_completion(item) for item in completions]
  319. return "\n".join(out)
  320. class BashComplete(ShellComplete):
  321. """Shell completion for Bash."""
  322. name: t.ClassVar[str] = "bash"
  323. source_template: t.ClassVar[str] = _SOURCE_BASH
  324. @staticmethod
  325. def _check_version() -> None:
  326. import shutil
  327. import subprocess
  328. bash_exe = shutil.which("bash")
  329. if bash_exe is None:
  330. match = None
  331. else:
  332. output = subprocess.run(
  333. [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'],
  334. stdout=subprocess.PIPE,
  335. )
  336. match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode())
  337. if match is not None:
  338. major, minor = match.groups()
  339. if major < "4" or major == "4" and minor < "4":
  340. echo(
  341. _(
  342. "Shell completion is not supported for Bash"
  343. " versions older than 4.4."
  344. ),
  345. err=True,
  346. )
  347. else:
  348. echo(
  349. _("Couldn't detect Bash version, shell completion is not supported."),
  350. err=True,
  351. )
  352. def source(self) -> str:
  353. self._check_version()
  354. return super().source()
  355. def get_completion_args(self) -> tuple[list[str], str]:
  356. cwords = split_arg_string(os.environ["COMP_WORDS"])
  357. cword = int(os.environ["COMP_CWORD"])
  358. args = cwords[1:cword]
  359. try:
  360. incomplete = cwords[cword]
  361. except IndexError:
  362. incomplete = ""
  363. return args, incomplete
  364. def format_completion(self, item: CompletionItem[t.Any]) -> str:
  365. return f"{item.type},{item.value}"
  366. class ZshComplete(ShellComplete):
  367. """Shell completion for Zsh."""
  368. name: t.ClassVar[str] = "zsh"
  369. source_template: t.ClassVar[str] = _SOURCE_ZSH
  370. def get_completion_args(self) -> tuple[list[str], str]:
  371. cwords = split_arg_string(os.environ["COMP_WORDS"])
  372. cword = int(os.environ["COMP_CWORD"])
  373. args = cwords[1:cword]
  374. try:
  375. incomplete = cwords[cword]
  376. except IndexError:
  377. incomplete = ""
  378. return args, incomplete
  379. def format_completion(self, item: CompletionItem[str]) -> str:
  380. help_ = item.help or "_"
  381. # The zsh completion script uses `_describe` on items with help
  382. # texts (which splits the item help from the item value at the
  383. # first unescaped colon) and `compadd` on items without help
  384. # text (which uses the item value as-is and does not support
  385. # colon escaping). So escape colons in the item value if and
  386. # only if the item help is not the sentinel "_" value, as used
  387. # by the completion script.
  388. #
  389. # (The zsh completion script is potentially widely deployed, and
  390. # thus harder to fix than this method.)
  391. #
  392. # See issue #1812 and issue #2703 for further context.
  393. value = item.value.replace(":", r"\:") if help_ != "_" else item.value
  394. return f"{item.type}\n{value}\n{help_}"
  395. class FishComplete(ShellComplete):
  396. """Shell completion for Fish."""
  397. name: t.ClassVar[str] = "fish"
  398. source_template: t.ClassVar[str] = _SOURCE_FISH
  399. def get_completion_args(self) -> tuple[list[str], str]:
  400. cwords = split_arg_string(os.environ["COMP_WORDS"])
  401. incomplete = os.environ["COMP_CWORD"]
  402. if incomplete:
  403. incomplete = split_arg_string(incomplete)[0]
  404. args = cwords[1:]
  405. # Fish stores the partial word in both COMP_WORDS and
  406. # COMP_CWORD, remove it from complete args.
  407. if incomplete and args and args[-1] == incomplete:
  408. args.pop()
  409. return args, incomplete
  410. def format_completion(self, item: CompletionItem[str]) -> str:
  411. """
  412. .. versionchanged:: 8.4.2
  413. Escape newlines and replace tabs with spaces in the help text to
  414. fix completion errors with multi-line help strings.
  415. """
  416. # According to https://fishshell.com/docs/current/cmds/complete.html
  417. # Command substitutions found in ARGUMENTS should return a newline-
  418. # separated list of arguments, and each argument may optionally have a tab
  419. # character followed by the argument description.
  420. if item.help:
  421. help_ = item.help.replace("\n", "\\n").replace("\t", " ")
  422. return f"{item.type},{item.value}\t{help_}"
  423. return f"{item.type},{item.value}"
  424. class PowerShellComplete(ShellComplete):
  425. """Shell completion for PowerShell (Windows PowerShell 5.1+ and pwsh 7+).
  426. .. versionadded:: 8.5.0
  427. """
  428. name: t.ClassVar[str] = "powershell"
  429. source_template: t.ClassVar[str] = _SOURCE_POWERSHELL
  430. def get_completion_args(self) -> tuple[list[str], str]:
  431. cwords = split_arg_string(os.environ["COMP_WORDS"])
  432. cword = int(os.environ["COMP_CWORD"])
  433. args = cwords[1:cword]
  434. try:
  435. incomplete = cwords[cword]
  436. except IndexError:
  437. incomplete = ""
  438. return args, incomplete
  439. def format_completion(self, item: CompletionItem[str]) -> str:
  440. # PowerShell parses the response by splitting on newlines and
  441. # consuming three lines per completion (type, value, help).
  442. # Multi-line help text would break that framing, so collapse
  443. # newlines and carriage returns to spaces. The literal "_"
  444. # sentinel matches what ZshComplete uses for "no help text".
  445. if item.help:
  446. help_ = item.help.replace("\r", " ").replace("\n", " ")
  447. else:
  448. help_ = "_"
  449. return f"{item.type}\n{item.value}\n{help_}"
  450. _available_shells: t.Final[dict[str, type[ShellComplete]]] = {
  451. "bash": BashComplete,
  452. "fish": FishComplete,
  453. "powershell": PowerShellComplete,
  454. "zsh": ZshComplete,
  455. }
  456. _ShellCompleteT = t.TypeVar("_ShellCompleteT", bound="ShellComplete")
  457. def add_completion_class(
  458. cls: type[_ShellCompleteT], name: str | None = None
  459. ) -> type[_ShellCompleteT]:
  460. """Register a :class:`ShellComplete` subclass under the given name.
  461. The name will be provided by the completion instruction environment
  462. variable during completion.
  463. :param cls: The completion class that will handle completion for the
  464. shell.
  465. :param name: Name to register the class under. Defaults to the
  466. class's ``name`` attribute.
  467. """
  468. if name is None:
  469. name = cls.name
  470. _available_shells[name] = cls
  471. return cls
  472. @t.overload
  473. def get_completion_class(shell: t.Literal["bash"]) -> type[BashComplete]: ...
  474. @t.overload
  475. def get_completion_class(shell: t.Literal["fish"]) -> type[FishComplete]: ...
  476. @t.overload
  477. def get_completion_class(shell: t.Literal["zsh"]) -> type[ZshComplete]: ...
  478. @t.overload
  479. def get_completion_class(shell: str) -> type[ShellComplete] | None: ...
  480. def get_completion_class(shell: str) -> type[ShellComplete] | None:
  481. """Look up a registered :class:`ShellComplete` subclass by the name
  482. provided by the completion instruction environment variable. If the
  483. name isn't registered, returns ``None``.
  484. :param shell: Name the class is registered under.
  485. """
  486. return _available_shells.get(shell)
  487. def split_arg_string(string: str) -> list[str]:
  488. """Split an argument string as with :func:`shlex.split`, but don't
  489. fail if the string is incomplete. Ignores a missing closing quote or
  490. incomplete escape sequence and uses the partial token as-is.
  491. .. code-block:: python
  492. split_arg_string("example 'my file")
  493. ["example", "my file"]
  494. split_arg_string("example my\\")
  495. ["example", "my"]
  496. :param string: String to split.
  497. .. versionchanged:: 8.2
  498. Moved to ``shell_completion`` from ``parser``.
  499. """
  500. import shlex
  501. lex = shlex.shlex(string, posix=True)
  502. lex.whitespace_split = True
  503. lex.commenters = ""
  504. out: list[str] = []
  505. try:
  506. out.extend(lex)
  507. except ValueError:
  508. # Raised when end-of-string is reached in an invalid state. Use
  509. # the partial token as-is. The quote or escape character is in
  510. # lex.state, not lex.token.
  511. out.append(lex.token)
  512. return out
  513. def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool:
  514. """Determine if the given parameter is an argument that can still
  515. accept values.
  516. :param ctx: Invocation context for the command represented by the
  517. parsed complete args.
  518. :param param: Argument object being checked.
  519. """
  520. if not isinstance(param, Argument):
  521. return False
  522. value = ctx.params.get(param.name)
  523. return (
  524. param.nargs == -1
  525. or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE
  526. or (
  527. param.nargs > 1
  528. and isinstance(value, (tuple, list))
  529. and len(value) < param.nargs
  530. )
  531. )
  532. def _start_of_option(ctx: Context, value: str) -> bool:
  533. """Check if the value looks like the start of an option."""
  534. if not value:
  535. return False
  536. c = value[0]
  537. return c in ctx._opt_prefixes
  538. def _is_incomplete_option(ctx: Context, args: list[str], param: Parameter) -> bool:
  539. """Determine if the given parameter is an option that needs a value.
  540. :param args: List of complete args before the incomplete value.
  541. :param param: Option object being checked.
  542. """
  543. if not isinstance(param, Option):
  544. return False
  545. if param.is_flag or param.count:
  546. return False
  547. last_option = None
  548. for index, arg in enumerate(reversed(args)):
  549. if index + 1 > param.nargs:
  550. break
  551. if _start_of_option(ctx, arg):
  552. last_option = arg
  553. break
  554. return last_option is not None and last_option in param.opts
  555. def _resolve_context(
  556. cli: Command,
  557. ctx_args: cabc.MutableMapping[str, t.Any],
  558. prog_name: str,
  559. args: list[str],
  560. ) -> Context:
  561. """Produce the context hierarchy starting with the command and
  562. traversing the complete arguments. This only follows the commands,
  563. it doesn't trigger input prompts or callbacks.
  564. :param cli: Command being called.
  565. :param prog_name: Name of the executable in the shell.
  566. :param args: List of complete args before the incomplete value.
  567. """
  568. ctx_args["resilient_parsing"] = True
  569. with cli.make_context(prog_name, args.copy(), **ctx_args) as ctx:
  570. args = ctx._protected_args + ctx.args
  571. while args:
  572. command = ctx.command
  573. if isinstance(command, Group):
  574. if not command.chain:
  575. name, cmd, args = command.resolve_command(ctx, args)
  576. if cmd is None:
  577. return ctx
  578. with cmd.make_context(
  579. name, args, parent=ctx, resilient_parsing=True
  580. ) as sub_ctx:
  581. ctx = sub_ctx
  582. args = ctx._protected_args + ctx.args
  583. else:
  584. sub_ctx = ctx
  585. while args:
  586. name, cmd, args = command.resolve_command(ctx, args)
  587. if cmd is None:
  588. return ctx
  589. with cmd.make_context(
  590. name,
  591. args,
  592. parent=ctx,
  593. allow_extra_args=True,
  594. allow_interspersed_args=False,
  595. resilient_parsing=True,
  596. ) as sub_sub_ctx:
  597. sub_ctx = sub_sub_ctx
  598. args = sub_ctx.args
  599. ctx = sub_ctx
  600. args = [*sub_ctx._protected_args, *sub_ctx.args]
  601. else:
  602. break
  603. return ctx
  604. def _resolve_incomplete(
  605. ctx: Context, args: list[str], incomplete: str
  606. ) -> tuple[Command | Parameter, str]:
  607. """Find the Click object that will handle the completion of the
  608. incomplete value. Return the object and the incomplete value.
  609. :param ctx: Invocation context for the command represented by
  610. the parsed complete args.
  611. :param args: List of complete args before the incomplete value.
  612. :param incomplete: Value being completed. May be empty.
  613. """
  614. # Different shells treat an "=" between a long option name and
  615. # value differently. Might keep the value joined, return the "="
  616. # as a separate item, or return the split name and value. Always
  617. # split and discard the "=" to make completion easier.
  618. if incomplete == "=":
  619. incomplete = ""
  620. elif "=" in incomplete and _start_of_option(ctx, incomplete):
  621. name, _, incomplete = incomplete.partition("=")
  622. args.append(name)
  623. # The "--" marker tells Click to stop treating values as options
  624. # even if they start with the option character. If it hasn't been
  625. # given and the incomplete arg looks like an option, the current
  626. # command will provide option name completions.
  627. if "--" not in args and _start_of_option(ctx, incomplete):
  628. return ctx.command, incomplete
  629. params = ctx.command.get_params(ctx)
  630. # If the last complete arg is an option name with an incomplete
  631. # value, the option will provide value completions.
  632. for param in params:
  633. if _is_incomplete_option(ctx, args, param):
  634. return param, incomplete
  635. # It's not an option name or value. The first argument without a
  636. # parsed value will provide value completions.
  637. for param in params:
  638. if _is_incomplete_argument(ctx, param):
  639. return param, incomplete
  640. # There were no unparsed arguments, the command may be a group that
  641. # will provide command name completions.
  642. return ctx.command, incomplete