This is not a duplicate against the suggested question. The problem turns out to be how to call a function from within PS1
(which requires escaping the function call), and have that function return a string with escape (color) codes.
Using Bash on MacBook Pro M1, in my ~/.bash_profile
I have some logic to provide a nice prompt including the current directory, current git branch etc. Also I have some coloring sequences to make the prompt look e.g. something like this (but with colors):
myuser ~/somepath (master, 1 file changed) $
However, I have a really annoying problem. Whenever a line gets too long, or I use cmd-R (reverse-i-search) to browse previous commands, the cursor will end up in the wrong place and/or the line will be cropped on the screen, making it impossible to alter a previously used line to add a new argument etc, since editing the line will just result in garbage.
My PS1
looks like this (simplified a bit since I managed to boil down to what causes the error described below to appear):
parse_git_branch() {
BRANCH=$(git branch --show-current 2> /dev/null)
if [[ -n $BRANCH ]]; then
# Add (<branch-name>) in purple to the prompt
echo -e "\033[95m(${BRANCH})\033[00m"
fi
}
# Prompt is "<username in yellow> <path in green> <git info> $ "
export PS1="\[\e[33m\]\u \[\e[32m\]\w \[\e[91m\]\$(parse_git_branch)\[\e[00m\]$ "
And this looks fine - the git branch name is added in purple color at the end of the prompt. But as soon as I start scrolling through bash history by using CMD-R or just going up to a previous command, it will behave strangely. For example, If I simply do
myuser ~/somepath (master)$ ls src
And then press CMD-r and type ls
, normally the prompt will behave like this:
(reverse-i-search)`ls': ls src
If I press e.g. cursor right, I will be able to edit that command with the cursor placed on the match (in this case on the l
in ls
).
But with my prompt, instead it will display
myuser ~/somepath (master)$ rch)`ls': ls src
with the cursor on the c
in rch
. And typing foo
will result in
myuser ~/somepath (master)$ rfooch)`ls': ls src
Which if pressing enter will in turn (obviously) result in:
-bash: lfoos: command not found
Clearly something is wrong here with how the line is rendered and where the cursor is placed, and where it appears to be.
I noticed that if I remove the escape sequences for coloring from my parse_git_branch
, it works:
parse_git_branch() {
BRANCH=$(git branch --show-current 2> /dev/null)
if [[ -n $BRANCH ]]; then
echo -e "(${BRANCH})"
fi
}
export PS1="\[\e[33m\]\u \[\e[32m\]\w \[\e[91m\]\$(parse_git_branch)\[\e[00m\]$ "
So I guess there's something wrong with the coloring sequences. I'm not very good at bash escape sequences so I mostly copied these coloring sequences from somewhere, and I guess there's a side-effect I don't understand.
Does anyone know why adding these sequences to the string echoed by parse_git_branch
will cause the prompt to look fine, but overwrite partial lines and behave as if the cursor is in a different position than it actually is when I start re-using old commands or use reverse-i-search?