Readline / bash: How to map Escape key and Arrow keys

bashcommand linekeyboard shortcutsreadlineterminal

From another piece of command-line driven software, I'm used to the following behavior: Arrow up / down go through the command history, matching lines that match the characters typed so far on the current line, and Esc deletes everything typed so far on the current line. I'm trying to make bash (via readline) do the same. Here's what I put into my .bashrc:

bind 'Escape: kill-whole-line'
bind '"\e[A": history-search-backward'
bind '"\e[B": history-search-forward'

The behavior is not as intended, due to the interference of the mapping of Escape="\e" with the mapping of the escape sequences "\e[A" and "\e[B".

My question: Is there a way to make this work? One possibility would be timing-based, i.e. if \e is followed quickly by another key it is treated as part of a sequence, but if nothing else is coming during some short delay it is treated as a key by itself. However, reading the bash and readline documentation I was not able to come up with such a thing.

Side question: Is there a modern terminal "emulator" which does not actually try to emulate the convoluted behavior of historical machines, but provides programs running in it with unambiguous information about the keys pressed? Which would also enable things like distinguishing between CTRL-A and CTRL-SHIFT-A… I tested these things in KDE's Konsole, which behaves like an xterm, and on the Linux console.

Best Answer

If you are using xterm, you can get it to send a CSI (0x9B) instead of the sequence \e[ by setting the eightBitControl boolean resource. For example, start xterm up like this:

xterm -xrm '*eightBitControl:true'

You can permanently set this resource by editing the XTerm application-specific resource file (Ubuntu seems to put this in /etc/X11/app-defaults but I think /usr/share/X11/app-defaults is more standard.)

But be warned: this will basically break your terminal until you fix up all your keybindings.

As for the more general question, I think it's more difficult than it might at first appear. The Linux console is pretty well designed around generating eight-bit character codes (so it can work with UTF-8). From an actual console (that is, not using X), you can get "raw" scancodes, but then you'd have to do all the keymapping logic yourself (which is what X does, in fact). You might be able to use the X keymapping facilities to generate some specific codes for alt+ctrl+letter combinations, but I don't know where you would squeeze them into the eight-bit coding sequence. I feel your pain, though :)