##// END OF EJS Templates
Full patch for better user color tweaking + patch for 'enter' synchro bug
Laurent Dufrechou -
Show More
@@ -107,8 +107,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
107 107
108 108
109 109 if not 'banner' in kwargs and self.banner is None:
110 self.banner = self.ipython0.BANNER + """
111 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
110 self.banner = self.ipython0.BANNER
112 111
113 112 self.start()
114 113
@@ -33,6 +33,12 b' import re'
33 33
34 34 # FIXME: Need to provide an API for non user-generated display on the
35 35 # screen: this should not be editable by the user.
36 #-------------------------------------------------------------------------------
37 # Constants
38 #-------------------------------------------------------------------------------
39 _COMPLETE_BUFFER_MARKER = 31
40 _ERROR_MARKER = 30
41 _INPUT_MARKER = 29
36 42
37 43 _DEFAULT_SIZE = 10
38 44 if sys.platform == 'darwin':
@@ -109,13 +115,44 b' class ConsoleWidget(editwindow.EditWindow):'
109 115 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
110 116 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
111 117 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
112 '1;34': [12, 'LIGHT BLUE'], '1;35':
113 [13, 'MEDIUM VIOLET RED'],
118 '1;34': [12, 'LIGHT BLUE'], '1;35': [13, 'MEDIUM VIOLET RED'],
114 119 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
115 120
116 121 # The color of the carret (call _apply_style() after setting)
117 122 carret_color = 'BLACK'
118 123
124 _COMPLETE_BUFFER_BG = '#FAFAF1' # Nice green
125 _INPUT_BUFFER_BG = '#FDFFD3' # Nice yellow
126 _ERROR_BG = '#FFF1F1' # Nice red
127
128 background_color = 'WHITE'
129
130 #we define platform specific fonts
131 if wx.Platform == '__WXMSW__':
132 faces = { 'times': 'Times New Roman',
133 'mono' : 'Courier New',
134 'helv' : 'Arial',
135 'other': 'Comic Sans MS',
136 'size' : 10,
137 'size2': 8,
138 }
139 elif wx.Platform == '__WXMAC__':
140 faces = { 'times': 'Times New Roman',
141 'mono' : 'Monaco',
142 'helv' : 'Arial',
143 'other': 'Comic Sans MS',
144 'size' : 10,
145 'size2': 8,
146 }
147 else:
148 faces = { 'times': 'Times',
149 'mono' : 'Courier',
150 'helv' : 'Helvetica',
151 'other': 'new century schoolbook',
152 'size' : 10,
153 'size2': 8,
154 }
155
119 156 # Store the last time a refresh was done
120 157 _last_refresh_time = 0
121 158
@@ -127,6 +164,9 b' class ConsoleWidget(editwindow.EditWindow):'
127 164 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
128 165 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
129 166 self._configure_scintilla()
167 self.enter_catched = False #this var track if 'enter' key as ever been processed
168 #thus it will only be reallowed until key goes up
169 self.current_prompt_pos = 0
130 170
131 171 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
132 172 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
@@ -227,26 +267,28 b' class ConsoleWidget(editwindow.EditWindow):'
227 267 """
228 268
229 269 #--------------------------------------------------------------------------
230 # Private API
270 # Styling API
231 271 #--------------------------------------------------------------------------
232
233 def _apply_style(self):
234 """ Applies the colors for the different text elements and the
235 carret.
236 """
237 self.SetCaretForeground(self.carret_color)
238
239 #self.StyleClearAll()
240 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
241 "fore:#FF0000,back:#0000FF,bold")
242 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
243 "fore:#000000,back:#FF0000,bold")
244
245 for style in self.ANSI_STYLES.values():
246 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
247 272
273 def set_new_style(self):
274 """ call this method with new style and ansi_style to change colors of the console """
275 self._configure_scintilla()
276
277 #--------------------------------------------------------------------------
278 # Private API
279 #--------------------------------------------------------------------------
248 280
249 281 def _configure_scintilla(self):
282 # Marker for complete buffer.
283 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
284 background = self._COMPLETE_BUFFER_BG)
285 # Marker for current input buffer.
286 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
287 background = self._INPUT_BUFFER_BG)
288 # Marker for tracebacks.
289 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
290 background = self._ERROR_BG)
291
250 292 self.SetEOLMode(stc.STC_EOL_LF)
251 293
252 294 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
@@ -289,8 +331,9 b' class ConsoleWidget(editwindow.EditWindow):'
289 331 self.SetMarginWidth(1, 0)
290 332 self.SetMarginWidth(2, 0)
291 333
292 self._apply_style()
293
334 #self._apply_style()
335 self.SetCaretForeground(self.carret_color)
336
294 337 # Xterm escape sequences
295 338 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
296 339 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
@@ -298,29 +341,59 b' class ConsoleWidget(editwindow.EditWindow):'
298 341 #self.SetEdgeMode(stc.STC_EDGE_LINE)
299 342 #self.SetEdgeColumn(80)
300 343
344
301 345 # styles
302 346 p = self.style
303 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
347
348 if 'default' in p:
349 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
350 else:
351 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "fore:%s,back:%s,size:%d,face:%s"
352 % (self.ANSI_STYLES['0;30'][1], self.background_color,
353 self.faces['size'], self.faces['mono']))
354
355 #all styles = default one
304 356 self.StyleClearAll()
305 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
306 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
307 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
308
309 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
310 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
311 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
312 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
313 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
314 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
315 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
316 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
317 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
318 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
319 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
320 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
321 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
322 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
323
357
358 # XXX: two lines below are usefull if not using the lexer
359 #for style in self.ANSI_STYLES.values():
360 # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
361
362 if 'stdout' in p:
363 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
364 if 'stderr' in p:
365 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
366 if 'trace' in p:
367 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
368 if 'bracegood' in p:
369 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
370 if 'bracebad' in p:
371 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
372 if 'comment' in p:
373 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
374 if 'number' in p:
375 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
376 if 'string' in p:
377 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
378 if 'char' in p:
379 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
380 if 'keyword' in p:
381 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
382 if 'keyword' in p:
383 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
384 if 'triple' in p:
385 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
386 if 'tripledouble' in p:
387 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
388 if 'class' in p:
389 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
390 if 'def' in p:
391 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
392 if 'operator' in p:
393 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
394 if 'comment' in p:
395 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
396
324 397 def _on_key_down(self, event, skip=True):
325 398 """ Key press callback used for correcting behavior for
326 399 console-like interfaces: the cursor is constraint to be after
@@ -359,14 +432,16 b' class ConsoleWidget(editwindow.EditWindow):'
359 432 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
360 433 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
361 434 catched = True
362 self.CallTipCancel()
363 self.write('\n', refresh=False)
364 # Under windows scintilla seems to be doing funny stuff to the
365 # line returns here, but the getter for input_buffer filters
366 # this out.
367 if sys.platform == 'win32':
368 self.input_buffer = self.input_buffer
369 self._on_enter()
435 if(not self.enter_catched):
436 self.CallTipCancel()
437 self.write('\n', refresh=False)
438 # Under windows scintilla seems to be doing funny stuff to the
439 # line returns here, but the getter for input_buffer filters
440 # this out.
441 if sys.platform == 'win32':
442 self.input_buffer = self.input_buffer
443 self._on_enter()
444 self.enter_catched = True
370 445
371 446 elif event.KeyCode == wx.WXK_HOME:
372 447 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
@@ -412,6 +487,7 b' class ConsoleWidget(editwindow.EditWindow):'
412 487 if self.GetCurrentPos() < self.current_prompt_pos:
413 488 self.GotoPos(self.current_prompt_pos)
414 489
490 self.enter_catched = False #we re-allow enter event processing
415 491
416 492
417 493 if __name__ == '__main__':
@@ -13,6 +13,8 b' You need wxPython to run this application.'
13 13 e.args = (e.message, ) + e.args[1:]
14 14 raise e
15 15
16 import wx.stc as stc
17
16 18 from wx_frontend import WxController
17 19 import __builtin__
18 20
@@ -25,8 +27,58 b' class IPythonXController(WxController):'
25 27 debug = False
26 28
27 29 def __init__(self, *args, **kwargs):
30
31 if kwargs['colorset'] == 'black':
32 self.prompt_in1 = \
33 '\n\x01\x1b[0;30m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;30m\x02]: \x01\x1b[0m\x02'
34
35 self.prompt_out = \
36 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
37
28 38 WxController.__init__(self, *args, **kwargs)
29 39 self.ipython0.ask_exit = self.do_exit
40
41 if kwargs['colorset'] == 'black':
42
43 self.carret_color = 'WHITE'
44 self.background_color = 'BLACK'
45
46 self.SetEdgeMode(stc.STC_EDGE_LINE)
47 self.SetEdgeColumn(88)
48
49 self.style = {
50 #'stdout' : '',#fore:#0000FF',
51 #'stderr' : '',#fore:#007f00',
52 #'trace' : '',#fore:#FF0000',
53
54 #'bracegood' : 'fore:#0000FF,back:#0000FF,bold',
55 #'bracebad' : 'fore:#FF0000,back:#0000FF,bold',
56 'default' : "fore:%s,back:%s,size:%d,face:%s,bold"
57 % ("#EEEEEE", self.background_color,
58 self.faces['size'], self.faces['mono']),
59
60 # properties for the various Python lexer styles
61 'comment' : 'fore:#BBBBBB,italic',
62 'number' : 'fore:#FF9692',
63 'string' : 'fore:#ed9d13,italic',
64 'char' : 'fore:#FFFFFF,italic',
65 'keyword' : 'fore:#6AB825,bold',
66 'triple' : 'fore:#FF7BDD',
67 'tripledouble' : 'fore:#FF7BDD',
68 'class' : 'fore:#FF00FF,bold,underline',
69 'def' : 'fore:#FFFF00,bold',
70 'operator' : 'bold'
71 }
72
73 #we define the background of old inputs
74 self._COMPLETE_BUFFER_BG = '#000000' # RRGGBB: Black
75 #we define the background of current input
76 self._INPUT_BUFFER_BG = '#444444' # RRGGBB: Light black
77 #we define the background when an error is reported
78 self._ERROR_BG = '#800000' #'#d22323' #'#AE0021' # RRGGBB: Black
79
80 self.set_new_style()
81
30 82 # Scroll to top
31 83 maxrange = self.GetScrollRange(wx.VERTICAL)
32 84 self.ScrollLines(-maxrange)
@@ -72,10 +124,10 b' class IPythonX(wx.Frame):'
72 124 """ Main frame of the IPythonX app.
73 125 """
74 126
75 def __init__(self, parent, id, title, debug=False):
127 def __init__(self, parent, id, title, debug=False, colorset='white'):
76 128 wx.Frame.__init__(self, parent, id, title, size=(300,250))
77 129 self._sizer = wx.BoxSizer(wx.VERTICAL)
78 self.shell = IPythonXController(self, debug=debug)
130 self.shell = IPythonXController(self, debug=debug, colorset=colorset)
79 131 self._sizer.Add(self.shell, 1, wx.EXPAND)
80 132 self.SetSizer(self._sizer)
81 133 self.SetAutoLayout(1)
@@ -101,6 +153,10 b' Simple graphical frontend to IPython, using WxWidgets."""'
101 153 action="store_true", dest="debug", default=False,
102 154 help="Enable debug message for the wx frontend.")
103 155
156 parser.add_option("-s", "--style",
157 dest="colorset", default="white",
158 help="style: white, black")
159
104 160 options, args = parser.parse_args()
105 161
106 162 # Clear the options, to avoid having the ipython0 instance complain
@@ -108,7 +164,7 b' Simple graphical frontend to IPython, using WxWidgets."""'
108 164 sys.argv = sys.argv[:1]
109 165
110 166 app = wx.PySimpleApp()
111 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
167 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug, colorset=options.colorset)
112 168 frame.shell.SetFocus()
113 169 frame.shell.app = app
114 170 frame.SetSize((680, 460))
@@ -41,20 +41,10 b' from IPython.frontend.prefilterfrontend import PrefilterFrontEnd'
41 41 # Constants
42 42 #-------------------------------------------------------------------------------
43 43
44 _COMPLETE_BUFFER_BG = '#FAFAF1' # Nice green
45 _INPUT_BUFFER_BG = '#FDFFD3' # Nice yellow
46 _ERROR_BG = '#FFF1F1' # Nice red
47
48 44 _COMPLETE_BUFFER_MARKER = 31
49 45 _ERROR_MARKER = 30
50 46 _INPUT_MARKER = 29
51 47
52 prompt_in1 = \
53 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
54
55 prompt_out = \
56 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
57
58 48 #-------------------------------------------------------------------------------
59 49 # Classes to implement the Wx frontend
60 50 #-------------------------------------------------------------------------------
@@ -65,10 +55,11 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
65 55 This class inherits from ConsoleWidget, that provides a console-like
66 56 widget to provide a text-rendering widget suitable for a terminal.
67 57 """
58 prompt_in1 = \
59 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
68 60
69 output_prompt_template = string.Template(prompt_out)
70
71 input_prompt_template = string.Template(prompt_in1)
61 prompt_out = \
62 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
72 63
73 64 # Print debug info on what is happening to the console.
74 65 debug = False
@@ -140,22 +131,14 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
140 131 *args, **kwds):
141 132 """ Create Shell instance.
142 133 """
134 self.load_prompt()
135
143 136 ConsoleWidget.__init__(self, parent, id, pos, size, style)
144 137 PrefilterFrontEnd.__init__(self, **kwds)
145 138
146 139 # Stick in our own raw_input:
147 140 self.ipython0.raw_input = self.raw_input
148 141
149 # Marker for complete buffer.
150 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
151 background=_COMPLETE_BUFFER_BG)
152 # Marker for current input buffer.
153 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
154 background=_INPUT_BUFFER_BG)
155 # Marker for tracebacks.
156 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
157 background=_ERROR_BG)
158
159 142 # A time for flushing the write buffer
160 143 BUFFER_FLUSH_TIMER_ID = 100
161 144 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
@@ -171,7 +154,12 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
171 154 # Inject our own raw_input in namespace
172 155 self.shell.user_ns['raw_input'] = self.raw_input
173 156
157 def load_prompt(self):
158 self.output_prompt_template = string.Template(self.prompt_out)
174 159
160 self.input_prompt_template = string.Template(self.prompt_in1)
161
162
175 163 def raw_input(self, prompt=''):
176 164 """ A replacement from python's raw_input.
177 165 """
General Comments 0
You need to be logged in to leave comments. Login now