Skip to content

Commit f5f2312

Browse files
committed
Modified readline, specifically completion support and various hooks,
so that it supports ipython 0.10.1 (with a minor patch on os.name in that codebase). Still requires user to provide an alternative properties file, that should be fixed before RC1. Fixes #1133.
1 parent 46dd861 commit f5f2312

2 files changed

Lines changed: 85 additions & 26 deletions

File tree

Lib/readline.py

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,53 @@
77
except AttributeError:
88
raise ImportError("Cannot access JLineConsole")
99

10+
history_list = None
11+
12+
def _setup_history():
13+
# This is obviously not desirable, but avoids O(n) workarounds to
14+
# modify the history (ipython uses the function
15+
# remove_history_item to mutate the history relatively frequently)
16+
global history_list
17+
18+
history = reader.history
19+
try:
20+
history_list_field = history.class.getDeclaredField("history")
21+
history_list_field.setAccessible(True)
22+
history_list = history_list_field.get(history)
23+
except:
24+
pass
25+
26+
_setup_history()
27+
1028
def parse_and_bind(string):
1129
# TODO this should probably reinitialize the reader, if possible
1230
# with any desired settings; this will require some more work to implement
1331

1432
# most importantly, need to support at least
1533
# readline.parse_and_bind("tab: complete")
1634
# but it's possible we can readily support other aspects of a readline file
35+
36+
# XXX first time through, print a warning message about the required setup
37+
# with jline properties (or potentially test...)
1738
pass
1839

1940
def get_line_buffer():
20-
return str(reader.cursorBuffer.buffer) # or use toString to get unicode?
41+
return str(reader.cursorBuffer.buffer)
2142

2243
def insert_text(string):
2344
reader.putString(string)
2445

2546
def read_init_file(filename=None):
26-
pass
47+
print "Not implemented: read_init_file", filename
2748

2849
def read_history_file(filename="~/.history"):
2950
expanded = os.path.expanduser(filename)
3051
new_history = reader.getHistory().getClass()()
3152
with open(expanded) as f:
3253
for line in f:
33-
new_history.addToHistory(line)
54+
new_history.addToHistory(line.rstrip())
3455
reader.history = new_history
56+
_setup_history()
3557

3658
def write_history_file(filename="~/.history"):
3759
expanded = os.path.expanduser(filename)
@@ -42,6 +64,9 @@ def write_history_file(filename="~/.history"):
4264
def clear_history():
4365
reader.history.clear()
4466

67+
def add_history(line):
68+
reader.addToHistory(line)
69+
4570
def get_history_length():
4671
return reader.history.maxSize
4772

@@ -55,22 +80,21 @@ def get_history_item(index):
5580
return reader.history.historyList[index]
5681

5782
def remove_history_item(pos):
58-
# TODO possible?
59-
raise Exception("not implemented")
83+
if history_list:
84+
history_list.remove(pos)
85+
else:
86+
print "Cannot remove history item at position:", pos
6087

6188
def redisplay():
6289
reader.redrawLine()
6390

6491
def set_startup_hook(function=None):
65-
# TODO add
66-
pass
67-
92+
sys._jy_interpreter.startupHook = function
93+
6894
def set_pre_input_hook(function=None):
69-
# TODO add
70-
pass
71-
95+
print "Not implemented: set_pre_input_hook", function
7296

73-
_completion_function = None
97+
_completer_function = None
7498

7599
def set_completer(function=None):
76100
"""set_completer([function]) -> None
@@ -79,42 +103,50 @@ def set_completer(function=None):
79103
for state in 0, 1, 2, ..., until it returns a non-string.
80104
It should return the next possible completion starting with 'text'."""
81105

82-
_completion_function = function
106+
global _completer_function
107+
_completer_function = function
83108

84109
def complete_handler(buffer, cursor, candidates):
110+
start = _get_delimited(buffer, cursor)[0]
111+
delimited = buffer[start:cursor]
85112
for state in xrange(100): # TODO arbitrary, what's the number used by gnu readline?
86113
completion = None
87114
try:
88-
completion = function(buffer[:cursor], state)
115+
completion = function(delimited, state)
89116
except:
90117
pass
91118
if completion:
92119
candidates.add(completion)
93120
else:
94121
break
95-
return 0
122+
return start
96123

97124
reader.addCompletor(complete_handler)
98125

99126

100127
def get_completer():
101-
return _completion_function
128+
return _completer_function
129+
130+
def _get_delimited(buffer, cursor):
131+
start = cursor
132+
for i in xrange(cursor-1, -1, -1):
133+
if buffer[i] in _completer_delims:
134+
break
135+
start = i
136+
return start, cursor
102137

103138
def get_begidx():
104-
# TODO add
105-
pass
139+
return _get_delimited(str(reader.cursorBuffer.buffer), reader.cursorBuffer.cursor)[0]
106140

107141
def get_endidx():
108-
# TODO add
109-
pass
142+
return _get_delimited(str(reader.cursorBuffer.buffer), reader.cursorBuffer.cursor)[1]
110143

111144
def set_completer_delims(string):
112-
pass
145+
global _completer_delims, _completer_delims_set
146+
_completer_delims = string
147+
_completer_delims_set = set(string)
113148

114149
def get_completer_delims():
115-
pass
116-
117-
def add_history(line):
118-
reader.addToHistory(line)
119-
150+
return _completer_delims
120151

152+
set_completer_delims(' \t\n`~!@#$%^&*()-=+[{]}\\|;:\'",<>/?')

src/org/python/util/JLineConsole.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public class JLineConsole extends InteractiveConsole {
3232
/** Main interface to JLine. */
3333
protected ConsoleReader reader;
3434

35+
/** Set by readline.set_startup_hook */
36+
protected PyObject startup_hook;
37+
38+
protected PyObject pre_input_hook;
39+
3540
/** Whether reader is a WindowsTerminal. */
3641
private boolean windows;
3742

@@ -116,6 +121,13 @@ public String raw_input(PyObject prompt) {
116121

117122
while (true) {
118123
try {
124+
if (startup_hook != null) {
125+
try {
126+
startup_hook.__call__();
127+
} catch (Exception ex) {
128+
System.err.println(ex);
129+
}
130+
}
119131
line = reader.readLine(promptString);
120132
break;
121133
} catch (IOException ioe) {
@@ -163,4 +175,19 @@ private boolean isEOF(String line) {
163175
public ConsoleReader getReader() {
164176
return reader;
165177
}
178+
179+
180+
/**
181+
* @return the startup hook (called prior to each readline)
182+
*/
183+
public PyObject getStartupHook() {
184+
return startup_hook;
185+
}
186+
187+
/**
188+
* Sets the startup hook (called prior to each readline)
189+
*/
190+
public void setStartupHook(PyObject hook) {
191+
startup_hook = hook;
192+
}
166193
}

0 commit comments

Comments
 (0)