Gilles Quénot
Gilles Quénot

Reputation: 185073

Colorize git branch name depending of the state using 'vcs_info'

I'm new to (I'm a long time user) I have a custom prompt (made with different sources mixed) with a specific part for git.: enter image description here

I would like to have: - (master) in green if git status says 'clean' - (master) in red if git status says 'not clean'

I don't know how can I do it, I'll very appreciate if someone knows.

My .zshrc :

# (...)
# Easy colors in ZSH scripting
autoload -U colors && colors

setopt prompt_subst
autoload -Uz vcs_info

function +vi-git-untracked() {
  if [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' ]] && \
  [[ $(git ls-files --other --directory --exclude-standard | sed q | wc -l | tr -d ' ') == 1 ]] ; then
  hook_com[unstaged]+='%F{red}??%f'
fi
}

# Show remote ref name and number of commits ahead-of or behind
function +vi-git-st() {
  local ahead behind remote
  local -a gitstatus

  # Are we on a remote-tracking branch?
  remote=${$(git rev-parse --verify ${hook_com[branch]}@{upstream} \
    --symbolic-full-name 2>/dev/null)/refs\/remotes\/}

  if [[ -n ${remote} ]] ; then
    ahead=$(git rev-list ${hook_com[branch]}@{upstream}..HEAD 2>/dev/null | wc -l)
    (( $ahead )) && gitstatus+=( "${c3}+${ahead}${c2}" )

    behind=$(git rev-list HEAD..${hook_com[branch]}@{upstream} 2>/dev/null | wc -l)
    (( $behind )) && gitstatus+=( "${c4}-${behind}${c2}" )

    hook_com[branch]="${hook_com[branch]}${(j:/:)gitstatus}"
  fi
}

# Show count of stashed changes
function +vi-git-stash() {
  local -a stashes

  if [[ -s ${hook_com[base]}/.git/refs/stash ]] ; then
    stashes=$(git stash list 2>/dev/null | wc -l)
    hook_com[misc]+="%f (%F{1}STASH=${stashes}%f)"
  fi
}

zstyle ':vcs_info:*' enable git
zstyle ':vcs_info:git*:*' get-revision true
zstyle ':vcs_info:git*:*' check-for-changes true

#zstyle ':vcs_info:*' stagedstr '%F{3}A%f' 
zstyle ':vcs_info:*' stagedstr '%F{3}A%f' 
zstyle ':vcs_info:*' unstagedstr 'M' 
zstyle ':vcs_info:*' actionformats '%f(%F{2}%b%F{3}|%F{1}%a%f)  '
# format the git part
zstyle ':vcs_info:*' formats '%f(%b) %F{2}%c%F{3}%u%m%f'
zstyle ':vcs_info:git*+set-message:*' hooks git-untracked git-stash git-st
zstyle ':vcs_info:*' enable git 
#zstyle ':vcs_info:*+*:*' debug true

# same as PROMPT_COMMAND in bash
precmd () { vcs_info }
# improve by putting branch name is red if branch is not clean
# conditional on exit code: %(?..%F) on affiche le code de retour uniquement si il est > 0
RPROMPT='%(?..[%F{red}ERROR%F{white}:%F{red}%?%f])'
PROMPT='%F{green}%n%F{orange}@%F{yellow}%m:%F{7}%3~%f ${vcs_info_msg_0_} %f%# '

Upvotes: 4

Views: 3990

Answers (1)

AnimiVulpis
AnimiVulpis

Reputation: 2726

My answer will be based on my personal preference and the example directory from zsh-users on how to use vcs_info

I would suggest you take the approach explained in Episode III in the vcs_info-examples file you can find here.

precmd() {
    # As always first run the system so everything is setup correctly.
    vcs_info
    # And then just set PS1, RPS1 and whatever you want to. This $PS1
    # is (as with the other examples above too) just an example of a very
    # basic single-line prompt. See "man zshmisc" for details on how to
    # make this less readable. :-)
    if [[ -n ${vcs_info_msg_0_} ]]; then
        # Oh hey, nothing from vcs_info, so we got more space.
        # Let's print a longer part of $PWD...
        PS1="%5~%# "
    else
        # vcs_info found something, that needs space. So a shorter $PWD
        # makes sense.
        PS1="%3~${vcs_info_msg_0_}%# "
    fi
}

Going on from that (and your provided code snippets) I would do it like this:

precmd() {
    vcs_info
    if [[ -n ${vcs_info_msg_0_} ]]; then
        # vcs_info found something (the documentation got that backwards
        # STATUS line taken from https://github.com/robbyrussell/oh-my-zsh/blob/master/lib/git.zsh
        STATUS=$(command git status --porcelain 2> /dev/null | tail -n1)
        if [[ -n $STATUS ]]; then
            PROMPT='%F{green}%n%F{orange}@%F{yellow}%m:%F{7}%3~%f %F{red}${vcs_info_msg_0_} %f%# '
        else
            PROMPT='%F{green}%n%F{orange}@%F{yellow}%m:%F{7}%3~%f %F{green}${vcs_info_msg_0_} %f%# '
        fi
    else
        # nothing from vcs_info
        PROMPT='%F{green}%n%F{orange}@%F{yellow}%m:%F{7}%3~%f %# '
    fi
}

A few notes:

  • The first if is wrong in the example file
  • The STATUS definition is taken from oh-my-zsh
  • You could change the zstyle if the STATUS is dirty instead
  • You can improve performance of the git status part by using flags like --untracked-files[=<mode>] --ignore-submodules[=<when>] for git-status

I hope that helps

Upvotes: 5

Related Questions