zsh inserts extra spaces when performing searches and completion - shell

I have written a small program that emits a command line prompt with some Git info. I use ANSI escape sequences to color it, and it looks something like this:
However, whenever I do tab completion or a search, zsh inserts several spaces after the prompt:
It seems to be inserting a space for each escape code character emitted by the prompt, since removing the color codes eliminates this behavior. Why is zsh doing so, and how can I stop this?
The actual character sequence emitted by my prompt program for this example is (assuming \e represents character 033)
~/s/promptd [\e[36mmaster \e[33m±\e[31m?\e[39m]
The relevant portion of my .zshrc is:
setopt PROMPT_SUBST
setopt PROMPT_PERCENT
PROMPT='%B$(promptd) %%%b '

After doing some additional research, the ZSH Prompt Expansion docs indicate that escape literals need to be enclosed in %{...%}.
This is bothersome since now I have to output those conditionally if I want the prompt program to work in other shells, but it seems to correct the behavior shown above.

Related

bash prompt line setting issue [duplicate]

This question already has an answer here:
Bash Prompt Wrapping Issue
(1 answer)
Closed 1 year ago.
I am using xshell to connect a cloud service of centos, and I set the $PS1 value in /etc/bashrc as \e[0;34m[\u#\h \W]$ \e[m which makes my promt a blue color so that I can tell which is my command input and which is the output.
However, this prompt could not automatically add a new line if my command is more than one line. If one line is full, it just starts padding from the left of the same line. You can see the screenshots as follows:
What I want is that the command can automatically add a new line when one line is full.
I tried \n but that just add a new line before command which is not the effect I want.
Now I tried PS1='[\e[0;34m[\u#\h \W]$ \e[m]', the effect is like:
bash can't tell how much space your prompt actually occupies on screen, because the ANSI escape sequences that set colors don't take any space. You need to enclose them (and only them) inside \[...\] to tell bash as much.
PS1='\[\e[0;34m\][\u#\h \W]$ \[\e[m\]'
bash already knows how to handle its own escape sequences \u, \h, and \W. The ANSI escape sequences only have special meaning to the terminal.
That is, \u et al are expanded before bash tries to determine how many characters are in the prompt. For all it knows, \e, [, 0, ;, 3, 4, and m will all be displayed literally as single characters. The terminal sees them, and instead of displaying them, changes the color used to print the following characters.

Bash prompt changes when using arrow keys sometimes

When I use my terminal (iTerm 2 Mac) with my PS1 set to "\[\e[38;5;117m\W \e[39;38;5;104m\$\e[39;0m\] " and I use the arrow keys to go through my bash history it sometimes changes my prompt from ~ $ to just the first character of it and whatever command I'm looking at. For example, going to rvim .bashrc from randomDir $ ls. This problem also persists in the default terminal app.
\W and \$ should not go inside the \[...\], since bash will know how much space each takes up on the terminal.
PS1="\[\e[38;5;117m\]\W \[\e[39;38;5;104m\]\$\[\e[39;0m\] "
Only the characters that make up the ANSI escape sequence (which only instruct the terminal to change colors, without displaying a single additional character) are enclosed in \[...\].
Putting them inside \[...\] tells bash to ignore their contribution to the length of the prompt, leading to incorrect redraws.

Break line in terminal PS1 fix

I have this code to color my terminal:
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\]"
But I have one problem, when text should be in the new line it overwrites the first line.
Example:
In order for bash to figure out how much screen space your prompt takes up (and therefore where the actual command line starts), you have to enclose the non-printing parts of the prompt in \[...\]. Mostly, that means escape sequences like \e[1;30m need to be written as \[\e[1;30m\]. You have some \['s and \]'s in your prompt, but they're in the wrong places, which is making bash very confused. Finding all the printing and non-printing parts of a prompt as complex as yours is not trivial, but I think this gets it right:
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\]'

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)

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