I have defined a bash prompt (using PROMPT_FUNCTION) like so:
function get_hg_prompt_prefix() {
local APPLIED_COLOR=$1; shift
local UNAPPLIED_COLOR=$1; shift
local ALERT_COLOUR=$1; shift
local TEXTCOLOR=$1; shift
local mercurial_prompt_line="{{patches|join(:)|pre_applied(${APPLIED_COLOR})|post_applied(${TEXTCOLOR})|pre_unapplied(${UNAPPLIED_COLOR})|post_unapplied(${TEXTCOLOR})}\n\r}"
local mercurial_status_prompt="{ ${ALERT_COLOUR}{status}${TEXTCOLOR}}"
echo "$(hg prompt "${mercurial_prompt_line}" 2>/dev/null)$(hg prompt "${mercurial_status_prompt}" 2>/dev/null)"
}
function set_prompt() {
bright='\[[01m\]'
colors_reset='\[[00m\]'
HOSTCOLOR=${colors_reset}='\[[34m\]'
USERCOLOR=${colors_reset}='\[[01m\]'
TEXTCOLOR=${colors_reset}='\[[32m\]'
APPLIED_COLOR=${colors_reset}='\[[32m\]'
UNAPPLIED_COLOR=${colors_reset}='\[[37m\]'
ALERT_COLOUR=${colors_reset}='\[[31m\]'
hg_status="$(get_hg_prompt_prefix $APPLIED_COLOR $UNAPPLIED_COLOR $ALERT_COLOUR $TEXTCOLOR)"
ps1_prefix="${hg_status}$colors_reset($bright$(basename $VIRTUAL_ENV)$colors_reset) "
PROMPTEND='$'
PS1="${ps1_prefix}${USERCOLOR}\u${colors_reset}${TEXTCOLOR}@${colors_reset}${HOSTCOLOR}\h${colors_reset}${TEXTCOLOR} (\W) ${PROMPTEND}${colors_reset} "
}
PROMPT_COMMAND=set_prompt
In general, this gives me a multi-line prompt that displays some hg status info as well as my current virtualenv, looking (without colour) like this:
buggy-wins.patch
! (saas) user@computer (~) $
The problem is, this is screwing with the calculation of the length of the prompt (I think!) and causing weird terminal wrapping issues and cursor placement. For example, in an 80-char terminal, here's the prompt I see (the **-surrounded character is the cursor location):
~) $ **a**nis) crose@chris-rose (~
In terminals wide enough to display the prompt, line wrapping occurs much earlier than it should; here's the most text I can fit on the first line of the prompt in a 108-char-wide terminal window (again, the ** marks my cursor location):
**(**advanis) crose@chris-rose (~) $ sdkfjlskdjflksdjff
When the line wraps over, it overwrites the prompt. The second line of input runs right to the edge of the terminal, however, and then wraps correctly.
So, clearly something is messing with the width of the prompt. How can I cause bash to determine the length of the PS1 string not according to the ANSI escape codes, but according to the actual displayed length of the prompt?