The following snippet causes mcd to be completed like mkdir:
compdefas () { if (($+_comps[$1])); then compdef $_comps[$1] ${^@[2,-1]}=$1 fi } compdefas mkdir mcd
The way it works is to look up the current completion setting for mkdir. The completion code for a function (generally the name of a completion function) is stored in the associative array _comps. Thus compdef $_comps[mkdir] mcd declares that mcd should be completed in the same way that mkdir is completed right now.
The function above adds a few niceties:
- The test for
(($+_comps[$1])) ensures that if $1 doesn't have a specified completion method then no completion method is set for the other arguments. ${@[2,-1]} is the list of arguments to the function starting with the second one, so you can specify more than one command name to define completions for. It's actually ${^@[a,-1]} so that the text around the array expansion is replicated for each array element. =$1 sets the service name to use. This matters only for a few commands whose completion function handles several closely-related commands. For example the completion function _gzip handles both gzip and gunzip as well as pigz and unpigz; compdef _gzip foo makes foo use the default behavior of _gzip while compdef _gzip foo=pigz makes foo use the behavior of _gzip when it completes for pigz.
Turning to your specific case, the default completion for mkdir not only offers directories, but also options, which your function does not support. So you'd actually be better off defining mcd as just completing existing directories. Zsh comes with a helper function for that (an undocumented wrapper around _files).
compdef _directories mcd
The reason you were getting these bizarre-looking completions for mcd is that it's the name of a command from a once moderately widespread suite of commands mtools.
take <directory_name>to achieve the same behaviour as yourmcdfunction.