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