dotfiles

Configs for programs I use!
git clone git://shipwreckt.co.uk/dotfiles.git
Log | Files | Refs | README | LICENSE

synth-shell-prompt.sh (35251B)


      1 #!/bin/bash
      2 
      3 ##
      4 ##
      5 ##  =======================
      6 ##  WARNING!!
      7 ##  DO NOT EDIT THIS FILE!!
      8 ##  =======================
      9 ##
     10 ##  This file was generated by an installation script.
     11 ##  It might be overwritten without warning at any time
     12 ##  and you will lose all your changes.
     13 ##
     14 ##  Visit for instructions and more information:
     15 ##  https://github.com/andresgongora/synth-shell/
     16 ##
     17 ##
     18 
     19 
     20 
     21 #!/bin/bash
     22 ##  +-----------------------------------+-----------------------------------+
     23 ##  |                                                                       |
     24 ##  | Copyright (c) 2019-2020, Andres Gongora <mail@andresgongora.com>.     |
     25 ##  |                                                                       |
     26 ##  | This program is free software: you can redistribute it and/or modify  |
     27 ##  | it under the terms of the GNU General Public License as published by  |
     28 ##  | the Free Software Foundation, either version 3 of the License, or     |
     29 ##  | (at your option) any later version.                                   |
     30 ##  |                                                                       |
     31 ##  | This program is distributed in the hope that it will be useful,       |
     32 ##  | but WITHOUT ANY WARRANTY; without even the implied warranty of        |
     33 ##  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
     34 ##  | GNU General Public License for more details.                          |
     35 ##  |                                                                       |
     36 ##  | You should have received a copy of the GNU General Public License     |
     37 ##  | along with this program. If not, see <http://www.gnu.org/licenses/>.  |
     38 ##  |                                                                       |
     39 ##  +-----------------------------------------------------------------------+
     40 ##
     41 ##	DESCRIPTION
     42 ##	===========
     43 ##
     44 ##	Script to colorize terminal text.
     45 ##	It works in either of two ways, either by providing the formatting
     46 ##	sequences that should be added to the text, or by directly wrapping
     47 ##	the text with the desired control sequences
     48 ##
     49 ##
     50 ##
     51 ##
     52 ##
     53 ##	USAGE
     54 ##	=====
     55 ##
     56 ##	Formating a text directly:
     57 ##		FORMATTED_TEXT=$(formatText "Hi!" -c red -b 13 -e bold)
     58 ##		echo -e "$FORMATTED_TEXT"
     59 ##
     60 ##	Getting the control sequences:
     61 ##		FORMAT=$(getFormatCode -c blue -b yellow -e bold -e blink)
     62 ##		NONE=$(getFormatCode -e none)
     63 ##		echo -e $FORMAT"Hello"$NONE
     64 ##
     65 ##	Options (More than one code may be specified)
     66 ##	-c	color name or 256bit code for font face
     67 ##	-b	background color name or 256bit code
     68 ##	-e	effect name (e.g. bold, blink, etc.)
     69 ##
     70 ##
     71 ##
     72 ##
     73 ##
     74 ##	BASH TEXT FORMATING
     75 ##	===================
     76 ##
     77 ##	Colors and text formatting can be achieved by preceding the text
     78 ##	with an escape sequence. An escape sequence starts with an <ESC>
     79 ##	character (commonly \e[), followed by one or more formatting codes
     80 ##	(its possible) to apply more that one color/effect at a time),
     81 ##	and finished by a lower case m. For example, the formatting code 1
     82 ##	tells the terminal to print the text bold face. This is acchieved as:
     83 ##		\e[1m Hello World!
     84 ##
     85 ##	But if nothing else is specified, then eveything that may be printed
     86 ##	after 'Hello world!' will be bold face as well. The code 0 is thus
     87 ##	meant to remove all formating from the text and return to normal:
     88 ##		\e[1m Hello World! \e[0m
     89 ##
     90 ##	It's also possible to paint the text in color (codes 30 to 37 and
     91 ##	codes 90 to 97), or its background (codes 40 to 47 and 100 to 107).
     92 ##	Red has code 31:
     93 ##		\e[31m Hello World! \e[0m
     94 ##
     95 ##	More than one code can be applied at a time. Codes are separated by
     96 ##	semicolons. For example, code 31 paints the text in red. Thus,
     97 ##	the following would print in red bold face:
     98 ##		\e[1;31m Hello World! \e[0m
     99 ##
    100 ##	Some formatting sequences are, in fact, comprised of two codes
    101 ##	that must go together. For example, the code 38;5; tells the terminal
    102 ##	that the next code (after the semicolon) should be interpreted as
    103 ##	a 256 bit formatting color. So, for example, the code 82 is a light
    104 ##	green. We can paint the text using this code as follows, plus bold
    105 ##	face as follows - but notice that not all terminal support 256 colors:##
    106 ##		\e[1;38;5;82m Hello World! \e[0m
    107 ##
    108 ##	For a detailed list of all codes, this site has an excellent guide:
    109 ##	https://misc.flogisoft.com/bash/tip_colors_and_formatting
    110 ##
    111 ##
    112 ##
    113 ##
    114 ##
    115 ##	TODO: When requesting an 8 bit colorcode, detect if terminal supports
    116 ##	256 bits, and return appropriate code instead
    117 ##
    118 ##	TODO: Improve this description/manual text
    119 ##
    120 ##	TODO: Currently, if only one parameter is passed, its treated as a
    121 ##	color. Addsupport to also detect whether its an effect code.
    122 ##		Now: getFormatCode blue == getFormatCode -c blue
    123 ##		Add: getFormatCode bold == getFormatCode -e bold
    124 ##
    125 ##	TODO: Clean up this script. Prevent functions like "get8bitCode()"
    126 ##	to be accessible from outside. These are only a "helper" function
    127 ##	that should only be available to this script
    128 ##
    129 ##==============================================================================
    130 ##	CODE PARSERS
    131 ##==============================================================================
    132 ##------------------------------------------------------------------------------
    133 ##
    134 get8bitCode()
    135 {
    136 	CODE=$1
    137 	case $CODE in
    138 		default)
    139 			echo 9
    140 			;;
    141 		none)
    142 			echo 9
    143 			;;
    144 		black)
    145 			echo 0
    146 			;;
    147 		red)
    148 			echo 1
    149 			;;
    150 		green)
    151 			echo 2
    152 			;;
    153 		yellow)
    154 			echo 3
    155 			;;
    156 		blue)
    157 			echo 4
    158 			;;
    159 		magenta|purple|pink)
    160 			echo 5
    161 			;;
    162 		cyan)
    163 			echo 6
    164 			;;
    165 		light-gray)
    166 			echo 7
    167 			;;
    168 		dark-gray)
    169 			echo 60
    170 			;;
    171 		light-red)
    172 			echo 61
    173 			;;
    174 		light-green)
    175 			echo 62
    176 			;;
    177 		light-yellow)
    178 			echo 63
    179 			;;
    180 		light-blue)
    181 			echo 64
    182 			;;
    183 		light-magenta|light-purple)
    184 			echo 65
    185 			;;
    186 		light-cyan)
    187 			echo 66
    188 			;;
    189 		white)
    190 			echo 67
    191 			;;
    192 		*)
    193 			echo 0
    194 	esac
    195 }
    196 ##------------------------------------------------------------------------------
    197 ##
    198 getColorCode()
    199 {
    200 	COLOR=$1
    201 	## Check if color is a 256-color code
    202 	if [ $COLOR -eq $COLOR ] 2> /dev/null; then
    203 		if [ $COLOR -gt 0 -a $COLOR -lt 256 ]; then
    204 			echo "38;5;$COLOR"
    205 		else
    206 			echo 0
    207 		fi
    208 	## Or if color key-workd
    209 	else
    210 		BITCODE=$(get8bitCode $COLOR)
    211 		COLORCODE=$(($BITCODE + 30))
    212 		echo $COLORCODE
    213 	fi
    214 }
    215 ##------------------------------------------------------------------------------
    216 ##
    217 getBackgroundCode()
    218 {
    219 	COLOR=$1
    220 	## Check if color is a 256-color code
    221 	if [ $COLOR -eq $COLOR ] 2> /dev/null; then
    222 		if [ $COLOR -gt 0 -a $COLOR -lt 256 ]; then
    223 			echo "48;5;$COLOR"
    224 		else
    225 			echo 0
    226 		fi
    227 	## Or if color key-workd
    228 	else
    229 		BITCODE=$(get8bitCode $COLOR)
    230 		COLORCODE=$(($BITCODE + 40))
    231 		echo $COLORCODE
    232 	fi
    233 }
    234 ##------------------------------------------------------------------------------
    235 ##
    236 getEffectCode()
    237 {
    238 	EFFECT=$1
    239 	NONE=0
    240 	case $EFFECT in
    241 	none)
    242 		echo $NONE
    243 		;;
    244 	default)
    245 		echo $NONE
    246 		;;
    247 	bold)
    248 		echo 1
    249 		;;
    250 	bright)
    251 		echo 1
    252 		;;
    253 	dim)
    254 		echo 2
    255 		;;
    256 	underline)
    257 		echo 4
    258 		;;
    259 	blink)
    260 		echo 5
    261 		;;
    262 	reverse)
    263 		echo 7
    264 		;;
    265 	hidden)
    266 		echo 8
    267 		;;
    268 	strikeout)
    269 		echo 9
    270 		;;
    271 	*)
    272 		echo $NONE
    273 	esac
    274 }
    275 ##------------------------------------------------------------------------------
    276 ##
    277 getFormattingSequence()
    278 {
    279 	START='\e[0;'
    280 	MIDLE=$1
    281 	END='m'
    282 	echo -n "$START$MIDLE$END"
    283 }
    284 ##==============================================================================
    285 ##	AUX
    286 ##==============================================================================
    287 applyCodeToText()
    288 {
    289 	local RESET=$(getFormattingSequence $(getEffectCode none))
    290 	TEXT=$1
    291 	CODE=$2
    292 	echo -n "$CODE$TEXT$RESET"
    293 }
    294 ##==============================================================================
    295 ##	MAIN FUNCTIONS
    296 ##==============================================================================
    297 ##------------------------------------------------------------------------------
    298 ##
    299 getFormatCode()
    300 {
    301 	local RESET=$(getFormattingSequence $(getEffectCode none))
    302 	## NO ARGUMENT PROVIDED
    303 	if [ "$#" -eq 0 ]; then
    304 		echo -n "$RESET"
    305 	## 1 ARGUMENT -> ASSUME TEXT COLOR
    306 	elif [ "$#" -eq 1 ]; then
    307 		TEXT_COLOR=$(getFormattingSequence $(getColorCode $1))
    308 		echo -n "$TEXT_COLOR"
    309 	## ARGUMENTS PROVIDED
    310 	else
    311 		FORMAT=""
    312 		while [ "$1" != "" ]; do
    313 			## PROCESS ARGUMENTS
    314 			TYPE=$1
    315 			ARGUMENT=$2
    316 			case $TYPE in
    317 			-c)
    318 				CODE=$(getColorCode $ARGUMENT)
    319 				;;
    320 			-b)
    321 				CODE=$(getBackgroundCode $ARGUMENT)
    322 				;;
    323 			-e)
    324 				CODE=$(getEffectCode $ARGUMENT)
    325 				;;
    326 			*)
    327 				CODE=""
    328 			esac
    329 			## ADD CODE SEPARATOR IF NEEDED
    330 			if [ "$FORMAT" != "" ]; then
    331 				FORMAT="$FORMAT;"
    332 			fi
    333 			## APPEND CODE
    334 			FORMAT="$FORMAT$CODE"
    335 			# Remove arguments from stack
    336 			shift
    337 			shift
    338 		done
    339 		## APPLY FORMAT TO TEXT
    340 		FORMAT_CODE=$(getFormattingSequence $FORMAT)
    341 		echo -n "${FORMAT_CODE}"
    342 	fi
    343 }
    344 ##------------------------------------------------------------------------------
    345 ##
    346 formatText()
    347 {
    348 	local RESET=$(getFormattingSequence $(getEffectCode none))
    349 	## NO ARGUMENT PROVIDED
    350 	if [ "$#" -eq 0 ]; then
    351 		echo -n "${RESET}"
    352 	## ONLY A STRING PROVIDED -> Append reset sequence
    353 	elif [ "$#" -eq 1 ]; then
    354 		TEXT=$1
    355 		echo -n "${TEXT}${RESET}"
    356 	## ARGUMENTS PROVIDED
    357 	else
    358 		TEXT=$1
    359 		FORMAT_CODE=$(getFormatCode "${@:2}")
    360 		applyCodeToText "$TEXT" "$FORMAT_CODE"
    361 	fi
    362 }
    363 ##------------------------------------------------------------------------------
    364 ##
    365 removeColorCodes()
    366 {
    367 	printf "$1" | sed 's/\x1b\[[0-9;]*m//g'
    368 }
    369 ##==============================================================================
    370 ##	DEBUG
    371 ##==============================================================================
    372 #formatText "$@"
    373 #FORMATTED_TEXT=$(formatText "HELLO WORLD!!" -c red -b 13 -e bold -e blink -e strikeout)
    374 #echo -e "$FORMATTED_TEXT"
    375 #FORMAT=$(getFormatCode -c blue -b yellow)
    376 #NONE=$(getFormatCode -e none)
    377 #echo -e $FORMAT"Hello"$NONE
    378 #!/bin/bash
    379 ##  +-----------------------------------+-----------------------------------+
    380 ##  |                                                                       |
    381 ##  | Copyright (c) 2019-2023, Andres Gongora <mail@andresgongora.com>.     |
    382 ##  |                                                                       |
    383 ##  | This program is free software: you can redistribute it and/or modify  |
    384 ##  | it under the terms of the GNU General Public License as published by  |
    385 ##  | the Free Software Foundation, either version 3 of the License, or     |
    386 ##  | (at your option) any later version.                                   |
    387 ##  |                                                                       |
    388 ##  | This program is distributed in the hope that it will be useful,       |
    389 ##  | but WITHOUT ANY WARRANTY; without even the implied warranty of        |
    390 ##  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
    391 ##  | GNU General Public License for more details.                          |
    392 ##  |                                                                       |
    393 ##  | You should have received a copy of the GNU General Public License     |
    394 ##  | along with this program. If not, see <http://www.gnu.org/licenses/>.  |
    395 ##  |                                                                       |
    396 ##  +-----------------------------------------------------------------------+
    397 ##
    398 ##	DESCRIPTION
    399 ##
    400 ##	This script takes a path name and shortens it.
    401 ##	- home is replaced by ~
    402 ##	- last folder in apth is never truncated
    403 ##
    404 ##
    405 ##	REFERENCES
    406 ##
    407 ##	Original source: WOLFMAN'S color bash promt
    408 ##	https://wiki.chakralinux.org/index.php?title=Color_Bash_Prompt#Wolfman.27s
    409 ##
    410 ##==============================================================================
    411 ##	FUNCTIONS
    412 ##==============================================================================
    413 ##------------------------------------------------------------------------------
    414 ##
    415 shortenPath()
    416 {
    417 	## GET PARAMETERS
    418 	local path=$1
    419 	local max_length=$2
    420 	local default_max_length=25
    421 	local trunc_symbol=${3:-"…"}
    422     ## CHECK PARAMETERS AND INIT
    423 	if   [ -z "$path" ]; then
    424 		echo ""
    425 		exit
    426 	elif [ -z "$max_length" ]; then
    427 		local max_length=$default_max_length
    428 	fi
    429 	## CLEANUP PATH
    430 	## Replace HOME with ~ for the current user, similar to sed.
    431 	local path=${path/#$HOME/\~}
    432 	## GET PRINT LENGHT
    433 	## - Get curred directory (last folder in path) to get its length (num characters).
    434 	## - Determine the actual max length we will use to truncate, choosing between either
    435     ##   $max_length, set by the usert, or the length of the current dir,
    436     ##   depending on which is greater. This ensures that even if we set a
    437     ##   relatively  low $max_length value, the name of the current dir will not
    438     ##   be truncated. Store in $print_length
    439 	local dir=${path##*/}
    440 	local dir_length=${#dir}
    441 	local path_length=${#path}
    442 	local print_length=$(( ( max_length < dir_length ) ? dir_length : max_length )) #
    443     ## TRUNCATE PATH TO
    444 	## - If $path_length > $print_lenght
    445 	##	- Truncate the path to max_length
    446 	##	- Clean off path fragments before first '/' (included)
    447     ##  - Check if the bit we have removed would have landed at home
    448     ##    - If at home, prepend '~' to the clean path
    449 	##	  - Else, prepend the "trunc_symbol" to the clean path
    450 	if [ $path_length -gt $print_length ]; then
    451 		local offset=$(( $path_length - $print_length ))
    452 		local truncated_path=${path:$offset}
    453 		local clean_path="/${truncated_path#*/}"
    454         local removed_path=${path%%"$clean_path"}
    455         if [ "$removed_path" == "~" ]; then
    456             local short_path="~${clean_path}"
    457         else
    458 		    local short_path=${trunc_symbol}${clean_path}
    459         fi
    460 	else
    461 		local short_path=$path
    462 	fi
    463 	## RETURN FINAL PATH
    464 	echo $short_path
    465 }
    466 ##==============================================================================
    467 ##	DEBUG
    468 ##==============================================================================
    469 #PATH1="/home/andy/my/imaginary/file/path"
    470 #echo "$PATH1"
    471 #echo "50: $(shortenPath "$PATH1" 50)"
    472 #echo "25: $(shortenPath "$PATH1" 25)"
    473 #echo "24: $(shortenPath "$PATH1" 24)"
    474 #echo "23: $(shortenPath "$PATH1" 23)"
    475 #echo "22: $(shortenPath "$PATH1" 22)"
    476 #echo "10: $(shortenPath "$PATH1" 10)"
    477 ##==============================================================================
    478 ## COLORS
    479 ##
    480 ## Control the color and format scheme of the bash prompt.
    481 ## The prompt is divided into segments, listed below starting from the left:
    482 ## -  USER: shows the user's name.
    483 ## -  HOST: shows the host's name.
    484 ## -   PWD: shows the current directory.
    485 ## -   GIT: if inside a git repository, shows the name of current branch.
    486 ## - PYENV: if inside a Python Virtual environment.
    487 ## -    TF: if inside a Terraform Workspace.
    488 ## - CLOCK: shows current time in H:M format.
    489 ## - INPUT: actual bash input.
    490 ##
    491 ## Valid color options:
    492 ## - white black light-gray dark-gray
    493 ##   red green yellow blue cyan purple
    494 ##   light-red light-green light-yellow light-blue light-cyan light-purple
    495 ## - Values in the range [0-255] for 256 bit colors. To check all number-color
    496 ##   pairs for your terminal, you may run the following snippet by HaleTom:
    497 ##     curl -s https://gist.githubusercontent.com/HaleTom/89ffe32783f89f403bba96bd7bcd1263/raw/ | bash
    498 ##   or search something like "bash 256 color codes" on the internet.
    499 ##
    500 ##==============================================================================
    501 ##==============================================================================
    502 ## MAIN FORMAT
    503 ##==============================================================================
    504 format="USER HOST PWD GIT PYENV TF KUBE"
    505 separator_char='\uE0B0'           # Separation character, '\uE0B0'=triangle
    506 separator_padding_left=''         # Add char or string to the left of the separator
    507 separator_padding_right=''        # Add char or string to the right of the separator
    508 segment_padding=' '               # Add char or string around segment text
    509 enable_vertical_padding=true      # Add extra new line over prompt
    510 enable_command_on_new_line=false  # Add new line between prompt and command
    511 ##==============================================================================
    512 ## USER
    513 ##==============================================================================
    514 font_color_user="white"
    515 background_user="blue"
    516 texteffect_user="bold"
    517 ##==============================================================================
    518 ## HOST
    519 ##==============================================================================
    520 font_color_host="white"
    521 background_host="light-blue"
    522 texteffect_host="bold"
    523 ##==============================================================================
    524 ## PWD (working dir)
    525 ##==============================================================================
    526 font_color_pwd="dark-gray"
    527 background_pwd="white"
    528 texteffect_pwd="bold"
    529 max_pwd_char="25"
    530 pwd_trunc_symbol="…"
    531 ##==============================================================================
    532 ## GIT
    533 ##==============================================================================
    534 font_color_git="light-gray"
    535 background_git="dark-gray"
    536 texteffect_git="bold"
    537 git_symbol_synced=''
    538 git_symbol_unpushed=' ▲'
    539 git_symbol_unpulled=' ▼'
    540 git_symbol_unpushedunpulled=' ◆'
    541 git_symbol_dirty=' ◔'
    542 git_symbol_dirty_unpushed=' ◔ △'
    543 git_symbol_dirty_unpulled=' ◔ ▽'
    544 git_symbol_dirty_unpushedunpulled=' ◔ ◇'
    545 git_symbol_stash='🗎'
    546 git_update_period_minutes=15	# Use -1 to disable automatic updates
    547 ##==============================================================================
    548 ## PYENV
    549 ##==============================================================================
    550 font_color_pyenv="white"
    551 background_pyenv="blue"
    552 texteffect_pyenv="bold"
    553 ##==============================================================================
    554 ## KUBERNETES
    555 ##==============================================================================
    556 font_color_kube="white"
    557 background_kube="purple"
    558 texteffect_kube="bold"
    559 ##==============================================================================
    560 ## TERRAFORM WORKSPACE
    561 ##==============================================================================
    562 font_color_tf="purple"
    563 background_tf="light-purple"
    564 texteffect_tf="bold"
    565 ##==============================================================================
    566 ## CLOCK
    567 ##==============================================================================
    568 font_color_clock="white"
    569 background_clock="light-blue"
    570 texteffect_clock="bold"
    571 clock_format="%H:%M"
    572 ##==============================================================================
    573 ## INPUT (user typed command)
    574 ##==============================================================================
    575 font_color_input="45"
    576 background_input="none"
    577 texteffect_input="bold"
    578 #!/bin/bash
    579 ##  +-----------------------------------+-----------------------------------+
    580 ##  |                                                                       |
    581 ##  | Copyright (c) 2018-2023, Andres Gongora <mail@andresgongora.com>.     |
    582 ##  |                                                                       |
    583 ##  | This program is free software: you can redistribute it and/or modify  |
    584 ##  | it under the terms of the GNU General Public License as published by  |
    585 ##  | the Free Software Foundation, either version 3 of the License, or     |
    586 ##  | (at your option) any later version.                                   |
    587 ##  |                                                                       |
    588 ##  | This program is distributed in the hope that it will be useful,       |
    589 ##  | but WITHOUT ANY WARRANTY; without even the implied warranty of        |
    590 ##  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
    591 ##  | GNU General Public License for more details.                          |
    592 ##  |                                                                       |
    593 ##  | You should have received a copy of the GNU General Public License     |
    594 ##  | along with this program. If not, see <http://www.gnu.org/licenses/>.  |
    595 ##  |                                                                       |
    596 ##  +-----------------------------------------------------------------------+
    597 ##
    598 ##	DESCRIPTION
    599 ##
    600 ##	This script updates your "PS1" environment variable to display colors.
    601 ##	Additionally, it also shortens the name of your current path to a
    602 ##	maximum 25 characters, which is quite useful when working in deeply
    603 ##	nested folders.
    604 ##
    605 ##
    606 ##
    607 ##	REFFERENCES
    608 ##
    609 ##	* http://tldp.org/HOWTO/Bash-Prompt-HOWTO/index.html
    610 ##
    611 ##
    612 ##==============================================================================
    613 ##	EXTERNAL DEPENDENCIES
    614 ##==============================================================================
    615 [ "$(type -t include)" != 'function' ]&&{ include(){ { [ -z "$_IR" ]&&_IR="$PWD"&&cd "$(dirname "${BASH_SOURCE[0]}")"&&include "$1"&&cd "$_IR"&&unset _IR;}||{ local d="$PWD"&&cd "$(dirname "$PWD/$1")"&&. "$(basename "$1")"&&cd "$d";}||{ echo "Include failed $PWD->$1"&&exit 1;};};}
    616 synth_shell_prompt()
    617 {
    618 ##==============================================================================
    619 ##	FUNCTIONS
    620 ##==============================================================================
    621 ##------------------------------------------------------------------------------
    622 ##
    623 ##	Returns current git branch for current directory, if (and only if)
    624 ##	the current directory is part of a git repository, and git is installed.
    625 ##
    626 ##	In addition, it adds a symbol to indicate the state of the repository.
    627 ##	By default, these symbols and their meaning are (set globally):
    628 ##
    629 ##		UPSTREAM	NO CHANGE		DIRTY
    630 ##		up to date	SSP_GIT_SYNCED		SSP_GIT_DIRTY
    631 ##		ahead		SSP_GIT_AHEAD		SSP_GIT_DIRTY_AHEAD
    632 ##		behind		SSP_GIT_BEHIND		SSP_GIT_DIRTY_BEHIND
    633 ##		diverged	SSP_GIT_DIVERGED	SSP_GIT_DIRTY_DIVERGED
    634 ##
    635 ##	Returns an empty string otherwise.
    636 ##
    637 ##	Inspired by twolfson's sexy-bash-prompt:
    638 ##	https://github.com/twolfson/sexy-bash-prompt
    639 ##
    640 getGitBranch()
    641 {
    642 	if ( which git > /dev/null 2>&1 ); then
    643 		## CHECK IF IN A GIT REPOSITORY, OTHERWISE SKIP
    644 		local branch=$(git branch 2> /dev/null |\
    645 		             sed -n '/^[^*]/d;s/*\s*\(.*\)/\1/p')
    646 		if [[ -n "$branch" ]]; then
    647 			## UPDATE LOCAL GIT BRANCH (i.e., fetch)
    648 			## This will talk to the remote repository to get the latest
    649 			## updates. Because doing so for every terminal prompt can
    650 			## (and will) be slow, the script will do so only if its globaly
    651 			## enabled and only periodically in the background.
    652 			if [ "$SSP_GIT_UPDATE_PERIOD_MINUTES" -ge 0 ]; then
    653 				## Find .git
    654 				local d="$PWD"
    655 				local max_lvls=25
    656 				while [ ! -e "./.git" -a $max_lvls -gt 0 ]; do
    657 					cd .. # Go up 1 level
    658 					max_lvls=$((max_lvls - 1))
    659 				done
    660 				local dot_git="${PWD}/.git"
    661 				cd "$d"
    662 				## Check if submodule
    663 				if [ -f "$dot_git" ]; then
    664 					local dot_git=$(cat $dot_git | grep 'gitdir' | sed 's/gitdir:\ //g')
    665 				fi
    666 				## Get timestamp
    667 				if [ -d "$dot_git" -a -e "${dot_git}/FETCH_HEAD" ]; then
    668 					local git_last_update=$(stat -c "%Y" "${dot_git}/FETCH_HEAD")
    669 				fi
    670 				## Update if it's time to do so
    671 				if [ ! -z $git_last_update ]; then
    672 					local current_timestamp=$(date +%s)
    673 					local elapsed_minutes=$(((current_timestamp-git_last_update)/60))
    674 					if [ "$elapsed_minutes" -ge "$SSP_GIT_UPDATE_PERIOD_MINUTES" ]; then
    675 						git fetch --recurse-submodules > /dev/null 2>&1 &
    676 					fi
    677 				fi
    678 			fi
    679 			## GET GIT STATUS
    680 			## This information contains whether the current branch is
    681 			## ahead, behind or diverged (ahead & behind), as well as
    682 			## whether any file has been modified locally (is dirty).
    683 			## --porcelain: script friendly output.
    684 			## -b:          show branch tracking info.
    685 			## -u no:       do not list untracked/dirty files
    686 			## From the first line we get whether we are synced, and if
    687 			## there are more lines, then we know it is dirty.
    688 			## NOTE: this requires that you fetch your repository,
    689 			##       otherwise your information is outdated.
    690 			local is_dirty=false &&\
    691 				       [[ -n "$(git status --porcelain)" ]] &&\
    692 				       is_dirty=true
    693 			local is_ahead=false &&\
    694 				       [[ "$(git status --porcelain -u no -b)" == *"ahead"* ]] &&\
    695 				       is_ahead=true
    696 			local is_behind=false &&\
    697 				        [[ "$(git status --porcelain -u no -b)" == *"behind"* ]] &&\
    698 				        is_behind=true
    699 			## SELECT SYMBOL
    700 			if   $is_dirty && $is_ahead && $is_behind; then
    701 				local symbol=$SSP_GIT_DIRTY_DIVERGED
    702 			elif $is_dirty && $is_ahead; then
    703 				local symbol=$SSP_GIT_DIRTY_AHEAD
    704 			elif $is_dirty && $is_behind; then
    705 				local symbol=$SSP_GIT_DIRTY_BEHIND
    706 			elif $is_dirty; then
    707 				local symbol=$SSP_GIT_DIRTY
    708 			elif $is_ahead && $is_behind; then
    709 				local symbol=$SSP_GIT_DIVERGED
    710 			elif $is_ahead; then
    711 				local symbol=$SSP_GIT_AHEAD
    712 			elif $is_behind; then
    713 				local symbol=$SSP_GIT_BEHIND
    714 			else
    715 				local symbol=$SSP_GIT_SYNCED
    716 			fi
    717             ## GET TAG (if any)
    718             [[ -n "$(git tag --points-at HEAD)" ]] && local readonly tag=" $(git tag --points-at HEAD)" || local readonly tag=""
    719             ## CHECK IF REPOSITORY HAS STASHED CODE
    720             local git_stash=""
    721             local readonly stashed_elements=$(git stash list 2> /dev/null | wc -l)
    722             if [ "$stashed_elements" -gt 0 ]; then
    723                 git_stash=" ${stashed_elements}${SSP_GIT_STASH}"
    724             fi
    725 			## RETURN STRING
    726 			echo "${branch}$symbol${git_stash}${tag}"
    727 		fi
    728 	fi
    729 	## DEFAULT
    730 	echo ""
    731 }
    732 ##------------------------------------------------------------------------------
    733 ##
    734 ##
    735 getTerraform()
    736 {
    737 	## Check if we are in a terraform directory
    738 	if [ -d .terraform ]; then
    739 		## Check if the terraform binary is in the path
    740 		if ( which terraform > /dev/null 2>&1 ); then
    741 			## Get the terraform workspace
    742 			local tf="$(terraform workspace show 2> /dev/null | tr -d '\n')"
    743 			echo "$tf"
    744 		fi
    745 	fi
    746 }
    747 ##------------------------------------------------------------------------------
    748 ##
    749 ##
    750 getPyenv()
    751 {
    752 	## Conda environment
    753 	if [ -n "$CONDA_DEFAULT_ENV" ]; then
    754 		echo "$CONDA_DEFAULT_ENV"
    755 	## Python virtual environment
    756 	elif [ -n "${VIRTUAL_ENV:-}" ]; then
    757         local regex='PS1=\"\((.*?)\)\s\$\{PS1'
    758         local pyenv=$(cat $VIRTUAL_ENV/bin/activate | perl -n -e"/$regex/ && print \$1" 2> /dev/null)
    759         if [ -z "${pyenv}" ]; then
    760             local pyenv=$(basename ${VIRTUAL_ENV})
    761         fi
    762 		echo "$pyenv"
    763 	fi
    764 }
    765 ##------------------------------------------------------------------------------
    766 ##
    767 ##
    768 getKube()
    769 {
    770 	type kubectl &>/dev/null && \
    771 	type yq &>/dev/null && \
    772 	echo -n "$(kubectl config view | yq '.contexts[].context.cluster |select(.contexts[].name == .current-context)' | head -n 1)"
    773 }
    774 ##------------------------------------------------------------------------------
    775 ##
    776 ## Print each word of the propmpt, i.e., a small text acompanied by the
    777 ## separator character and formated with colors and background.
    778 ##
    779 printSegment()
    780 {
    781 	## GET PARAMETERS
    782 	local text=$1
    783 	local font_color=$2
    784 	local background_color=$3
    785 	local next_background_color=$4 # needed for the separator, it participates in this and the next text segment
    786 	local font_effect=$5
    787 	## COMPUTE COLOR FORMAT CODES
    788 	local no_color="\[$(getFormatCode -e reset)\]"
    789 	local text_format="\[$(getFormatCode -c $font_color -b $background_color -e $font_effect)\]"
    790 	local separator_format="\[$(getFormatCode -c $background_color -b $next_background_color)\]"
    791 	## GENERATE TEXT
    792 	printf "${text_format}${segment_padding}${text}${segment_padding}${separator_padding_left}${separator_format}${separator_char}${separator_padding_right}${no_color}"
    793 }
    794 ##------------------------------------------------------------------------------
    795 ##
    796 ##
    797 get_colors_for_element()
    798 {
    799 	case $1 in
    800 		"USER")  echo "${SSP_COLORS_USER[@]}" ;;
    801 		"HOST")  echo "${SSP_COLORS_HOST[@]}" ;;
    802 		"PWD")   echo "${SSP_COLORS_PWD[@]}"  ;;
    803 		"GIT")   echo "${SSP_COLORS_GIT[@]}"  ;;
    804 		"PYENV") echo "${SSP_COLORS_PYENV[@]}";;
    805 		"KUBE")  echo "${SSP_COLORS_KUBE[@]}";;
    806 		"TF")    echo "${SSP_COLORS_TF[@]}"   ;;
    807 		"CLOCK") echo "${SSP_COLORS_CLOCK[@]}";;
    808 		"INPUT") echo "${SSP_COLORS_INPUT[@]}";;
    809 		*)
    810 	esac
    811 }
    812 ##------------------------------------------------------------------------------
    813 ##
    814 ##
    815 combine_elements()
    816 {
    817 	local first=$1
    818 	local second=$2
    819 	local colors_first=($(get_colors_for_element $first))
    820 	local colors_second=($(get_colors_for_element $second))
    821 	case $first in
    822 		"USER")  local text="$user" ;;
    823 		"HOST")  local text="$host" ;;
    824 		"PWD")   local text="$path" ;;
    825 		"GIT")   local text="$git_branch" ;;
    826 		"PYENV") local text="$pyenv" ;;
    827 		"KUBE")  local text="$kube" ;;
    828 		"TF")    local text="$tf" ;;
    829 		"CLOCK") local text="$clock" ;;
    830 		"INPUT") local text="" ;;
    831 		*)       local text="" ;;
    832 	esac
    833 	local text_color=${colors_first[0]}
    834 	local bg_color=${colors_first[1]}
    835 	local next_bg_color=${colors_second[1]}
    836 	local text_effect=${colors_first[2]}
    837 	printSegment "$text" "$text_color" "$bg_color" "$next_bg_color" "$text_effect"
    838 }
    839 ##==============================================================================
    840 ##	HOOK
    841 ##==============================================================================
    842 prompt_command_hook()
    843 {
    844 	## GET PARAMETERS
    845 	## This might be a bit redundant, but it makes it easier to maintain
    846 	local elements=(${SSP_ELEMENTS[@]})
    847 	local user=$USER
    848 	local host=$HOSTNAME
    849 	local path="$(shortenPath "$PWD" $SSP_MAX_PWD_CHAR $SSP_PWD_TRUNC_SYMBOL)" # bash-tools::shortenPath
    850 	local git_branch="$(getGitBranch)"
    851 	local pyenv="$(getPyenv)"
    852 	local kube="$(getKube)"
    853 	local tf="$(getTerraform)"
    854 	local clock="$(date +"${SSP_CLOCK_FORMAT}")"
    855 	## ADAPT DYNAMICALLY ELEMENTS TO BE SHOWN
    856 	## Check if elements such as GIT and the Python environment should be
    857 	## shown and adapt the variables as needed. This usually implies removing
    858 	## the appropriate field from the "elements" array if the user set them
    859 	if [ -z "$git_branch" ]; then
    860 		elements=( ${elements[@]/"GIT"} ) # Remove GIT from elements to be shown
    861 	fi
    862 	if [ -z "$pyenv" ]; then
    863 		elements=( ${elements[@]/"PYENV"} ) # Remove PYENV from elements to be shown
    864 	fi
    865 	if [ -z "$tf" ]; then
    866 		elements=( ${elements[@]/"TF"} ) # Remove TF from elements to be shown
    867 	fi
    868 	if [ -z "$kube" ]; then
    869 		elements=( ${elements[@]/"KUBE"} ) # Remove KUBE from elements to be shown
    870 	fi
    871 	## WINDOW TITLE
    872 	## Prevent messed up terminal-window titles, must be set in the PS1 variable
    873 	case $TERM in
    874 	xterm*|rxvt*)
    875 		SSP_PWD="$path"
    876 		local titlebar="\[\033]0;\${USER}@\${HOSTNAME}: \${SSP_PWD}\007\]"
    877 		;;
    878 	*)
    879 		local titlebar=""
    880 		;;
    881 	esac
    882 	## CONSTRUCT PROMPT ITERATIVELY
    883 	## Iterate through all elements to be shown and combine them. Stop once only
    884 	## 1 element is left, which should be the "INPUT" element; then apply the
    885 	## INPUT formatting.
    886 	## Notice that this reuses the PS1 variables over and over again, and appends
    887 	## all extra formatting elements to the end of it.
    888 	PS1="${titlebar}${SSP_VERTICAL_PADDING}${SSP_NEW_LINE_LINK_TOP}"
    889 	while [ "${#elements[@]}" -gt 1 ]; do
    890 		local current=${elements[0]}
    891 		local next=${elements[1]}
    892 		local elements=("${elements[@]:1}") #remove the 1st element
    893 		PS1="$PS1$(combine_elements $current $next)"
    894 	done
    895 	local input_colors=($(get_colors_for_element ${elements[0]}))
    896 	local input_color=${input_colors[0]}
    897 	local input_bg=${input_colors[1]}
    898 	local input_effect=${input_colors[2]}
    899 	local input_format="\[$(getFormatCode -c $input_color -b $input_bg -e $input_effect)\]"
    900 	local command_start_symbol="${input_format}${SSP_BASH_SYMBOL}"
    901 	## the prompt is then the prompt we build above, the separation between prompt and command and in
    902 	## the case of a new line inbetween, the corresponding link and $ symbol to start the command.
    903 	PS1="${PS1}${SSP_PROMPT_COMM_SEP}${SSP_NEW_LINE_LINK_BOTTOM}${command_start_symbol} $input_format"
    904 	## Once this point is reached, PS1 is formatted and set. The terminal session
    905 	## will then use that variable to prompt the user :)
    906 }
    907 ##==============================================================================
    908 ##	MAIN
    909 ##==============================================================================
    910 	## LOAD USER CONFIGURATION
    911 	local user_config_file="$HOME/.config/synth-shell/synth-shell-prompt.config"
    912 	local root_config_file="/etc/synth-shell/synth-shell-prompt.root.config"
    913 	local sys_config_file="/etc/synth-shell/synth-shell-prompt.config"
    914 	if   [ -f $user_config_file ]; then
    915 		source $user_config_file
    916 	elif [ -f $root_config_file  -a "$USER" == "root"  ]; then
    917 		source $root_config_file
    918 	elif [ -f $sys_config_file ]; then
    919 		source $sys_config_file
    920 	fi
    921 	## PADDING
    922 	if $enable_vertical_padding; then
    923 		local vertical_padding="\n"
    924 	else
    925 		local vertical_padding=""
    926 	fi
    927 	## NEW LINE
    928 	if $enable_command_on_new_line; then
    929 		local new_line_link_top="╭"
    930 		local new_line_link_bottom="╰"
    931 		local prompt_command_separation="\n"
    932 		local bash_symbol="\$"
    933 	else
    934 		local new_line_link_top=""
    935 		local new_line_link_top=""
    936 		local prompt_command_separation=""
    937 		local bash_symbol=""
    938 	fi
    939     ## CONFIG FOR "prompt_command_hook()"
    940 	SSP_ELEMENTS=($format "INPUT") # Append INPUT to elements that have to be shown
    941 	SSP_COLORS_USER=($font_color_user $background_user $texteffect_user)
    942 	SSP_COLORS_HOST=($font_color_host $background_host $texteffect_host)
    943 	SSP_COLORS_PWD=($font_color_pwd $background_pwd $texteffect_pwd)
    944 	SSP_COLORS_GIT=($font_color_git $background_git $texteffect_git)
    945 	SSP_COLORS_PYENV=($font_color_pyenv $background_pyenv $texteffect_pyenv)
    946 	SSP_COLORS_KUBE=($font_color_kube $background_kube $texteffect_kube)
    947 	SSP_COLORS_TF=($font_color_tf $background_tf $texteffect_tf)
    948 	SSP_COLORS_CLOCK=($font_color_clock $background_clock $texteffect_clock)
    949 	SSP_COLORS_INPUT=($font_color_input $background_input $texteffect_input)
    950 	SSP_VERTICAL_PADDING=$vertical_padding
    951 	SSP_NEW_LINE_LINK_TOP=$new_line_link_top
    952 	SSP_NEW_LINE_LINK_BOTTOM=$new_line_link_bottom
    953 	SSP_PROMPT_COMM_SEP=$prompt_command_separation
    954 	SSP_BASH_SYMBOL=$bash_symbol
    955 	SSP_MAX_PWD_CHAR=${max_pwd_char:-25}
    956 	SSP_PWD_TRUNC_SYMBOL=${pwd_trunc_symbol:-"..."}
    957 	SSP_GIT_SYNCED=$git_symbol_synced
    958 	SSP_GIT_AHEAD=$git_symbol_unpushed
    959 	SSP_GIT_BEHIND=$git_symbol_unpulled
    960 	SSP_GIT_DIVERGED=$git_symbol_unpushedunpulled
    961 	SSP_GIT_DIRTY=$git_symbol_dirty
    962 	SSP_GIT_DIRTY_AHEAD=$git_symbol_dirty_unpushed
    963 	SSP_GIT_DIRTY_BEHIND=$git_symbol_dirty_unpulled
    964 	SSP_GIT_DIRTY_DIVERGED=$git_symbol_dirty_unpushedunpulled
    965 	SSP_GIT_STASH=$git_symbol_stash
    966 	SSP_GIT_UPDATE_PERIOD_MINUTES=$git_update_period_minutes
    967 	SSP_CLOCK_FORMAT=${clock_format:-"%H:%M"}
    968 	## For terminal line coloring, leaving the rest standard
    969 	none="$(tput sgr0)"
    970 	trap 'echo -ne "${none}"' DEBUG
    971 	## ADD HOOK TO UPDATE PS1 AFTER EACH COMMAND
    972 	## Bash provides an environment variable called PROMPT_COMMAND.
    973 	## The contents of this variable are executed as a regular Bash command
    974 	## just before Bash displays a prompt.
    975 	## We want it to call our own command to truncate PWD and store it in NEW_PWD
    976 	PROMPT_COMMAND=prompt_command_hook
    977 } # synth_shell_prompt()
    978 ##------------------------------------------------------------------------------
    979 ##
    980 ## CALL SCRIPT FUNCTION
    981 ## - CHECK IF SCRIPT IS _NOT_ BEING SOURCED
    982 ## - CHECK IF COLOR SUPPORTED
    983 ##     - Check if compliant with Ecma-48 (ISO/IEC-6429)
    984 ##	   - Call script
    985 ## - Unset script
    986 ## If not running interactively, don't do anything
    987 if [ -n "$( echo $- | grep i )" ]; then
    988 	if [ "${BASH_SOURCE[0]}" == "${0}" ]; then
    989 		echo -e "Do not run this script, it will do nothing.\nPlease source it instead by running:\n"
    990 		echo -e "\t. ${BASH_SOURCE[0]}\n"
    991 	elif [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
    992 		synth_shell_prompt
    993 	fi
    994 	unset synth_shell_prompt
    995 	unset include
    996 fi