]> granicus.if.org Git - python/commitdiff
Merged revisions 74970 via svnmerge from
authorRonald Oussoren <ronaldoussoren@mac.com>
Sun, 20 Sep 2009 14:53:22 +0000 (14:53 +0000)
committerRonald Oussoren <ronaldoussoren@mac.com>
Sun, 20 Sep 2009 14:53:22 +0000 (14:53 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r74970 | ronald.oussoren | 2009-09-20 16:18:15 +0200 (Sun, 20 Sep 2009) | 7 lines

  Issue 6877: this patch makes it possible to link the readline extension
  to the libedit emulation of the readline API on OSX 10.5 or later.

  This also adds a minimal testsuite for readline to check that the
  history manipuation functions have the same interface with both
  C libraries.
........

Doc/library/readline.rst
Lib/test/test_readline.py [new file with mode: 0644]
Misc/NEWS
Modules/readline.c
setup.py

index b59f680c064daa12722e8cac00ee66eab6c6d2d1..ab4a099e8696f76020d9a63c7e1fc1aac6a0cb19 100644 (file)
@@ -14,6 +14,17 @@ made using  this module affect the behaviour of both the interpreter's
 interactive prompt  and the prompts offered by the built-in :func:`input`
 function.
 
+..note::
+
+  On MacOS X the :mod:`readline` module can be implemented using
+  the ``libedit`` library instead of GNU readline.
+
+  The configuration file for ``libedit`` is different from that
+  of GNU readline. If you programmaticly load configuration strings
+  you can check for the text "libedit" in :const:`readline.__doc__`
+  to differentiate between GNU readline and libedit.
+
+
 The :mod:`readline` module defines the following functions:
 
 
@@ -166,7 +177,6 @@ The :mod:`readline` module defines the following functions:
 
    Append a line to the history buffer, as if it was the last line typed.
 
-
 .. seealso::
 
    Module :mod:`rlcompleter`
diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py
new file mode 100644 (file)
index 0000000..b2495a3
--- /dev/null
@@ -0,0 +1,42 @@
+"""
+Very minimal unittests for parts of the readline module.
+
+These tests were added to check that the libedit emulation on OSX and
+the "real" readline have the same interface for history manipulation. That's
+why the tests cover only a small subset of the interface.
+"""
+import unittest
+from test.support import run_unittest
+
+import readline
+
+class TestHistoryManipulation (unittest.TestCase):
+    def testHistoryUpdates(self):
+        readline.clear_history()
+
+        readline.add_history("first line")
+        readline.add_history("second line")
+
+        self.assertEqual(readline.get_history_item(0), None)
+        self.assertEqual(readline.get_history_item(1), "first line")
+        self.assertEqual(readline.get_history_item(2), "second line")
+
+        readline.replace_history_item(0, "replaced line")
+        self.assertEqual(readline.get_history_item(0), None)
+        self.assertEqual(readline.get_history_item(1), "replaced line")
+        self.assertEqual(readline.get_history_item(2), "second line")
+
+        self.assertEqual(readline.get_current_history_length(), 2)
+
+        readline.remove_history_item(0)
+        self.assertEqual(readline.get_history_item(0), None)
+        self.assertEqual(readline.get_history_item(1), "second line")
+
+        self.assertEqual(readline.get_current_history_length(), 1)
+
+
+def test_main():
+    run_unittest(TestHistoryManipulation)
+
+if __name__ == "__main__":
+    test_main()
index 3c4c67b6afdb838116d59f9d7cc3341f89e9e11c..528b3fdc3b030737bfad34be71114bd7367cdc47 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -194,6 +194,8 @@ Library
 
 Extension Modules
 -----------------
+- Issue #6877: It is now possible to link the readline extension to the
+  libedit readline emulation on OSX 10.5 or later.
 
 - Issue #6848: Fix curses module build failure on OS X 10.6.
 
index 8925d8da004c42ccfebc33f13121b0195eef0c99..03c95e3555cf7f63a0dcd7bbfc22350c8ac2779b 100644 (file)
@@ -42,6 +42,25 @@ extern char **completion_matches(char *, CPFunction *);
 #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
+ *
+ * Currently there is one know API incompatibility: 
+ * - 'get_history' has a 1-based index with GNU readline, and a 0-based
+ *   index with libedit's emulation.
+ * - Note that replace_history and remove_history use a 0-based index
+ *   with both implementation.
+ */
+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 +497,29 @@ get_history_item(PyObject *self, PyObject *args)
 
        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 PyUnicode_FromString(hist_ent->line);
        else {
@@ -977,6 +1019,15 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
                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 = "";
@@ -1010,6 +1061,10 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
 PyDoc_STRVAR(doc_module,
 "Importing this module enables command line editing using GNU readline.");
 
+#ifdef __APPLE__
+PyDoc_STRVAR(doc_module_le,
+"Importing this module enables command line editing using libedit readline.");
+#endif /* __APPLE__ */
 
 static struct PyModuleDef readlinemodule = {
        PyModuleDef_HEAD_INIT,
@@ -1023,15 +1078,29 @@ static struct PyModuleDef readlinemodule = {
        NULL
 };
 
+
 PyMODINIT_FUNC
 PyInit_readline(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_emulation) 
+               readlinemodule.m_doc = doc_module_le;
+
+#endif /* __APPLE__ */
+
        m = PyModule_Create(&readlinemodule);
+
        if (m == NULL)
                return NULL;
 
+
+
        PyOS_ReadlineFunctionPointer = call_readline;
        setup_readline();
        return m;
index a6aff54e83538099ac6d2b7c538c3dd5a459b3bb..ebe2344a4e982aefc6af65dd4f5a70ad18218468 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -493,16 +493,16 @@ class PyBuildExt(build_ext):
 
         # 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
+                if find_file('readline/rlconf.h', inc_dirs, []) is None:
+                    do_readline = False
         if do_readline:
-            if sys.platform == 'darwin':
+            if platform == 'darwin' and 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 entire path.