自定义命令的动态 zsh 自动完成

zsq*_*are 28 zsh autocomplete

我正在尝试为我编写的一些自定义函数编写完成函数,但即使是最基本的函数似乎也很挣扎。

一个示例函数是:

function eb_instances() {
    if [ "$#" -ne 2 ]; then
        echo "Usage eb_instances <aws profile name> <environment name>"
        echo "e.g.:"
        echo " eb_instances production kraken-prod-api"
        return 1
    fi

    aws ec2 describe-instances --filters  "Name=instance-state-name,Values=running"   "Name=tag:Name,Values=$2" --profile=$1 --output=json | jq -r ".Reservations[].Instances[].PrivateIpAddress"
}
Run Code Online (Sandbox Code Playgroud)

这有两个位置参数,<aws profile name><environment name>

我希望 的完成选项<aws profile name>通过运行动态可用 sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ',并<environment name>通过运行我调用的另一个函数动态可用的完成选项eb_names

我发现文档非常稀疏且难以理解。我也看到了类似命令的 zsh-completions 存储库,但似乎找不到与我需要的类似的东西。

任何帮助入门将不胜感激!

更新

根据@cuonglm 的回答,我使用了:

#compdef ebinstances

_ebinstances() {
  local state

  _arguments \
    '1: :->aws_profile'\
    '*: :->eb_name'

  case $state in
    (aws_profile) _arguments '1:profiles:($(sed -n -E "s/\[([a-zA-Z0-9_\-]+)\]/\1/p" ~/.aws/credentials | tr \\n " "))' ;;
              (*) compadd "$@" foo bar
  esac
}

_ebinstances "$@"
Run Code Online (Sandbox Code Playgroud)

我在原始问题中忘记提及的是,我还希望第二个参数的完成依赖于第一个参数(两者都是基于动态执行某些代码的),例如:

$ eb_instances <cursor>TAB
cuonglm  test
Run Code Online (Sandbox Code Playgroud)

得到我想要的完成。一旦我选择说第一个,并尝试自动完成:

$ eb_instances cuonglm <cursor>TAB
Run Code Online (Sandbox Code Playgroud)

我想通过执行来生成完成选项eb_names cuonglm,如果可能的话,还可以钻取完成,例如,如果正确的候选人是foo-bar

$ eb_instances cuonglm foo<cursor>TAB
Run Code Online (Sandbox Code Playgroud)

我想通过执行来生成完成选项 eb_names cuonglm foo

cuo*_*glm 33

乍一看zsh 补全系统似乎非常复杂,难以掌握。让我们尝试一个例子。

您需要知道的第一件事是,zsh完成系统将从$fpath. 确保您的完成目录出现在:

print -rl -- $fpath
Run Code Online (Sandbox Code Playgroud)

(如果您使用oh-my-zsh,则.oh-my-zsh/completions存在于 中$fpath,您可以创建它并将完成功能放在那里)

现在,您必须为您的函数创建一个完成文件,其名称必须以下划线开头_,加上您的函数名称。在您的情况下,它的名称是_eb_instances.

将这些行添加到_eb_instances文件中:

#compdef eb_instances

_eb_instances() {
  local state

  _arguments \
    '1: :->aws_profile'\
    '*: :->eb_name'

  case $state in
    (aws_profile) _arguments '1:profiles:(cuonglm test)' ;;
              (*) compadd "$@" prod staging dev
  esac
}

_eb_instances "$@"
Run Code Online (Sandbox Code Playgroud)

你完成了。保存文件并开始新会话以测试完成。你会看到这样的事情:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging
Run Code Online (Sandbox Code Playgroud)

您可以阅读有关_arguments函数、state变量的zsh 完成系统文档。您还需要更改(cuonglm test)您的sed命令并更改prod staging dev您的eb_names功能。

如果要根据传递的第一个参数生成第二个参数,可以使用$words[2]变量:

case $state in
  (aws_profile) _arguments '1:profiles:(cuonglm test)' ;;
            (*) compadd "$@" $(echo $words[2]) ;;
esac
Run Code Online (Sandbox Code Playgroud)

替换echo为您的真实功能,在您的情况下,它是$(eb_names $words[2]).

如果你仍然觉得很难做到这一点,只需在你的then 调用完成中定义_eb_instances和:eb_instances.zshrc

compdef _eb_instances eb_instances
Run Code Online (Sandbox Code Playgroud)

您需要使用以下命令初始化完成系统:

autoload -U compinit
compinit
Run Code Online (Sandbox Code Playgroud)

(如果你用过oh-my-zsh,它已经加载了)

  • 你是个巫师,哈利。 (3认同)