I have zsh completion file for custom script foo.

It should complete regular files in $HOME/foo :

#compdef foo

_arguments -S : \
    '-i' \
    '1:thing:_path_files -W $HOME/foo -g "*(.)"'

I need to modify the completion as follows:

Add optional parameter --dir.

When I type foo --dir<TAB>, it should offer completion for directories in $HOME/foo

foo --dir=<TAB>

And also, the file completion path (which is $HOME/foo by default) should change to $HOME/foo/my_dir, where my_dir is the name provided as --dir=my_dir.


Basically, the completion rule is supposed to have 2 modes of operation:

  1. when I type foo -<TAB>, it is supposed to offer me optional parameters (-d -w -l -i). Then, depending on the optional parameter chosen:

1a) foo -d <TAB> completes only directories in the path

1b) foo -w / -l / -i <TAB> completes regular files in the path

this works as desired.

  1. when I type foo <TAB>, the completion rule is supposed to offer regular files in the path. Currently, this does not work as desired. It still offers me the optional parameters, and I have to chose one, to then have directories/files completed.

When I type foo <TAB> (without the -), it only offers me the option parameters. Only after I have chosen one of the optional parameters, does my completion rule offer directories/files in the path.

How can I fix my script, so that it works without any optional parameters, and in such case simply completes regular files from the path ?

Here is the completion rule:

#compdef foo

local -A opt_args

_arguments -S -C \
    '-i[select file]:thing_file:_path_files -W $HOME/manuals/${opt_args[-d]} -g "*(.)"' \
    '-l[select file]:thing_file:_path_files -W $HOME/manuals/${opt_args[-d]} -g "*(.)"' \
    '-w[select file]:thing_file:_path_files -W $HOME/manuals/${opt_args[-d]} -g "*(.)"' \
    '-d[select directory]:directory_file:_path_files -/ -W $HOME/manuals' \
     && return 0

And one last small issue. The completion rule expects (completes) only one optional parameter.

When I type foo -i -<TAB> it does not offer other remaining optional parameters. These parameters should not be mutually exclusive. It should be possible to use:

foo -i -l -w <TAB>

1 Answer 1


Like that:

#compdef foo

local -A opt_args

_arguments -S -C \
    '-i[select file]:thing_file:_path_files -W $HOME/foo/${opt_args[-d]} -g "*(.)"' \
    '-d[select directory]:directory_file:_path_files -/ -W $HOME/foo' \
     && return 0

To explain how it works functionally:

Create ~/foo:

mkdir ~/foo

Create 10 directories inside ~/foo:

mkdir ~/foo/DIR{1..10}

Create a file in the 4th directory:

$ touch ~/foo/DIR4/FILE4

And a file in ~/foo:

touch ~/foo/FILE-IN-FOO


foo -d

and press Tab. It shows:

$foo -d DIR1/
DIR1/   DIR10/  DIR2/   DIR3/   DIR4/   DIR5/   DIR6/   DIR7/   DIR8/   DIR9/

Only directories are shown so no FILE-IN-FOO.

Select DIR4 and add -i:

foo -d DIR4 -i

and press Tab. It shows:

foo -d DIR4 -i FILE4
  • I have small problem with the completion rule. I have started a bounty. Would you please look, I have explained it in the UPDATE. Thank you. May 18, 2022 at 4:38

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.