diff --git a/IPython/frontend/linefrontendbase.py b/IPython/frontend/linefrontendbase.py index 3944a03..d1729ac 100644 --- a/IPython/frontend/linefrontendbase.py +++ b/IPython/frontend/linefrontendbase.py @@ -56,6 +56,9 @@ class LineFrontEndBase(FrontEndBase): # programatic control of the frontend. last_result = dict(number=0) + # The input buffer being edited + input_buffer = '' + #-------------------------------------------------------------------------- # FrontEndBase interface #-------------------------------------------------------------------------- @@ -123,7 +126,7 @@ class LineFrontEndBase(FrontEndBase): # thus want to consider an empty string as a complete # statement. return True - elif ( len(self.get_current_edit_buffer().split('\n'))>2 + elif ( len(self.input_buffer.split('\n'))>2 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)): return False else: @@ -132,12 +135,6 @@ class LineFrontEndBase(FrontEndBase): return FrontEndBase.is_complete(self, string.rstrip() + '\n\n') - def get_current_edit_buffer(self): - """ Return the current buffer being entered. - """ - raise NotImplementedError - - def write(self, string): """ Write some characters to the display. @@ -145,12 +142,6 @@ class LineFrontEndBase(FrontEndBase): """ print >>sys.__stderr__, string - - def add_to_edit_buffer(self, string): - """ Add the given string to the current edit buffer. - """ - raise NotImplementedError - def new_prompt(self, prompt): """ Prints a prompt and starts a new editing buffer. @@ -159,6 +150,7 @@ class LineFrontEndBase(FrontEndBase): terminal is put in a state favorable for a new line input. """ + self.input_buffer = '' self.write(prompt) @@ -213,15 +205,15 @@ class LineFrontEndBase(FrontEndBase): """ Called when the return key is pressed in a line editing buffer. """ - current_buffer = self.get_current_edit_buffer() + current_buffer = self.input_buffer cleaned_buffer = self.prefilter_input(current_buffer) if self.is_complete(cleaned_buffer): self.execute(cleaned_buffer, raw_string=current_buffer) else: - self.add_to_edit_buffer(self._get_indent_string( - current_buffer[:-1])) + self.input_buffer += self._get_indent_string( + current_buffer[:-1]) if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'): - self.add_to_edit_buffer('\t') + self.input_buffer += '\t' def _get_indent_string(self, string): diff --git a/IPython/frontend/tests/test_prefilterfrontend.py b/IPython/frontend/tests/test_prefilterfrontend.py index 07f4151..8e36bb9 100644 --- a/IPython/frontend/tests/test_prefilterfrontend.py +++ b/IPython/frontend/tests/test_prefilterfrontend.py @@ -21,36 +21,23 @@ class TestPrefilterFrontEnd(PrefilterFrontEnd): input_prompt_template = string.Template('') output_prompt_template = string.Template('') - edit_buffer = '' - - def __init__(self): self.out = StringIO() PrefilterFrontEnd.__init__(self) - def get_current_edit_buffer(self): - return self.edit_buffer - - def add_to_edit_buffer(self, string): - self.edit_buffer += string - def write(self, string): self.out.write(string) def _on_enter(self): - self.add_to_edit_buffer('\n') + self.input_buffer += '\n' PrefilterFrontEnd._on_enter(self) - def new_prompt(self, prompt): - self.edit_buffer = '' - PrefilterFrontEnd.new_prompt(self, prompt) - def test_execution(): """ Test execution of a command. """ f = TestPrefilterFrontEnd() - f.edit_buffer='print 1\n' + f.input_buffer = 'print 1\n' f._on_enter() assert f.out.getvalue() == '1\n' @@ -59,17 +46,17 @@ def test_multiline(): """ Test execution of a multiline command. """ f = TestPrefilterFrontEnd() - f.edit_buffer='if True:' + f.input_buffer = 'if True:' f._on_enter() - f.add_to_edit_buffer('print 1') + f.input_buffer += 'print 1' f._on_enter() assert f.out.getvalue() == '' f._on_enter() assert f.out.getvalue() == '1\n' f = TestPrefilterFrontEnd() - f.edit_buffer='(1 +' + f.input_buffer='(1 +' f._on_enter() - f.add_to_edit_buffer('0)') + f.input_buffer += '0)' f._on_enter() assert f.out.getvalue() == '' f._on_enter() @@ -81,11 +68,13 @@ def test_capture(): """ # Test on the OS-level stdout, stderr. f = TestPrefilterFrontEnd() - f.edit_buffer='import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()' + f.input_buffer = \ + 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()' f._on_enter() assert f.out.getvalue() == '1' f = TestPrefilterFrontEnd() - f.edit_buffer='import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()' + f.input_buffer = \ + 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()' f._on_enter() assert f.out.getvalue() == '1' @@ -96,7 +85,7 @@ def test_magic(): This test is fairly fragile and will break when magics change. """ f = TestPrefilterFrontEnd() - f.add_to_edit_buffer('%who\n') + f.input_buffer += '%who\n' f._on_enter() assert f.out.getvalue() == 'Interactive namespace is empty.\n' @@ -105,26 +94,27 @@ def test_help(): """ Test object inspection. """ f = TestPrefilterFrontEnd() - f.add_to_edit_buffer("def f():") + f.input_buffer += "def f():" f._on_enter() - f.add_to_edit_buffer("'foobar'") + f.input_buffer += "'foobar'" f._on_enter() - f.add_to_edit_buffer("pass") + f.input_buffer += "pass" f._on_enter() f._on_enter() - f.add_to_edit_buffer("f?") + f.input_buffer += "f?" f._on_enter() assert f.out.getvalue().split()[-1] == 'foobar' + def test_completion(): """ Test command-line completion. """ f = TestPrefilterFrontEnd() - f.edit_buffer = 'zzza = 1' + f.input_buffer = 'zzza = 1' f._on_enter() - f.edit_buffer = 'zzzb = 2' + f.input_buffer = 'zzzb = 2' f._on_enter() - f.edit_buffer = 'zz' + f.input_buffer = 'zz' if __name__ == '__main__': diff --git a/IPython/frontend/wx/console_widget.py b/IPython/frontend/wx/console_widget.py index 2ad60b0..0943ee6 100644 --- a/IPython/frontend/wx/console_widget.py +++ b/IPython/frontend/wx/console_widget.py @@ -80,6 +80,22 @@ class ConsoleWidget(editwindow.EditWindow): # stored. title = 'Console' + # The buffer being edited. + def _set_input_buffer(self, string): + self.SetSelection(self.current_prompt_pos, self.GetLength()) + self.ReplaceSelection(string) + self.GotoPos(self.GetLength()) + + def _get_input_buffer(self): + """ Returns the text in current edit buffer. + """ + input_buffer = self.GetTextRange(self.current_prompt_pos, + self.GetLength()) + input_buffer = input_buffer.replace(LINESEP, '\n') + return input_buffer + + input_buffer = property(_get_input_buffer, _set_input_buffer) + style = _DEFAULT_STYLE.copy() # Translation table from ANSI escape sequences to color. Override @@ -168,23 +184,6 @@ class ConsoleWidget(editwindow.EditWindow): wx.Yield() self.EnsureCaretVisible() - - def replace_current_edit_buffer(self, text): - """ Replace currently entered command line with given text. - """ - self.SetSelection(self.current_prompt_pos, self.GetLength()) - self.ReplaceSelection(text) - self.GotoPos(self.GetLength()) - - - def get_current_edit_buffer(self): - """ Returns the text in current edit buffer. - """ - current_edit_buffer = self.GetTextRange(self.current_prompt_pos, - self.GetLength()) - current_edit_buffer = current_edit_buffer.replace(LINESEP, '\n') - return current_edit_buffer - def scroll_to_bottom(self): maxrange = self.GetScrollRange(wx.VERTICAL) @@ -205,7 +204,7 @@ class ConsoleWidget(editwindow.EditWindow): def write_completion(self, possibilities): # FIXME: This is non Wx specific and needs to be moved into # the base class. - current_buffer = self.get_current_edit_buffer() + current_buffer = self.input_buffer self.write('\n') max_len = len(max(possibilities, key=len)) + 1 @@ -228,7 +227,7 @@ class ConsoleWidget(editwindow.EditWindow): # and wx_frontend, here. self.new_prompt(self.input_prompt_template.substitute( number=self.last_result['number'] + 1)) - self.replace_current_edit_buffer(current_buffer) + self.input_buffer = current_buffer #-------------------------------------------------------------------------- # Private API @@ -343,7 +342,7 @@ class ConsoleWidget(editwindow.EditWindow): if event.KeyCode == ord('L') and event.ControlDown() : self.scroll_to_bottom() elif event.KeyCode == ord('K') and event.ControlDown() : - self.replace_current_edit_buffer('') + self.input_buffer = '' elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown(): self.ScrollPages(-1) elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown(): @@ -364,11 +363,10 @@ class ConsoleWidget(editwindow.EditWindow): self.CallTipCancel() self.write('\n') # Under windows scintilla seems to be doing funny stuff to the - # line returns here, but get_current_edit_buffer filters this - # out. + # line returns here, but the getter for input_buffer filters + # this out. if sys.platform == 'win32': - self.replace_current_edit_buffer( - self.get_current_edit_buffer()) + self.input_buffer = self.input_buffer self._on_enter() elif event.KeyCode == wx.WXK_HOME: diff --git a/IPython/frontend/wx/ipythonx.py b/IPython/frontend/wx/ipythonx.py index 3d48991..ac7bf34 100644 --- a/IPython/frontend/wx/ipythonx.py +++ b/IPython/frontend/wx/ipythonx.py @@ -22,7 +22,7 @@ class IPythonXController(WxController): def _on_key_down(self, event, skip=True): # Intercept Ctrl-D to quit if event.KeyCode == ord('D') and event.ControlDown() and \ - self.get_current_edit_buffer()=='' and \ + self.input_buffer == '' and \ self._input_state == 'readline': wx.CallAfter(self.ask_exit) else: diff --git a/IPython/frontend/wx/wx_frontend.py b/IPython/frontend/wx/wx_frontend.py index 07cc366..bb0639b 100644 --- a/IPython/frontend/wx/wx_frontend.py +++ b/IPython/frontend/wx/wx_frontend.py @@ -58,7 +58,7 @@ prompt_out = \ #------------------------------------------------------------------------------- # Classes to implement the Wx frontend #------------------------------------------------------------------------------- -class WxController(PrefilterFrontEnd, ConsoleWidget): +class WxController(ConsoleWidget, PrefilterFrontEnd): """Classes to provide a Wx frontend to the IPython.kernel.core.interpreter. @@ -83,6 +83,21 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): title = property(_get_title, _set_title) + + # The buffer being edited. + # We are duplicating the defination here because of multiple + # inheritence + def _set_input_buffer(self, string): + return ConsoleWidget._set_input_buffer(self, string) + + def _get_input_buffer(self): + """ Returns the text in current edit buffer. + """ + return ConsoleWidget._get_input_buffer(self) + + input_buffer = property(_get_input_buffer, _set_input_buffer) + + #-------------------------------------------------------------------------- # Private Attributes #-------------------------------------------------------------------------- @@ -149,7 +164,7 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): sleep(0.1) self._on_enter = self.__old_on_enter self._input_state = 'buffering' - return self.get_current_edit_buffer().rstrip('\n') + return self.input_buffer.rstrip('\n') def system_call(self, command_string): @@ -173,11 +188,11 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): """ if self.debug: print >>sys.__stdout__, "do_completion", - line = self.get_current_edit_buffer() + line = self.input_buffer new_line, completions = self.complete(line) if len(completions)>1: self.write_completion(completions) - self.replace_current_edit_buffer(new_line) + self.input_buffer = new_line if self.debug: print >>sys.__stdout__, completions @@ -188,7 +203,7 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): if self.debug: print >>sys.__stdout__, "do_calltip" separators = re.compile('[\s\{\}\[\]\(\)\= ,:]') - symbol = self.get_current_edit_buffer() + symbol = self.input_buffer symbol_string = separators.split(symbol)[-1] base_symbol_string = symbol_string.split('.')[0] if base_symbol_string in self.shell.user_ns: @@ -216,7 +231,7 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): """ if self.debug: print >>sys.__stdout__, "_popup_completion", - line = self.get_current_edit_buffer() + line = self.input_buffer if (self.AutoCompActive() and not line[-1] == '.') \ or create==True: suggestion, completions = self.complete(line) @@ -290,13 +305,6 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): self.MarkerAdd(i, _ERROR_MARKER) - def add_to_edit_buffer(self, string): - """ Add the given string to the current edit buffer. - """ - # XXX: I should check the input_state here. - self.write(string) - - #-------------------------------------------------------------------------- # ConsoleWidget interface #-------------------------------------------------------------------------- @@ -314,12 +322,6 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): ConsoleWidget.write(self, *args, **kwargs) - def get_current_edit_buffer(self): - # Avoid multiple inheritence, be explicit about which - # parent method class gets called - return ConsoleWidget.get_current_edit_buffer(self) - - def _on_key_down(self, event, skip=True): """ Capture the character events, let the parent widget handle them, and put our logic afterward. @@ -374,9 +376,9 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) ) or event.ControlDown() ): new_buffer = self.get_history_previous( - self.get_current_edit_buffer()) + self.input_buffer) if new_buffer is not None: - self.replace_current_edit_buffer(new_buffer) + self.input_buffer = new_buffer if self.GetCurrentLine() > self.current_prompt_line: # Go to first line, for seemless history up. self.GotoPos(self.current_prompt_pos) @@ -387,10 +389,10 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): or event.ControlDown() ): new_buffer = self.get_history_next() if new_buffer is not None: - self.replace_current_edit_buffer(new_buffer) + self.input_buffer = new_buffer # Tab-completion elif event.KeyCode == ord('\t'): - last_line = self.get_current_edit_buffer().split('\n')[-1] + last_line = self.input_buffer.split('\n')[-1] if not re.match(r'^\s*$', last_line): self.do_completion() else: @@ -414,7 +416,7 @@ class WxController(PrefilterFrontEnd, ConsoleWidget): """ Called on return key down, in readline input_state. """ if self.debug: - print >>sys.__stdout__, repr(self.get_current_edit_buffer()) + print >>sys.__stdout__, repr(self.input_buffer) PrefilterFrontEnd._on_enter(self)