cat /var/log/life

An Asynchronous Shell Prompt

A blocking shell prompt that is slow can lead to a pretty terrible user
experience.

Above is a demo of a stock oh-my-zsh install (left) compared to an
asynchronously updated prompt (right). Everything is running on one machine, in
parallel, using tmux pane synchronization to send the same exact input
at the same exact time to both shells. Observe that the shell on the left
blocks the user from executing commands, while the shell on the right
asynchronously updates the prompt, allowing the user to run commands without
delay.

Causes

Shell prompts are usually configured to display contextual information such as
the current directory, username, hostname, and so on. It is quite common for
users to include the version control system status in the prompt as well. Some
of the information that appears in the prompt can be computed almost
instantaneously. For example, computing the name of the current working
directory does not take all that much time.

On the other hand, some information can take much longer to compute, sometimes
on the order of several seconds, as shown above. For example, determining the
version control system status can take quite a long time, because it usually
requires a traversal of the entire directory tree from the root of the
repository. If the metadata is not already in the buffer cache, it can take a
ton of time, and even when the information is in the cache, the traversal is
still noticeably time-consuming.

Programmed in the straightforward way, complex prompts can take up to a couple
seconds to render, degrading the experience of using a terminal. Until the
prompt is computed, the shell blocks and prevents the user from running
commands.

A Non-blocking Prompt

This problem can be solved using an asynchronously updated shell prompt, using
a technique that is fairly straightforward to implement in zsh. The shell
supports displaying a prompt on both the left and right sides of the screen by
setting PROMPT and RPROMPT. Separating information between the two parts,
information that is slow to update can be kept in the right side prompt. The
shell can be configured to update the left prompt synchronously and update the
right prompt asynchronously, providing a smooth user experience.

The general method for updating the prompt asynchronously is to fork off
processes to compute the information in the background and send a signal to the
shell once the information is ready. Then, the shell can read in and display
this information, updating the prompt.

In zsh, the precmd function is executed before displaying each prompt, so
this can be used to fork off a background process.

The following is example code that can be used in ~/.zshrc to implement an
asynchronous prompt. In the example, prompt_cmd is the command that generates
the content to be displayed in PROMPT, and rprompt_cmd is the command that
generates the content to be displayed in RPROMPT.