How to "bind -x" keyboard shortcut and refresh prompt
I'm trying to bind git branch toggling to a keystroke via following configuration:
bind -x '"\et":"git checkout -"'
This works like charm, however I also have following setup code for displaying branch name in PS1:
PS1='${debian_chroot:+($debian_chroot)}\u@:\W $(parse_git_branch)\$ '
The branch name is nor refreshed after calling my keyboard shortcut until I do, say, cd .
.
The only known workaround I'm aware of is to update config as follows:
bind '"\et":"git checkout - \n"'
Not a big deal, but I wonder what would be the best way to achieve desirable behavior with '-x' key preserved. What I've googled so far is there's redraw-current-line
function but the thing is it's not installed on my Ubuntu and I have no idea how to install it.
Solution 1:
redraw-current-line
is a command in readline, you don't install it. Bash uses the readline library and that's it, the command is already there. You use it with the bind
builtin.
My tests indicate redraw-current-line
redraws the prompt without re-evaluating it. PROMPT_COMMAND
is not triggered, so you cannot use it to update the prompt either. For comparison: clear-screen
behaves similarly.
In other words Bash remembers your prompt and redraws it without running parse_git_branch
again. It seems the only way to actually re-evaluate is to type a command (possibly empty) and hit Enter. Your "git checkout - \n"
emulates this: git checkout -
is the command and \n
works like Enter.
I understand in at least one aspect bind -x '"\et":"git checkout -"'
is better than bind '"\et":"git checkout - \n"'
. The former binding can be used while typing a random command and it doesn't interfere with what you typed. The latter binding generates a mess in such case.
But only the latter binding re-evaluates the prompt.
There is a relatively complex way to have your cake and eat it:
_save_command_line() {
READLINE_LINE_OLD="$READLINE_LINE"
READLINE_POINT_OLD="$READLINE_POINT"
READLINE_LINE=
READLINE_POINT=0
}
_restore_command_line() {
READLINE_LINE="$READLINE_LINE_OLD"
READLINE_POINT="$READLINE_POINT_OLD"
}
bind -x '"\C-x\C-s":"_save_command_line; git checkout -"'
bind -x '"\C-x\C-r":"_restore_command_line"'
bind '"\et":"\C-x\C-s\n\C-x\C-r"'
Now if you type Esct then Bash will:
- send Ctrl+x,Ctrl+s to itself, this will run
_save_command_line; git checkout -
; note_save_command_line
not only saves but also clears the command line; - send
\n
to itself, i.e. Ctrl+j which works like Enter; so it's Enter in our now empty command line; this will re-evaluatePS1
and print a new prompt; - send Ctrl+x,Ctrl+r to itself, this will run
_restore_command_line
.
This way you can run git checkout -
and re-evaluate the prompt without disrupting the current command line.