Shell 完成 — 单击文档

来自菜鸟教程
Click/docs/8.0.x/shell-completion
跳转至:导航、​搜索

壳完成

Click 为 Bash(4.4 及更高版本)、Zsh 和 Fish 提供选项卡补全支持。 也可以添加对其他 shell 的支持,并且可以在多个级别自定义建议。

Shell 完成建议命令名称、选项名称以及选择、文件和路径参数类型的值。 仅当至少输入了一个破折号时才会列出选项。 隐藏的命令和选项不会显示。

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

启用完成

只有通过入口点安装和调用脚本时才能完成,而不是通过 python 命令。 参见 Setuptools 集成 。 安装可执行文件后,使用特殊环境变量调用它会使 Click 进入完成模式。

为了使用完成,用户需要在他们的 shell 中注册一个特殊的函数。 每个 shell 的脚本都不同,当调用 _{PROG_NAME}_COMPLETE 设置为 {shell}_source 时,Click 将输出它。 {PROG_NAME} 是大写的可执行文件名称,破折号由下划线代替。 内置外壳有 bashzshfish

为您的用户提供以下根据您的程序名称定制的说明。 这里以foo-bar为例。

使用 eval 意味着每次启动 shell 时都会调用和评估该命令,这会延迟 shell 响应。 要加快速度,请将生成的脚本写入文件,然后将其作为源。 您可以提前生成文件并将它们与您的程序一起分发,从而为您的用户节省一个步骤。

修改 shell 配置后,您需要启动一个新的 shell 才能加载更改。


自定义类型补全

创建自定义 ParamType 时,覆盖其 shell_complete() 方法以为具有该类型的参数提供 shell 补全。 该方法必须返回 CompletionItem 对象的列表。 除了值之外,这些对象还包含 shell 支持可能使用的元数据。 内置实现使用 type 表示对路径的特殊处理,并使用 help 表示支持在建议旁边显示帮助字符串的 shell。

在此示例中,该类型将建议以不完整值开头的环境变量。

class EnvVarType(ParamType):
    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])

覆盖值完成

通过提供 shell_complete 函数,可以在没有自定义类型的情况下自定义参数的值完成。 使用该函数代替该类型提供的任何完成。 它传递了 3 个关键字参数:

  • ctx - 当前命令上下文。
  • param - 当前参数请求完成。
  • incomplete - 正在完成的部分字。 如果尚未输入任何字符,则可能为空字符串。

它必须返回一个 CompletionItem 对象列表,或者作为快捷方式它可以返回一个字符串列表。

在此示例中,该命令将建议以不完整值开头的环境变量。

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]}")

添加对 Shell 的支持

可以添加对非内置 shell 的支持。 一定要检查 PyPI,看看是否已经有一个包添加了对你的 shell 的支持。 这个主题非常技术性,您需要查看 Click 的源代码以研究内置实现。

Shell 支持由 ShellComplete 的子类提供,这些子类通过 add_completion_class() 注册。 在完成模式下调用 Click 时,它调用 source() 输出完成脚本,或调用 complete() 输出完成。 基类提供了需要实现一些较小部分的默认实现。

首先,您需要弄清楚 shell 的完成系统是如何工作的,并编写一个脚本来将它与 Click 集成。 它必须在环境变量 _{PROG_NAME}_COMPLETE 设置为 {shell}_complete 的情况下调用您的程序,并传递完整的参数和不完整的值。 它如何传递这些值,以及来自 Click 的完成响应的格式取决于您。

在您的子类中,将 source_template 设置为完成脚本。 默认实现将使用以下变量执行 % 格式化:

  • complete_func - 脚本中定义的完成函数的安全名称。
  • complete_var - 传递 {shell}_complete 指令的环境变量名称。
  • prog_name - 正在完成的可执行文件的名称。

示例代码是一个组成的外壳程序“My Shell”或简称“mysh”。

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 %(prog_name)s)
    # parse response and set completions somehow
}
call-on-complete %(prog_name)s %(complete_func)s
"""

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

接下来,实现 get_completion_args()。 这必须从完成脚本中获取、解析和返回完整的参数和不完整的值。 例如,对于 Bash 实现,COMP_WORDS 环境变量包含作为字符串的命令行参数,而 COMP_CWORD 环境变量包含不完整参数的索引。 该方法必须返回一个 (args, incomplete) 元组。

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, ""

最后,实现 format_completion()。 调用它可以将每个 CompletionItem 格式化为一个字符串。 例如,Bash 实现返回 f"{item.type},{item.value}(它不支持帮助字符串),而 Zsh 实现返回由换行符分隔的每个部分,用 _ 占位符替换空帮助。 这种格式完全取决于您使用完成脚本解析的内容。

type 的值通常是 plain,但也可以是补全脚本可以打开的另一个值。 例如,filedir 可以告诉 shell 处理路径补全,因为 shell 在这方面比 Click 更好。

class MyshComplete(ShellComplete):
    ...

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

实现了这三件事后,新的 shell 支持就准备好了。 如果这些还不够,还有更多的部分可以被覆盖,但这可能不是必需的。

激活说明将再次取决于您的 shell 的工作方式。 使用以下命令生成完成脚本,然后以某种方式将其加载到 shell 中。

_FOO_BAR_COMPLETE=mysh_source foo-bar