Zsh Source Command – Functions Not Reloading

functionmacosshellshell-scriptzsh

(This is on MacOS with zsh 5.7.1)

Here is how I load custom functions in zsh:

# Custom functions
fpath=($HOME/.zfunc $fpath)
autoload -Uz mackupbackup
autoload -Uz tac
autoload -Uz airplane
autoload -Uz wakeMyDesktop

Each function is its own file in the ~/.zfunc directory. Note this directory is symlinked into a different directory thanks to mackup.

I wrote a new function to copy the current commit hash to the clipboard. I created a file in my $fpath called ghash, wrote the function, added a new autoload line in my .zshrc and executed source ~/.zshrc.

Here's the function

# copy the commit hash of the given git reference, or HEAD if none is given
ref=$1

if [[ $ref ]]; then
  git rev-parse $1 | pbcopy
else
  git rev-parse HEAD | pbcopy
fi

After sourcing .zshrc, the function became available and it worked, but I wanted to add a line to print a confirmation that it worked:

echo "Copied $(pbpaste) to clipboard"

So I added that line, saved the file, then I sourced .zshrc again.

I ran the function again, but its behaviour didn't change!

I thought I'd done something wrong, so I kept making changes to the function and sourcing .zshrc to no effect. All in all, I re-sourced .zshrc 22 times, by which point that operation took 37 seconds to complete…

Then I realised maybe it wasn't reloading the function, so I ran zsh to start a fresh instance (which took about 1 second), and the function started working as expected!

Anyone know why source picked up my new function, but didn't update it when the function changed?

Bonus question: why'd it take longer to run source ~/.zshrc each time I ran it?

Best Answer

Sourcing an rc file rarely if ever works in practice, because people rarely write them to be idempotent. A case in point is your own, where you are prepending the same directory to the fpath path every time, which of course means that searching that path takes a little longer each time. No doubt this isn't the only place where you are doing that sort of thing, moreover.

You also do not understand autoloading correctly. As the doco states, autoloading of a function without a body happens the first time that the function is executed. Obviously, if the function is already loaded, and thus has a body, it does not get loaded again.

You need to unfunction the function before autoloading it again.

The sample .zshrc in the Z shell source contains an freload() function that does this very thing for all of the functions named as its arguments. It also does typeset -U path cdpath fpath manpath, notice.

Related Question