Zsh completion arguments: Difference between revisions

From wikinotes
Line 183: Line 183:
== Dynamic Arguments ==
== Dynamic Arguments ==
<blockquote>
<blockquote>
Generate autocomplete options based on the options that were entered
Generate autocomplete options based on the options that were entered<br>
previously. This can do just about anything you need it to, it's really cool.  
previously. This can do just about anything you need it to, it's really cool.<br>
This isn't my example, and I haven't yet needed this level of flexibility yet.  
This isn't my example, and I haven't yet needed this level of flexibility yet.<br>
This example is just so clear, I had to add it.<br>
This example is just so clear, I had to add it.<br>



Revision as of 22:33, 24 July 2021

The _arguments function is one method available for producing completions.

Syntax

Basics

arguments \
  '( ${excludes} )${param}:[:]${message}:${action}'
# ${excludes} is an array of param ${state_descr}s
#    arguments \
#      '::one:_normal' \
#      '::two:_normal' \
#      '(one)::three:(foo bar baz)'   
#
# don't complete 'three' if 'one' has been used
# ${param} has different formats depending the param
# (or the next param, depending on param type)
#    ex: '-h[show help]'  # flag
#    ex: '1'              # positional
#    ex: '*'              # rest argument(s)
#    ex: ''               # optional
# ':' vs '::' 
#    here ${param}:${message}:${action}  is a required param
#    here ${param}::${message}:${action} is an optional param
# ${message} is the name of the param
#    this is the name of the param, when referred to in other completer functions.
#    it gets bound to ${state_descr}.
# ${action} is instructions on how to complete the next param
#    '1:one:'                  # ? valid ?
#    '1:one:(one two three)'   # argument must be one, two, or three
#    '1:one:_user'             # argument uses '_user' (function) to provide completions

Flag Arguments

_arguments \
   {-h,--help}'[show help]' \
       # param:   -h/--help
       # desc:    show help
       # action:  (none)
   '-o[output file]:::_files' \
       # param:   -o
       # desc:    output file
       # action:  (complete any file)

Positional Arguments

# ex: ${position}:${state_descr}:${action}

_arguments \
    '1:user:_users' \              # 1st positional arg (required)
    '2:priority:(low med high)' \  # 2nd positional arg (required) (complete to low/med/high)
    '3::group:_groups' \           # 3nd positional arg (optional)

The argument-name is bound to $state_descr.

Value for last defined Param

:${message}:${action}   # reqd completion for prev command
::${message}:${action}  # optional completion for prev command
_arguments \
    {-h,--help}'[show help]' \
    '*::extra:(foo bar baz)' \  # any extra parameters, (complete to (foo bar baz))
    ':value:(foo bar baz)'      # after prev param (extra), always complete one of these words

Rest Arguments

Any arguments not consumed earlier use this completer.

*:${message}:${action}    # 
*::${message}:${action}   # 
*:::${message}:${action}  #

State Setting/Parsing

The -C argument enables state-setting.
This lets you determine the parser that gets used based on the state you set.

local state               # scope state locally

_arguments -C \
    '*:extra:->my-state'  # sets `$state='my-state'`

case $state in
    (my-state)
        _arguments '1:foo:(one two three four)'
        ;;
esac

Strategies

TODO:

This section is unclear, requires experimentation and clarity

Subparsers

Sometimes, the use of a particular flag opens up a chain of possible sub-commands. (ex: git add, git commit, ...). This can be handled in ZSH as follows:

#compdef wtest

_wtest() {
    # limit scope of variables used by zsh completer
    local context state line expl implementation

    # list of subparsers
    local -a subparsers
    subparsers=(archive display data)

    # Determine completer for subcommand
    # (based on 1st positional argument)
    _arguments -C \
        {-h,--help}'[show help information]' \
        '1:subcommand:compadd -a subparsers' \
        '*:: :->subcmd' && return

    # parsers for each subparser
    subparser="$words[1]"
    curcontext="${curcontext%:*}-$subparser:"  # <-- unecessary (?)
    case $subparser in
    (archive)
        _arguments -A "-*" \
            '-a[append files to archive]' \
            '-e[extract files to archive]'
        ;;
    (display)
        _arguments -A "-*" \
            '-n[next file in archive]' \
            '-p[previous file in archive]'
        ;;
    (data)
        _arguments -A "-*" \
            '-s[shuffle order of wallpapers]' 
        ;;
    (*)
        _message "unknown sub-command: $subparser"
        ;;
    esac
}

_wtest "$@"

Dynamic Arguments

Generate autocomplete options based on the options that were entered
previously. This can do just about anything you need it to, it's really cool.
This isn't my example, and I haven't yet needed this level of flexibility yet.
This example is just so clear, I had to add it.

Some Background Info:

  • $words[] is an array of all arguments used so far
  • $state is set in _arguments. In the below example. If completion is used for '1', the value of $state will be 'country'
#compdef hello
 
_hello() { 
    # limit scope of zsh vars bound by completer
    local curcontext="$curcontext" state line
    typeset -A opt_args

    _arguments \
        '1: :->country' \
        '*: :->city'

    case $state in
    country)
        _arguments '1:Countries:(France Germany Italy)'
    ;;
    *)
        case $words[2] in
        France)
            compadd "$@" Paris Lyon Marseille
        ;;
        Germany)
            compadd "$@" Berlin Munich Dresden
        ;;
        Italy)
            compadd "$@" Rome Napoli Palermo
        ;;
        *)
            _files 
        esac
    esac
}
 
_hello "$@"