07 Apr 2023To pad a string with leading spaces in zs, you can use ${(r(15)( ))variableName)
.
r(15)
pads on the r
ight (use l
for l
eft padding)- The
15
defines the maximum length of the string ( )
defines the character to use for padding (here, a
space)
03 Apr 2023Commands like sudo
take other commands as input and run them in a specific context. I also have a command similar, called lazyloadNvm
that runs nvm use
when needed.
I wanted zsh to suggest completion for the passed commands instead of completion for the initial command (sudo
or lazyloadNvm
).
The solution was to create a _nvm-lazyload
comdef file like this:
#compdef
function _nvm-lazyload() {
# Remove the first word (lazyloadNvm)
shift words
# Update which word is currently being focused for tab completion
(( CURRENT-- ))
# Re-run completion with the new input
_normal
}
shift words
removes the first element of the words
array (sudo git status
becomes git status
)(( CURRENT-- ))
decreases the index of the word focused by tab completion. Updating words
doesn't automatically updates CURRENT
_normal
re-runs the completion functions with the current words
and CURRENT
context.
03 Apr 2023If I add too much code in my .zshrc
, my zsh takes longer to load. As I use a lot of different terminal windows (splitting one main tmux window), I want those split to happen quickly. This is why I'm trying very hard to keep the loading time of zsh under 150ms.
Hyperfine
One way to evaluate the current loading speed and track potential regressions and improvement is to use hyperfine
hyperfine --warmup 3 "zsh -i -c exit"
This will benchmark how long it will take on average to load zsh. The -i
makes it load in interactive mode (so, by sourcing ~/.zshrc
), and -c exit
makes it execute the exit command.
Note that if you have any commands running asynchronously in the background (like prompt optimization), they will purposefuly not be included in the time.
zprof
The other debugging tool is to use zprof
, which is the zsh profiler.
Include zmodload zsh/zprof
at the top of your ~/.zshrc
file, and zprof
at the bottom. Next time you'll open zsh, you'll see a table like this:
num calls time self name
-----------------------------------------------------------------------------------
1) 1 240,22 240,22 65,76% 240,22 240,22 65,76% oroshi_tools_pyenv
2) 1 72,98 72,98 19,98% 72,98 72,98 19,98% oroshi_theming_index
3) 1 14,77 14,77 4,04% 14,77 14,77 4,04% compinit
4) 1 14,12 14,12 3,86% 14,12 14,12 3,86% oroshi-completion-styling
5) 1 5,85 5,85 1,60% 5,85 5,85 1,60% oroshi_tools_fzf
6) 1 4,95 4,95 1,35% 4,95 4,95 1,35% _zsh_highlight_bind_widgets
7) 1 4,56 4,56 1,25% 3,01 3,01 0,82% oroshi_tools_z
8) 1 2,27 2,27 0,62% 2,27 2,27 0,62% _zsh_highlight_load_highlighters
9) 2 2,17 1,09 0,60% 2,17 1,09 0,60% promptinit
10) 1 2,10 2,10 0,58% 2,10 2,10 0,58% oroshi_tools_ls
11) 7 1,51 0,22 0,41% 1,51 0,22 0,41% add-zsh-hook
12) 7 0,64 0,09 0,17% 0,64 0,09 0,17% compdef
13) 2 0,63 0,31 0,17% 0,63 0,31 0,17% is-at-least
14) 1 14,85 14,85 4,07% 0,09 0,09 0,02% oroshi_completion_compinit
This shows where most of the time is spend, the number of times a specific function is called, and if you scroll down you'll see details of the stacktrace of each sub command.
In this example, it is clear that my oroshi_tools_pyenv
method is too slow, and I need to optimize it.
Note that this only tracks the time to run functions, not the time to source files, so if you need to benchmark a specific sourced file, wrap it in a function that you invoke immediatly.
23 Mar 2023To get only parts of a specific string in zsh, you can use the ${var:start:stop}
syntax.
If stop
is omitted, it will cut until the end of the string. You can also pass negative values.
20 Mar 2023To get the path of the folder of the script currently running in zsh, use ${0:a:h}
. $0
is the path to the currently running script, a
forces it to absolute, and h
to keep the head (the folder).
This is useful when you need to reference scripts that are not in your $PATH
, but are stored close to your initial script.