Customize your ZSH-Prompt for Git and SSH [Update 1]

12 Jun

The Z-Shell is one of the most powerfull shells I know. Why not customize it to your needs? Mine looks like this:

zsh

Here are some explanations of the prompt:

  1. This is the default Prompt. It contains the username (cyan), the current directory (magenta) and the number of the next history entry (repeat cd .env by typing !2090). The green arrow means that the last command ended with the return code 0
  2. We switched into an SVN repository. The first line contains the name of the repository (yellow), the current branch (green) and the commit number (blue).
  3. The second line is merle the same as in 1…
  4. … but it now only contains the path inside the repository (magenta).
  5. This is a git repository; the information is the same:repository name, branch name and commit id
  6. Changes are indicated as circles: untracked is red, changes is yellow, staged is green
  7. Outside a repository, the full pathname is shown
  8. If we are on a remote machine (detemined by checking SSH_CLIENT) the hostname is added (yellow)
  9. The state of the battery and the result of the last command (either :-) or :-( is shown on the right)

I have to give some credits. Important parts and ideas are explained in a open source press book (german) and two blog posts from Bart Trojanowski and Matija Šuklje.

So here is the code:

# customize prompts
autoload -U promptnl
autoload -Uz vcs_info
setopt prompt_subst #allow function calls in prompt
 
if [[ $UID != 0 ]]; then
        prompt_arrow=→
else
        prompt_arrow=⇒
fi
 
if [[ -z "$SSH_CLIENT" ]]; then
        prompt_host=""
else
        prompt_host=%{$fg_bold[white]%}@%{$reset_color$fg[yellow]%}$(hostname -s)
fi
 
common_fmt_prompt_pre="%{$fg[cyan]%}%n%{$fg_bold[white]%}${prompt_host}:%{$fg_bold[magenta]%}"
common_fmt_prompt_post="%{$fg[white]%}[%!]%{$fg_bold[white]%}%1(j. (%j%).)%{%(?.$fg_bold[green].$fg_bold[red])%}${prompt_arrow}%{$reset_color%} "
common_fmt_post="%{$reset_color%}"$'\n┕'"${common_fmt_prompt_pre}%S ${common_fmt_prompt_post}"
native_prompt="${common_fmt_prompt_pre}%~ ${common_fmt_prompt_post}"
 
zstyle ':vcs_info:*:prompt:*' check-for-changes true
zstyle ':vcs_info:*:prompt:*' stagedstr     "%{$fg_bold[green]●%}"
zstyle ':vcs_info:*:prompt:*' unstagedstr   "%{$fg_bold[yellow]●%}"
zstyle ':vcs_info:*:prompt:*' nvcsformats   "${native_prompt}"
zstyle ':vcs_info:*:prompt:*' branchformat  "%b"
zstyle ':vcs_info:*' enable git svn
zstyle ':vcs_info:*:prompt:*' get-revision 'true'
 
function precmd  {
        if [[ -n "$UPDATE_PROMPT" || -n "$UPDATE_PROMPT_ONCE" ]]; then
                if [[ -z $(git ls-files --other --exclude-standard -- $(git rev-parse --show-cdup 2>/dev/null) 2>/dev/null) ]] {
                        untracked=''
                } else {
                        untracked="%{$fg_bold[red]%}●"
                }
                common_fmt_pre="┍%{$fg[red]%}%s%{$fg[white]%}:%{$fg[yellow]%}%r%{$fg[white]%}[%{$fg_bold[green]%}%b%{$fg[white]%}:%{$fg[blue]%}%i%{$reset_color$fg[white]%}] %c%u$untracked%{$reset_color%}"
 
                zstyle ':vcs_info:*:prompt:*' actionformats "${common_fmt_pre} $fg[cyan](%a) ${common_fmt_post}"
                zstyle ':vcs_info:*:prompt:*' formats       "${common_fmt_pre} ${common_fmt_post}"
 
                vcs_info 'prompt'
                UPDATE_PROMPT_ONCE=
        fi
}
 
UPDATE_PROMPT=1
faster() { UPDATE_PROMPT= }
slower() { UPDATE_PROMPT=1 }
function u {
        UPDATE_PROMPT_ONCE=1
}
 
chpwd_functions+=('u')
 
PROMPT='${vcs_info_msg_0_}'
 
setopt transient_rprompt #remove rprompt after enter
if type test >/dev/null && acpi -b 2>/dev/null | grep 'Battery 0' >/dev/null; then
        RPROMPT='[$(acpi -b | sed "s/.* \([0-9]\+\)%.*/\1/")%%] '"%(?.%{$fg_bold[green]%}:-%).%{$fg_bold[red]%}:-()%{$reset_color%}"
else
        RPROMPT="%(?.%{$fg_bold[green]%}:-%).%{$fg_bold[red]%}:-()%{$reset_color%}"
fi
SPROMPT="zsh: correct %R to %r? ([Y]es/[No]/[E]dit/[A]bort) "

The lines 6-16 are workarounds, because %m and (!.⇒.→) did not work correctly with vcs_info (i.e. vcs_info stores different information in %m). The lines 18-29 define most of the left prompt. The function precmd is executed before each command and updates the variable parts of the prompt. The lines 48-55 are for slower environments like cygwin: typing faster does not update the prompt until you change your directory or type u, while slower restores the default behaviour. Line 57 defines the result of vcs_info_msg_0_ as your prompt (vcs_info constructs this string).

The Lines 59-64 define the right part of the prompt (item 9 in the screenshot). The battery state is only shown if a battery exists.

Take this as an idea what is possible with your prompt. If you add other cool features or find faster solutions, just drop me a line 😉

Update 1: Changed condition in line 33 so that the whole repository is scanned for new files.

2 Replies to “Customize your ZSH-Prompt for Git and SSH [Update 1]

  1. Hallo, ich bin an deiner zsh prompt Konfiguration interessiert.
    Leider fehlen mir vielleicht einige dependencies an fonts (powerline?).
    Waere cool wenn du einmal deine prompt Konfiguration neu hochladen koenntest, zumindest sehe ich in deiner Box mit dem Code in der precmd() methode diverse Sonderzeichen, von welchen ich nicht glaube das diese Teil der eigentlichen prompt Konfiguration seien soll („â•”).

    Liebe Gruesse

    • Hallo,

      freut mich, dass du über den Artikel gestolpert bist! Ich habe ihn repariert. Da ist irgendwas bei der Migration des Blogs kaputtgegangen.

      Der hier gezeigte Prompt verwendet zwar ein paar UTF-8 Zeichen, dass sollte aber eigentlich in jeder modernen Schriftart vorhanden sein.

      Beachte, dass der Artikel von 2012 ist. Mittlerweile ist einiges passiert. Ich konfiguriere meine Shells (ich nutze immer noch die ZSH 😉 ) nicht mehr von Grund auf selbst, sondern nutze dazu Vorarbeit von anderen. Im Kern passiert natürlich am Ende immer noch das gleiche und wenn man alles mal selbst gemacht hat, dann versteht man besser, was im Hintergrund passiert.

      Heute verwende ich als Prompt Powerlevel10k: https://github.com/romkatv/powerlevel10k#getting-started
      Dieser Prompt setzt allerdings wirklich eine benutzerdefinierte Schriftart voraus. Diese gibt es auf https://www.nerdfonts.com/font-downloads

      Eine kurze Installationsanleitung gibt es auf im ersten Link (wenn du keine weiteren Konfigurations-Frameworks verwendest, empfehle ich die Installations-Methode „manual“).

      Da ich nicht nur einen Prompt haben möchte, sondern auch diverse weitere Features nutzen will, nutze ich prezto (https://github.com/sorin-ionescu/prezto/). Das ist kompromisslos schnell, allerdings passiert da im Moment nicht viel. Das ist für mich okay, es kann alles, was man sich wünscht. Eine bekannte Alternative ist oh-my-zsh (https://github.com/robbyrussell/oh-my-zsh/). Beide können Powerlevel10k konfigurieren, sie bringen aber auch zahlreiche weitere Konfigurationsmethoden mit.
      Wenn du tief in Shells eintauchen willst, würde ich dir empfehlen, eines dieser beiden Projekte anzusehen.

      Viele Grüße
      Jochen

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert