diff --git a/IPython/frontend/linefrontendbase.py b/IPython/frontend/linefrontendbase.py index 84d45f0..b33ea50 100644 --- a/IPython/frontend/linefrontendbase.py +++ b/IPython/frontend/linefrontendbase.py @@ -188,16 +188,6 @@ class LineFrontEndBase(FrontEndBase): # Create a false result, in case there is an exception self.last_result = dict(number=self.prompt_number) - ## try: - ## self.history.input_cache[-1] = raw_string.rstrip() - ## result = self.shell.execute(python_string) - ## self.last_result = result - ## self.render_result(result) - ## except: - ## self.show_traceback() - ## finally: - ## self.after_execute() - try: try: self.history.input_cache[-1] = raw_string.rstrip() @@ -318,9 +308,20 @@ class LineFrontEndBase(FrontEndBase): # Private API #-------------------------------------------------------------------------- - def _on_enter(self): + def _on_enter(self, new_line_pos=0): """ Called when the return key is pressed in a line editing buffer. + + Parameters + ---------- + new_line_pos : integer, optional + Position of the new line to add, starting from the + end (0 adds a new line after the last line, -1 before + the last line...) + + Returns + ------- + True if execution is triggered """ current_buffer = self.input_buffer # XXX: This string replace is ugly, but there should be no way it @@ -331,14 +332,25 @@ class LineFrontEndBase(FrontEndBase): cleaned_buffer = self.prefilter_input(prompt_less_buffer) if self.is_complete(cleaned_buffer): self.execute(cleaned_buffer, raw_string=current_buffer) + return True else: - self.input_buffer += self.continuation_prompt() + \ - self._get_indent_string(prompt_less_buffer[:-1]) - if len(current_buffer.split('\n')) == 2: - self.input_buffer += '\t' + new_line_pos = -new_line_pos + lines = current_buffer.split('\n')[:-1] + prompt_less_lines = prompt_less_buffer.split('\n') + new_line = self.continuation_prompt() + \ + self._get_indent_string('\n'.join( + prompt_less_lines[:new_line_pos-1])) + if len(lines) == 2: + new_line += '\t' if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'): - self.input_buffer += '\t' + new_line += '\t' + if new_line_pos == 0: + lines.append(new_line) + else: + lines.insert(new_line_pos, new_line) + self.input_buffer = '\n'.join(lines) + def _get_indent_string(self, string): """ Return the string of whitespace that prefixes a line. Used to diff --git a/IPython/frontend/wx/console_widget.py b/IPython/frontend/wx/console_widget.py index 35c2d9c..56761e8 100644 --- a/IPython/frontend/wx/console_widget.py +++ b/IPython/frontend/wx/console_widget.py @@ -472,6 +472,11 @@ class ConsoleWidget(editwindow.EditWindow): Return True if event as been catched. """ catched = True + # XXX: Would the right way to do this be to have a + # dictionary at the instance level associating keys with + # callbacks? How would we deal with inheritance? And Do the + # different callbacks share local variables? + # Intercept some specific keys. if event.KeyCode == ord('L') and event.ControlDown() : self.scroll_to_bottom() @@ -489,6 +494,10 @@ class ConsoleWidget(editwindow.EditWindow): self.ScrollPages(-1) elif event.KeyCode == wx.WXK_PAGEDOWN: self.ScrollPages(1) + elif event.KeyCode == wx.WXK_HOME: + self.GotoPos(self.GetLength()) + elif event.KeyCode == wx.WXK_END: + self.GotoPos(self.GetLength()) elif event.KeyCode == wx.WXK_UP and event.ShiftDown(): self.ScrollLines(-1) elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown(): @@ -500,17 +509,19 @@ class ConsoleWidget(editwindow.EditWindow): event.Skip() else: if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \ - event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN): + event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN, + wx.MOD_SHIFT): catched = True if not self.enter_catched: self.CallTipCancel() - self.write('\n', refresh=False) - # Under windows scintilla seems to be doing funny - # stuff to the line returns here, but the getter for - # input_buffer filters this out. - if sys.platform == 'win32': - self.input_buffer = self.input_buffer - self._on_enter() + if event.Modifiers == wx.MOD_SHIFT: + # Try to force execution + self.GotoPos(self.GetLength()) + self.write('\n' + self.continuation_prompt(), + refresh=False) + self._on_enter() + else: + self._on_enter() self.enter_catched = True elif event.KeyCode == wx.WXK_HOME: diff --git a/IPython/frontend/wx/wx_frontend.py b/IPython/frontend/wx/wx_frontend.py index b6c963c..e20e558 100644 --- a/IPython/frontend/wx/wx_frontend.py +++ b/IPython/frontend/wx/wx_frontend.py @@ -284,6 +284,8 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): """ Execute a command, not only in the model, but also in the view. """ + # XXX: This method needs to be integrated in the base fronted + # interface if hidden: return self.shell.execute(command) else: @@ -386,7 +388,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): widget handle them, and put our logic afterward. """ # FIXME: This method needs to be broken down in smaller ones. - current_line_number = self.GetCurrentLine() + current_line_num = self.GetCurrentLine() if event.KeyCode in (ord('c'), ord('C')) and event.ControlDown(): # Capture Control-C if self._input_state == 'subprocess': @@ -432,7 +434,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): else: # Up history if event.KeyCode == wx.WXK_UP and ( - ( current_line_number == self.current_prompt_line and + ( current_line_num == self.current_prompt_line and event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) ) or event.ControlDown() ): new_buffer = self.get_history_previous( @@ -444,7 +446,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): self.GotoPos(self.current_prompt_pos) # Down history elif event.KeyCode == wx.WXK_DOWN and ( - ( current_line_number == self.LineCount -1 and + ( current_line_num == self.LineCount -1 and event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) ) or event.ControlDown() ): new_buffer = self.get_history_next() @@ -452,7 +454,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): self.input_buffer = new_buffer # Tab-completion elif event.KeyCode == ord('\t'): - current_line, current_line_number = self.CurLine + current_line, current_line_num = self.CurLine if not re.match(r'^\s*$', current_line): self.complete_current_input() if self.AutoCompActive(): @@ -467,16 +469,16 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): # independant of IPython current_line, _ = self.CurLine current_pos = self.GetCurrentPos() - current_line_number = self.LineFromPosition(current_pos) + current_line_num = self.LineFromPosition(current_pos) current_col = self.GetColumn(current_pos) len_prompt = len(self.continuation_prompt()) if ( current_line.startswith(self.continuation_prompt()) - and current_col == len_prompt): + and current_col == len_prompt): new_lines = [] for line_num, line in enumerate( self.input_buffer.split('\n')): if (line_num + self.current_prompt_line == - current_line_number): + current_line_num): new_lines.append(line[len_prompt:]) else: new_lines.append('\n'+line) @@ -515,9 +517,22 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): def _on_enter(self): """ Called on return key down, in readline input_state. """ + last_line_num = self.LineFromPosition(self.GetLength()) + current_line_num = self.LineFromPosition(self.GetCurrentPos()) + new_line_pos = (last_line_num - current_line_num) if self.debug: print >>sys.__stdout__, repr(self.input_buffer) - PrefilterFrontEnd._on_enter(self) + self.write('\n', refresh=False) + # Under windows scintilla seems to be doing funny + # stuff to the line returns here, but the getter for + # input_buffer filters this out. + if sys.platform == 'win32': + self.input_buffer = self.input_buffer + has_executed = PrefilterFrontEnd._on_enter(self, + new_line_pos=new_line_pos) + if not has_executed: + self.GotoPos(self.GetLineEndPosition(current_line_num + 1)) + return has_executed #--------------------------------------------------------------------------