dotfiles

🎜 Clone'em, tweak'em, stick'em in your $HOME 🎝
git clone https://git.kevinlegouguec.net/dotfiles
Log | Files | Refs | README

.bash_prompt (4074B)


      1 # Emacs?  -*- shell-script -*- please.
      2 
      3 # Environment variables:
      4 #
      5 # PS1_SHOWHOSTNAME
      6 #       'auto' (default):       Only show hostname over SSH
      7 #       'yes':                  Always show hostname
      8 #       anything else:          Never show hostname
      9 
     10 
     11 __show-hostname ()
     12 {
     13     case ${PS1_SHOWHOSTNAME} in
     14         (''|auto)
     15             test "${SSH_CONNECTION}";;
     16         (yes)
     17             true;;
     18         (*)
     19             false;;
     20     esac
     21 }
     22 
     23 __have-gitprompt ()
     24 {
     25     test -f /usr/lib/git-core/git-sh-prompt
     26 }
     27 
     28 __set-title ()
     29 {
     30     local title=${USER}
     31     __show-hostname && title+=@${HOSTNAME}
     32     title+=:
     33     title+=${PWD/~/\~}
     34 
     35     # Cf. console_codes(4):
     36     #
     37     #   ESC ] 2 ; txt ST        Set window title to txt.
     38     #
     39     # ST is a "string terminator", either "ESC \" or "BEL".
     40 
     41     printf $'\E]2;%s\a' "${title}"
     42 }
     43 
     44 # Bash relies on \[ \] to distinguish non-printing characters in prompts.
     45 __start-nonprinting ()
     46 {
     47     test ${BUILDING_PS} && printf '\['
     48 }
     49 
     50 __end-nonprinting ()
     51 {
     52     test ${BUILDING_PS} && printf '\]'
     53 }
     54 
     55 __fontify ()
     56 {
     57     local -r text=$1
     58     shift
     59 
     60     local -Ar codes=(
     61         [bold]=1
     62         [dim]=2
     63         [reverse]=7
     64         [red]=31
     65         [green]=32
     66         [blue]=34
     67     )
     68 
     69     local -a params=()
     70     local c
     71     for c
     72     do
     73         params+=(${codes[${c}]})
     74     done
     75 
     76     local params_seq
     77     IFS=';' eval 'params_seq="${params[*]}"'
     78 
     79     __start-nonprinting
     80     printf $'\E[%sm' "${params_seq}"
     81     __end-nonprinting
     82 
     83     printf %s "${text}"
     84 
     85     __start-nonprinting
     86     printf $'\E[0m'
     87     __end-nonprinting
     88 }
     89 
     90 __current-column ()
     91 {
     92     # Cf. console_codes(4) § ECMA-48 Status Report Commands.
     93 
     94     local position
     95     read -sdR -p$'\E[6n' position
     96 
     97     local -r pattern='\[[0-9]+;([0-9]+)'
     98 
     99     [[ ${position} =~ ${pattern} ]] || {
    100         echo 0
    101         return
    102     }
    103     echo ${BASH_REMATCH[1]}
    104 }
    105 
    106 __signal-no-newline ()
    107 {
    108     __fontify ∅ bold red
    109     echo
    110 }
    111 
    112 __draw-rule ()
    113 {
    114     local -ir pos=$(__current-column)
    115     local -ir rule_len=$((COLUMNS-pos))
    116 
    117     local rule
    118     # Hey Future Me 👋 Breaking this down:
    119     # -v rule       "put this in LINE, do not write to stdout"
    120     # "%…s"         "pad string…"
    121     #  -            " … with spaces…"
    122     #  *            " … with length given by next argument"
    123     # ${rule_len}   (padding length)
    124     # ∅             (psych! no arg for %s, default to null string)
    125     printf -v rule '%-*s' ${rule_len}
    126     rule=${rule// /─}
    127 
    128     # Flush line to avoid future text being shoved offscreen when autowrap
    129     # is off.
    130     rule+=$'\n'
    131 
    132     __fontify "${rule}" "$@"
    133 }
    134 
    135 __write-context ()
    136 {
    137     __fontify '\u' green
    138 
    139     __show-hostname && {
    140         __fontify @ dim
    141         __fontify '\H' bold green
    142     }
    143 
    144     printf ' '
    145     __fontify '\w' bold blue
    146 
    147     test "${PS1_SHOWGITSTATUS}" && {
    148         printf ' '
    149         __fontify "$(__git_ps1 '(%s)')" red
    150     }
    151 }
    152 
    153 __smart-term/set-ps1 ()
    154 {
    155     BUILDING_PS=t
    156 
    157     PS1="$(__write-context)\n$(__fontify '\$' dim) "
    158 
    159     unset BUILDING_PS
    160 }
    161 
    162 __smart-term/refresh ()
    163 {
    164     local -ir rc=$?
    165 
    166     __set-title
    167 
    168     local -ir pos=$(__current-column)
    169     ((pos != 1)) && __signal-no-newline
    170 
    171     if ((rc))
    172     then
    173         __fontify "${rc} " bold red
    174         __draw-rule dim red
    175     else
    176         __draw-rule dim
    177     fi
    178 
    179     __smart-term/set-ps1
    180 }
    181 
    182 __smart-term/init ()
    183 {
    184     # Prompts.
    185 
    186     __have-gitprompt && {
    187         . /usr/lib/git-core/git-sh-prompt
    188         GIT_PS1_SHOWDIRTYSTATE=t
    189         GIT_PS1_SHOWUPSTREAM=auto
    190 
    191         PS1_SHOWGITSTATUS=t
    192     }
    193 
    194     PROMPT_COMMAND=__smart-term/refresh
    195 
    196     PS2=$(
    197         BUILDING_PS=t
    198         __fontify '… ' dim
    199     )
    200 
    201     # Bindings.
    202 
    203     bind -f ~/.bash_inputrc
    204 
    205     # Unset the TTY's "stop" char, so that readline receives C-s.
    206     tty -s && stty stop ''
    207 }
    208 
    209 __dumb-term/set-ps1 ()
    210 {
    211     local -ir rc=$?
    212 
    213     BUILDING_PS=t
    214 
    215     PS1=''
    216     ((rc)) && PS1+=$(__fontify "${rc} " bold red)
    217     PS1+='\W\$ '
    218 
    219     unset BUILDING_PS
    220 }
    221 
    222 __dumb-term/init ()
    223 {
    224     PROMPT_COMMAND=__dumb-term/set-ps1
    225 }
    226 
    227 
    228 case "${TERM}"
    229 in
    230     dumb)   __dumb-term/init ;;
    231     *)      __smart-term/init ;;
    232 esac