Zsh prompt with asynchronous Git status
Vincent Bernat
Zsh ships vcs_info
, a function fetching information about the
VCS state for the current directory and populating a variable that can
be used in a shell prompt. It supports several VCS, including Git and
SVN. Here is an example of configuration:
autoload -Uz vcs_info zstyle ':vcs_info:*' enable git () { local formats="${PRCH[branch]} %b%c%u" local actionformats="${formats}%{${fg[default]}%} ${PRCH[sep]} %{${fg[green]}%}%a" zstyle ':vcs_info:*:*' formats $formats zstyle ':vcs_info:*:*' actionformats $actionformats zstyle ':vcs_info:*:*' stagedstr "%{${fg[green]}%}${PRCH[circle]}" zstyle ':vcs_info:*:*' unstagedstr "%{${fg[yellow]}%}${PRCH[circle]}" zstyle ':vcs_info:*:*' check-for-changes true } add-zsh-hook precmd vcs_info
You can use ${vcs_info_msg_0_}
in your prompt to display the current
branch, the presence of staged and unstaged changes, as well as the
ongoing action.1 Have a look at the documentation for more
details.
On large repositories, some information are expensive to fetch. While
vcs_info
queries Git, interactions with Zsh are stuck. A possible
solution is to execute vcs_info
asynchronously with zsh-async.
The first step is to define a wrapper around vcs_info
. This
wrapper will run into a separate process and should communicate its
result using the standard output. It expects the current directory as
its first argument.
_vbe_vcs_info() { cd -q $1 vcs_info print ${vcs_info_msg_0_} }
The second step is to define a worker, vcs_info
, and attach a
function to handle the result received from the wrapper. The
registered function calls zle reset-prompt
to force a refresh of the
prompt with the updated information from ${vcs_info_msg_0_}
.
source $ZSH/.../async.zsh async_init async_start_worker vcs_info async_register_callback vcs_info _vbe_vcs_info_done _vbe_vcs_info_done() { local stdout=$3 vcs_info_msg_0_=$stdout zle reset-prompt }
The last step is to schedule the wrapper function in the worker
queue before displaying the prompt. This replaces the synchronous
invocation of vcs_info
:
_vbe_vcs_precmd() { async_flush_jobs vcs_info async_job vcs_info _vbe_vcs_info $PWD } add-zsh-hook precmd _vbe_vcs_precmd
That’s it!
Without relying on vcs_info
, it should be possible to have a better
experience by fetching the current branch name before retrieving the
more expensive information. However, without much effort, this simple
integration can make your prompt snappier! Have a look at the
complete code: it contains some small enhancements.
-
Actions include “merge,” “rebase” and “bisect.” ↩︎