One way is to look for the : and behave different like depending:
#compdef foo # put this file into a $fpath directory (typically one you create # and prefix to that array) then `rm ~/.zcompdump && exec zsh` # until work-making (a temporary `print -z "foo "` in your .zshrc # may also speed debugging, as then you can go directly to the # mashing-of-tab stage) local curcontext="$curcontext" state line local suf typeset -A opt_args _arguments -C -s \ '1: :->dofoo' \ && return 0 case "$state" in dofoo) if compset -P '*[:]'; then _values "parameters" $(_call_program getparam ls /) else if compset -S '[:]*'; then suf=() else suf=( -qS ':' ) fi _wanted "schemes" expl "scheme" compadd $suf[@] $(_call_program getscheme ls /) fi ;; esac
The ls / bits will need to be your appropriate commands, perhaps with additional complications to properly split the output into a list, depending on what those programs emit, etc.
How I learned this: mostly cd $fpath[-1] and then poking around in especially the _chown and _users completions, which have completion for : handing. More info.