Search code examples
bashreadline

Refreshing bash prompt after calling bind -x command


I have a bash function that changes the directory of my current bash session. I'd like to call the function by pressing Alt-M and am using bind -x to create this mapping. After entering Alt-M on my keyboard, nothing happens in my bash prompt - there is no new line as there would be if a function were typed and then Enter was pressed. I have to press Enter again to get a new prompt on a new line.

How can I force there to be a new prompt on a new line? If I call the function directly/normally (i.e. by typing foo and then hitting enter), the command will work as expected and there will be a bash prompt on a new line, with a refreshed PS1.

Using echo or printf commands in the function doesn't work - it prints a new line, but above the bash prompt, and the bash prompt doesn't refresh. What exactly is not happening here that I want to happen?

foo(){
    dir="/some/path"
    cd $dir
}

bind -x '"\em": foo'

Solution

  • If you use a macro instead of a shell function, you can inject a return keypress:

    bind '"\em": "\C-ex\C-u foo\C-m\C-y\C-b\C-d"'
    
    • \C-e moves to end of line
    • x appends something to ensure line is not empty
    • \C-u deletes the line and saves it in the kill ring
    • foo is the command - leading space stops it getting added to history (assuming HISTCONTROL=ignorespace)
    • \C-m injects the return keypress
    • \C-y restores the original line
    • \C-b\C-d removes the extraneous x we added

    I don't know how to move the cursor back to its original position if it wasn't at end of line. Also the kill ring gets polluted.