Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Writing completion for non-GNU-style command

Hi all,

I'm about to write my first completion script and it seems I picked a
program that is not easy to implement completions for.

The project is question is called Paket
(https://github.com/fsprojects/Paket). Its command line supports
arguments that don't follow the standard GNU conventions. For example,
a valid Paket invocation might look like this:

paket add nuget <package id> [group <group name>] [project <project
file>] [version <version>] [--verbose] [--more-args ...]


paket add nuget NUnit group Test --verbose

The command is the "paket add nuget NUnit" part and the rest of the
command line are arguments, despite that "group Test" doesn't look
like one. Apart from "group" there might be more optional arguments
without dashes (i.e. project and version) and with dashes (--verbose).

I'm struggling to find a solution to this as none of the completions I
found (e.g. git) implement a similar command line.

I tried combining _describe (for group etc.) and _arguments (for
--verbose etc.) but then I would need to deduplicate the non-GNU
arguments myself as group can only appear once. _arguments alone
chokes on "group" not starting with a dash. _values won't work because
"group" etc. aren't just values.

What also puzzles me is that zsh removes anything on $line that was
parsed successfully, but doesn't do that for the word following
"nuget" (the package id).

I've attached my current appoach below. There's one additional issue
with it, as options after the line

paket add nuget NUnit group Test -<tab>

don't show up at all.

Any pointers into the right direction are greatly appreciated!



_paket-add() {
  local curcontext=$curcontext state line ret=1
  local -A opt_args
  local context state_descr
  typeset -A val_args

  local -a args
    '(--verbose)'--verbose'[Be verbose]'
    '(--no-install)'--no-install'[Skip install process (patching of
project files) after the generation of paket.lock file]'

  _arguments -C \
    '--help[Display paket add help]' \
    ': :->command' \
    '*:: :->option-or-argument' \
  && ret=0

  case $state in
      local -a commands

        nuget:'Add NuGet package by its package ID'

      _describe -t commands command commands && ret=0


      case $line[1] in
          _arguments -C \
            ':package ID: ' \
            '*::: :->option-or-argument' \
          && ret=0

          case $state in
              case $line[$CURRENT] in
                  _arguments '*: :_paket_groups' && ret=0
                  return ret

                  _arguments '*:project:_path_files -g "**/*.??proj"' && ret=0
                  return ret

                  _arguments '*:version: ' && ret=0
                  return ret

              local -a should_be_args

                group:'Add the package to the given group. Default: Main group'
                project:'Add the package to a single project only'
                version:'Version of the package'

              # Remove entries from should_be_args that match words.
              # _arguments would have done this automatically, but we can't
              # use it because they are not args (i.e. not starting with -).
              local word
              for word in $words; do

              ((${#should_be_args} != 0)) && _describe -t
should-be-args 'command option' should_be_args && ret=0
              _arguments $args && ret=0

  return $ret

Messages sorted by: Reverse Date, Date, Thread, Author