.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