Transient prompt with Zsh
Vincent Bernat
4-minute read
Filed under
Powerlevel10k is a theme for Zsh. It contains some powerful features, is astoundingly fast, and easy to customize. I am quite amazed at the skills of its main author. Be sure to also have a look at Zsh for Humans, a complete Zsh configuration including this theme.
One of the nice features of Powerlevel10k is transient prompts: past prompts are reduced to a more minimal configuration to save space by removing unneeded information.

When it comes to configuring my shell, I still prefer writing and understanding each line going into it. Therefore, I am still building my Zsh configuration from scratch. Here is how I have integrated the above transient feature into my prompt.
The first step is to configure the appearance of the prompt in its
compact form. Let’s assume we have a variable, $_vbe_prompt_compact
set to 1 when we want a compact prompt. We use the
following function to define the prompt appearance:
_vbe_prompt () {
local retval=$?
# When compact, just time + prompt sign
if (( $_vbe_prompt_compact )); then
# Current time (with timezone for remote hosts)
_vbe_prompt_segment cyan default "%D{%H:%M${SSH_TTY+ %Z}}"
# Hostname for remote hosts
[[ $SSH_TTY ]] && \
_vbe_prompt_segment black magenta "%B%M%b"
# Status of the last command
if (( $retval )); then
_vbe_prompt_segment red default ${PRCH[reta]}
else
_vbe_prompt_segment green cyan ${PRCH[ok]}
fi
# End of prompt
_vbe_prompt_end
return
fi
# Regular prompt with many information
# […]
}
setopt prompt_subst
PS1='$(_vbe_prompt) '
Update (2021-05)
The following part has been rewritten to be more robust. The code is stolen from Powerlevel10k’s issue #888. See the comments for more details.
Our next step is to redraw the prompt after accepting a command. We wrap Zsh line editor into a function:1
_vbe-zle-line-init() {
[[ $CONTEXT == start ]] || return 0
# Start regular line editor
(( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[1]
zle .recursive-edit
local -i ret=$?
(( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[2]
# If we received EOT, we exit the shell
if [[ $ret == 0 && $KEYS == $'\4' ]]; then
_vbe_prompt_compact=1
zle .reset-prompt
exit
fi
# Line edition is over. Shorten the current prompt.
_vbe_prompt_compact=1
zle .reset-prompt
unset _vbe_prompt_compact
if (( ret )); then
# Ctrl-C
zle .send-break
else
# Enter
zle .accept-line
fi
return ret
}
zle -N zle-line-init _vbe-zle-line-init
That’s all!
One downside of using the powerline fonts is that it messes with copy/paste. As I am using tmux, I use the following snippet to work around this issue and use only standard Unicode characters when copying from the terminal:
bind-key -T copy-mode M-w \
send -X copy-pipe-and-cancel "sed 's/.*/%/g' | xclip -i -selection clipboard" \;\
display-message "Selection saved to clipboard!"
Copying and pasting the text from the screenshot above yields the following text:
14:21 % ssh eizo.luffy.cx
Linux eizo 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64
Last login: Fri Apr 23 14:20:39 2021 from 2a01:cb00:3f:b02:9db6:efa4:d85:7f9f
14:21 CEST % uname -a
Linux eizo 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 GNU/Linux
14:21 CEST %
Connection to eizo.luffy.cx closed.
14:22 % git status
On branch article/zsh-transient
Untracked files:
(use "git add <file>..." to include in what will be committed)
../../media/images/zsh-compact-prompt@2x.jpg
nothing added to commit but untracked files present (use "git add" to track)