From 13f5ecd846e6a891690a6fcb477d7d719020e1a4 Mon Sep 17 00:00:00 2001 From: Thomas Preisner Date: Sun, 18 Sep 2022 18:01:32 +0200 Subject: [PATCH] zsh: display some info about vcs in current directory --- zsh/prompt.zsh | 27 +++++++++++++++----- zsh/vcs.zsh | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ zshrc | 1 + 3 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 zsh/vcs.zsh diff --git a/zsh/prompt.zsh b/zsh/prompt.zsh index c53daf9..1e9b4a7 100644 --- a/zsh/prompt.zsh +++ b/zsh/prompt.zsh @@ -18,6 +18,9 @@ setopt transient_rprompt # only show the rprompt on the current prompt # ===== set the prompt zshrc_prompt_precmd() { + # call vcs_info before every prompt + vcs_info + # regex to remove all zerospace elements. Used to calculate the width of # the top prompt. local zero='%([BSUBfksu]|([FB]|){*})' @@ -52,6 +55,14 @@ zshrc_prompt_precmd() { # username, green for normal users, red for root local user="%(!.%F{red}.%F{green})%n%f" + # information about unstaged/staged changes in VCS in current directory + local vcs="${vcs_info_msg_0_}" + local vcs_width=${#${(S%%%)vcs//$~zero/}} + if [[ $vcs_width -ne 0 ]]; then + # add brackets if vcs is non-empty + vcs="${bracket_open}${vcs}${bracket_close}" + fi + # hostname, underlined if running on a remote system through SSH local host="%F{green}%m%f" if [[ -n $SSH_CONNECTION ]]; then @@ -95,6 +106,7 @@ zshrc_prompt_precmd() { # combine them to create the prompt local top_left="" local top_right="${bracket_open}${time}${bracket_close}" + local top_middle="${vcs}" local bottom_left="${bracket_open}${user}%F{green}@%f${host}${bracket_close}${exitcode}${separator}${symbol}" local bottom_right= @@ -109,15 +121,16 @@ zshrc_prompt_precmd() { local width_top_prefix=${#${(S%%%)top_prefix//$~zero/}} local width_top_suffix=${#${(S%%%)top_suffix//$~zero/}} local width_top_left=${#${(S%%%)top_left//$~zero/}} + local width_top_middle=${#${(S%%%)top_middle//$~zero/}} local width_top_right=${#${(S%%%)top_right//$~zero/}} # calculate the maximum width of ${top_left}: - # (-4 for brackets, -1 as spacing between top_left and top_right) + # (-4 for brackets and as spacing between top_left, top_middle and top_right) local top_left_width_max=$(( COLUMNS - $width_top_prefix - - $width_top_left - 4 - - 1 - - $width_top_right + - $width_top_left - 2 + - $width_top_middle + - $width_top_right - 2 - $width_top_suffix )) @@ -129,12 +142,14 @@ zshrc_prompt_precmd() { local width=$(( COLUMNS - width_top_prefix - width_top_left + - width_top_middle - width_top_right - width_top_suffix )) - local top_separator="%F{cyan}${(pl:${width}::$dash:)}%f" + local top_left_separator="%F{cyan}${(pl:$((width / 2))::$dash:)}%f" + local top_right_separator="%F{cyan}${(pl:$((width / 2 + width % 2))::$dash:)}%f" - PROMPT="${top_prefix}${top_left}${top_separator}${top_right}${top_suffix} + PROMPT="${top_prefix}${top_left}${top_left_separator}${top_middle}${top_right_separator}${top_right}${top_suffix} ${bottom_prefix}${bottom_left} " RPROMPT="${bottom_right}${bottom_suffix}" diff --git a/zsh/vcs.zsh b/zsh/vcs.zsh new file mode 100644 index 0000000..ef69f50 --- /dev/null +++ b/zsh/vcs.zsh @@ -0,0 +1,69 @@ +autoload -Uz vcs_info + +# only look for certain VCS +zstyle ':vcs_info:*' enable git + +# check repository for changes so that they can be used in %u/%c +# (this might be slow for bigger repositories) +zstyle ':vcs_info:*' check-for-changes yes + +# display current branch (%b -> green), unstaged + staged changes (%u/%c -> green), +# VCS (%s -> blue) and custom messages (%m). +zstyle ':vcs_info:*' formats \ + "%F{green}%b%u%c%F{default}:%F{blue}%s%F{default}%m" +# during special actions (e.g. merge, rebase), also display those (%a -> red) +zstyle ':vcs_info:*' actionformats \ + "(%F{green}%b%u%c%F{default}/%F{red}%a%F{default}:%F{blue}%s%F{default}%m)" + +# set style for formats/actionformats when unstaged (%u) and staged (%c) +# changes are detected in the repository +# (check-for-changes must be true for this to work) +zstyle ':vcs_info:*' unstagedstr '¹' +zstyle ':vcs_info:*' stagedstr '²' + +# force vcs_info to be run. this prevents running it later for performance reasons. +# default to run vcs_info. will be prevented from running later if possible +# (for speedup) +zshrc_force_run_vcs_info=1 + +# cache data +zstyle ':vcs_info:*+pre-get-data:*' hooks pre-get-data ++vi-pre-get-data() { + # only git and mercurial support and need caching. ignore all other VCS + [[ $vcs != git && $vcs != hg ]] && return + + # run vcs_info on startup, on directory change (or for other custom reasons) + if [[ -n $zshrc_force_run_vcs_info ]]; then + zshrc_force_run_vcs_info= + return + fi + + # don't run vcs_info by default to speed up the shell + ret=1 + case $(fc -ln $(($HISTCMD-1))) in + # vcs status might need an update after running git/hg + git* | g\ *) + ret=0 + ;; + esac +} + +# display stash count +function +vi-git-stashes() { + if [[ -s ${hook_com[base]/.git/refs/stash} ]]; then + local -a stashes + # "grep" output of git stash list via (M) and :#(...) + stashes=( ${(M)${(f)"$(git stash list 2>/dev/null)"}:#(*WIP*)} ) + + if [[ ${#stashes} -gt 0 ]]; then + hook_com[misc]+=" %F{yellow}${#stashes}s%F{default}" + fi + fi +} +zstyle ':vcs_info:git*+set-message:*' hooks git-stashes + +# enforce running vcs_info when changing directory +prompt_chpwd() { + zshrc_force_run_vcs_info=1 +} +chpwd_functions+=(prompt_chpwd) diff --git a/zshrc b/zshrc index d147f0b..a0c35fb 100644 --- a/zshrc +++ b/zshrc @@ -2,6 +2,7 @@ source ~/.zsh/keybindings.zsh source ~/.zsh/setopt.zsh source ~/.zsh/general.zsh +source ~/.zsh/vcs.zsh source ~/.zsh/prompt.zsh source ~/.zsh/completion.zsh source ~/.zsh/history.zsh