This one may be a bug with readline/bash itself, but I noticed after using fzf keybindings, which make use of redraw-current-line, that my prompt doubled up a lot.
You can reproduce this without fzf, with just bash by doing this:
bind '"\er": redraw-current-line'
PS1="first\nsecond"
Your prompt should now show
second
After pushing ESC-r a few times (or meta-r), then it shows
first
first
second
This is showing that the first line is overlapping with the last line. I say last, as you could set it to PS1="first\nsecond\nthird" and you get
second
first
second
first
second
third
Let me know if I should just file this with bash/readline directly, or whether you want it here to find a way around it?
Cheers,
Hugh
Interesting. Thanks for the heads up. Do you think we can find a workaround?
Haha, I'm googling this as we speak. I don't really want to go back to a single line prompt after getting used to my multi line one for so long... Though the extra new lines (my first line of my PS1 is just a blank) do take up a lot of vertical space.
Will let you know if I find a workaround, otherwise probably need to send this to bash/readline.
Not sure if similar behaviour happens on the other shells.
Cheers,
Hugh
Sent this to bash:
From: Hugh Davenport <scrubbed>
To: bug-bash AT gnu.org,bash AT packages.debian.org
Subject: redraw-current-line fails with multiline prompts
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall
uname output: Linux laptop 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u2 (2016-01-02) x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu
Bash Version: 4.3
Patch Level: 30
Release Status: release
Description:
Assume I have a multiline prompt (`PS1="first\nsecond"`), and a bind to
redraw-current-line (`bind '"\er": redraw-current-line'`). When I
refresh the line with M-r, I get the following output:
first
first
second
What is happening is that the redraw-current-line is assuming that I
only have a single line prompt, and is just redrawing that current
line. Two possible solutions to this are:
1) Work out the last line of the prompt and only redraw that (makes
sense with function name, or
2) Work out number of lines in the prompt, and redraw entire prompt.
Repeat-By:
Have a rc file with the following
PS1="first\nsecond"
bind '"\er": redraw-current-line'
Then start bash with that rc file, and hit M-r a few times, notice that
the last line gets overwritten, but the first line doesn't. You can
expand this by having PS="first\nsecond\nthird" and seeing that the
third line gets overwritten, but not the first and the second. This
leads to a lot of wasted vertical space if you are redrawing often.
Fix:
I've got a patch for option 2, which works well with existing methods,
but makes the function name a bit misleading.
index f29adf8..183aea4 100644
--- a/lib/readline/text.c
+++ b/lib/readline/text.c
@@ -562,8 +562,14 @@ rl_refresh_line (ignore1, ignore2)
int ignore1, ignore2;
{
int curr_line;
+ int newlines;
+ char *s;
curr_line = _rl_current_display_line ();
+ /* Detect any new lines on current prompt */
+ for (newlines = 0, s = rl_prompt; s[newlines]; s[newlines] == '\n' ? newlines++ : *s++);
+ /* Shift up current line by number of new lines */
+ curr_line -= newlines;
_rl_move_vert (curr_line);
_rl_move_cursor_relative (0, rl_line_buffer); /* XXX is this right */
Nice :+1:
Possibly related: using C-R in bash when _not_ on the first (visible) line and pushing Esc right after that causes the bash prompt to repaint one line up, and leave an artifact on the bottom line.
himdel@niniel:~$ #cursor is here now
himdel@niniel:~$ $(__fzf_history__)
(bash version 4.3.42, libreadline5 5.2)
Got a reply from chat (bug maintainer).
Thanks for the report. It's sufficient to change the call from
rl_forced_update_display to rl_redraw_prompt_last_line (your option 1).
This is what bash does for bash_execute_unix_command().
Chet
I replied:
Hey Chet,
Thanks for your reply. OK, so my patch doesn't need that weird for loop.
I couldn't find the redraw_prompt_last_line function when I had a quick
search.
Would that change be something that you would do to replace the readline
function binding redraw_current_line, or would it be something else that
would be exposed? It would be great if there was a way to redraw the prompt
without it generating a lot of extra vertical lines.
Cheers,
Hugh
@himdel hmm, I don't see that on same version when I use unmodified fzf bindings. I get the $(fzf_history) line removed and stay on the same line. Was that when you just did a brand new shell and pushed enter once then ctrl-r then esc? Or would you need more to reproduce it?
Cheers,
Hugh
Chets reply:
This is something that will be in bash-4.4/readline-7.0. You can get the
current development sources to see how it will work. According to my
change logs, it was added in November, 2014.
Chet
So this is something that will come eventually. I haven't figured out a workaround short of patching bash sadly...
@hughdavenport yes, I open a brand new bash, push enter, push ctrl+r, push escape .. and I get that output.
In case it's locale-dependent, I use en_US.UTF-8, and my terminal is rxvt-unicode. But trying different terminals, it seems xterm and lxterm are not affected, but aterm and rxvt-unicode are.
FWIW: I'm also seeing this behavior in zsh in iTerm2 (OS X).
I was on rxvt-unicode as well, and also on iterm2 osx. Locale was prob en_NZ for both
Same (?) issue on Zsh. I have a $PS1 with a line break in it. If I do CtrlR to search history with fzf, and then select a result (or just hit Esc to exit), the last line before my prompt is deleted. Demo: https://asciinema.org/a/uzF7EeuA2FLSd5UdVeIs8p5eD
Same issue with zsh and a multi-line $PS1.
IIRC, it is part of Zsh鈥檚 behavior that a call to the redisplay widget will cause the prompt to double up (and not be erased and redrawn) when you are using a multi-line prompt. Perhaps someone could look into the Zsh sources and maybe find a way to improve this.
In case you don鈥檛 find any better solution, you might also want to consider implementing a multiline prompt by using a single-line PROMPT and printing any additional lines before the prompt via a pre-command function. This also helped me work around some other issues, such as quirks when resizing the terminal.
Most helpful comment
Same (?) issue on Zsh. I have a
$PS1with a line break in it. If I do CtrlR to search history with fzf, and then select a result (or just hit Esc to exit), the last line before my prompt is deleted. Demo: https://asciinema.org/a/uzF7EeuA2FLSd5UdVeIs8p5eD