From d1575c192976a50796932e5ef4298482abda88b7 2009-02-22 22:54:09 From: Laurent Dufrechou Date: 2009-02-22 22:54:09 Subject: [PATCH] Full patch for better user color tweaking + patch for 'enter' synchro bug --- diff --git a/IPython/frontend/prefilterfrontend.py b/IPython/frontend/prefilterfrontend.py index c6182a1..fa25d7e 100644 --- a/IPython/frontend/prefilterfrontend.py +++ b/IPython/frontend/prefilterfrontend.py @@ -107,8 +107,7 @@ class PrefilterFrontEnd(LineFrontEndBase): if not 'banner' in kwargs and self.banner is None: - self.banner = self.ipython0.BANNER + """ -This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code.""" + self.banner = self.ipython0.BANNER self.start() diff --git a/IPython/frontend/wx/console_widget.py b/IPython/frontend/wx/console_widget.py index 30ec0b8..ebc50d7 100644 --- a/IPython/frontend/wx/console_widget.py +++ b/IPython/frontend/wx/console_widget.py @@ -33,6 +33,12 @@ import re # FIXME: Need to provide an API for non user-generated display on the # screen: this should not be editable by the user. +#------------------------------------------------------------------------------- +# Constants +#------------------------------------------------------------------------------- +_COMPLETE_BUFFER_MARKER = 31 +_ERROR_MARKER = 30 +_INPUT_MARKER = 29 _DEFAULT_SIZE = 10 if sys.platform == 'darwin': @@ -109,13 +115,44 @@ class ConsoleWidget(editwindow.EditWindow): '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'], '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'], '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'], - '1;34': [12, 'LIGHT BLUE'], '1;35': - [13, 'MEDIUM VIOLET RED'], + '1;34': [12, 'LIGHT BLUE'], '1;35': [13, 'MEDIUM VIOLET RED'], '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']} # The color of the carret (call _apply_style() after setting) carret_color = 'BLACK' + _COMPLETE_BUFFER_BG = '#FAFAF1' # Nice green + _INPUT_BUFFER_BG = '#FDFFD3' # Nice yellow + _ERROR_BG = '#FFF1F1' # Nice red + + background_color = 'WHITE' + + #we define platform specific fonts + if wx.Platform == '__WXMSW__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Courier New', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 10, + 'size2': 8, + } + elif wx.Platform == '__WXMAC__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Monaco', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 10, + 'size2': 8, + } + else: + faces = { 'times': 'Times', + 'mono' : 'Courier', + 'helv' : 'Helvetica', + 'other': 'new century schoolbook', + 'size' : 10, + 'size2': 8, + } + # Store the last time a refresh was done _last_refresh_time = 0 @@ -127,6 +164,9 @@ class ConsoleWidget(editwindow.EditWindow): size=wx.DefaultSize, style=wx.WANTS_CHARS, ): editwindow.EditWindow.__init__(self, parent, id, pos, size, style) self._configure_scintilla() + self.enter_catched = False #this var track if 'enter' key as ever been processed + #thus it will only be reallowed until key goes up + self.current_prompt_pos = 0 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down) self.Bind(wx.EVT_KEY_UP, self._on_key_up) @@ -227,26 +267,28 @@ class ConsoleWidget(editwindow.EditWindow): """ #-------------------------------------------------------------------------- - # Private API + # Styling API #-------------------------------------------------------------------------- - - def _apply_style(self): - """ Applies the colors for the different text elements and the - carret. - """ - self.SetCaretForeground(self.carret_color) - - #self.StyleClearAll() - self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, - "fore:#FF0000,back:#0000FF,bold") - self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, - "fore:#000000,back:#FF0000,bold") - - for style in self.ANSI_STYLES.values(): - self.StyleSetSpec(style[0], "bold,fore:%s" % style[1]) + def set_new_style(self): + """ call this method with new style and ansi_style to change colors of the console """ + self._configure_scintilla() + + #-------------------------------------------------------------------------- + # Private API + #-------------------------------------------------------------------------- def _configure_scintilla(self): + # Marker for complete buffer. + self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND, + background = self._COMPLETE_BUFFER_BG) + # Marker for current input buffer. + self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND, + background = self._INPUT_BUFFER_BG) + # Marker for tracebacks. + self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND, + background = self._ERROR_BG) + self.SetEOLMode(stc.STC_EOL_LF) # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside @@ -289,8 +331,9 @@ class ConsoleWidget(editwindow.EditWindow): self.SetMarginWidth(1, 0) self.SetMarginWidth(2, 0) - self._apply_style() - + #self._apply_style() + self.SetCaretForeground(self.carret_color) + # Xterm escape sequences self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?') self.title_pat = re.compile('\x1b]0;(.*?)\x07') @@ -298,29 +341,59 @@ class ConsoleWidget(editwindow.EditWindow): #self.SetEdgeMode(stc.STC_EDGE_LINE) #self.SetEdgeColumn(80) + # styles p = self.style - self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default']) + + if 'default' in p: + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default']) + else: + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "fore:%s,back:%s,size:%d,face:%s" + % (self.ANSI_STYLES['0;30'][1], self.background_color, + self.faces['size'], self.faces['mono'])) + + #all styles = default one self.StyleClearAll() - self.StyleSetSpec(_STDOUT_STYLE, p['stdout']) - self.StyleSetSpec(_STDERR_STYLE, p['stderr']) - self.StyleSetSpec(_TRACE_STYLE, p['trace']) - - self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood']) - self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad']) - self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment']) - self.StyleSetSpec(stc.STC_P_NUMBER, p['number']) - self.StyleSetSpec(stc.STC_P_STRING, p['string']) - self.StyleSetSpec(stc.STC_P_CHARACTER, p['char']) - self.StyleSetSpec(stc.STC_P_WORD, p['keyword']) - self.StyleSetSpec(stc.STC_P_WORD2, p['keyword']) - self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple']) - self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble']) - self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class']) - self.StyleSetSpec(stc.STC_P_DEFNAME, p['def']) - self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator']) - self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment']) - + + # XXX: two lines below are usefull if not using the lexer + #for style in self.ANSI_STYLES.values(): + # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1]) + + if 'stdout' in p: + self.StyleSetSpec(_STDOUT_STYLE, p['stdout']) + if 'stderr' in p: + self.StyleSetSpec(_STDERR_STYLE, p['stderr']) + if 'trace' in p: + self.StyleSetSpec(_TRACE_STYLE, p['trace']) + if 'bracegood' in p: + self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood']) + if 'bracebad' in p: + self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad']) + if 'comment' in p: + self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment']) + if 'number' in p: + self.StyleSetSpec(stc.STC_P_NUMBER, p['number']) + if 'string' in p: + self.StyleSetSpec(stc.STC_P_STRING, p['string']) + if 'char' in p: + self.StyleSetSpec(stc.STC_P_CHARACTER, p['char']) + if 'keyword' in p: + self.StyleSetSpec(stc.STC_P_WORD, p['keyword']) + if 'keyword' in p: + self.StyleSetSpec(stc.STC_P_WORD2, p['keyword']) + if 'triple' in p: + self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple']) + if 'tripledouble' in p: + self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble']) + if 'class' in p: + self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class']) + if 'def' in p: + self.StyleSetSpec(stc.STC_P_DEFNAME, p['def']) + if 'operator' in p: + self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator']) + if 'comment' in p: + self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment']) + def _on_key_down(self, event, skip=True): """ Key press callback used for correcting behavior for console-like interfaces: the cursor is constraint to be after @@ -359,14 +432,16 @@ class ConsoleWidget(editwindow.EditWindow): if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \ event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN): catched = True - 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(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() + self.enter_catched = True elif event.KeyCode == wx.WXK_HOME: if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN): @@ -412,6 +487,7 @@ class ConsoleWidget(editwindow.EditWindow): if self.GetCurrentPos() < self.current_prompt_pos: self.GotoPos(self.current_prompt_pos) + self.enter_catched = False #we re-allow enter event processing if __name__ == '__main__': diff --git a/IPython/frontend/wx/ipythonx.py b/IPython/frontend/wx/ipythonx.py index af7d322..e25e197 100644 --- a/IPython/frontend/wx/ipythonx.py +++ b/IPython/frontend/wx/ipythonx.py @@ -13,6 +13,8 @@ You need wxPython to run this application. e.args = (e.message, ) + e.args[1:] raise e +import wx.stc as stc + from wx_frontend import WxController import __builtin__ @@ -25,8 +27,58 @@ class IPythonXController(WxController): debug = False def __init__(self, *args, **kwargs): + + if kwargs['colorset'] == 'black': + self.prompt_in1 = \ + '\n\x01\x1b[0;30m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;30m\x02]: \x01\x1b[0m\x02' + + self.prompt_out = \ + '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02' + WxController.__init__(self, *args, **kwargs) self.ipython0.ask_exit = self.do_exit + + if kwargs['colorset'] == 'black': + + self.carret_color = 'WHITE' + self.background_color = 'BLACK' + + self.SetEdgeMode(stc.STC_EDGE_LINE) + self.SetEdgeColumn(88) + + self.style = { + #'stdout' : '',#fore:#0000FF', + #'stderr' : '',#fore:#007f00', + #'trace' : '',#fore:#FF0000', + + #'bracegood' : 'fore:#0000FF,back:#0000FF,bold', + #'bracebad' : 'fore:#FF0000,back:#0000FF,bold', + 'default' : "fore:%s,back:%s,size:%d,face:%s,bold" + % ("#EEEEEE", self.background_color, + self.faces['size'], self.faces['mono']), + + # properties for the various Python lexer styles + 'comment' : 'fore:#BBBBBB,italic', + 'number' : 'fore:#FF9692', + 'string' : 'fore:#ed9d13,italic', + 'char' : 'fore:#FFFFFF,italic', + 'keyword' : 'fore:#6AB825,bold', + 'triple' : 'fore:#FF7BDD', + 'tripledouble' : 'fore:#FF7BDD', + 'class' : 'fore:#FF00FF,bold,underline', + 'def' : 'fore:#FFFF00,bold', + 'operator' : 'bold' + } + + #we define the background of old inputs + self._COMPLETE_BUFFER_BG = '#000000' # RRGGBB: Black + #we define the background of current input + self._INPUT_BUFFER_BG = '#444444' # RRGGBB: Light black + #we define the background when an error is reported + self._ERROR_BG = '#800000' #'#d22323' #'#AE0021' # RRGGBB: Black + + self.set_new_style() + # Scroll to top maxrange = self.GetScrollRange(wx.VERTICAL) self.ScrollLines(-maxrange) @@ -72,10 +124,10 @@ class IPythonX(wx.Frame): """ Main frame of the IPythonX app. """ - def __init__(self, parent, id, title, debug=False): + def __init__(self, parent, id, title, debug=False, colorset='white'): wx.Frame.__init__(self, parent, id, title, size=(300,250)) self._sizer = wx.BoxSizer(wx.VERTICAL) - self.shell = IPythonXController(self, debug=debug) + self.shell = IPythonXController(self, debug=debug, colorset=colorset) self._sizer.Add(self.shell, 1, wx.EXPAND) self.SetSizer(self._sizer) self.SetAutoLayout(1) @@ -101,6 +153,10 @@ Simple graphical frontend to IPython, using WxWidgets.""" action="store_true", dest="debug", default=False, help="Enable debug message for the wx frontend.") + parser.add_option("-s", "--style", + dest="colorset", default="white", + help="style: white, black") + options, args = parser.parse_args() # Clear the options, to avoid having the ipython0 instance complain @@ -108,7 +164,7 @@ Simple graphical frontend to IPython, using WxWidgets.""" sys.argv = sys.argv[:1] app = wx.PySimpleApp() - frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug) + frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug, colorset=options.colorset) frame.shell.SetFocus() frame.shell.app = app frame.SetSize((680, 460)) diff --git a/IPython/frontend/wx/wx_frontend.py b/IPython/frontend/wx/wx_frontend.py index d3ae507..adb9481 100644 --- a/IPython/frontend/wx/wx_frontend.py +++ b/IPython/frontend/wx/wx_frontend.py @@ -41,20 +41,10 @@ from IPython.frontend.prefilterfrontend import PrefilterFrontEnd # Constants #------------------------------------------------------------------------------- -_COMPLETE_BUFFER_BG = '#FAFAF1' # Nice green -_INPUT_BUFFER_BG = '#FDFFD3' # Nice yellow -_ERROR_BG = '#FFF1F1' # Nice red - _COMPLETE_BUFFER_MARKER = 31 _ERROR_MARKER = 30 _INPUT_MARKER = 29 -prompt_in1 = \ - '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02' - -prompt_out = \ - '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02' - #------------------------------------------------------------------------------- # Classes to implement the Wx frontend #------------------------------------------------------------------------------- @@ -65,10 +55,11 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): This class inherits from ConsoleWidget, that provides a console-like widget to provide a text-rendering widget suitable for a terminal. """ + prompt_in1 = \ + '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02' - output_prompt_template = string.Template(prompt_out) - - input_prompt_template = string.Template(prompt_in1) + prompt_out = \ + '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02' # Print debug info on what is happening to the console. debug = False @@ -140,22 +131,14 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): *args, **kwds): """ Create Shell instance. """ + self.load_prompt() + ConsoleWidget.__init__(self, parent, id, pos, size, style) PrefilterFrontEnd.__init__(self, **kwds) # Stick in our own raw_input: self.ipython0.raw_input = self.raw_input - # Marker for complete buffer. - self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND, - background=_COMPLETE_BUFFER_BG) - # Marker for current input buffer. - self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND, - background=_INPUT_BUFFER_BG) - # Marker for tracebacks. - self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND, - background=_ERROR_BG) - # A time for flushing the write buffer BUFFER_FLUSH_TIMER_ID = 100 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID) @@ -171,7 +154,12 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): # Inject our own raw_input in namespace self.shell.user_ns['raw_input'] = self.raw_input + def load_prompt(self): + self.output_prompt_template = string.Template(self.prompt_out) + self.input_prompt_template = string.Template(self.prompt_in1) + + def raw_input(self, prompt=''): """ A replacement from python's raw_input. """