Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2efd924

Browse files
Merged revisions 74970 via svnmerge from
svn+ssh://[email protected]/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. ........
1 parent f172f31 commit 2efd924

5 files changed

Lines changed: 133 additions & 10 deletions

File tree

Doc/library/readline.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ made using this module affect the behaviour of both the interpreter's
1414
interactive prompt and the prompts offered by the built-in :func:`input`
1515
function.
1616

17+
..note::
18+
19+
On MacOS X the :mod:`readline` module can be implemented using
20+
the ``libedit`` library instead of GNU readline.
21+
22+
The configuration file for ``libedit`` is different from that
23+
of GNU readline. If you programmaticly load configuration strings
24+
you can check for the text "libedit" in :const:`readline.__doc__`
25+
to differentiate between GNU readline and libedit.
26+
27+
1728
The :mod:`readline` module defines the following functions:
1829

1930

@@ -166,7 +177,6 @@ The :mod:`readline` module defines the following functions:
166177

167178
Append a line to the history buffer, as if it was the last line typed.
168179

169-
170180
.. seealso::
171181

172182
Module :mod:`rlcompleter`

Lib/test/test_readline.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
Very minimal unittests for parts of the readline module.
3+
4+
These tests were added to check that the libedit emulation on OSX and
5+
the "real" readline have the same interface for history manipulation. That's
6+
why the tests cover only a small subset of the interface.
7+
"""
8+
import unittest
9+
from test.support import run_unittest
10+
11+
import readline
12+
13+
class TestHistoryManipulation (unittest.TestCase):
14+
def testHistoryUpdates(self):
15+
readline.clear_history()
16+
17+
readline.add_history("first line")
18+
readline.add_history("second line")
19+
20+
self.assertEqual(readline.get_history_item(0), None)
21+
self.assertEqual(readline.get_history_item(1), "first line")
22+
self.assertEqual(readline.get_history_item(2), "second line")
23+
24+
readline.replace_history_item(0, "replaced line")
25+
self.assertEqual(readline.get_history_item(0), None)
26+
self.assertEqual(readline.get_history_item(1), "replaced line")
27+
self.assertEqual(readline.get_history_item(2), "second line")
28+
29+
self.assertEqual(readline.get_current_history_length(), 2)
30+
31+
readline.remove_history_item(0)
32+
self.assertEqual(readline.get_history_item(0), None)
33+
self.assertEqual(readline.get_history_item(1), "second line")
34+
35+
self.assertEqual(readline.get_current_history_length(), 1)
36+
37+
38+
def test_main():
39+
run_unittest(TestHistoryManipulation)
40+
41+
if __name__ == "__main__":
42+
test_main()

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ Library
194194

195195
Extension Modules
196196
-----------------
197+
- Issue #6877: It is now possible to link the readline extension to the
198+
libedit readline emulation on OSX 10.5 or later.
197199

198200
- Issue #6848: Fix curses module build failure on OS X 10.6.
199201

Modules/readline.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,25 @@ extern char **completion_matches(char *, CPFunction *);
4242
#endif
4343
#endif
4444

45+
#ifdef __APPLE__
46+
/*
47+
* It is possible to link the readline module to the readline
48+
* emulation library of editline/libedit.
49+
*
50+
* On OSX this emulation library is not 100% API compatible
51+
* with the "real" readline and cannot be detected at compile-time,
52+
* hence we use a runtime check to detect if we're using libedit
53+
*
54+
* Currently there is one know API incompatibility:
55+
* - 'get_history' has a 1-based index with GNU readline, and a 0-based
56+
* index with libedit's emulation.
57+
* - Note that replace_history and remove_history use a 0-based index
58+
* with both implementation.
59+
*/
60+
static int using_libedit_emulation = 0;
61+
static const char libedit_version_tag[] = "EditLine wrapper";
62+
#endif /* __APPLE__ */
63+
4564
static void
4665
on_completion_display_matches_hook(char **matches,
4766
int num_matches, int max_length);
@@ -478,6 +497,29 @@ get_history_item(PyObject *self, PyObject *args)
478497

479498
if (!PyArg_ParseTuple(args, "i:index", &idx))
480499
return NULL;
500+
#ifdef __APPLE__
501+
if (using_libedit_emulation) {
502+
/* Libedit emulation uses 0-based indexes,
503+
* the real one uses 1-based indexes,
504+
* adjust the index to ensure that Python
505+
* code doesn't have to worry about the
506+
* difference.
507+
*/
508+
HISTORY_STATE *hist_st;
509+
hist_st = history_get_history_state();
510+
511+
idx --;
512+
513+
/*
514+
* Apple's readline emulation crashes when
515+
* the index is out of range, therefore
516+
* test for that and fail gracefully.
517+
*/
518+
if (idx < 0 || idx >= hist_st->length) {
519+
Py_RETURN_NONE;
520+
}
521+
}
522+
#endif /* __APPLE__ */
481523
if ((hist_ent = history_get(idx)))
482524
return PyUnicode_FromString(hist_ent->line);
483525
else {
@@ -977,6 +1019,15 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
9771019
char *line;
9781020
HISTORY_STATE *state = history_get_history_state();
9791021
if (state->length > 0)
1022+
#ifdef __APPLE__
1023+
if (using_libedit_emulation) {
1024+
/*
1025+
* Libedit's emulation uses 0-based indexes,
1026+
* the real readline uses 1-based indexes.
1027+
*/
1028+
line = history_get(state->length - 1)->line;
1029+
} else
1030+
#endif /* __APPLE__ */
9801031
line = history_get(state->length)->line;
9811032
else
9821033
line = "";
@@ -1010,6 +1061,10 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
10101061
PyDoc_STRVAR(doc_module,
10111062
"Importing this module enables command line editing using GNU readline.");
10121063

1064+
#ifdef __APPLE__
1065+
PyDoc_STRVAR(doc_module_le,
1066+
"Importing this module enables command line editing using libedit readline.");
1067+
#endif /* __APPLE__ */
10131068

10141069
static struct PyModuleDef readlinemodule = {
10151070
PyModuleDef_HEAD_INIT,
@@ -1023,15 +1078,29 @@ static struct PyModuleDef readlinemodule = {
10231078
NULL
10241079
};
10251080

1081+
10261082
PyMODINIT_FUNC
10271083
PyInit_readline(void)
10281084
{
10291085
PyObject *m;
10301086

1087+
#ifdef __APPLE__
1088+
if (strncmp(rl_library_version, libedit_version_tag, strlen(libedit_version_tag)) == 0) {
1089+
using_libedit_emulation = 1;
1090+
}
1091+
1092+
if (using_libedit_emulation)
1093+
readlinemodule.m_doc = doc_module_le;
1094+
1095+
#endif /* __APPLE__ */
1096+
10311097
m = PyModule_Create(&readlinemodule);
1098+
10321099
if (m == NULL)
10331100
return NULL;
10341101

1102+
1103+
10351104
PyOS_ReadlineFunctionPointer = call_readline;
10361105
setup_readline();
10371106
return m;

setup.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -493,16 +493,16 @@ def detect_modules(self):
493493

494494
# readline
495495
do_readline = self.compiler_obj.find_library_file(lib_dirs, 'readline')
496-
if platform == 'darwin': # and os.uname()[2] < '9.':
497-
# MacOSX 10.4 has a broken readline. Don't try to build
498-
# the readline module unless the user has installed a fixed
499-
# readline package
500-
# FIXME: The readline emulation on 10.5 is better, but the
501-
# readline module doesn't compile out of the box.
502-
if find_file('readline/rlconf.h', inc_dirs, []) is None:
503-
do_readline = False
496+
if platform == 'darwin':
497+
os_release = int(os.uname()[2].split('.')[0])
498+
if os_release < 9:
499+
# MacOSX 10.4 has a broken readline. Don't try to build
500+
# the readline module unless the user has installed a fixed
501+
# readline package
502+
if find_file('readline/rlconf.h', inc_dirs, []) is None:
503+
do_readline = False
504504
if do_readline:
505-
if sys.platform == 'darwin':
505+
if platform == 'darwin' and os_release < 9:
506506
# In every directory on the search path search for a dynamic
507507
# library and then a static library, instead of first looking
508508
# for dynamic libraries on the entire path.

0 commit comments

Comments
 (0)