Bash prompt line wrapping issue - macos

Newbie question, I recently changed my PS1 into this:
RESET="\[\017\]"
NORMAL="\[\033[0m\]"
YELLOW="\[\033[0;33m\]"
CYAN="\[\033[0;36m\]"
export PS1="\[$RESET\]\u#\h:\[$CYAN\]\w\[$YELLOW\]\$(__git_ps1)\[$NORMAL\] \$ "
But now I get a line wrapping error. I created a gif to explain the problem:
Any ideas what might be wrong?

I think you're double-quoting your escape codes with [ and ]. Try this one:
export PS1="$RESET\u#\h:$CYAN\w$YELLOW\$(__git_ps1)$NORMAL \$ "

The wrapping error occurs whenever a non-printing character is not escaped (such as the escape codes that change the prompt color). It also occurs when the locale is set to something that does not understand unicode characters and the prompt includes them. An example would be non-breaking spaces. When the locale is "C" and there are unicode characters in the prompt, the shell thinks more characters are being printed than truly are, and the prompt wraps around prematurely.

shopt -s checkwinsize this should fix your problem.
This will set the variable checkwinsize on. This is set by default in /etc/bashrc however since you're using your custom .bashrc file you can put this code in there or in your .bashrc file load the /etc/bashrc by adding . /etc/bashrc at the top of your .bashrc file.

Related

Adding to $PS1 variable on Git Bash for Windows using ~/.bash_profile causes an issue with __git_ps1

So I am trying to customize the PS1 value to add a check mark or x to the prompt depending on the result of the previous command. Surprisingly I got that part to work fine.
However, it has broken the part of the prompt that shows the Git branch when viewing a Git repository.
Here is the previous PS1 value:
user#PC MINGW64 ~/Git
$ echo $PS1
\[\033]0;$TITLEPREFIX:$PWD\007\]\n\[\033[32m\]\u#\h \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\]`__git_ps1`\[\033[0m\]\n$
and here is the new ~/.bash_profile script that breaks it:
function nonzero_return() {
RETVAL=$?
if [[ $RETVAL -ne 0 ]]
then
echo "❌ ($RETVAL)"
else
echo "✅"
fi
}
export PS1="\[\e[31m\]\`nonzero_return\`\[\e[m\]\[\033]0;$TITLEPREFIX:$PWD\007\]\n\[\033[32m\]\u#\h \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\]`__git_ps1`\[\033[0m\]\n$"
Here is an example of the old prompt versus the new one:
user#PC MINGW64 ~/Git/docker-brew-ubuntu-core (dist-amd64)
$
✅
user#PC MINGW64 ~/Git/docker-brew-ubuntu-core
$
❌ (127)
user#PC MINGW64 ~/Git/docker-brew-ubuntu-core
$
SOLUTION
Thanks to #davlet, #joanis, and #torek for helping me resolve this issue. I also used some other suggestions from them to edit my PS1 value even further into a place that I really liked. If anyone is curious, here is the new ~/.bash_profile script:
function nonzero_return() {
local RETVAL=$?
if [[ $RETVAL -ne 0 ]]
then
echo "❌($RETVAL)"
else
echo "✅"
fi
}
PS1='\[\e]0;Git Bash: $MSYSTEM\007\]\n\[\e[31m\]`nonzero_return`\[\e[32m\] \u#\h \[\e[35m\]\w\[\e[36m\]`__git_ps1`\e[0m\n$'
I think you want to use single quotes when assigning to PS1, and loose the backslashes before backticks. Also PS1 shouldn’t be exported:
PS1='\[\e[31m\]`nonzero_return`[...]'
Also, make RETVAL local in your helper function, otherwise it may interfere with other scripts, ie:
local RETVAL=$?
I'm going to steal that prompt, I really like it!
You just need to escape the backticks around __git_ps1:
export PS1="\[\e[31m\]\`nonzero_return\`\[\e[m\]\[\033]0;$TITLEPREFIX:$PWD\007\]\n\[\033[32m\]\u#\h \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\]\`__git_ps1\`\[\033[0m\]\n$"
The difference is
...\`__git_ps1\`...
instead of
...`__git_ps1`...
in the export statement.
A bit of an explanation
The way the PS1 variable works is that it gets evaluated each time the prompt is printed. That's why you can have functions in it like __git_ps1 or your nonzero_return do something different each time the prompt is printed.
When you use double quotes to define PS1, e.g.:
PS1="...`my_function`...$MYVAR..." # won't work
the shell applies normal double quote expansion right when PS1 is defined, which includes expanding that backtick'd function call, and filling in the current value of $MYVAR, storing only the results in PS1, which is not what you want.
If you escape the backticks, or, better yet, use single quotes as #davlet said, PS1 now contains those backticks and variables themselves, which get evaluation each time the prompt is printed.
You can give it a try: if you use single quotes and then change the value of $MSYSTEM, your prompt will reflect that change right away. The get the same effect with double quotes, you'd have to escape the $.
Getting rid of that newline
In the comments, you ask how to remove the newline after the checkmark or X. That newline comes from the \n you have in the middle of your PS1 definition. But I personally like that newline, because it means my prompt is preceded by a blank line, separating it more nicely from the output of the previous command, especially if that didn't output its own newline.
Here's how I would tweak your prompt:
PS1='\[\033]0;$TITLEPREFIX:$PWD\007\]\n\[\e[31m\]`nonzero_return`\[\e[m\]\[\033[32m\]\u#\h \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\]`__git_ps1`\[\033[0m\]\n$'
Details:
\[\033]0;$TITLEPREFIX:$PWD\007\] sets the Window's title bar
\n separates the prompt from the previous command's output
[\e[31m\]nonzero_return\[\e[m\] your return code function in bold red (note that the \[\e[m|] is superfluous here: it says reset the colour, but your next thing sets the colour again)
\[\033[32m\]\u#\h user#host in green
\[\033[35m\]$MSYSTEM the value of $MSYSTEM in purple
\[\033[33m\]\w current working directory in yellow
\[\033[36m\]`__git_ps1` is the Git status in Cyan
\[\033[0m\] resets the font
\n is the newline
$ is the "superuser indicator" which turns to # when you are the superuser.
More notes:
As #torek points out, \[ and \] are unnecessary before the final \n
You mix \e and \033: those are both escape sequences inserting an actual escape character in there. I prefer to use \e everywhere because I find it more legible.
This is a useful reference on bash prompts: https://wiki.archlinux.org/title/Bash/Prompt_customization

What is the equivalent of \[ ... \] in zsh?

In my .bashrc file, when I colour the prompt, I use \[ ... \] to prevent new bash lines overwriting previous ones (also prevent writing buffer overflow/underflow or cases when text being typed in random locations). This only happens when using colours. In my .bashrc file I have:
WHITE="\[$(tty -s && tput setaf 254)\]";
PS1+="${WHITE} # "
But \[ escapes don't work on zsh in .zshrc
How can I fix this please?
The zsh equivalent is %{ ... %}. However, it's not needed as frequently because zsh has a much richer set of prompt escapes that eliminate the need to use raw escape sequences. For example, the %F escape lets you select a foreground color by name or number. zsh already knows how to query your terminal for the exact bytes to use, and zsh also knows that those bytes should not count towards the width of the prompt.
PS1+="%F{white} # "
or
PS1+="%F{254} # "

What in PS1 is causing my Terminal.app commands to get stuck on the screen?

When cycling through statements entered to the console, I occasionally find that the text I entered isn't refreshed and the prompt is moved to the right.
My original, intended prompt: http://cl.ly/image/04080N260L1V.
What happens after hitting the Up and Down arrows about a dozen times: http://cl.ly/image/1n3S2K31340R.
In case the screenshots aren't clear, the underlined text (in this case, "vim ~/.bas") is getting "added" to the prompt. I can't delete it out. However, if I delete as much as I can, clearing any text after the prompt, and hit Enter, I'm greeted with my clean, original prompt again: http://cl.ly/image/2O1h1Z2y0n2I.
Here's what ~/.bash_profile contains:
# Simpler bash prompt in Terminal.app
promptColor="\e[1;34m"
endColor="\e[m"
#export PS1='\e[0;36m\w$ \e[0m'
export PS1="$promptColor\w$ $endColor"
# Syntax highlighting for commands like `ls` and such
alias ls="ls -G"
# PATH ammendment to put Homebrew-installed apps in front of system-provided ones
homebrew=/usr/local/bin:/usr/local/sbin:/usr/local/share/npm/bin
export PATH=$homebrew:$PATH
I've narrowed the culprit down to the PS1 variable. (You can see I've tried this a few different ways.) Based on what I've read, I'm using the color codes correctly.
Any help would be fantastic. Thanks.
This is a FAQ. In order for Bash to be able to compute the display length of the prompt correctly, any non-printing sequences such as color codes need to be inside a \[...\] sequence.
I think you want:
promptColor='\e[1;34m'
endColor='\e[m'
export PS1="$promptColor"'\w$ '"$endColor"
(Notice all the subtle changes from double to single-quotes)
The problem is that bash is doing expansion on the following when they need to be interpreted explicitly:
\e[1;34m
\w$
\e[m
Single-quotes and double-quotes mean different things in shell: Strong Quoting vs. Weak Quoting.
I would also just copy and paste the lines with escaped characters and modify them (note that they aren't the same as literal representations)

Mac OS X Terminal command stuck after pressing up arrow

In my mac terminal, after pressing up a couple of times to see my previous commands, a command gets stuck in the terminal. It goes something like this,
Normal:
[ 10:23:34 ] > MY_COMMAND
After a couple of times pressing up
[ 10:23:34 ] > git commit -mMY_COMMAND
[ 10:23:35 ] > git commit -mMY_COMMAND
[ 10:23:36 ] > git commit -mMY_COMMAND
The git commit -m is just stuck there until I type 'clear' in the terminal. How do I fix this?
The most likely cause is an incorrectly formatted PS1 prompt string. When you put non-printing control characters in the prompt you must surround them with \[ … \] to tell Bash to not count them when calculating the width of the prompt.
If the width calculation is incorrect, the command-line display can get messed up in several ways, including the way you've described.
In a comment you wrote:
This is my .bash_profile export PATH=${PATH}:/Users/offirgolan/android-sdk-macosx/platform-tools export TERM="xterm-color" alias ls="ls -G" export PS1="\e[1;30m][\e[\e[1;30m]\e[1;33m] \u#\H [\e[1;32m]\w[\e[0m] \e[1;30m]]\n[[ \e[1;31m]\T[\e[0m]\e[1;30m] ] > \e[37m]"
It looks like you may have intended to include bracketing, because of all the extra brackets without a leading backslash, but they are inconsistent and your string even contains incomplete escape sequences like \e[\e[. It's difficult to tell which brackets, if any, you intended to display in the prompt, and what color you want them, but your PS1 should be something more like
PS1='\[\e[1;30m\][\[\e[1;30m\e[1;33m\] \u#\H [\[\e[1;32m\] \w\[\e[0m \e[1;30m\]]\n[ \[\e[1;31m\]\T\[\e[0m\e[1;30m\] ] > \[\e[37m\]'
Pro-Tip: Don't hard-code terminal commands in your prompt—they aren't portable and won't work with all terminals. Instead, use tput to select the appropriate command sequences for the current terminal. For example
PS1="\[$(tput setaf 1)\]Red Text\[$(tput sgr0)\] \$ "
will display the prompt "Red Text $ " with “Red Text” in red. This also makes it much easier to see whether the \[ \] brackets are correct, because you don't have literal escape characters littering the string, and the mnemonic tput codes make it easier to figure out what commands are being sent.

Why is this bash prompt acting strangely/disappearing, and how do I fix it (OS X)?

I admit that I use a somewhat long-winded bash prompt:
--(username)-(Wed April 01|12:00:00)--(~ $
Recently, I got the bright idea to change it so that depending on the exit value from the previous command, if success, the interior elements of the ()'s would be green, and if failure, they would be red. I got it working for the most part (some odd exit statuses will change the color to something else, but I'm ok with it), but when typing a command which is more than one line, and causes the terminal to scroll, the prompt disappears! My prompt worked fine when there was no color, so I'm guessing it is related to my color escaping, and particularly my unclosed ['s, but I can't pin it down.
#.profile
export PS1='--(\e[$((32-${?}))m\u\e[0m)-(\e[$((32-${?}))m\d\e[0m|\e[$((32-${?}))m\T\e[0m)--(\e[$((32-${?}))m\w\e[0m \$ '
Thanks in advance!
It sounds like this should solve your problem.
This seems to work for me*:
export PS1='--(\[\e[$((32-${?}))m\]\u\[\e[0m\])-(\[\e[$((32-${?}))m\]\d\[\e[0m\]|\[\e[$((32-${?}))m\]\T\[\e[0m\])--(\[\e[$((32-${?}))m\]\w\[\e[0m\] \$ '
* well, really export PS1='\u#\h:\w\$ ' works for me
To quote the linked post, the answer lies in adding \[ and \] around all of your color sequences in your PS1 declaration:
Before I had the following value for PS1:
'\e[0;34m\h:\w [!]\$\e[0m '
which gave me a nice blue prompt of the following form
hostname:working-directory [command-number]$
However, I had the same line-wrapping problem you did. The fix was to insert \[ and \] around the ANSI escapes so that the shell knows not to include them in the line wrapping calculation. This results in the following value for PS1:
'\[\e[0;34m\]\h:\w [!]\$\[\e[m\] '
http://mywiki.wooledge.org/BashFAQ/053 -- I have a fancy prompt with colors, and now bash doesn't seem to know how wide my terminal is. Lines wrap around incorrectly.
By the way; for your reference; here's my PS1 which looks like this:
(source: lyndir.com)
\[$reset$bold$green\]\u#\h\[$blue\] \W \[$red\]${?/#0/\[$green\]}\$\[$reset\]
Notice how I put all the color codes in $parameters to make it neater, but more importantly, because you should be using tput to generate them. See:
http://mywiki.wooledge.org/BashFAQ/037 -- How can I print text in various colors?
I declare my color parameters in a utility script that gets sourced by my ~/.bashrc (and any scripts I write) which is called bashlib.
On a final note; put your PS1 definition in ~/.bashrc and don't export it. There's absolutely no reason why you should add your PS1 definition to the environment of any and all processes you spawn from your shell.
You just seem to be missing the start and end brackets around your escapes (before the first '\e' and after the last 'm'):
PS1='--(\[\e[$((32-${?}))m\u\e[0m)-(\e[$((32-${?}))m\d\e[0m|\e[$((32-${?}))m\T\e[0m)--(\e[$((32-${?}))m\w\e[0m\] \$ '
As mentioned, the PS1 var does not need to be exported: only your shell needs to see it.

Resources