1

Is there a way to access already provided argument as a variable in a ZSH completion scripts?

here is the example:

#compdef test

_test_comp(){
 t=($(cat /tmp/file_with_opts))
 _wanted t expl "availavle options" compadd -a t
}

_arguments -C -S  \
 '-f[input file]:filename:_files' \
 '*:test_autocomplete:_test_comp'

the test script will pick up options from the hardcoded file /tmp/file_with_opts, I'd like to be able to pick up autocomplete options from a file defined via -f. Or rather if -f <filename> is defined I'd like to parse this file and not the default one. Any hint how to do this?

2

This seems something like an XY problem; what exactly motivates this changing of the completion via a provided option? Like could the change instead be done via an environment variable, or why does the completion need to vary?

Anyways, a file at some point during the option processing may cause problems depending on where -f ... appears relative to other things on the command line. Also the completion code will be repeatedly invoked so maintaining state across different calls to the same and new instances of a command may be tricky. And also $(cat /tmp/file_with_opts) is bad as it needlessly forks out to cat and then splits the contents on...well, who knows.

With these problems in mind, one way to figure out what options are available is to add something like set > ~/tmp/what-is-set to an appropriate part of the completion code, then hit tab with the cursor at various places with and without the -f ... option and then check the output file to see what things are available to a completion script:

% grep file_ what-is-set
BUFFER='foo  -f file_with_opts '
RBUFFER=' -f file_with_opts '
opt_args=( [-f]=file_with_opts )
words=( foo '' -f file_with_opts )

In that case I was tab completing just after foo and before -f ..., so to vary the completion behavior one could check BUFFER or better yet the words array as BUFFER might have -f ... from other commands unrelated to your program that could confuse your completion script.

So if we loop over words, we can vary what file is read depending on whether (without much error checking) the -f ... option is present with something like:

#compdef foo

local curcontext="$curcontext" state line ret=1

_arguments -C -S  \
  '-f[input file]:filename:_files' \
  '*:options:->vary' \
  && ret=0

case "$state" in
  vary)
    integer i
    local optsfile
    #set > ~/tmp/what-is-set
    # default filename
    optsfile=~/tmp/file_with_opts
    for (( i = 1; i <= $#words - 1; i++ )); do
      if [[ $words[$i] == -f ]]; then
        optsfile=$words[$((i+1))]
        break
      fi
    done
    # cat-free read of file with split on newlines
    t=(${(f)"$(<$optsfile)"})
    _wanted t expl "available options" compadd -a t
  ;;
esac

return $ret

It may be helpful to study the existing completions under the $fpath[-1] directory.

  • Thank you very much! this clarifies a lot for me. I can't use environment vars in this case. It is very handy to pick up completions from a file, but sometimes the program operates on a different file and thus it would be silly to provide wrong completions. Thank you also for providing example for cat-free read of file it is definitely useful and finally I know what it means in other _completions files on my system:). – mestia Nov 14 '18 at 10:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.