I have a function that uses zcompile to create a digest like so:
function fpath-setup {
local FLATFPATH="${TMPPREFIX}-${ZSH_VERSION}-fpath.zwc"
function {
typeset -a zarr
blacklist=('ztodo' 'zed')
blacklist="^(${(j:|:)blacklist})"
setopt LOCAL_OPTIONS EXTENDED_GLOB
for fp in "$fpath[@]"; do
local ztail=(${zarr:t})
for it in "${fp}/"$~blacklist; do
if [[ -z "${ztail[(r)${it:t}]}" ]]; then
if zcompile "${TMPPREFIX}-try-zcompile" "${it}" &>/dev/null; then
zarr+="${it}"
else
echo "CANNOT COMPILE: ${it}"
fi
else
echo "DUPLICATE: ${it}"
fi
done
done
zcompile "${FLATFPATH}" "$zarr[@]"
zcompile -t "${FLATFPATH}" 'compinit' '_complete' || {
print "Important functions missing from ${FLATFPATH}" >&2
return 1
}
}
if (( $? )); then
print "The fpath is left unchanged." >&2
return 1
else
fpath=("${FLATFPATH}")
fi
}
At the point this runs, the $fpath looks like this:
/usr/local/share/zsh/site-functions
/usr/local/Cellar/zsh/5.2/share/zsh/functions
After this runs, the $fpath looks like this:
/var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc
As you can see here, the core Zsh functions are in the digest:
https://ghostbin.com/paste/wgauy
This seems to work fine until I try and use this prompt theme:
https://github.com/sindresorhus/pure/blob/master/pure.zsh#L328
I get the following error at every prompt:
vcs_info: configured unknown backend: 'git'
vcs_info: use 'vcs_info_printsys' to find supported systems.
This can be resolved by not creating the digest in the first place, or by running the following command before invoking the prompt:
autoload -Uz VCS_INFO_get_data_git VCS_INFO_detect_git
So, my questions are:
- Is it a bad idea to use
zcompileon core Zsh functions? - Why do I need to manually
autoloadsome stuff when using thezcompiledigest, but that's not the case when using regular files in a directory?
Edit:
I've done some more investigating, and have found that with an fpath like:
/var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-circuit.zwc
The command:
prompt pure # ...vcs_info errors
print -f '%s\n' "${(k)functions[@]}" | grep VCS_INFO_get_data_git
Returns nothing. However, with an fpath like:
/var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc
/usr/local/Cellar/zsh/5.2/share/zsh/functions
The command:
prompt pure # NO vcs_info errors!
type $(print -f '%s\n' "${(k)functions[@]}" | grep VCS_INFO_get_data_git)
Returns:
VCS_INFO_get_data_git is a shell function from /var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc/VCS_INFO_get_data_git
So, somehow the mere existence of the core directory /usr/local/Cellar/zsh/5.2/share/zsh/functions causes the VCS_INFO_get_data_git function to be loaded from /var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc.
Does that mean Zsh gives special treatment the core directory? To test that theory, I copy the core function files to a temporary location:
cp -r /usr/local/Cellar/zsh/5.2/share/zsh/functions /tmp
Then in a fresh session, with an fpath like:
/var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc
/tmp/functions
The command:
prompt pure # NO vcs_info errors!!
type $(print -f '%s\n' "${(k)functions[@]}" | grep VCS_INFO_get_data_git)
Returns:
VCS_INFO_get_data_git is a shell function from /var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc/VCS_INFO_get_data_git
Thus, I must conclude that Zsh is NOT treating it's core directory specially, but instead it is autoloading VCS_INFO_get_data_git if a FILE of that name exists in any of the directories on the fpath... However, Zsh will still load from the DIGEST if that comes first in the fpath.
This is strange.
I haven't seen this behavior documented anywhere, and it's not clear to me how Zsh goes about this (maybe someone that knows Zsh internals can explain).
To try and figure out WHEN autoloading happens, I fiddle with the fpath in a fresh session, by changing the fpath from:
/var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc
/tmp/functions
To remove the /tmp/functions directory:
/var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc
Then I try changing the prompt:
prompt pure
Which gives the original vcs_info errors, as before:
vcs_info: configured unknown backend: 'git'
vcs_info: use 'vcs_info_printsys' to find supported systems.
To be sure, the test:
print -f '%s\n' "${(k)functions[@]}" | grep VCS_INFO_get_data_git
Returns nothing! Now, if at this point I add the /tmp/functions directory BACK to the fpath again, so it looks like:
/var/folders/kb/ydt74z19765cv9vb86rwvcrr0000gn/T/zsh-5.2-fpath.zwc
/tmp/functions
The vcs_info errors continue to persist!
Can anyone explain what the heck is going on here with Zsh version 5.2?
zcompile, or is it just a layer of complexity waiting to mug you?autoload -w "${FLATFPATH}". This gets the job done, though I'm not sure why it's not necessary to explicitly mark anything when using just directories and not a digest. Maybe somebody can explain? I thought a functions digest was supposed to be treated the same as a directory of function files._lsfor autoload-ing using the-wflag to the digest file does not play nice with how Zsh automagically loads it's_*completion functions. Zsh just HAS to see an actual real file in thefpathsomewhere named_lsbefore it is convinced to try calling_lsas a completion function. This is very similar to the problem of not autoloading regular functions from digest if they were not also represented as real files somewhere in thefpath(which WAS solved by the-wflag, but that doesn't solve the special case of completion functions).compinit, usingcompdefto manually register functions starting with an_, like this: ghostbin.com/paste/7gzc8 ...So at least it is possible.