更新:

更新:

我有自定义脚本,需要:

  1. 短/长格式的可选参数
  2. 一个必需的命令行参数

短/长命令行选项例如:

-r, --readonly
-m, --mount

对于一个必需的参数,这些参数实际上在脚本中指定为 case 语句,即foobar此示例中:

case $1 in
  foo )
  :
  ;;

  bar )
  :
  ;;

如何zsh completion为我的脚本创建,以便在参数以 开头时完成可选参数-,并从我的脚本 case 语句中获取所需参数?

更新:

这是我到目前为止所得到的,受到答案的启发@Marlon Richert

假设调用我的自定义脚本myscript.sh并且我创建的完成规则位于/usr/share/zsh/functions/Completion/Unix/_myscript.sh

#compdef myscript.sh

_myscript () {
  local -a args

  args+=(
    {-r,--readonly}'[description for "readonly"]' 
    {-m,--mount}'[description for "mount"]' 
  )

  _arguments $args && return
}

_myscript "$@"

我的脚本myscript.sh本身位于/usr/local/bin/myscript.sh.

因此,现在当我有了可选参数-r-m得到处理时,我需要修改我的完成规则,以便对于我的脚本所需的命令行参数,来自 case 语句的项目/usr/local/bin/myscript.sh作为完成提供。

另外,我不确定args+=(完成脚本中第 6 行开始的块的语法是否正确。我必须在哪里放置单引号?

答案1

假设您要为其定义完成的函数称为myfunc

首先,让我们设置实际的功能:

  1. 将您的函数放在名为myfunc.笔记:
    • 这不会以.zsh或结尾.sh
    • 当您将函数放入其自己的文件中时,无需添加funcname() {…}样板文件。
  2. 确保包含该文件的目录myfunc位于您的$fpath.例如,如果文件myfunc位于~/Functions,请将其添加到您的~/.zshrc文件中:
    fpath+=( ~/Functions )
    
  3. 最后,自动加载myfunc到您的文件中~/.zshrc
    # We pass a couple of options that make the code 
    # less likely to break:
    # -U suppresses alias expansion
    # -z marks the function for zsh-style autoloading == 
    #    `unsetopt KSH_AUTOLOAD`
    autoload -Uz myfunc
    

您现在应该能够myfunc在命令行上使用(但还没有任何完成)。

接下来,让我们创建完成函数:

  1. 创建一个名为_myfunc.
  2. 放入此文件中:
    #compdef myfunc
    
    # The line above means "This function generates 
    # completions for myfunc."
    # The combination of that line, plus the file name
    # starting with an `_`, plus having this file's 
    # parent dir in your `$fpath`, ensures this file 
    # will be autoloaded when you call `compinit`.
    
    # `+X` makes sure `myfunc`'s definition will get 
    # loaded immediately, even if you have not called 
    # this function yet.
    autoload +X -Uz myfunc
    
    # Get the definition of `myfunc` in string form.
    local funcdef="$( type -f myfunc )"
    
    # Get the part that matches `case*esac`, then split
    # it on whitespace and put the resulting words in an 
    # array.
    local -a words=( ${=funcdef[(r)case,(r)esac]} )
    
    # Keep only the words that start with `(` and end 
    # with `)`.
    # Even if you used the `case` syntax with only the 
    # closing `)`s, `type -f` will show your cases with
    # both `(` and `)`.
    local -a required=( ${(M)words:#'('*')'} )
    
    # `-s`: Allow options to `myfunc ` to be stacked, 
    # that is, you are allowed to specify `myfunc -rm`.
    # If not, remove the `-s` option.
    # `*:`: Let this argument be completed in any 
    # position.
    _arguments -s \
        {-r,--readonly}'[description for "readonly"]' \
        {-m,--mount}'[description for "mount"]' \
        "*:required argument:( ${required//[()]/}  )"
    
    • 替换required argument为您想要调用的任何参数。
    • 填写选项的说明。
  3. 再次确保该文件所在的目录位于您的$fpath.
  4. 确保你autoload -Uz compinit; compinit在你的.zshrc执行此操作并确保它运行上面的目录已添加到您的$fpath.
  5. 重新启动你的 shellexec zsh或者关闭你的终端窗口并打开一个新窗口。

您现在应该能够完成myfunc.


如果readonlymount互斥,您需要重写完成函数的最后一行,如下所示:

_arguments \
    (-m --mount){-r,--readonly}'[description for "readonly"]' \
    (-r --readonly){-m,--mount}'[description for "mount"]' \
    "*:required argument:( ${required//[()]/}  )"

相关内容