Skip to content

Instantly share code, notes, and snippets.

@clux
Last active February 2, 2022 21:20
Show Gist options
  • 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 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