.bash_prompt (4236B)
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 32 __show-hostname && title+=@${HOSTNAME} 33 34 # Empirically, no need to escape slashes in $HOME: Bash seems to 35 # parse ${VAR/#PAT/REP} by (1) splitting VAR, PAT & REP (2) *then* 36 # expanding PAT? 37 title+=:${PWD/#${HOME}/\~} 38 39 # Cf. console_codes(4): 40 # 41 # ESC ] 2 ; txt ST Set window title to txt. 42 # 43 # ST is a "string terminator", either "ESC \" or "BEL". 44 45 printf $'\E]2;%s\a' "${title}" 46 } 47 48 # Bash relies on \[ \] to distinguish non-printing characters in prompts. 49 __start-nonprinting () 50 { 51 test ${BUILDING_PS} && printf '\[' 52 } 53 54 __end-nonprinting () 55 { 56 test ${BUILDING_PS} && printf '\]' 57 } 58 59 __fontify () 60 { 61 local -r text=$1 62 shift 63 64 local -Ar codes=( 65 [bold]=1 66 [dim]=2 67 [reverse]=7 68 [red]=31 69 [green]=32 70 [blue]=34 71 ) 72 73 local -a params=() 74 local c 75 for c 76 do 77 params+=(${codes[${c}]}) 78 done 79 80 local params_seq 81 IFS=';' eval 'params_seq="${params[*]}"' 82 83 __start-nonprinting 84 printf $'\E[%sm' "${params_seq}" 85 __end-nonprinting 86 87 printf %s "${text}" 88 89 __start-nonprinting 90 printf $'\E[0m' 91 __end-nonprinting 92 } 93 94 __current-column () 95 { 96 # Cf. console_codes(4) § ECMA-48 Status Report Commands. 97 98 local position 99 read -sdR -p$'\E[6n' position 100 101 local -r pattern='\[[0-9]+;([0-9]+)' 102 103 [[ ${position} =~ ${pattern} ]] || { 104 echo 0 105 return 106 } 107 echo ${BASH_REMATCH[1]} 108 } 109 110 __signal-no-newline () 111 { 112 local -ir col=$(__current-column) 113 ((col > 1)) || return 114 115 __fontify ∅ bold red 116 echo 117 } 118 119 __write-epilogue () 120 { 121 local -ir rc=$1 122 local -r rc_hex=$(printf %02x ${rc}) 123 124 local -r stamp=$(printf '%(%T)T') 125 126 __fontify '[ ' dim 127 if ((rc)) 128 then 129 __fontify '$?:' dim red 130 __fontify ${rc_hex} bold red 131 else 132 __fontify "\$?:${rc_hex}" dim 133 fi 134 135 __fontify " | ${stamp} ]" dim 136 echo 137 } 138 139 __smart-term/set-ps1 () 140 { 141 PS1=$( 142 BUILDING_PS=t 143 __fontify '\u' green 144 145 __show-hostname && { 146 __fontify @ dim 147 __fontify '\H' bold green 148 } 149 150 printf ' ' 151 152 __fontify '\w' bold blue 153 154 test "${PS1_SHOWGITSTATUS}" && { 155 printf ' ' 156 __fontify "$(__git_ps1 '(%s)')" red 157 } 158 159 printf '\\n' 160 161 __fontify '\$' dim 162 printf ' ' 163 ) 164 } 165 166 __smart-term/refresh () 167 { 168 local -ir rc=$? 169 170 __set-title 171 __signal-no-newline 172 __write-epilogue ${rc} 173 __smart-term/set-ps1 174 } 175 176 __smart-term/init () 177 { 178 # Prompts. 179 180 __have-gitprompt && { 181 . /usr/lib/git-core/git-sh-prompt 182 GIT_PS1_SHOWDIRTYSTATE=t 183 GIT_PS1_SHOWUPSTREAM=auto 184 185 PS1_SHOWGITSTATUS=t 186 } 187 188 PROMPT_COMMAND=__smart-term/refresh 189 190 PS2=$( 191 BUILDING_PS=t 192 __fontify '… ' dim 193 ) 194 195 # Bindings. 196 197 bind -f ~/.bash_inputrc 198 199 # Unset the TTY's "stop" char, so that readline receives C-s. 200 tty -s && stty stop '' 201 } 202 203 __dumb-term/refresh () 204 { 205 local -ir rc=$? 206 __write-epilogue ${rc} 207 } 208 209 __dumb-term/init () 210 { 211 PROMPT_COMMAND=__dumb-term/refresh 212 PS1='\W\$ ' 213 214 # I configure 'M-x shell' to use TERM=dumb-emacs-ansi; empirically 215 # this makes Bash emit this bracketed paste sequence… 216 # 217 # ^[[?2004l^M^J^[[?2004h 218 # 219 # … whenever I send a command in a nested shell ('bash' started 220 # within the original shell, without --noediting). 221 # 222 # Until I figure something smarter: 223 bind 'set enable-bracketed-paste off' 2>/dev/null 224 # (Silence stderr: 'bind' complains when run with --noediting) 225 } 226 227 228 case "${TERM}" 229 in 230 dumb*) __dumb-term/init ;; 231 *) __smart-term/init ;; 232 esac