##// END OF EJS Templates
ENH: Add continuation prompts
Gael Varoquaux -
Show More
@@ -295,6 +295,17 b' class LineFrontEndBase(FrontEndBase):'
295 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 309 def execute_command(self, command, hidden=False):
299 310 """ Execute a command, not only in the model, but also in the
300 311 view, if any.
@@ -310,14 +321,19 b' class LineFrontEndBase(FrontEndBase):'
310 321 buffer.
311 322 """
312 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 330 if self.is_complete(cleaned_buffer):
315 331 self.execute(cleaned_buffer, raw_string=current_buffer)
316 332 else:
317 self.input_buffer += self._get_indent_string(
318 current_buffer[:-1])
333 self.input_buffer += self.continuation_prompt() + \
334 self._get_indent_string(prompt_less_buffer[:-1])
319 335 if len(current_buffer.split('\n')) == 2:
320 self.input_buffer += '\t\t'
336 self.input_buffer += '\t'
321 337 if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
322 338 self.input_buffer += '\t'
323 339
@@ -24,6 +24,7 b' __docformat__ = "restructuredtext en"'
24 24 import sys
25 25 import pydoc
26 26 import os
27 import re
27 28 import __builtin__
28 29
29 30 from IPython.ipmaker import make_IPython
@@ -113,9 +114,9 b' class PrefilterFrontEnd(LineFrontEndBase):'
113 114
114 115
115 116 if not 'banner' in kwargs and self.banner is None:
116 self.banner = self.ipython0.BANNER + """
117 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
117 self.banner = self.ipython0.BANNER
118 118
119 # FIXME: __init__ and start should be two different steps
119 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 183 def complete(self, line):
183 184 # FIXME: This should be factored out in the linefrontendbase
184 185 # method.
186 word = self._get_completion_text(line)
185 187 word = line.split('\n')[-1].split(' ')[-1]
188 print 'Completion', word
186 189 completions = self.ipython0.complete(word)
187 190 # FIXME: The proper sort should be done in the complete method.
188 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 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 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 230 # EditWindow API
221 231 #--------------------------------------------------------------------------
@@ -391,15 +401,16 b' class ConsoleWidget(editwindow.EditWindow):'
391 401 catched = True
392 402
393 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 405 event.Skip()
396 406 catched = True
397 407
398 408 if skip and not catched:
399 409 # Put the cursor back in the edit region
400 if self.GetCurrentPos() < self.current_prompt_pos:
401 self.GotoPos(self.current_prompt_pos)
402 else:
410 if not self._keep_cursor_in_buffer():
411 if (self.GetCurrentPos() == self.GetLength()
412 and event.KeyCode == wx.WXK_DELETE):
413 pass
403 414 event.Skip()
404 415
405 416 return catched
@@ -408,9 +419,44 b' class ConsoleWidget(editwindow.EditWindow):'
408 419 def _on_key_up(self, event, skip=True):
409 420 """ If cursor is outside the editing region, put it back.
410 421 """
411 event.Skip()
412 if self.GetCurrentPos() < self.current_prompt_pos:
422 if skip:
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 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 485 wx.CallAfter(self._popup_completion, create=True)
486 486 else:
487 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 496 def _on_enter(self):
General Comments 0
You need to be logged in to leave comments. Login now