Allow __git_ps1 to be used in PROMPT_COMMAND

Changes __git_ps1 to allow its use as PROMPT_COMMAND in bash in addition to setting PS1 with __git_ps1 in a command substitution. PROMPT_COMMAND has advantages for using color without running into prompt-wrapping issues. Only by assigning \[ and \] to PS1 directly can bash know that these and the enclosed zero-width codes in between don't count in the length of the prompt. Signed-off-by: Simon Oosthoek <s.oosthoek@xs4all.nl> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Simon Oosthoek committed Oct 10, 2012 at 21:31 UTC 1bfc51ac814125de03ddf1900245e42d6ce0d250
1 file changed +45 -6
contrib/completion/git-prompt.sh
+45 -6
@@ -10,9 +10,14 @@
10 # 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
11 # 2) Add the following line to your .bashrc/.zshrc:
12 # source ~/.git-prompt.sh
13 -# 3) Change your PS1 to also show the current branch:
14 -# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
15 -# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
13 +# 3a) In ~/.bashrc set PROMPT_COMMAND=__git_ps1
14 +# To customize the prompt, provide start/end arguments
15 +# PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
16 +# 3b) Alternatively change your PS1 to call __git_ps1 as
17 +# command-substitution:
18 +# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
19 +# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
20 +# the optional argument will be used as format string
21 #
22 # The argument to __git_ps1 will be displayed only if you are currently
23 # in a git repository. The %s token will be the name of the current
@@ -195,11 +200,39 @@ __git_ps1_show_upstream ()
200
201
202 # __git_ps1 accepts 0 or 1 arguments (i.e., format string)
198 -# returns text to add to bash PS1 prompt (includes branch name)
203 +# when called from PS1 using command substitution
204 +# in this mode it prints text to add to bash PS1 prompt (includes branch name)
205 +#
206 +# __git_ps1 requires 2 arguments when called from PROMPT_COMMAND (pc)
207 +# in that case it _sets_ PS1. The arguments are parts of a PS1 string.
208 +# when both arguments are given, the first is prepended and the second appended
209 +# to the state string when assigned to PS1.
210 __git_ps1 ()
211 {
212 + local pcmode=no
213 + #defaults/examples:
214 + local ps1pc_start='\u@\h:\w '
215 + local ps1pc_end='\$ '
216 + local printf_format=' (%s)'
217 +
218 + case "$#" in
219 + 2) pcmode=yes
220 + ps1pc_start="$1"
221 + ps1pc_end="$2"
222 + ;;
223 + 0|1) printf_format="${1:-$printf_format}"
224 + ;;
225 + *) return
226 + ;;
227 + esac
228 +
229 local g="$(__gitdir)"
202 - if [ -n "$g" ]; then
230 + if [ -z "$g" ]; then
231 + if [ $pcmode = yes ]; then
232 + #In PC mode PS1 always needs to be set
233 + PS1="$ps1pc_start$ps1pc_end"
234 + fi
235 + else
236 local r=""
237 local b=""
238 if [ -f "$g/rebase-merge/interactive" ]; then
@@ -285,6 +318,12 @@ __git_ps1 ()
318 fi
319
320 local f="$w$i$s$u"
288 - printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
321 + if [ $pcmode = yes ]; then
322 + PS1="$ps1pc_start("
323 + PS1="$PS1$c${b##refs/heads/}${f:+ $f}$r$p"
324 + PS1="$PS1)$ps1pc_end"
325 + else
326 + printf -- "$printf_format" "$c${b##refs/heads/}${f:+ $f}$r$p"
327 + fi
328 fi
329 }