##// END OF EJS Templates
More code reuse between GUI-independant frontend and Wx frontend: getting...
gvaroquaux -
Show More
@@ -56,6 +56,9 b' class LineFrontEndBase(FrontEndBase):'
56 # programatic control of the frontend.
56 # programatic control of the frontend.
57 last_result = dict(number=0)
57 last_result = dict(number=0)
58
58
59 # The input buffer being edited
60 input_buffer = ''
61
59 #--------------------------------------------------------------------------
62 #--------------------------------------------------------------------------
60 # FrontEndBase interface
63 # FrontEndBase interface
61 #--------------------------------------------------------------------------
64 #--------------------------------------------------------------------------
@@ -123,7 +126,7 b' class LineFrontEndBase(FrontEndBase):'
123 # thus want to consider an empty string as a complete
126 # thus want to consider an empty string as a complete
124 # statement.
127 # statement.
125 return True
128 return True
126 elif ( len(self.get_current_edit_buffer().split('\n'))>2
129 elif ( len(self.input_buffer.split('\n'))>2
127 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
130 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
128 return False
131 return False
129 else:
132 else:
@@ -132,12 +135,6 b' class LineFrontEndBase(FrontEndBase):'
132 return FrontEndBase.is_complete(self, string.rstrip() + '\n\n')
135 return FrontEndBase.is_complete(self, string.rstrip() + '\n\n')
133
136
134
137
135 def get_current_edit_buffer(self):
136 """ Return the current buffer being entered.
137 """
138 raise NotImplementedError
139
140
141 def write(self, string):
138 def write(self, string):
142 """ Write some characters to the display.
139 """ Write some characters to the display.
143
140
@@ -145,12 +142,6 b' class LineFrontEndBase(FrontEndBase):'
145 """
142 """
146 print >>sys.__stderr__, string
143 print >>sys.__stderr__, string
147
144
148
149 def add_to_edit_buffer(self, string):
150 """ Add the given string to the current edit buffer.
151 """
152 raise NotImplementedError
153
154
145
155 def new_prompt(self, prompt):
146 def new_prompt(self, prompt):
156 """ Prints a prompt and starts a new editing buffer.
147 """ Prints a prompt and starts a new editing buffer.
@@ -159,6 +150,7 b' class LineFrontEndBase(FrontEndBase):'
159 terminal is put in a state favorable for a new line
150 terminal is put in a state favorable for a new line
160 input.
151 input.
161 """
152 """
153 self.input_buffer = ''
162 self.write(prompt)
154 self.write(prompt)
163
155
164
156
@@ -213,15 +205,15 b' class LineFrontEndBase(FrontEndBase):'
213 """ Called when the return key is pressed in a line editing
205 """ Called when the return key is pressed in a line editing
214 buffer.
206 buffer.
215 """
207 """
216 current_buffer = self.get_current_edit_buffer()
208 current_buffer = self.input_buffer
217 cleaned_buffer = self.prefilter_input(current_buffer)
209 cleaned_buffer = self.prefilter_input(current_buffer)
218 if self.is_complete(cleaned_buffer):
210 if self.is_complete(cleaned_buffer):
219 self.execute(cleaned_buffer, raw_string=current_buffer)
211 self.execute(cleaned_buffer, raw_string=current_buffer)
220 else:
212 else:
221 self.add_to_edit_buffer(self._get_indent_string(
213 self.input_buffer += self._get_indent_string(
222 current_buffer[:-1]))
214 current_buffer[:-1])
223 if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
215 if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
224 self.add_to_edit_buffer('\t')
216 self.input_buffer += '\t'
225
217
226
218
227 def _get_indent_string(self, string):
219 def _get_indent_string(self, string):
@@ -21,36 +21,23 b' class TestPrefilterFrontEnd(PrefilterFrontEnd):'
21 input_prompt_template = string.Template('')
21 input_prompt_template = string.Template('')
22 output_prompt_template = string.Template('')
22 output_prompt_template = string.Template('')
23
23
24 edit_buffer = ''
25
26
27 def __init__(self):
24 def __init__(self):
28 self.out = StringIO()
25 self.out = StringIO()
29 PrefilterFrontEnd.__init__(self)
26 PrefilterFrontEnd.__init__(self)
30
27
31 def get_current_edit_buffer(self):
32 return self.edit_buffer
33
34 def add_to_edit_buffer(self, string):
35 self.edit_buffer += string
36
37 def write(self, string):
28 def write(self, string):
38 self.out.write(string)
29 self.out.write(string)
39
30
40 def _on_enter(self):
31 def _on_enter(self):
41 self.add_to_edit_buffer('\n')
32 self.input_buffer += '\n'
42 PrefilterFrontEnd._on_enter(self)
33 PrefilterFrontEnd._on_enter(self)
43
34
44 def new_prompt(self, prompt):
45 self.edit_buffer = ''
46 PrefilterFrontEnd.new_prompt(self, prompt)
47
48
35
49 def test_execution():
36 def test_execution():
50 """ Test execution of a command.
37 """ Test execution of a command.
51 """
38 """
52 f = TestPrefilterFrontEnd()
39 f = TestPrefilterFrontEnd()
53 f.edit_buffer='print 1\n'
40 f.input_buffer = 'print 1\n'
54 f._on_enter()
41 f._on_enter()
55 assert f.out.getvalue() == '1\n'
42 assert f.out.getvalue() == '1\n'
56
43
@@ -59,17 +46,17 b' def test_multiline():'
59 """ Test execution of a multiline command.
46 """ Test execution of a multiline command.
60 """
47 """
61 f = TestPrefilterFrontEnd()
48 f = TestPrefilterFrontEnd()
62 f.edit_buffer='if True:'
49 f.input_buffer = 'if True:'
63 f._on_enter()
50 f._on_enter()
64 f.add_to_edit_buffer('print 1')
51 f.input_buffer += 'print 1'
65 f._on_enter()
52 f._on_enter()
66 assert f.out.getvalue() == ''
53 assert f.out.getvalue() == ''
67 f._on_enter()
54 f._on_enter()
68 assert f.out.getvalue() == '1\n'
55 assert f.out.getvalue() == '1\n'
69 f = TestPrefilterFrontEnd()
56 f = TestPrefilterFrontEnd()
70 f.edit_buffer='(1 +'
57 f.input_buffer='(1 +'
71 f._on_enter()
58 f._on_enter()
72 f.add_to_edit_buffer('0)')
59 f.input_buffer += '0)'
73 f._on_enter()
60 f._on_enter()
74 assert f.out.getvalue() == ''
61 assert f.out.getvalue() == ''
75 f._on_enter()
62 f._on_enter()
@@ -81,11 +68,13 b' def test_capture():'
81 """
68 """
82 # Test on the OS-level stdout, stderr.
69 # Test on the OS-level stdout, stderr.
83 f = TestPrefilterFrontEnd()
70 f = TestPrefilterFrontEnd()
84 f.edit_buffer='import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
71 f.input_buffer = \
72 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
85 f._on_enter()
73 f._on_enter()
86 assert f.out.getvalue() == '1'
74 assert f.out.getvalue() == '1'
87 f = TestPrefilterFrontEnd()
75 f = TestPrefilterFrontEnd()
88 f.edit_buffer='import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
76 f.input_buffer = \
77 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
89 f._on_enter()
78 f._on_enter()
90 assert f.out.getvalue() == '1'
79 assert f.out.getvalue() == '1'
91
80
@@ -96,7 +85,7 b' def test_magic():'
96 This test is fairly fragile and will break when magics change.
85 This test is fairly fragile and will break when magics change.
97 """
86 """
98 f = TestPrefilterFrontEnd()
87 f = TestPrefilterFrontEnd()
99 f.add_to_edit_buffer('%who\n')
88 f.input_buffer += '%who\n'
100 f._on_enter()
89 f._on_enter()
101 assert f.out.getvalue() == 'Interactive namespace is empty.\n'
90 assert f.out.getvalue() == 'Interactive namespace is empty.\n'
102
91
@@ -105,26 +94,27 b' def test_help():'
105 """ Test object inspection.
94 """ Test object inspection.
106 """
95 """
107 f = TestPrefilterFrontEnd()
96 f = TestPrefilterFrontEnd()
108 f.add_to_edit_buffer("def f():")
97 f.input_buffer += "def f():"
109 f._on_enter()
98 f._on_enter()
110 f.add_to_edit_buffer("'foobar'")
99 f.input_buffer += "'foobar'"
111 f._on_enter()
100 f._on_enter()
112 f.add_to_edit_buffer("pass")
101 f.input_buffer += "pass"
113 f._on_enter()
102 f._on_enter()
114 f._on_enter()
103 f._on_enter()
115 f.add_to_edit_buffer("f?")
104 f.input_buffer += "f?"
116 f._on_enter()
105 f._on_enter()
117 assert f.out.getvalue().split()[-1] == 'foobar'
106 assert f.out.getvalue().split()[-1] == 'foobar'
118
107
108
119 def test_completion():
109 def test_completion():
120 """ Test command-line completion.
110 """ Test command-line completion.
121 """
111 """
122 f = TestPrefilterFrontEnd()
112 f = TestPrefilterFrontEnd()
123 f.edit_buffer = 'zzza = 1'
113 f.input_buffer = 'zzza = 1'
124 f._on_enter()
114 f._on_enter()
125 f.edit_buffer = 'zzzb = 2'
115 f.input_buffer = 'zzzb = 2'
126 f._on_enter()
116 f._on_enter()
127 f.edit_buffer = 'zz'
117 f.input_buffer = 'zz'
128
118
129
119
130 if __name__ == '__main__':
120 if __name__ == '__main__':
@@ -80,6 +80,22 b' class ConsoleWidget(editwindow.EditWindow):'
80 # stored.
80 # stored.
81 title = 'Console'
81 title = 'Console'
82
82
83 # The buffer being edited.
84 def _set_input_buffer(self, string):
85 self.SetSelection(self.current_prompt_pos, self.GetLength())
86 self.ReplaceSelection(string)
87 self.GotoPos(self.GetLength())
88
89 def _get_input_buffer(self):
90 """ Returns the text in current edit buffer.
91 """
92 input_buffer = self.GetTextRange(self.current_prompt_pos,
93 self.GetLength())
94 input_buffer = input_buffer.replace(LINESEP, '\n')
95 return input_buffer
96
97 input_buffer = property(_get_input_buffer, _set_input_buffer)
98
83 style = _DEFAULT_STYLE.copy()
99 style = _DEFAULT_STYLE.copy()
84
100
85 # Translation table from ANSI escape sequences to color. Override
101 # Translation table from ANSI escape sequences to color. Override
@@ -168,23 +184,6 b' class ConsoleWidget(editwindow.EditWindow):'
168 wx.Yield()
184 wx.Yield()
169 self.EnsureCaretVisible()
185 self.EnsureCaretVisible()
170
186
171
172 def replace_current_edit_buffer(self, text):
173 """ Replace currently entered command line with given text.
174 """
175 self.SetSelection(self.current_prompt_pos, self.GetLength())
176 self.ReplaceSelection(text)
177 self.GotoPos(self.GetLength())
178
179
180 def get_current_edit_buffer(self):
181 """ Returns the text in current edit buffer.
182 """
183 current_edit_buffer = self.GetTextRange(self.current_prompt_pos,
184 self.GetLength())
185 current_edit_buffer = current_edit_buffer.replace(LINESEP, '\n')
186 return current_edit_buffer
187
188
187
189 def scroll_to_bottom(self):
188 def scroll_to_bottom(self):
190 maxrange = self.GetScrollRange(wx.VERTICAL)
189 maxrange = self.GetScrollRange(wx.VERTICAL)
@@ -205,7 +204,7 b' class ConsoleWidget(editwindow.EditWindow):'
205 def write_completion(self, possibilities):
204 def write_completion(self, possibilities):
206 # FIXME: This is non Wx specific and needs to be moved into
205 # FIXME: This is non Wx specific and needs to be moved into
207 # the base class.
206 # the base class.
208 current_buffer = self.get_current_edit_buffer()
207 current_buffer = self.input_buffer
209
208
210 self.write('\n')
209 self.write('\n')
211 max_len = len(max(possibilities, key=len)) + 1
210 max_len = len(max(possibilities, key=len)) + 1
@@ -228,7 +227,7 b' class ConsoleWidget(editwindow.EditWindow):'
228 # and wx_frontend, here.
227 # and wx_frontend, here.
229 self.new_prompt(self.input_prompt_template.substitute(
228 self.new_prompt(self.input_prompt_template.substitute(
230 number=self.last_result['number'] + 1))
229 number=self.last_result['number'] + 1))
231 self.replace_current_edit_buffer(current_buffer)
230 self.input_buffer = current_buffer
232
231
233 #--------------------------------------------------------------------------
232 #--------------------------------------------------------------------------
234 # Private API
233 # Private API
@@ -343,7 +342,7 b' class ConsoleWidget(editwindow.EditWindow):'
343 if event.KeyCode == ord('L') and event.ControlDown() :
342 if event.KeyCode == ord('L') and event.ControlDown() :
344 self.scroll_to_bottom()
343 self.scroll_to_bottom()
345 elif event.KeyCode == ord('K') and event.ControlDown() :
344 elif event.KeyCode == ord('K') and event.ControlDown() :
346 self.replace_current_edit_buffer('')
345 self.input_buffer = ''
347 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
346 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
348 self.ScrollPages(-1)
347 self.ScrollPages(-1)
349 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
348 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
@@ -364,11 +363,10 b' class ConsoleWidget(editwindow.EditWindow):'
364 self.CallTipCancel()
363 self.CallTipCancel()
365 self.write('\n')
364 self.write('\n')
366 # Under windows scintilla seems to be doing funny stuff to the
365 # Under windows scintilla seems to be doing funny stuff to the
367 # line returns here, but get_current_edit_buffer filters this
366 # line returns here, but the getter for input_buffer filters
368 # out.
367 # this out.
369 if sys.platform == 'win32':
368 if sys.platform == 'win32':
370 self.replace_current_edit_buffer(
369 self.input_buffer = self.input_buffer
371 self.get_current_edit_buffer())
372 self._on_enter()
370 self._on_enter()
373
371
374 elif event.KeyCode == wx.WXK_HOME:
372 elif event.KeyCode == wx.WXK_HOME:
@@ -22,7 +22,7 b' class IPythonXController(WxController):'
22 def _on_key_down(self, event, skip=True):
22 def _on_key_down(self, event, skip=True):
23 # Intercept Ctrl-D to quit
23 # Intercept Ctrl-D to quit
24 if event.KeyCode == ord('D') and event.ControlDown() and \
24 if event.KeyCode == ord('D') and event.ControlDown() and \
25 self.get_current_edit_buffer()=='' and \
25 self.input_buffer == '' and \
26 self._input_state == 'readline':
26 self._input_state == 'readline':
27 wx.CallAfter(self.ask_exit)
27 wx.CallAfter(self.ask_exit)
28 else:
28 else:
@@ -58,7 +58,7 b' prompt_out = \\'
58 #-------------------------------------------------------------------------------
58 #-------------------------------------------------------------------------------
59 # Classes to implement the Wx frontend
59 # Classes to implement the Wx frontend
60 #-------------------------------------------------------------------------------
60 #-------------------------------------------------------------------------------
61 class WxController(PrefilterFrontEnd, ConsoleWidget):
61 class WxController(ConsoleWidget, PrefilterFrontEnd):
62 """Classes to provide a Wx frontend to the
62 """Classes to provide a Wx frontend to the
63 IPython.kernel.core.interpreter.
63 IPython.kernel.core.interpreter.
64
64
@@ -83,6 +83,21 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
83
83
84 title = property(_get_title, _set_title)
84 title = property(_get_title, _set_title)
85
85
86
87 # The buffer being edited.
88 # We are duplicating the defination here because of multiple
89 # inheritence
90 def _set_input_buffer(self, string):
91 return ConsoleWidget._set_input_buffer(self, string)
92
93 def _get_input_buffer(self):
94 """ Returns the text in current edit buffer.
95 """
96 return ConsoleWidget._get_input_buffer(self)
97
98 input_buffer = property(_get_input_buffer, _set_input_buffer)
99
100
86 #--------------------------------------------------------------------------
101 #--------------------------------------------------------------------------
87 # Private Attributes
102 # Private Attributes
88 #--------------------------------------------------------------------------
103 #--------------------------------------------------------------------------
@@ -149,7 +164,7 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
149 sleep(0.1)
164 sleep(0.1)
150 self._on_enter = self.__old_on_enter
165 self._on_enter = self.__old_on_enter
151 self._input_state = 'buffering'
166 self._input_state = 'buffering'
152 return self.get_current_edit_buffer().rstrip('\n')
167 return self.input_buffer.rstrip('\n')
153
168
154
169
155 def system_call(self, command_string):
170 def system_call(self, command_string):
@@ -173,11 +188,11 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
173 """
188 """
174 if self.debug:
189 if self.debug:
175 print >>sys.__stdout__, "do_completion",
190 print >>sys.__stdout__, "do_completion",
176 line = self.get_current_edit_buffer()
191 line = self.input_buffer
177 new_line, completions = self.complete(line)
192 new_line, completions = self.complete(line)
178 if len(completions)>1:
193 if len(completions)>1:
179 self.write_completion(completions)
194 self.write_completion(completions)
180 self.replace_current_edit_buffer(new_line)
195 self.input_buffer = new_line
181 if self.debug:
196 if self.debug:
182 print >>sys.__stdout__, completions
197 print >>sys.__stdout__, completions
183
198
@@ -188,7 +203,7 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
188 if self.debug:
203 if self.debug:
189 print >>sys.__stdout__, "do_calltip"
204 print >>sys.__stdout__, "do_calltip"
190 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
205 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
191 symbol = self.get_current_edit_buffer()
206 symbol = self.input_buffer
192 symbol_string = separators.split(symbol)[-1]
207 symbol_string = separators.split(symbol)[-1]
193 base_symbol_string = symbol_string.split('.')[0]
208 base_symbol_string = symbol_string.split('.')[0]
194 if base_symbol_string in self.shell.user_ns:
209 if base_symbol_string in self.shell.user_ns:
@@ -216,7 +231,7 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
216 """
231 """
217 if self.debug:
232 if self.debug:
218 print >>sys.__stdout__, "_popup_completion",
233 print >>sys.__stdout__, "_popup_completion",
219 line = self.get_current_edit_buffer()
234 line = self.input_buffer
220 if (self.AutoCompActive() and not line[-1] == '.') \
235 if (self.AutoCompActive() and not line[-1] == '.') \
221 or create==True:
236 or create==True:
222 suggestion, completions = self.complete(line)
237 suggestion, completions = self.complete(line)
@@ -290,13 +305,6 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
290 self.MarkerAdd(i, _ERROR_MARKER)
305 self.MarkerAdd(i, _ERROR_MARKER)
291
306
292
307
293 def add_to_edit_buffer(self, string):
294 """ Add the given string to the current edit buffer.
295 """
296 # XXX: I should check the input_state here.
297 self.write(string)
298
299
300 #--------------------------------------------------------------------------
308 #--------------------------------------------------------------------------
301 # ConsoleWidget interface
309 # ConsoleWidget interface
302 #--------------------------------------------------------------------------
310 #--------------------------------------------------------------------------
@@ -314,12 +322,6 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
314 ConsoleWidget.write(self, *args, **kwargs)
322 ConsoleWidget.write(self, *args, **kwargs)
315
323
316
324
317 def get_current_edit_buffer(self):
318 # Avoid multiple inheritence, be explicit about which
319 # parent method class gets called
320 return ConsoleWidget.get_current_edit_buffer(self)
321
322
323 def _on_key_down(self, event, skip=True):
325 def _on_key_down(self, event, skip=True):
324 """ Capture the character events, let the parent
326 """ Capture the character events, let the parent
325 widget handle them, and put our logic afterward.
327 widget handle them, and put our logic afterward.
@@ -374,9 +376,9 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
374 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
376 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
375 or event.ControlDown() ):
377 or event.ControlDown() ):
376 new_buffer = self.get_history_previous(
378 new_buffer = self.get_history_previous(
377 self.get_current_edit_buffer())
379 self.input_buffer)
378 if new_buffer is not None:
380 if new_buffer is not None:
379 self.replace_current_edit_buffer(new_buffer)
381 self.input_buffer = new_buffer
380 if self.GetCurrentLine() > self.current_prompt_line:
382 if self.GetCurrentLine() > self.current_prompt_line:
381 # Go to first line, for seemless history up.
383 # Go to first line, for seemless history up.
382 self.GotoPos(self.current_prompt_pos)
384 self.GotoPos(self.current_prompt_pos)
@@ -387,10 +389,10 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
387 or event.ControlDown() ):
389 or event.ControlDown() ):
388 new_buffer = self.get_history_next()
390 new_buffer = self.get_history_next()
389 if new_buffer is not None:
391 if new_buffer is not None:
390 self.replace_current_edit_buffer(new_buffer)
392 self.input_buffer = new_buffer
391 # Tab-completion
393 # Tab-completion
392 elif event.KeyCode == ord('\t'):
394 elif event.KeyCode == ord('\t'):
393 last_line = self.get_current_edit_buffer().split('\n')[-1]
395 last_line = self.input_buffer.split('\n')[-1]
394 if not re.match(r'^\s*$', last_line):
396 if not re.match(r'^\s*$', last_line):
395 self.do_completion()
397 self.do_completion()
396 else:
398 else:
@@ -414,7 +416,7 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
414 """ Called on return key down, in readline input_state.
416 """ Called on return key down, in readline input_state.
415 """
417 """
416 if self.debug:
418 if self.debug:
417 print >>sys.__stdout__, repr(self.get_current_edit_buffer())
419 print >>sys.__stdout__, repr(self.input_buffer)
418 PrefilterFrontEnd._on_enter(self)
420 PrefilterFrontEnd._on_enter(self)
419
421
420
422
General Comments 0
You need to be logged in to leave comments. Login now