Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I'm trying to configure bash to display the current git branch, based off the example here, but I can't figure out how to get bash to stop escaping the colour strings. Everything I try results in the colour strings being outputted in the prompt line.

My prompt looks like this:

valorin@gandalf:~/workspace/wyoa (\[\033[0;31m\]master\[\033[00m\])$

The relevant section in .bashrc:

##
# Custom Git Branch name in prompt
##
function git_prompt {
    if !  git rev-parse --git-dir > /dev/null 2>&1; then
        return 0
    fi

    git_branch=$(git branch 2>/dev/null| sed -n '/^\*/s/^\* //p')

    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
        if git diff --quiet 2>/dev/null >&2; then
            echo " (\[\033[0;31m\]$git_branch\[\033[00m\])"
        else
            echo " (\[\033[0;33m\]$git_branch\[\033[00m\])"
        fi
    else
        if git diff --quiet 2>/dev/null >&2; then
            echo " ($git_branch)"
        else
            echo "($git_branch*)"
        fi
    fi
}


if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$(git_prompt)$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(git_prompt)\$ '
fi

Any help would be appreciated.

share|improve this question
    
The first thing that comes to mind: have you tried escape the "\" ? Like \\[\\033.... Or delete it at all maybe. –  int_ua Jul 14 '12 at 6:17
add comment

1 Answer

up vote 2 down vote accepted

You cannot have a function that outputs both text and color, in the bash prompt. Everything the function outputs gets taken literally. I suggest going about it a different way.

First off, what the prompt tries to do, is check if you're in a git tree, and if so, add a colored (branch) to the prompt. Instead of checking everytime the prompt is printed, you really only need to do that check whenever you change directory, so we can override the only three commands that can change directory to set the variable git_branch to the name of the current branch, if any.

cd() {
    builtin cd "$@" || return
    git_branch=$(git branch 2>/dev/null|sed -n '/^[*] /s///p') || true
}
pushd() {
    builtin pushd "$@" || return
    git_branch=$(git branch 2>/dev/null|sed -n '/^[*] /s///p') || true
}
popd() {
    builtin popd "$@" || return
    git_branch=$(git branch 2>/dev/null|sed -n '/^[*] /s///p') || true
}

Next up, check if stderr is a terminal, and set colors with tput

user_color= dir_color= git_color= reset=
if [[ -t 2 ]]; then
    user_color=$(tput setaf 2; tput bold)
    dir_color=$(tput setaf 4; tput bold)
    reset=$(tput sgr0)
fi

And a function that outputs one of two colors based on whether there are changes or not

_git_color() {
    [[ $git_branch && -t 2 ]] || return
    if git diff --quiet >/dev/null 2>&1; then
        tput setaf 1
    else
        tput setaf 3
    fi
}

Now, putting the prompt together. This is a bit cumbersome as some variables should be expanded at assignment (now), while some should be expanded when the prompt is printed, so we need to alternate quotes, plus it gets rather long. Using an array for this should help keep the overview

prompt=(
    "\[$user_color\]" '\u@\h' "\[$reset\]"
    : "\[$dir_color\]" '\w' "\[$reset\]"

    '${git_branch:+ (}'
    '\[$(_git_color)\]' '$git_branch' "\[$reset\]"  
    '${git_branch:+)}'

    '\$ '
)

I ommited the debian_chroot stuff here, I've never needed it myself, you can of course add that if you want. Finally, join the prompt array and clean up the variables we no longer need.

printf -v PS1 %s "${prompt[@]}"
unset user_color dir_color reset prompt
share|improve this answer
    
Wow, thanks :) One comment though, you've overlooked the case when you change branches in git, it will keep displaying the branch from when you first changed into the directory... –  Valorin Jul 14 '12 at 14:01
    
@Valorin Ah, I'm not too experienced with git, so I indeed didn't think of that. Then you could either override the git command in addition, something like git() { local r; command git "$@"; r=$?; [[ $1 = branch ]] && git_branch=$(...); return "$r"; } , or drop all the functions and do the git_branch assignment in PROMPT_COMMAND instead. –  geirha Jul 14 '12 at 18:49
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.