0

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?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
JHH
  • 8,567
  • 8
  • 47
  • 91
  • My feeling is that somehow the escape sequences in the prompt are considered real printable chracters. After all, bash does not "know" anything about escape codes. For verifying it, you could temporarily remove all the escape sequences and see whether the behaviour is back to normal then? – user1934428 Jan 10 '23 at 15:00
  • 1
    BTW, while the differences aren't relevant to your problem, `echo -e ...` is a bad practice as a whole; `printf '%b\n' ...` is the preferred alternative. See [Why is printf better than echo?](https://unix.stackexchange.com/questions/65803/why-is-printf-better-than-echo) over at [unix.se]. – Charles Duffy Jan 10 '23 at 16:34
  • 1
    And yes, bash only knows which things in a prompt are nonprintable by the `\[` and `\]` sequences around them; don't add those, and the characters are expected to move the cursor like any other. This is [BashFAQ #53](https://mywiki.wooledge.org/BashFAQ/053). – Charles Duffy Jan 10 '23 at 16:35

0 Answers0