Index: Modules/readline.c =================================================================== --- Modules/readline.c (revision 74805) +++ Modules/readline.c (working copy) @@ -42,6 +42,19 @@ #endif #endif +#ifdef __APPLE__ +/* + * It is possible to link the readline module to the readline + * emulation library of editline/libedit. + * + * On OSX this emulation library is not 100% API compatible + * with the "real" readline and cannot be detected at compile-time, + * hence we use a runtime check to detect if we're using libedit + */ +static int using_libedit_emulation = 0; +static const char libedit_version_tag[] = "EditLine wrapper"; +#endif /* __APPLE__ */ + static void on_completion_display_matches_hook(char **matches, int num_matches, int max_length); @@ -478,6 +491,29 @@ if (!PyArg_ParseTuple(args, "i:index", &idx)) return NULL; +#ifdef __APPLE__ + if (using_libedit_emulation) { + /* Libedit emulation uses 0-based indexes, + * the real one uses 1-based indexes, + * adjust the index to ensure that Python + * code doesn't have to worry about the + * difference. + */ + HISTORY_STATE *hist_st; + hist_st = history_get_history_state(); + + idx --; + + /* + * Apple's readline emulation crashes when + * the index is out of range, therefore + * test for that and fail gracefully. + */ + if (idx < 0 || idx >= hist_st->length) { + Py_RETURN_NONE; + } + } +#endif /* __APPLE__ */ if ((hist_ent = history_get(idx))) return PyString_FromString(hist_ent->line); else { @@ -978,6 +1014,15 @@ char *line; HISTORY_STATE *state = history_get_history_state(); if (state->length > 0) +#ifdef __APPLE__ + if (using_libedit_emulation) { + /* + * Libedit's emulation uses 0-based indexes, + * the real readline uses 1-based indexes. + */ + line = history_get(state->length - 1)->line; + } else +#endif /* __APPLE__ */ line = history_get(state->length)->line; else line = ""; @@ -1011,16 +1056,34 @@ PyDoc_STRVAR(doc_module, "Importing this module enables command line editing using GNU readline."); +#ifdef __APPLE__ +PyDoc_STRVAR(doc_module_rl, +"Importing this module enables command line editing using libedit readline."); + PyMODINIT_FUNC initreadline(void) { PyObject *m; +#ifdef __APPLE__ + if (strncmp(rl_library_version, libedit_version_tag, strlen(libedit_version_tag)) == 0) { + using_libedit_emulation = 1; + } + + if (using_libedit_emultation) + m = Py_InitModule4("readline", readline_methods, doc_module, + (PyObject *)NULL, PYTHON_API_VERSION); + else + +#endif /* __APPLE__ */ + m = Py_InitModule4("readline", readline_methods, doc_module, (PyObject *)NULL, PYTHON_API_VERSION); if (m == NULL) return; + + PyOS_ReadlineFunctionPointer = call_readline; setup_readline(); } Index: setup.py =================================================================== --- setup.py (revision 74805) +++ setup.py (working copy) @@ -546,22 +546,26 @@ # readline do_readline = self.compiler_obj.find_library_file(lib_dirs, 'readline') - if platform == 'darwin': # and os.uname()[2] < '9.': - # MacOSX 10.4 has a broken readline. Don't try to build - # the readline module unless the user has installed a fixed - # readline package - # FIXME: The readline emulation on 10.5 is better, but the - # readline module doesn't compile out of the box. - if find_file('readline/rlconf.h', inc_dirs, []) is None: - do_readline = False + if platform == 'darwin': + os_release = int(os.uname()[2].split('.')[0]) + if os_release < 9: + # MacOSX 10.4 has a broken readline. Don't try to build + # the readline module unless the user has installed a fixed + # readline package + # readline module doesn't compile out of the box. + if find_file('readline/rlconf.h', inc_dirs, []) is None: + do_readline = False if do_readline: if sys.platform == 'darwin': - # In every directory on the search path search for a dynamic - # library and then a static library, instead of first looking - # for dynamic libraries on the entiry path. - # This way a staticly linked custom readline gets picked up - # before the (broken) dynamic library in /usr/lib. - readline_extra_link_args = ('-Wl,-search_paths_first',) + if os_release < 9: + # In every directory on the search path search for a dynamic + # library and then a static library, instead of first looking + # for dynamic libraries on the entiry path. + # This way a staticly linked custom readline gets picked up + # before the (broken) dynamic library in /usr/lib. + readline_extra_link_args = ('-Wl,-search_paths_first',) + else: + readline_extra_link_args = () else: readline_extra_link_args = () Index: Doc/library/readline.rst =================================================================== --- Doc/library/readline.rst (revision 74805) +++ Doc/library/readline.rst (working copy) @@ -15,6 +15,17 @@ interactive prompt and the prompts offered by the :func:`raw_input` and :func:`input` built-in functions. +..note:: + + On MacOS X the :mod:`readline` module can be implemented + using the ``libedit`` C library, which has a configuration + file that is different from GNU readline. + + The string ``libedit`` will be present in the doc-string of + the :mod:`readline` module when it is linked to libedit and + not when linked with GNU readline. + + The :mod:`readline` module defines the following functions: @@ -182,7 +193,6 @@ Append a line to the history buffer, as if it was the last line typed. - .. seealso:: Module :mod:`rlcompleter`