Using Readline-Type Features with Apple's Python on OS X 10.5
Edward Moy, an Apple engineer, helped us realize that Mac OSX uses libEdit, rather that GNU readline.
The functionality is basically the same, but the "names" of the functions are different. So you have to use different commands to map keyboard events to the functions. If you try to bind to the GNU readline function names, either it won't work (no readline behavior) or it might crash. Ouch.
I cobbled up two patches for IPython that check to see if the Python is bound to Leopard's libEdit, and if so, to avoid GNU readline bindings, and (as a special case) bind the TAB key to the readline completer function.
This is a great start, but it may not be entirely satisfactory. However, it seems to work well enough for many IPython users.
These patches were applied to the IPython subversion trunk, and I believe that they made it into the 0.82 release.
NOTE: THESE PATCHES EFFECTIVELY DISABLE READLINE COMMANDS IN YOUR .ipythonrc -- YOU WILL NEED TO ADD ANY READLINE KEYBOARD CONFIGURATIONS TO YOUR .editrc instead.
man editrc
Patch 1
1 --- IPython/rlineimpl.py 2007-10-30 17:34:13.000000000 -0600
2 +++ IPython/rlineimpl.py 2007-10-31 10:54:23.000000000 -0600
3 @@ -29,6 +29,16 @@
4 print "Failed GetOutputFile"
5 have_readline = False
6
7 +uses_libedit = False
8 +if sys.platform == 'darwin' and have_readline:
9 + import commands
10 + (status, result) = commands.getstatusoutput( "otool -L %s | grep libedit" % _rl.__file__ )
11 + if status == 0 and len(result) > 0:
12 + # we are bound to libedit - new in Leopard
13 + _rl.parse_and_bind("bind ^I rl_complete")
14 + print "Leopard libedit detected."
15 + uses_libedit = True
16 +
17 # the clear_history() function was only introduced in Python 2.4 and is
18 # actually optional in the readline API, so we must explicitly check for its
19 # existence. Some known platforms actually don't have it. This thread:
Patch 2
1 --- IPython/iplib.py.orig 2007-10-31 13:01:11.000000000 -0600
2 +++ IPython/iplib.py 2007-10-31 13:12:05.000000000 -0600
3 @@ -1325,7 +1325,10 @@
4 if inputrc_name is None:
5 home_dir = get_home_dir()
6 if home_dir is not None:
7 - inputrc_name = os.path.join(home_dir,'.inputrc')
8 + inputrc_name = '.inputrc'
9 + if readline.uses_libedit:
10 + inputrc_name = '.editrc'
11 + inputrc_name = os.path.join(home_dir, inputrc_name)
12 if os.path.isfile(inputrc_name):
13 try:
14 readline.read_init_file(inputrc_name)
15 @@ -1340,8 +1343,9 @@
16 self.set_completer()
17
18 # Configure readline according to user's prefs
19 - for rlcommand in self.rc.readline_parse_and_bind:
20 - readline.parse_and_bind(rlcommand)
21 + if not readline.uses_libedit:
22 + for rlcommand in self.rc.readline_parse_and_bind:
23 + readline.parse_and_bind(rlcommand)
24
25 # remove some chars from the delimiters list
26 delims = readline.get_completer_delims()