From f41be11b51f04dc57d8ec32fb167daf8658d173f 2008-07-19 07:18:25 From: Gael Varoquaux Date: 2008-07-19 07:18:25 Subject: [PATCH] Usability tweaks. Better auto tab completion. Terminal size more compatible with 80 cols. --- diff --git a/IPython/frontend/wx/console_widget.py b/IPython/frontend/wx/console_widget.py index db69dfc..d224207 100644 --- a/IPython/frontend/wx/console_widget.py +++ b/IPython/frontend/wx/console_widget.py @@ -63,7 +63,7 @@ _TRACE_STYLE = 17 # system colors -SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND) +#SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND) #------------------------------------------------------------------------------- # The console widget class @@ -100,12 +100,7 @@ class ConsoleWidget(editwindow.EditWindow): #-------------------------------------------------------------------------- def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, - size=wx.DefaultSize, style=0, - autocomplete_mode='popup'): - """ Autocomplete_mode: Can be 'popup' or 'text' - 'text' show autocompletion in the text buffer - 'popup' show it with a dropdown popup - """ + size=wx.DefaultSize, style=0, ): editwindow.EditWindow.__init__(self, parent, id, pos, size, style) self.configure_scintilla() @@ -114,8 +109,6 @@ class ConsoleWidget(editwindow.EditWindow): '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02' self.new_prompt(self.prompt % 1) - self.autocomplete_mode = autocomplete_mode - self.Bind(wx.EVT_KEY_DOWN, self._on_key_down) self.Bind(wx.EVT_KEY_UP, self._on_key_up) @@ -154,9 +147,10 @@ class ConsoleWidget(editwindow.EditWindow): self.SetTabWidth(4) self.EnsureCaretVisible() - # Tell autocompletion to choose automaticaly out of a single - # choice list - self.AutoCompSetChooseSingle(True) + # we don't want scintilla's autocompletion to choose + # automaticaly out of a single choice list, as we pop it up + # automaticaly + self.AutoCompSetChooseSingle(False) self.AutoCompSetMaxHeight(10) self.SetMargins(3, 3) #text is moved away from border with 3px @@ -278,42 +272,41 @@ class ConsoleWidget(editwindow.EditWindow): self.StyleSetSpec(style[0], "bold,fore:%s" % style[1]) - def write_completion(self, possibilities, mode=None): - if mode=='text' or self.autocomplete_mode == 'text': - # FIXME: This is non Wx specific and needs to be moved into - # the base class. - current_buffer = self.get_current_edit_buffer() - - self.write('\n') - max_len = len(max(possibilities, key=len)) - - #now we check how much symbol we can put on a line... - chars_per_line = self.GetSize()[0]/self.GetCharWidth() - symbols_per_line = max(1, chars_per_line/max_len) - - pos = 1 - buf = [] - for symbol in possibilities: - if pos < symbols_per_line: - buf.append(symbol.ljust(max_len)) - pos += 1 - else: - buf.append(symbol.rstrip() +'\n') - pos = 1 - self.write(''.join(buf)) - self.new_prompt(self.prompt % (self.last_result['number'] + 1)) - self.replace_current_edit_buffer(current_buffer) - - else: - self.AutoCompSetIgnoreCase(False) - self.AutoCompSetAutoHide(False) - # compute the length ot the last word - separators = [' ', '(', '[', '{', '\n', '\t', '.'] - symbol = self.get_current_edit_buffer() - for separator in separators: - symbol = symbol.split(separator)[-1] - self.AutoCompSetMaxHeight(len(possibilities)) - self.AutoCompShow(len(symbol), " ".join(possibilities)) + 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() + + self.write('\n') + max_len = len(max(possibilities, key=len)) + 1 + + #now we check how much symbol we can put on a line... + chars_per_line = self.GetSize()[0]/self.GetCharWidth() + symbols_per_line = max(1, chars_per_line/max_len) + + pos = 1 + buf = [] + for symbol in possibilities: + if pos < symbols_per_line: + buf.append(symbol.ljust(max_len)) + pos += 1 + else: + buf.append(symbol.rstrip() +'\n') + pos = 1 + self.write(''.join(buf)) + self.new_prompt(self.prompt % (self.last_result['number'] + 1)) + self.replace_current_edit_buffer(current_buffer) + + + def pop_completion(self, possibilities, offset=0): + """ Pops up an autocompletion menu. Offset is the offset + in characters of the position at which the menu should + appear, relativ to the cursor. + """ + self.AutoCompSetIgnoreCase(False) + self.AutoCompSetAutoHide(False) + self.AutoCompSetMaxHeight(len(possibilities)) + self.AutoCompShow(offset, " ".join(possibilities)) def scroll_to_bottom(self): @@ -344,6 +337,10 @@ class ConsoleWidget(editwindow.EditWindow): self.ScrollPages(-1) elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown(): self.ScrollPages(1) + elif event.KeyCode == wx.WXK_UP and event.ShiftDown(): + self.ScrollLines(-1) + elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown(): + self.ScrollLinees(1) else: catched = False diff --git a/IPython/frontend/wx/wx_frontend.py b/IPython/frontend/wx/wx_frontend.py index 9da5747..8bf9c77 100644 --- a/IPython/frontend/wx/wx_frontend.py +++ b/IPython/frontend/wx/wx_frontend.py @@ -41,7 +41,7 @@ _RUNNING_BUFFER_MARKER = 31 class IPythonWxController(PrefilterFrontEnd, ConsoleWidget): output_prompt = \ - '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02' + '\n\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02' #-------------------------------------------------------------------------- # Public API @@ -64,14 +64,13 @@ class IPythonWxController(PrefilterFrontEnd, ConsoleWidget): - def do_completion(self, mode=None): + def do_completion(self): """ Do code completion. - mode can be 'text', 'popup' or 'none' to use default. """ line = self.get_current_edit_buffer() new_line, completions = self.complete(line) if len(completions)>1: - self.write_completion(completions, mode=mode) + self.write_completion(completions) self.replace_current_edit_buffer(new_line) @@ -91,21 +90,31 @@ class IPythonWxController(PrefilterFrontEnd, ConsoleWidget): return False for name in base_symbol_string.split('.')[1:] + ['__doc__']: symbol = getattr(symbol, name) - self.CallTipShow(self.GetCurrentPos(), symbol) + try: + self.CallTipShow(self.GetCurrentPos(), symbol) + except TypeError: + # The retrieve symbol couldn't be converted to a string + pass - def update_completion(self): + def popup_completion(self, create=False): + """ Updates the popup completion menu if it exists. If create is + true, open the menu. + """ line = self.get_current_edit_buffer() - if self.AutoCompActive() and not line[-1] == '.': - line = line[:-1] - completions = self.complete(line) - choose_single = self.AutoCompGetChooseSingle() - self.AutoCompSetChooseSingle(False) - self.write_completion(completions, mode='popup') - self.AutoCompSetChooseSingle(choose_single) + if (self.AutoCompActive() and not line[-1] == '.') \ + or create==True: + suggestion, completions = self.complete(line) + offset=0 + if completions: + complete_sep = re.compile('[\s\{\}\[\]\(\)\= ]') + residual = complete_sep.split(line)[-1] + offset = len(residual) + self.pop_completion(completions, offset=offset) def execute(self, python_string, raw_string=None): + self.CallTipCancel() self._cursor = wx.BusyCursor() if raw_string is None: raw_string = python_string @@ -113,6 +122,10 @@ class IPythonWxController(PrefilterFrontEnd, ConsoleWidget): + max(1, len(raw_string.split('\n'))-1) for i in range(self.current_prompt_line, end_line): self.MarkerAdd(i, 31) + # Remove the trailing "\n" for cleaner display + self.SetSelection(self.GetLength()-1, self.GetLength()) + self.ReplaceSelection('') + self.GotoPos(self.GetLength()) PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string) @@ -134,10 +147,10 @@ class IPythonWxController(PrefilterFrontEnd, ConsoleWidget): if self.AutoCompActive(): event.Skip() if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE): - wx.CallAfter(self.do_completion) + wx.CallAfter(self.popup_completion) elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT): - wx.CallAfter(self.update_completion) + wx.CallAfter(self.popup_completion) else: # Up history if event.KeyCode == wx.WXK_UP and ( @@ -162,7 +175,7 @@ class IPythonWxController(PrefilterFrontEnd, ConsoleWidget): elif event.KeyCode == ord('\t'): last_line = self.get_current_edit_buffer().split('\n')[-1] if not re.match(r'^\s*$', last_line): - self.do_completion(mode='text') + self.do_completion() else: event.Skip() elif event.KeyCode == ord('('): @@ -176,7 +189,7 @@ class IPythonWxController(PrefilterFrontEnd, ConsoleWidget): if event.KeyCode == 59: # Intercepting '.' event.Skip() - #self.do_completion(mode='popup') + self.popup_completion(create=True) else: ConsoleWidget._on_key_up(self, event, skip=skip) @@ -195,7 +208,7 @@ if __name__ == '__main__': app = wx.PySimpleApp() frame = MainWindow(None, wx.ID_ANY, 'Ipython') frame.shell.SetFocus() - frame.SetSize((660, 460)) + frame.SetSize((680, 460)) self = frame.shell app.MainLoop()