The following is a function I use in my .zshrc
file to achieve some form of lazy evaluation.
local function lazy_load() {
local -xr thunk="$(cat)"
# (u) removes duplicates
local -xr triggers=(${(u)@})
# Only if length of triggers is greater than zero
# otherwise the function will immediately execute.
# (X) reports errors if any
if [ ${(X)#triggers} -gt 0 ]; then
eval " ${(@)triggers}() {
trigger=\"\$0\"
unfunction ${(@)triggers}
${thunk}
if type \$trigger > /dev/null; then
\$trigger \${@}
fi
}"
fi
}
Before I explain how the function works, let me just show you how to use it:
# lazy load sdkman
lazy_load 'sdk' 'kotlin' 'gradle' 'mvn' <<- 'EOF'
#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!
export SDKMAN_DIR="${HOME}/.sdkman"
[ -s "$SDKMAN_DIR/bin/sdkman-init.sh" ] && source "$SDKMAN_DIR/bin/sdkman-init.sh"
EOF
Now when I open a new shell and type which mvn
, I get the following:
mvn () {
trigger="$0"
unfunction sdk kotlin gradle mvn
export SDKMAN_DIR="${HOME}/.sdkman"
[ -s "$SDKMAN_DIR/bin/sdkman-init.sh" ] && source "$SDKMAN_DIR/bin/sdkman-init.sh"
if type $trigger > /dev/null
then
$trigger ${@}
fi
}
After I type mvn --help
and do another which mvn
, I get:
/home/chigozirim/.sdkman/candidates/maven/current/bin/mvn
Cool! 🚀
How it works
The function works in the following way:
- Read the contents of the shell command you would have had to execute when the
.zshrc
is read. This is read from stdin - Saves this
thunk
as a local variable within the function - Use
eval
to create a new function based on the triggers specified (zsh allows us to create a function with multiple names; how convienient!)- Note: The triggers should really just be commands that correspond to what is being loaded, but you can use anything you want.
- Any of the triggers/commands can now be used to cause the loading of the saved
thunk
- After being triggered, the generated function is forgotten and deletes the other triggers
- The generated function will now test if the trigger is an actual command, and try to execute it.
Profit! 💸
The inspiration to do this came from reading this blog post:
https://frederic-hemberger.de/notes/shell/speed-up-initial-zsh-startup-with-lazy-loading/
Hope this helps someone ❤️
P.S.
At the end of your .zshrc
, please add:
unfunction lazy_load
This is mostly for security 👮 due to the use of eval
👿.