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