最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

zsh completion - Mix _arguments and _values in zsh autocomplete script - Stack Overflow

programmeradmin5浏览0评论

I have a command with a very structured input like

cmd --help
cmd A -flagA1 X
cmd A -flagA2 Y
cmd B -flagB1 Z

Where X,Y,Z are fixed values and depend on whether A or B is enabled.

Ideally, I'm trying to generate an autocomplete script for zsh to have the following behavior

cmd subA <tab> --> display X,Y
cmd subA -<tab> --> display flagA1, flagA2

My current script look like this

#compdef _cmd

_cmd () {
    typeset -A opt_args
    local state line curcontext="$curcontext" state_descr

    _arguments -C \
               ': :->command'  \
               ': :->subcmd' \
        && ret=0

    case $state in
        (command)
            # local array variable
            local -a subcommands
            subcommands=(
                'A:Do A'
                'B:Do B'
            )
            _describe -t commands 'subcommands' subcommands && ret=0
            ;;
        (subcmd)
            case $line[1] in
                (A)
                    _cmd_A_cmd
                    ;;
                (B)
                    ;;
            esac
            ;;
    esac
}

_cmd_A_cmd () {
    typeset -A opt_args
    local state line curcontext="$curcontext" state_descr

    _arguments -C \
               ':: :->options'  \
               ': :->subcmd' \
        && ret=0
    case $state in
        (options)
            _arguments
                '-flagA1:the flag A1' \
                '-flagA2:flag A2'
                ;;
        (subcmd)
            _values "A subcommand"\
                'X[X option]' \
                'Y[Y option]'
            ;;
    esac
}

It works to get command A and B, and within A to get option X,Y, but I can't get the flags to work.

Any help appreciated.

I have a command with a very structured input like

cmd --help
cmd A -flagA1 X
cmd A -flagA2 Y
cmd B -flagB1 Z

Where X,Y,Z are fixed values and depend on whether A or B is enabled.

Ideally, I'm trying to generate an autocomplete script for zsh to have the following behavior

cmd subA <tab> --> display X,Y
cmd subA -<tab> --> display flagA1, flagA2

My current script look like this

#compdef _cmd

_cmd () {
    typeset -A opt_args
    local state line curcontext="$curcontext" state_descr

    _arguments -C \
               ': :->command'  \
               ': :->subcmd' \
        && ret=0

    case $state in
        (command)
            # local array variable
            local -a subcommands
            subcommands=(
                'A:Do A'
                'B:Do B'
            )
            _describe -t commands 'subcommands' subcommands && ret=0
            ;;
        (subcmd)
            case $line[1] in
                (A)
                    _cmd_A_cmd
                    ;;
                (B)
                    ;;
            esac
            ;;
    esac
}

_cmd_A_cmd () {
    typeset -A opt_args
    local state line curcontext="$curcontext" state_descr

    _arguments -C \
               ':: :->options'  \
               ': :->subcmd' \
        && ret=0
    case $state in
        (options)
            _arguments
                '-flagA1:the flag A1' \
                '-flagA2:flag A2'
                ;;
        (subcmd)
            _values "A subcommand"\
                'X[X option]' \
                'Y[Y option]'
            ;;
    esac
}

It works to get command A and B, and within A to get option X,Y, but I can't get the flags to work.

Any help appreciated.

Share Improve this question asked Mar 21 at 15:21 DavidbrczDavidbrcz 2,43920 silver badges28 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

To use _arguments with below in mind could help especially in some completion codes with subcommands completion:

  1. describe options (for example --help[show help] --flag[some flag] etc).
  2. put subcommands definitions (: :->command).
  3. more arguments (*:: :->arg) which means some more subcommands specified or no more arguments.
#compdef _cmd

_cmd () {
    typeset -A opt_args
    local state line curcontext="$curcontext" state_descr ret=1

    _arguments -C : \
        '--help[show help]' \
        ': :->command' \
        '*:: :->arg' \
        && ret=0
    case $state in
        (command)
            local -a commands
            commands=(
                'A:Do A'
                'B:Do B')
            _describe -t commands 'subcommands' commands && ret=0
            ;;
        (arg)
            _call_function ret _cmd-"$line[1]"
            ;;
    esac
    return ret
}

_cmd-A () {
    typeset -A opt_args
    local state line curcontext="$curcontext" state_descr ret=1

    _arguments -C : \
        '-flagA1[the flag A1]' \
        '-flagA2[the flag A2]' \
        ': :->command' \
        '*:: :->arg' \
        && ret=0
    case $state in
        (command)
            _values "A subcommand"\
                'X[X option]' \
                'Y[Y option]' && ret=0
#            local -a commands
#            commands=(
#                'X:X option'
#                'Y:Y option')
#            _describe -t commands 'A subcommands' commands && ret=0
            ;;
        (arg)
            _nothing
            ;;
    esac
    return ret
}

If *:: :->arg specified, this is described in zsh manual (from _arguments):

*::MESSAGE:ACTION
...
With two colons before the MESSAGE, the words special array and the CURRENT special parameter are modified to refer only to the normal arguments when the ACTION is executed or evaluated.

like this: (*) denotes the cursor's position,

$ cmd A --(*)<TAB>
;; words=(cmd A --), CURRENT=3
;; encounters `*:: ->arg` then,
;; words=(A --), CURRENT=2
;; eventually the function `_cmd-A` gets called

so the function _cmd-A could be written like an A command's completion.

发布评论

评论列表(0)

  1. 暂无评论