I invested a chunk of time yesterday resolving one of life's great mysteries:
Why does Ctrl-W in the Python shell on the Mac delete the whole previous line instead of only the previous word?
Normally in readline programs, Ctrl-W is bound to the unix-word-rubout
command, which deletes the previous word. I'm used to using it to undo typos or change the ends of commands in bash, so it's enraging when using it in the Python shell deletes the rest of the juicy useful line accidentally.
I read a bunch of interesting things about readline, none of which actually seemed to affect the shell at all. For instance, Ctrl-Underscore should be useful to undo Ctrl-W's infuriating line-blanking... except that also, for the same mysterious reason, doesn't work on the Mac. According to man readline
, this (on demand, in the Python shell) should fix it:
>>> readline.bind_and_parse(r'C-w: unix-word-rubout')
and yet that, too, does absolutely nothing.
Ultimately my ever-widening whorl of searches hit readline on pypi, and also this post of Peter Woodman's that records the admission buried deep in the Mac's man python2.6:
The Python inteterpreter [sic] supports editing of the current input line and history substitution, similar to facilities found in the Korn shell and the GNU Bash shell. However, rather than being implemented using the GNU Readline library, this Python interpreter uses the BSD EditLine library editline(3) with a GNU Readline emulation layer.
ARGH.
I was doubly astrayed from this conclusion because man readline worked perfectly well on my Mac, so obviously the readline library is available. When I look where it is, though, I realize:
mark@mac:~$ man -w readline
/usr/local/share/man/man3/readline.3
mark@mac:~$ readlink `man -w readline`
../../../Cellar/readline/6.0/share/man/man3/readline.3
it's finding the Homebrew version of readline, which of course isn't what the stock Mac Python's readline module is using.
What to do about it
The PyPI description of readline suggests installing it and being done. I decided to take an alternate tack, which was to make a new .editrc
file to configurate editline apps. Editline doesn't even use the same command names for the regular commands, so instead of unix-word-rubout
, I consulted man editrc
to find that:
- the
readline.parse_and_bind()
s I tried in the Python shell didn't work because the bind command syntax is entirely different, and - I wanted
ed-delete-prev-word
to delete the previous word.
So my .editrc
ends up like this:
bind ^W ed-delete-prev-word
bind ^R ed-search-prev-history
bind ^_ vi-undo
Unfortunately editline also includes a much less awesome history search, so maybe I should just install readline from PyPI anyway. At least I can again delete bad words with impunity—which is great, since it aroused so many to choose from.
great background research. this kind of almost-but-not-quite-right behavior drives me nuts in the mysql shell as well.
Posted by: finn | 07/26/2010 at 11:22 AM