123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- #!/usr/bin/env bash
- # _____ _ _
- # | __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
- # | __| _| -_| -_| . | . | | . | . | | -_|
- # |__| |_| |___|___|___|___|_|_|_|___|___|_|_|___|
- #
- # Freedom in the Cloud
-
- # Based on https://github.com/undu/bash-powerline
-
- __powerline() {
-
- # User config variables,
- # it's recommended to override those variables through .bashrc or similar
- #
- # Use powerline mode
- # readonly POWERLINE_FONT=''
- #
- # Always show user in the prompt
- # readonly SHOW_USER=''
- #
- # Never show a default user
- # readonly DEFAULT_USER='user'
-
- # Default background and foreground ANSI colours
- readonly DEFAULT_BG=0
- readonly DEFAULT_FG=7
-
- # Max length of full path
- readonly MAX_PATH_LENGTH=30
-
- # Unicode symbols
- if [ -z "${POWERLINE_FONT+x}" ]; then
- readonly GIT_BRANCH_SYMBOL=''
- else
- readonly GIT_BRANCH_SYMBOL=''
- fi
- readonly GIT_BRANCH_CHANGED_SYMBOL=''
- readonly GIT_NEED_PUSH_SYMBOL=''
- readonly GIT_NEED_PULL_SYMBOL=''
-
- # Powerline symbols
- readonly BLOCK_START=''
-
- # ANSI Colours
- readonly BLACK=0
- readonly RED=1
- readonly GREEN=2
- readonly YELLOW=3
- readonly BLUE=4
- readonly MAGENTA=5
- readonly CYAN=6
- readonly WHITE=7
-
- readonly BLACK_BRIGHT=8
- readonly RED_BRIGHT=9
- readonly GREEN_BRIGHT=10
- readonly YELLOW_BRIGHT=11
- readonly BLUE_BRIGHT=12
- readonly MAGENTA_BRIGHT=13
- readonly CYAN_BRIGHT=14
- readonly WHITE_BRIGHT=15
-
- # Font effects
- readonly DIM="\\[$(tput dim)\\]"
- readonly REVERSE="\\[$(tput rev)\\]"
- readonly RESET="\\[$(tput sgr0)\\]"
- readonly BOLD="\\[$(tput bold)\\]"
-
- # Generate terminal colour codes
- # $1 is an int (a colour) and $2 must be 'fg' or 'bg'
- __colour() {
- case "$2" in
- 'fg'*)
- echo "\\[$(tput setaf "$1")\\]"
- ;;
- 'bg'*)
- echo "\\[$(tput setab "$1")\\]"
- ;;
- *)
- echo "\\[$(tput setab "$1")\\]"
- ;;
- esac
- }
-
- # Generate a single-coloured block for the prompt
- __prompt_block() {
- local bg; local fg
- if [ ! -z "${1+x}" ]; then
- bg=$1
- else
- if [ ! -z "$last_bg" ]; then
- bg=$last_bg
- else
- bg=$DEFAULT_BG
- fi
- fi
- if [ ! -z "${2+x}" ]; then
- fg=$2
- else
- fg=$DEFAULT_FG
- fi
-
- local block
-
- # Need to generate a separator if the background changes
- if [[ ! -z "$last_bg" && "$bg" != "$last_bg" && ! -z "${POWERLINE_FONT+x}" ]]; then
- block+="$(__colour "$bg" 'bg')"
- block+="$(__colour "$last_bg" 'fg')"
- block+="$BLOCK_START $RESET"
- block+="$(__colour "$bg" 'bg')"
- block+="$(__colour "$fg" 'fg')"
- else
- block+="$(__colour "$bg" 'bg')"
- block+="$(__colour "$fg" 'fg')"
- block+=" "
- fi
-
- if [ ! -z "${3+x}" ]; then
- block+="$3 $RESET"
- fi
-
- last_bg=$bg
-
- __block_text="$block"
- }
-
- function __end_block() {
- __block_text=''
- if [ ! -z "$last_bg" ]; then
- if [ ! -z "${POWERLINE_FONT+x}" ]; then
- __block_text+="$(__colour $DEFAULT_BG 'bg')"
- __block_text+="$(__colour "$last_bg" 'fg')"
- __block_text+="$BLOCK_START$RESET"
- __block_text+="$(__colour $DEFAULT_BG 'bg')"
- __block_text+="$(__colour "$DEFAULT_FG" 'fg')"
- else
- __block_text+="$(__colour $DEFAULT_BG 'bg')"
- __block_text+="$(__colour "$DEFAULT_FG" 'fg')"
- fi
- fi
- __block_text+=' '
- }
-
- ### Prompt components
-
- __git_block() {
- if ! command -V git > /dev/null; then
- # git not found
- __block_text=''
- return
- fi
- # force git output in English to make our work easier
- local git_eng="env LANG=C git"
-
- # check if pwd is under git
- if ! git rev-parse --is-inside-git-dir > /dev/null 2> /dev/null; then
- # not in a git repo, bail out
- __block_text=''
- return
- fi
-
- # get current branch name or short SHA1 hash for detached head
- local branch; local ref_symbol
- branch="$($git_eng symbolic-ref --short HEAD 2>/dev/null)"
- # shellcheck disable=SC2181
- if [ $? != 0 ]; then
- branch="$($git_eng describe --tags --always 2>/dev/null)"
- ref_symbol=''
- else
- ref_symbol=$GIT_BRANCH_SYMBOL
- fi
-
- # In pcmode (and only pcmode) the contents of
- # $gitstring are subject to expansion by the shell.
- # Avoid putting the raw ref name in the prompt to
- # protect the user from arbitrary code execution via
- # specially crafted ref names (e.g., a ref named
- # '$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' would execute
- # 'sudo rm -rf /' when the prompt is drawn). Instead,
- # put the ref name in a new global variable (in the
- # __git_ps1_* namespace to avoid colliding with the
- # user's environment) and reference that variable from
- # PS1.
- # note that the $ is escaped -- the variable will be
- # expanded later (when it's time to draw the prompt)
- if shopt -q promptvars; then
- export __git_ps1_block="$branch"
- ref="$ref_symbol \${__git_ps1_block}"
- else
- ref="$ref_symbol $branch"
- fi
-
- local marks
-
- # check if HEAD is dirty
- if [ -n "$($git_eng status --porcelain 2>/dev/null)" ]; then
- dirty='y'
- marks+=" $GIT_BRANCH_CHANGED_SYMBOL"
- fi
-
- # how many commits local branch is ahead/behind of remote?
- local stat; local aheadN; local behindN
- stat="$($git_eng status --porcelain --branch 2>/dev/null | grep '^##' | grep -o '\[.\+\]$')"
- aheadN="$(echo "$stat" | grep -o 'ahead [[:digit:]]\+' | grep -o '[[:digit:]]\+')"
- behindN="$(echo "$stat" | grep -o 'behind [[:digit:]]\+' | grep -o '[[:digit:]]\+')"
- [ -n "$aheadN" ] && marks+=" $GIT_NEED_PUSH_SYMBOL$aheadN"
- [ -n "$behindN" ] && marks+=" $GIT_NEED_PULL_SYMBOL$behindN"
-
- local bg; local fg
- fg=$BLACK
- if [ -z "$dirty" ]; then
- bg=$GREEN
- else
- bg=$YELLOW
- fi
-
- __prompt_block $bg $fg "$ref$marks"
- }
-
- __virtualenv_block() {
- # Copied from Python virtualenv's activate.sh script.
- # https://github.com/pypa/virtualenv/blob/a9b4e673559a5beb24bac1a8fb81446dd84ec6ed/virtualenv_embedded/activate.sh#L62
- # License: MIT
- if [ -n "$VIRTUAL_ENV" ]; then
- local venv
- # In pcmode (and only pcmode) the contents of
- # $gitstring are subject to expansion by the shell.
- # Avoid putting the raw ref name in the prompt to
- # protect the user from arbitrary code execution via
- # specially crafted ref names (e.g., a ref named
- # '$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' would execute
- # 'sudo rm -rf /' when the prompt is drawn). Instead,
- # put the ref name in a new global variable (in the
- # __git_ps1_* namespace to avoid colliding with the
- # user's environment) and reference that variable from
- # PS1.
- # note that the $ is escaped -- the variable will be
- # expanded later (when it's time to draw the prompt)
- if shopt -q promptvars; then
- export __venv_ps1_block
- __venv_ps1_block=$(basename "$VIRTUAL_ENV")
- venv="$ref_symbol \${__venv_ps1_block}"
- else
- venv="$(basename "$VIRTUAL_ENV")"
- fi
- __prompt_block $WHITE $BLACK "$venv"
- else
- __block_text=''
- fi
- }
-
- __pwd_block() {
- # Use ~ to represent $HOME prefix
- local pwd; pwd=$(pwd | sed -e "s|^$HOME|~|")
- # shellcheck disable=SC1001,SC2088
- if [[ ( $pwd = ~\/*\/* || $pwd = \/*\/*/* ) && ${#pwd} -gt $MAX_PATH_LENGTH ]]; then
- local IFS='/'
- read -ra split <<< "$pwd"
- if [[ $pwd = ~* ]]; then
- pwd="~/${split[1]}/.../${split[*]:(-2):1}/${split[*]:(-1)}"
- else
- pwd="/${split[1]}/.../${split[*]:(-2):1}/${split[*]:(-1)}"
- fi
- fi
- __prompt_block $BLACK_BRIGHT $WHITE_BRIGHT "$pwd"
- }
-
- # superuser or not, here I go!
- __user_block() {
- # Colours to use
- local fg=$WHITE_BRIGHT
- local bg=$BLUE
-
- if [[ ! -z "$SSH_CLIENT" ]]; then
- local show_host="y"
- bg=$CYAN
- fi
-
- if [ -z "$(id -u "$USER")" ]; then
- bg=$RED
- fi
-
- # shellcheck disable=SC2153
- if [[ ! -z "${SHOW_USER+x}" || ( ! -z "${DEFAULT_USER+x}" && "$DEFAULT_USER" != "$(whoami)" ) ]]; then
- local show_user="y"
- fi
-
- local text
- if [ ! -z ${show_user+x} ]; then
- text+="$BOLD$(whoami)"
- fi
- if [ ! -z ${show_host+x} ]; then
- if [ ! -z "${text+x}" ]; then
- text+="@"
- fi
- text+="\\h"
- fi
-
- if [ ! -z ${text+x} ]; then
- __prompt_block $bg $fg $text
- fi
- }
-
- __status_block() {
- local text
- if [ "$exit_code" != 0 ]; then
- __prompt_block $BLACK $RED ''
- text+=$__block_text
- fi
-
- if [ "$(id -u "$USER")" == 0 ]; then
- __prompt_block $BLACK $YELLOW ''
- text+=$__block_text
- fi
-
- if [ "$(jobs -l | wc -l)" != 0 ]; then
- __prompt_block $BLACK $CYAN ''
- text+=$__block_text
- fi
-
- if [ ! -z "$text" ]; then
- __block_text=$text
- else
- __block_text=''
- fi
- }
-
- # Build the prompt
- prompt() {
- # I don't like bash; execute first to capture correct status code
- local exit_code=$?
- # shellcheck disable=SC2091
- $(history -a ; history -n)
-
- last_bg=''
-
- PS1=''
-
- __status_block
- PS1+=$__block_text
-
- __virtualenv_block
- PS1+=$__block_text
-
- __user_block
- PS1+=$__block_text
-
- __pwd_block
- PS1+=$__block_text
-
- __git_block
- PS1+=$__block_text
-
- __end_block
- PS1+=$__block_text
- }
-
- PROMPT_COMMAND=prompt
- }
-
- __powerline
- unset __powerline
|