Skip to content

Instantly share code, notes, and snippets.

@clux
Last active February 2, 2022 21:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save clux/864a4168712b9c28515a27de77f7c503 to your computer and use it in GitHub Desktop.
Save clux/864a4168712b9c28515a27de77f7c503 to your computer and use it in GitHub Desktop.
git-prompt-powerline-style
#!/bin/bash
export TERM=xterm-256color
show_cwd() {
local dir_limit="3"
local truncation="⋯"
local first_char
local part_count=0
local formatted_cwd=""
local dir_sep="  "
local tilde="~"
local cwd="${PWD/#$HOME/$tilde}"
# get first char of the path, i.e. tilde or slash
first_char=${cwd::1}
# remove leading tilde
cwd="${cwd#\~}"
while [[ "$cwd" == */* && "$cwd" != "/" ]]; do
# pop off last part of cwd
local part="${cwd##*/}"
cwd="${cwd%/*}"
formatted_cwd="$dir_sep$part$formatted_cwd"
part_count=$((part_count+1))
[[ $part_count -eq $dir_limit ]] && first_char="$truncation" && break
done
echo -e "$first_char$formatted_cwd"
}
show_git_differences() {
[[ $(git rev-parse --is-inside-work-tree 2>/dev/null) == true ]] || return 1
local unmerged=0 modified=0 has_untracked=0 added=0 is_clean=""
# shellcheck disable=SC2046
set -- $(git rev-list --left-right --count "@{upstream}...HEAD" 2>/dev/null)
local behind_count=$1
local ahead_count=$2
# Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), changed (T), Unmerged (U), Unknown (X), Broken (B)
while read -r line; do
case "$line" in
M*) modified=$(( modified + 1 )) ;;
U*) unmerged=$(( unmerged + 1 )) ;;
esac
done < <(git diff --name-status)
while read -r line; do
case "$line" in
*) added=$(( added + 1 )) ;;
esac
done < <(git diff --name-status --cached)
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
has_untracked=1
fi
local -r stashed=$(( $(git rev-parse --verify refs/stash 2> /dev/null | wc -l) ));
if [ $(( unmerged + modified + has_untracked + added )) -eq 0 ]; then
is_clean=1
fi
local s=""
# We always print at least one of these due to definition of is_clean
# Thus `s` always begins with a leading space
[[ $ahead_count -gt 0 ]] && s+=" ↑$ahead_count"
[[ $behind_count -gt 0 ]] && s+=" ↓$behind_count"
[[ $modified -gt 0 ]] && s+=" +$modified"
[[ $unmerged -gt 0 ]] && s+=" ✗$unmerged"
[[ $added -gt 0 ]] && s+=" ●" #$added
[[ $has_untracked -gt 0 ]] && s+=" …"
[[ $stashed -gt 0 ]] && s+=" ⚑" #$stashed
[[ $is_clean -gt 0 ]] && s+=" ✔"
# remove leading space
echo -e "$s" | sed 's/\s//'
}
prompt_git() {
local branchName=''
local s=''
# Check if the current directory is in a Git repository.
if git rev-parse --is-inside-work-tree &>/dev/null; then
s=$(show_git_differences)
# Get the short symbolic ref.
# If HEAD isn’t a symbolic ref, get the short SHA for the latest commit
# Otherwise, just give up.
branchName="$(git symbolic-ref --quiet --short HEAD 2> /dev/null || \
git rev-parse --short HEAD 2> /dev/null || \
echo '(unknown)')"
echo -e "  ${vcstxt}${branchName}  ${s}"
fi
}
prompt_lal() {
local branchName=''
local res
if res=$(lal env 2> /dev/null); then
echo -e " (${yellow}${res}${maintxt})"
fi
}
set_prompt() {
local -r rc=$? # Must save this
tput sgr0 # reset colors
# Solarized colors, taken from http://git.io/solarized-colors.
#local -r bold="\[$(tput bold)\]"
local -r reset="\[$(tput sgr0)\]"
#local -r black="\[$(tput setaf 0)\]"
#local -r blue="\[$(tput setaf 33)\]"
local -r cyan="\[$(tput setaf 38)\]"
#local -r green="\[$(tput setaf 64)\]"
#local -r orange="\[$(tput setaf 166)\]"
local -r purple="\[$(tput setaf 125)\]"
local -r red="\[$(tput setaf 124)\]"
#local -r violet="\[$(tput setaf 61)\]"
local -r white="\[$(tput setaf 15)\]"
local -r yellow="\[$(tput setaf 136)\]"
# Short indication for when your inline shell script is incomplete
PS2="${yellow}⚡${reset} "
# color info
# - bg color is the background color for each of the up to three chunks
# - txt colors are the colors used inside the chunks
# - fg color is only used to replace background colors between chunks
# -  separator takes last bg color as new fg color for one character only
# - reset only used at the end for partially transparent end separator
# First (optional) chunk with return code (if != 0)
local -r has_warn=$(( rc ))
local -r warnbg="\[$(tput setab 9)\]" # red-ish
local -r warnfg="\[$(tput setaf 9)\]"
local -r warntxt="${white}"
# Second (optional) chunk with hostname (when connected via ssh)
local -r has_host="${SSH_TTY}"
local -r hostbg="\[$(tput setab 235)\]" # light-grey
local -r hostfg="\[$(tput setaf 235)\]"
local -r hosttxt="${white}"
# Third (main mandatory) chunk with cwd and (optionally) git status
local -r mainbg="\[$(tput setab 232)\]" # dark-grey
local -r mainfg="\[$(tput setaf 232)\]"
local -r maintxt="${white}"
local -r vcstxt="${cyan}"
# Return code when non-zero
PS1="${mainbg}" # initialize bg for warn and no host blocks
if [[ $has_warn -gt 0 ]]; then
PS1+="${warnbg}${warntxt} ${rc} ${warnfg}"
if [[ -n $has_host ]]; then # shade for hostname block if on ssh
PS1+="${hostbg}"
else
PS1+="${mainbg}"
fi
fi
# Show the hostname when connected via SSH
if [[ -n $has_host ]]; then
PS1+="${hostbg}${hosttxt} ${HOSTNAME} ${hostfg}"
PS1+="${mainbg}"
fi
# Show CWD
PS1+="${maintxt} "
# Prepend (root) if root
if [ $EUID -eq 0 ]; then
"(${red}root${maintxt}) "
fi
PS1+="$(show_cwd)"
if [ -n "${VIRTUAL_ENV}" ]; then
# Append (pyv) if in venv
PS1+=" (${purple}pyv${maintxt})"
elif [ -d .lal ]; then
# Append lal environment if inside a lal repo
PS1+="$(prompt_lal)"
fi
# Show git status
PS1+="${mainbg}"
PS1+="$(prompt_git) " # git repository (fast and detailed)
# Make last separator half-transparent
PS1+="${reset}${mainfg}${reset} "
}
PROMPT_COMMAND='set_prompt'
@clux
Copy link
Author

clux commented Sep 20, 2016

Look

prompt

Installation:

Note that the powerline-fonts in arch and fonts-powerline packages in ubuntu/debian do not include the hacked versions of the fonts correctly.

Put file under home as .prompt and source ~/.prompt in your ~/.bashrc.

Font selection

The font you want is generally DejaVu Sans Mono for Powerline unless you use guake, gnome-term, or the ubuntu terminal in which case you want Roboto Mono for Powerline.

Where to set the font

Typically either done by setting it in ~/.Xresources for certain terminals, or in the operating system gui options elsewhere for other terminals:

  • guake (set in guake options - don't use system wide font and select the font)
  • rxvt (set in ~/.Xresources (see below))
  • gnome-terminal (set somewhere in its preferences)
  • ubuntu terminal (right click -> profiles -> profile preferences, swap font from system default)

Xresources example

This is how you set it for rxvt:

URxvt.font:                 xft:DejaVu Sans Mono for Powerline:size=16:Regular
URxvt.boldFont:             xft:DejaVu Sans Mono for Powerline:size=16:Bold
URxvt.italicFont:           xft:DejaVu Sans Mono for Powerline:size=16:Italic
URxvt.boldItalicFont:       xft:DejaVu Sans Mono for Powerline:size=16:Bold:Italic

put that in your ~/.Xresources and run xrdb -merge ~/.Xresources.

more xresouces example usage are available here, otherwise there are good docs on the arch wiki.

Common issues

  • If you failed to install the font correctly, you will not be able to see the special fat arrow character: "" and the thin "" arrow.
  • If you failed to select the right font for your terminal, the fat arrow character will be slightly misaligned with the background

@clux
Copy link
Author

clux commented May 8, 2017

Added lal integration to it today.
lalprompt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment