如何以不同的方式自动完成每个参数?

如何以不同的方式自动完成每个参数?

我有一个名为 load_pg 的函数,其定义如下:

load_pg () {
    pg_restore --verbose --clean --no-acl --no-owner -h localhost -U $1 -d $2 $3
}

我正在尝试使用以下代码自动完成每个参数:

#compdef load_pg
_arguments -s \
  "1::_ldpguser" \
  "2::_ldpgdb" \
  "3::_ldpgfile"

_ldpguser () {
  compadd $USER
}

_ldpgdb () {
  compadd $(cat config/database.yml | grep -i database | awk '{print $2}')
}

_ldpgfile () {
  compadd $(ls *.dump*)
}

不幸的是,当我按 TAB 时什么也没有发生。我究竟做错了什么?我尝试使用来自以下答案

答案1

_arguments第一个障碍: is where的参数语法不允许为空。如果您添加消息,您会看到一些进展:n:message:actionmessage

_arguments -s \
  "1:username:_ldpguser" \
  "2:database:_ldpgdb" \
  "3:dump file:_ldpgfile"

下一个障碍是辅助函数是在_arguments运行后定义的,因此第一次完成参数时,您将收到一条错误消息,抱怨其中一个函数不存在。在使用函数之前先定义它们。更好的是,明确函数的定义_load_pg并在自动加载文件的末尾调用它。这看起来很笨拙,但这是 zsh 附带的大多数多功能完成函数的编写方式。

#compdef load_pg

_ldpguser () {
  compadd $USER
}

_ldpgdb () {
  compadd $(cat config/database.yml | grep -i database | awk '{print $2}')
}

_ldpgfile () {
  compadd $(ls *.dump*)
}

_load_pg () {
  _arguments -s \
    "1:user:_ldpguser" \
    "2:database:_ldpgdb" \
    "3:dump file:_ldpgfile"
}

_load_pg "$@"

这为您提供了该功能的核心。然后您需要清理各个函数。最低限度:

  • compadd $USER似乎毫无意义:如果你只想用你的用户名调用该函数,为什么不把它内置进去呢?要完成用户名,请调用_users
  • 命令替换替换所有空格。要分割线,请使用@f 参数扩展标志。您还应该使您的grep命令更加精确,并且您可以将其与grep.
  • 当您compadd从 中调用操作时_arguments,请将 中的上下文选项传递给它$expl
  • 您可能需要提供完成的描述_describe
  • $(ls *.dump*)是一种复杂的书写方式“ *.dump*,如果没有匹配,则根据当前 shell 设置执行某些操作”。不解析输出ls,嗯嗯?你可以使用N 全局限定符当没有匹配时有一个空的完成列表。但是,您应该调用_files除其他细节外,它还负责完成子目录中的文件。
#compdef load_pg

_ldpgdb () {
  compadd $expl[@] -- "${(@f)$(<config/database.yml grep -i database | awk '{print $2}')}"
}

_load_pg () {
  _arguments -s \
    '1:user:_users' \
    '2:database:_ldpgdb' \
    '3:dump file:_files -g "*.dump*"'
}

_load_pg "$@"

相关内容