Custom Bash prompt is overwriting itself
Asked Answered
C

3

39

I'm using custom bash prompt to show git branch.

Everything is in /etc/bash/bashrc:

function formattedGitBranch {
    _branch="$(git branch 2>/dev/null | sed -e "/^\s/d" -e "s/^\*\s//")"
    # tried these:
    echo -e "\e[0;91m ($_branch)"                       
    echo -e "\e[0;91m ($_branch) \e[m"                  
    echo -e $'\e[0;91m'"($_branch)"
    echo "($_branch)"                                   
    echo "$(tput setaf 2) ($_branch) $(tput setaf 9)"
    printf "\e[0;91m ($_branch)"
}

# color is set before function call
PS1='\[\033[01;34m\] \[\033[0;91m\]$(formattedGitBranch) \$\[\033[00m\] '
# color is set inside function
PS1='\[\033[01;34m\] $(formattedGitBranch) \$\[\033[00m\] '

Problem is that when I set color for $_branch in the function, my prompt will be overwritten when EOL is reached:

mmmmmmmmmmmmp/rainyday.js (master) $ mmmmmmmm

Tried all possible variants tput, printf, $'' notation.

I solved the problem by setting the colour only in PS1:

ad@gentoo /tmp/rainyday.js (master) $ mmmmmmm

But..

  1. I would like to know why it is overwriting my prompt
  2. How to fix this issue when function is used

I'm using Gentoo Linux. GNU bash, verze 4.2.37(1)-release (i686-pc-linux-gnu)

Crawler answered 30/9, 2013 at 10:57 Comment(0)
C
68

1) I would like to know why it is overwriting my prompt

Because every non-printable characters have to be escaped by \[ and \] otherwise readline cannot keep track of the cursor position correctly.

You must put \[ and \] around any non-printing escape sequences in your prompt.
Without the \[ \] bash will think the bytes which constitute the escape sequences for the color codes will actually take up space on the screen, so bash won't be able to know where the cursor actually is.

\[ Begin a sequence of non-printing characters. (like color escape sequences). This allows bash to calculate word wrapping correctly.

\] End a sequence of non-printing characters. -- BashFAQ

...note the escapes for the non printing characters, these ensure that readline can keep track of the cursor position correctly. -- ss64.com

2) How to fix this issue when function is used

If you want to set colours inside a function whose output is used in PS you have two options.

  • Either escape the whole function call:

    PS1='\[ $(formattedGitBranch) \] '

  • Or replace the non-printing Escape sequences inside echo. That is, replace:

    \[ and \] with \001 \002

    (thanks to user grawity!)

  • echo -e is not aware of bash's \[ \] so you have to substitute these with \001 & \002 ASCII control codes to delimit non-printable chars from printable:

    function formattedGitBranch { echo -e "\001\e[0;91m\002 ($_branch)"; } PS1='$(formattedGitBranch) '

Crawler answered 21/10, 2013 at 18:1 Comment(4)
I was using \[ without using \] and it was causing a similar issue to OP. Thank you.Quetzal
If it's not already obvious: in addition to ensuring that all non-printable characters are wrapped in \[ \], you also have to ensure that all printable characters are not wrapped. Incorrectly wrapping a printable character causes the same type of problems as failing to wrap a non-printable one.Superstructure
I wasn't using echo -e for my prompt-string, but I had the same issue. Using \001 and \002 instead of \[ and \] also solved it. Many thanks!! It was bugging me for over a year, now.Haya
The link also suggests to use the hexadecimal versions \x01 and \x02 instead to avoid a "bash bug that causes it to eat one digit too many when processing octal escapes".Alenaalene
S
16

Strings like \e[0;91m needs additional quoting, to prevent bash from calculating its length.

Enclose these strings from formattedGitBranch in \[ & \] as, \[\e[0;91m\]

You have done it correctly in other places. Just missed it in formattedGitBranch.

Sweep answered 30/9, 2013 at 11:1 Comment(6)
No I omitted it becase I have a note in my bashrc that it doesn't work. (My) echo -e can't handle \[ \] i.sstatic.net/4T0VQ.png But you are probably right that the closing is needed, but I don't have clue how to close it in echo.Crawler
echo is just producing the characters for the value of PS1. The bash shell will handle the actual display of your prompt after removing the \[ and \].Strained
@Sweep did you mean: \[ $(formattedGitBranch) \]? I was very confused by your last sentence "Just missed it in formattedGitBranch." Thought you are talking about echo -e ... which is INside formattedGitBranch function.Crawler
^^ I have not really tried echo -e in PS1, but I suspected that it was the only missing thing. \[$(formattedGitBranch)\] is worth trying too.Sweep
downvoter, please let me know what was the mistake, so that I can rectify and learn...Sweep
This was exactly what caused my spacing issue! Replaced \e[1;32m by \[\e[1;32m\] etc. and the prompt was not overwritten / jumped sooner than expected!Gabbert
G
0

You have to take care of non printable character inside [\ and ] otherwise you might be getting cursor right on top of command prompt as shared in question itself , so I found something and just sharing it :-

For getting cursor after PS1 output on the same line :

After

few examples :

PS1='[\u@\h:\w]\$
PS1='[\[\033[0;32m\]\u@\h:\[\033[36m\]\W\[\033[0m\]]\$ '

Refer Link : syntax for bash PS1

Galliot answered 10/5, 2017 at 15:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.