completion.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import sys
  2. import textwrap
  3. from optparse import Values
  4. from pip._internal.cli.base_command import Command
  5. from pip._internal.cli.status_codes import SUCCESS
  6. from pip._internal.utils.misc import get_prog
  7. BASE_COMPLETION = """
  8. # pip {shell} completion start{script}# pip {shell} completion end
  9. """
  10. COMPLETION_SCRIPTS = {
  11. "bash": """
  12. _pip_completion()
  13. {{
  14. local IFS=$' \\t\\n'
  15. COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\
  16. COMP_CWORD=$COMP_CWORD \\
  17. PIP_AUTO_COMPLETE=1 "$1" 2>/dev/null ) )
  18. }}
  19. complete -o default -F _pip_completion {prog}
  20. """,
  21. "zsh": """
  22. #compdef -P pip[0-9.]#
  23. __pip() {{
  24. compadd $( COMP_WORDS="$words[*]" \\
  25. COMP_CWORD=$((CURRENT-1)) \\
  26. PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null )
  27. }}
  28. if [[ $zsh_eval_context[-1] == loadautofunc ]]; then
  29. # autoload from fpath, call function directly
  30. __pip "$@"
  31. else
  32. # eval/source/. command, register function for later
  33. compdef __pip -P 'pip[0-9.]#'
  34. fi
  35. """,
  36. "fish": """
  37. function __fish_complete_pip
  38. set -lx COMP_WORDS \\
  39. (commandline --current-process --tokenize --cut-at-cursor) \\
  40. (commandline --current-token --cut-at-cursor)
  41. set -lx COMP_CWORD (math (count $COMP_WORDS) - 1)
  42. set -lx PIP_AUTO_COMPLETE 1
  43. set -l completions
  44. if string match -q '2.*' $version
  45. set completions (eval $COMP_WORDS[1])
  46. else
  47. set completions ($COMP_WORDS[1])
  48. end
  49. string split \\ -- $completions
  50. end
  51. complete -fa "(__fish_complete_pip)" -c {prog}
  52. """,
  53. "powershell": """
  54. if ((Test-Path Function:\\TabExpansion) -and -not `
  55. (Test-Path Function:\\_pip_completeBackup)) {{
  56. Rename-Item Function:\\TabExpansion _pip_completeBackup
  57. }}
  58. function TabExpansion($line, $lastWord) {{
  59. $lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart()
  60. if ($lastBlock.StartsWith("{prog} ")) {{
  61. $Env:COMP_WORDS=$lastBlock
  62. $Env:COMP_CWORD=$lastBlock.Split().Length - 1
  63. $Env:PIP_AUTO_COMPLETE=1
  64. (& {prog}).Split()
  65. Remove-Item Env:COMP_WORDS
  66. Remove-Item Env:COMP_CWORD
  67. Remove-Item Env:PIP_AUTO_COMPLETE
  68. }}
  69. elseif (Test-Path Function:\\_pip_completeBackup) {{
  70. # Fall back on existing tab expansion
  71. _pip_completeBackup $line $lastWord
  72. }}
  73. }}
  74. """,
  75. }
  76. class CompletionCommand(Command):
  77. """A helper command to be used for command completion."""
  78. ignore_require_venv = True
  79. def add_options(self) -> None:
  80. self.cmd_opts.add_option(
  81. "--bash",
  82. "-b",
  83. action="store_const",
  84. const="bash",
  85. dest="shell",
  86. help="Emit completion code for bash",
  87. )
  88. self.cmd_opts.add_option(
  89. "--zsh",
  90. "-z",
  91. action="store_const",
  92. const="zsh",
  93. dest="shell",
  94. help="Emit completion code for zsh",
  95. )
  96. self.cmd_opts.add_option(
  97. "--fish",
  98. "-f",
  99. action="store_const",
  100. const="fish",
  101. dest="shell",
  102. help="Emit completion code for fish",
  103. )
  104. self.cmd_opts.add_option(
  105. "--powershell",
  106. "-p",
  107. action="store_const",
  108. const="powershell",
  109. dest="shell",
  110. help="Emit completion code for powershell",
  111. )
  112. self.parser.insert_option_group(0, self.cmd_opts)
  113. def run(self, options: Values, args: list[str]) -> int:
  114. """Prints the completion code of the given shell"""
  115. shells = COMPLETION_SCRIPTS.keys()
  116. shell_options = ["--" + shell for shell in sorted(shells)]
  117. if options.shell in shells:
  118. script = textwrap.dedent(
  119. COMPLETION_SCRIPTS.get(options.shell, "").format(prog=get_prog())
  120. )
  121. print(BASE_COMPLETION.format(script=script, shell=options.shell))
  122. return SUCCESS
  123. else:
  124. sys.stderr.write(
  125. "ERROR: You must pass {}\n".format(" or ".join(shell_options))
  126. )
  127. return SUCCESS