##// END OF EJS Templates
ENH: Add continuation prompts
Gael Varoquaux -
Show More
@@ -295,6 +295,17 b' class LineFrontEndBase(FrontEndBase):'
295 self.write(prompt)
295 self.write(prompt)
296
296
297
297
298 def continuation_prompt(self):
299 """Returns the current continuation prompt.
300 Overridden to generate a continuation prompt matching the length of the
301 current prompt."""
302
303 # FIXME: This is a bad hack.. I need to find a way to use the 'Prompt2'
304 # class in IPython/kernel/prompts.py. Basically, I am trying to get the
305 # length of the current prompt ("In ['number']").
306 return ("."*(5+len(str(self.last_result['number']))) + ':')
307
308
298 def execute_command(self, command, hidden=False):
309 def execute_command(self, command, hidden=False):
299 """ Execute a command, not only in the model, but also in the
310 """ Execute a command, not only in the model, but also in the
300 view, if any.
311 view, if any.
@@ -310,14 +321,19 b' class LineFrontEndBase(FrontEndBase):'
310 buffer.
321 buffer.
311 """
322 """
312 current_buffer = self.input_buffer
323 current_buffer = self.input_buffer
313 cleaned_buffer = self.prefilter_input(current_buffer)
324 # XXX: This string replace is ugly, but there should be no way it
325 # fails.
326 prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
327 '', current_buffer).replace('\n' + self.continuation_prompt(),
328 '\n')
329 cleaned_buffer = self.prefilter_input(prompt_less_buffer)
314 if self.is_complete(cleaned_buffer):
330 if self.is_complete(cleaned_buffer):
315 self.execute(cleaned_buffer, raw_string=current_buffer)
331 self.execute(cleaned_buffer, raw_string=current_buffer)
316 else:
332 else:
317 self.input_buffer += self._get_indent_string(
333 self.input_buffer += self.continuation_prompt() + \
318 current_buffer[:-1])
334 self._get_indent_string(prompt_less_buffer[:-1])
319 if len(current_buffer.split('\n')) == 2:
335 if len(current_buffer.split('\n')) == 2:
320 self.input_buffer += '\t\t'
336 self.input_buffer += '\t'
321 if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
337 if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
322 self.input_buffer += '\t'
338 self.input_buffer += '\t'
323
339
@@ -24,6 +24,7 b' __docformat__ = "restructuredtext en"'
24 import sys
24 import sys
25 import pydoc
25 import pydoc
26 import os
26 import os
27 import re
27 import __builtin__
28 import __builtin__
28
29
29 from IPython.ipmaker import make_IPython
30 from IPython.ipmaker import make_IPython
@@ -113,9 +114,9 b' class PrefilterFrontEnd(LineFrontEndBase):'
113
114
114
115
115 if not 'banner' in kwargs and self.banner is None:
116 if not 'banner' in kwargs and self.banner is None:
116 self.banner = self.ipython0.BANNER + """
117 self.banner = self.ipython0.BANNER
117 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
118
118
119 # FIXME: __init__ and start should be two different steps
119 self.start()
120 self.start()
120
121
121 #--------------------------------------------------------------------------
122 #--------------------------------------------------------------------------
@@ -182,7 +183,9 b' This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""'
182 def complete(self, line):
183 def complete(self, line):
183 # FIXME: This should be factored out in the linefrontendbase
184 # FIXME: This should be factored out in the linefrontendbase
184 # method.
185 # method.
186 word = self._get_completion_text(line)
185 word = line.split('\n')[-1].split(' ')[-1]
187 word = line.split('\n')[-1].split(' ')[-1]
188 print 'Completion', word
186 completions = self.ipython0.complete(word)
189 completions = self.ipython0.complete(word)
187 # FIXME: The proper sort should be done in the complete method.
190 # FIXME: The proper sort should be done in the complete method.
188 key = lambda x: x.replace('_', '')
191 key = lambda x: x.replace('_', '')
@@ -255,3 +258,18 b' This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""'
255 """
258 """
256 self.ipython0.atexit_operations()
259 self.ipython0.atexit_operations()
257
260
261
262 def _get_completion_text(self, line):
263 """ Returns the text to be completed by breaking the line at specified
264 delimiters.
265 """
266 # Break at: spaces, '=', all parentheses (except if balanced).
267 # FIXME2: In the future, we need to make the implementation similar to
268 # that in the 'pyreadline' module (modes/basemode.py) where we break at
269 # each delimiter and try to complete the residual line, until we get a
270 # successful list of completions.
271 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
272 complete_sep = re.compile(expression)
273 text = complete_sep.split(line)[-1]
274 return text
275
@@ -216,6 +216,16 b' class ConsoleWidget(editwindow.EditWindow):'
216 """
216 """
217 return self.GetSize()[0]/self.GetCharWidth()
217 return self.GetSize()[0]/self.GetCharWidth()
218
218
219
220 def clear_screen(self):
221 """ Empty completely the widget.
222 """
223 self.ClearAll()
224 self.new_prompt(self.input_prompt_template.substitute(
225 number=(self.last_result['number'] + 1)))
226
227
228
219 #--------------------------------------------------------------------------
229 #--------------------------------------------------------------------------
220 # EditWindow API
230 # EditWindow API
221 #--------------------------------------------------------------------------
231 #--------------------------------------------------------------------------
@@ -391,15 +401,16 b' class ConsoleWidget(editwindow.EditWindow):'
391 catched = True
401 catched = True
392
402
393 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
403 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
394 if self.GetCurrentPos() > self.current_prompt_pos:
404 if not self._keep_cursor_in_buffer():
395 event.Skip()
405 event.Skip()
396 catched = True
406 catched = True
397
407
398 if skip and not catched:
408 if skip and not catched:
399 # Put the cursor back in the edit region
409 # Put the cursor back in the edit region
400 if self.GetCurrentPos() < self.current_prompt_pos:
410 if not self._keep_cursor_in_buffer():
401 self.GotoPos(self.current_prompt_pos)
411 if (self.GetCurrentPos() == self.GetLength()
402 else:
412 and event.KeyCode == wx.WXK_DELETE):
413 pass
403 event.Skip()
414 event.Skip()
404
415
405 return catched
416 return catched
@@ -408,9 +419,44 b' class ConsoleWidget(editwindow.EditWindow):'
408 def _on_key_up(self, event, skip=True):
419 def _on_key_up(self, event, skip=True):
409 """ If cursor is outside the editing region, put it back.
420 """ If cursor is outside the editing region, put it back.
410 """
421 """
411 event.Skip()
422 if skip:
412 if self.GetCurrentPos() < self.current_prompt_pos:
423 event.Skip()
424 self._keep_cursor_in_buffer()
425
426
427 def _keep_cursor_in_buffer(self):
428 """ Checks if the cursor is where it is allowed to be. If not,
429 put it back.
430
431 Returns
432 -------
433 cursor_moved: Boolean
434 whether or not the cursor was moved by this routine.
435
436 Notes
437 ------
438 WARNING: This does proper checks only for horizontal
439 movements.
440 """
441 current_pos = self.GetCurrentPos()
442 if current_pos < self.current_prompt_pos:
413 self.GotoPos(self.current_prompt_pos)
443 self.GotoPos(self.current_prompt_pos)
444 return True
445 line, line_pos = self.GetCurLine()
446 # Jump the continuation prompt
447 continuation_prompt = self.continuation_prompt()
448 if ( line.startswith(continuation_prompt)
449 and line_pos < len(continuation_prompt)+1):
450 if line_pos < 2:
451 # We are at the beginning of the line, trying to move
452 # forward: jump forward.
453 self.GotoPos(current_pos + 1 +
454 len(continuation_prompt) - line_pos)
455 else:
456 # Jump back up
457 self.GotoPos(self.GetLineEndPosition(self.GetCurrentLine()-1))
458 return True
459 return False
414
460
415
461
416
462
@@ -485,6 +485,12 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
485 wx.CallAfter(self._popup_completion, create=True)
485 wx.CallAfter(self._popup_completion, create=True)
486 else:
486 else:
487 ConsoleWidget._on_key_up(self, event, skip=skip)
487 ConsoleWidget._on_key_up(self, event, skip=skip)
488 if (self.input_buffer.split('\n')[-1] == self.continuation_prompt()
489 and self._input_state == 'readline'):
490 # Make sure the continuation_prompt is followed by a whitespace
491 position = self.GetCurrentPos()
492 self.input_buffer += ' '
493 self.GotoPos(position)
488
494
489
495
490 def _on_enter(self):
496 def _on_enter(self):
General Comments 0
You need to be logged in to leave comments. Login now