##// END OF EJS Templates
Tweak the line colorisation for windows.
gvaroquaux -
Show More
@@ -1,480 +1,482 b''
1 # encoding: utf-8 -*- test-case-name:
1 # encoding: utf-8 -*- test-case-name:
2 # FIXME: Need to add tests.
2 # FIXME: Need to add tests.
3 # ipython1.frontend.wx.tests.test_wx_frontend -*-
3 # ipython1.frontend.wx.tests.test_wx_frontend -*-
4
4
5 """Classes to provide a Wx frontend to the
5 """Classes to provide a Wx frontend to the
6 IPython.kernel.core.interpreter.
6 IPython.kernel.core.interpreter.
7
7
8 This class inherits from ConsoleWidget, that provides a console-like
8 This class inherits from ConsoleWidget, that provides a console-like
9 widget to provide a text-rendering widget suitable for a terminal.
9 widget to provide a text-rendering widget suitable for a terminal.
10 """
10 """
11
11
12 __docformat__ = "restructuredtext en"
12 __docformat__ = "restructuredtext en"
13
13
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Copyright (C) 2008 The IPython Development Team
15 # Copyright (C) 2008 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-------------------------------------------------------------------------------
19 #-------------------------------------------------------------------------------
20
20
21 #-------------------------------------------------------------------------------
21 #-------------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-------------------------------------------------------------------------------
23 #-------------------------------------------------------------------------------
24
24
25 # Major library imports
25 # Major library imports
26 import re
26 import re
27 import __builtin__
27 import __builtin__
28 from time import sleep
28 from time import sleep
29 import sys
29 import sys
30 from threading import Lock
30 from threading import Lock
31 import string
31 import string
32
32
33 import wx
33 import wx
34 from wx import stc
34 from wx import stc
35
35
36 # Ipython-specific imports.
36 # Ipython-specific imports.
37 from IPython.frontend._process import PipedProcess
37 from IPython.frontend._process import PipedProcess
38 from console_widget import ConsoleWidget
38 from console_widget import ConsoleWidget
39 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
39 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
40
40
41 #-------------------------------------------------------------------------------
41 #-------------------------------------------------------------------------------
42 # Constants
42 # Constants
43 #-------------------------------------------------------------------------------
43 #-------------------------------------------------------------------------------
44
44
45 _COMPLETE_BUFFER_BG = '#FAFAF1' # Nice green
45 _COMPLETE_BUFFER_BG = '#FAFAF1' # Nice green
46 _INPUT_BUFFER_BG = '#FDFFD3' # Nice yellow
46 _INPUT_BUFFER_BG = '#FDFFD3' # Nice yellow
47 _ERROR_BG = '#FFF1F1' # Nice red
47 _ERROR_BG = '#FFF1F1' # Nice red
48
48
49 _COMPLETE_BUFFER_MARKER = 31
49 _COMPLETE_BUFFER_MARKER = 31
50 _ERROR_MARKER = 30
50 _ERROR_MARKER = 30
51 _INPUT_MARKER = 29
51 _INPUT_MARKER = 29
52
52
53 prompt_in1 = \
53 prompt_in1 = \
54 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
54 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
55
55
56 prompt_out = \
56 prompt_out = \
57 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
57 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
58
58
59 #-------------------------------------------------------------------------------
59 #-------------------------------------------------------------------------------
60 # Classes to implement the Wx frontend
60 # Classes to implement the Wx frontend
61 #-------------------------------------------------------------------------------
61 #-------------------------------------------------------------------------------
62 class WxController(ConsoleWidget, PrefilterFrontEnd):
62 class WxController(ConsoleWidget, PrefilterFrontEnd):
63 """Classes to provide a Wx frontend to the
63 """Classes to provide a Wx frontend to the
64 IPython.kernel.core.interpreter.
64 IPython.kernel.core.interpreter.
65
65
66 This class inherits from ConsoleWidget, that provides a console-like
66 This class inherits from ConsoleWidget, that provides a console-like
67 widget to provide a text-rendering widget suitable for a terminal.
67 widget to provide a text-rendering widget suitable for a terminal.
68 """
68 """
69
69
70 output_prompt_template = string.Template(prompt_out)
70 output_prompt_template = string.Template(prompt_out)
71
71
72 input_prompt_template = string.Template(prompt_in1)
72 input_prompt_template = string.Template(prompt_in1)
73
73
74 # Print debug info on what is happening to the console.
74 # Print debug info on what is happening to the console.
75 debug = False
75 debug = False
76
76
77 # The title of the terminal, as captured through the ANSI escape
77 # The title of the terminal, as captured through the ANSI escape
78 # sequences.
78 # sequences.
79 def _set_title(self, title):
79 def _set_title(self, title):
80 return self.Parent.SetTitle(title)
80 return self.Parent.SetTitle(title)
81
81
82 def _get_title(self):
82 def _get_title(self):
83 return self.Parent.GetTitle()
83 return self.Parent.GetTitle()
84
84
85 title = property(_get_title, _set_title)
85 title = property(_get_title, _set_title)
86
86
87
87
88 # The buffer being edited.
88 # The buffer being edited.
89 # We are duplicating the definition here because of multiple
89 # We are duplicating the definition here because of multiple
90 # inheritence
90 # inheritence
91 def _set_input_buffer(self, string):
91 def _set_input_buffer(self, string):
92 ConsoleWidget._set_input_buffer(self, string)
92 ConsoleWidget._set_input_buffer(self, string)
93 wx.Yield()
93 wx.Yield()
94 self._colorize_input_buffer()
94 self._colorize_input_buffer()
95
95
96 def _get_input_buffer(self):
96 def _get_input_buffer(self):
97 """ Returns the text in current edit buffer.
97 """ Returns the text in current edit buffer.
98 """
98 """
99 return ConsoleWidget._get_input_buffer(self)
99 return ConsoleWidget._get_input_buffer(self)
100
100
101 input_buffer = property(_get_input_buffer, _set_input_buffer)
101 input_buffer = property(_get_input_buffer, _set_input_buffer)
102
102
103
103
104 #--------------------------------------------------------------------------
104 #--------------------------------------------------------------------------
105 # Private Attributes
105 # Private Attributes
106 #--------------------------------------------------------------------------
106 #--------------------------------------------------------------------------
107
107
108 # A flag governing the behavior of the input. Can be:
108 # A flag governing the behavior of the input. Can be:
109 #
109 #
110 # 'readline' for readline-like behavior with a prompt
110 # 'readline' for readline-like behavior with a prompt
111 # and an edit buffer.
111 # and an edit buffer.
112 # 'subprocess' for sending the raw input directly to a
112 # 'subprocess' for sending the raw input directly to a
113 # subprocess.
113 # subprocess.
114 # 'buffering' for buffering of the input, that will be used
114 # 'buffering' for buffering of the input, that will be used
115 # when the input state switches back to another state.
115 # when the input state switches back to another state.
116 _input_state = 'readline'
116 _input_state = 'readline'
117
117
118 # Attribute to store reference to the pipes of a subprocess, if we
118 # Attribute to store reference to the pipes of a subprocess, if we
119 # are running any.
119 # are running any.
120 _running_process = False
120 _running_process = False
121
121
122 # A queue for writing fast streams to the screen without flooding the
122 # A queue for writing fast streams to the screen without flooding the
123 # event loop
123 # event loop
124 _out_buffer = []
124 _out_buffer = []
125
125
126 # A lock to lock the _out_buffer to make sure we don't empty it
126 # A lock to lock the _out_buffer to make sure we don't empty it
127 # while it is being swapped
127 # while it is being swapped
128 _out_buffer_lock = Lock()
128 _out_buffer_lock = Lock()
129
129
130 _markers = dict()
130 _markers = dict()
131
131
132 #--------------------------------------------------------------------------
132 #--------------------------------------------------------------------------
133 # Public API
133 # Public API
134 #--------------------------------------------------------------------------
134 #--------------------------------------------------------------------------
135
135
136 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
136 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
137 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
137 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
138 *args, **kwds):
138 *args, **kwds):
139 """ Create Shell instance.
139 """ Create Shell instance.
140 """
140 """
141 ConsoleWidget.__init__(self, parent, id, pos, size, style)
141 ConsoleWidget.__init__(self, parent, id, pos, size, style)
142 PrefilterFrontEnd.__init__(self)
142 PrefilterFrontEnd.__init__(self)
143
143
144 # Marker for complete buffer.
144 # Marker for complete buffer.
145 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
145 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
146 background=_COMPLETE_BUFFER_BG)
146 background=_COMPLETE_BUFFER_BG)
147 # Marker for current input buffer.
147 # Marker for current input buffer.
148 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
148 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
149 background=_INPUT_BUFFER_BG)
149 background=_INPUT_BUFFER_BG)
150 # Marker for tracebacks.
150 # Marker for tracebacks.
151 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
151 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
152 background=_ERROR_BG)
152 background=_ERROR_BG)
153
153
154 # A time for flushing the write buffer
154 # A time for flushing the write buffer
155 BUFFER_FLUSH_TIMER_ID = 100
155 BUFFER_FLUSH_TIMER_ID = 100
156 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
156 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
157 wx.EVT_TIMER(self, BUFFER_FLUSH_TIMER_ID, self._buffer_flush)
157 wx.EVT_TIMER(self, BUFFER_FLUSH_TIMER_ID, self._buffer_flush)
158
158
159 # Inject self in namespace, for debug
159 # Inject self in namespace, for debug
160 if self.debug:
160 if self.debug:
161 self.shell.user_ns['self'] = self
161 self.shell.user_ns['self'] = self
162
162
163
163
164 def raw_input(self, prompt):
164 def raw_input(self, prompt):
165 """ A replacement from python's raw_input.
165 """ A replacement from python's raw_input.
166 """
166 """
167 self.new_prompt(prompt)
167 self.new_prompt(prompt)
168 self.waiting = True
168 self.waiting = True
169 self.__old_on_enter = self._on_enter
169 self.__old_on_enter = self._on_enter
170 def my_on_enter():
170 def my_on_enter():
171 self.waiting = False
171 self.waiting = False
172 self._on_enter = my_on_enter
172 self._on_enter = my_on_enter
173 # XXX: Busy waiting, ugly.
173 # XXX: Busy waiting, ugly.
174 while self.waiting:
174 while self.waiting:
175 wx.Yield()
175 wx.Yield()
176 sleep(0.1)
176 sleep(0.1)
177 self._on_enter = self.__old_on_enter
177 self._on_enter = self.__old_on_enter
178 self._input_state = 'buffering'
178 self._input_state = 'buffering'
179 return self.input_buffer.rstrip('\n')
179 return self.input_buffer.rstrip('\n')
180
180
181
181
182 def system_call(self, command_string):
182 def system_call(self, command_string):
183 self._input_state = 'subprocess'
183 self._input_state = 'subprocess'
184 self._running_process = PipedProcess(command_string,
184 self._running_process = PipedProcess(command_string,
185 out_callback=self.buffered_write,
185 out_callback=self.buffered_write,
186 end_callback = self._end_system_call)
186 end_callback = self._end_system_call)
187 self._running_process.start()
187 self._running_process.start()
188 # XXX: another one of these polling loops to have a blocking
188 # XXX: another one of these polling loops to have a blocking
189 # call
189 # call
190 wx.Yield()
190 wx.Yield()
191 while self._running_process:
191 while self._running_process:
192 wx.Yield()
192 wx.Yield()
193 sleep(0.1)
193 sleep(0.1)
194 # Be sure to flush the buffer.
194 # Be sure to flush the buffer.
195 self._buffer_flush(event=None)
195 self._buffer_flush(event=None)
196
196
197
197
198 def do_calltip(self):
198 def do_calltip(self):
199 """ Analyse current and displays useful calltip for it.
199 """ Analyse current and displays useful calltip for it.
200 """
200 """
201 if self.debug:
201 if self.debug:
202 print >>sys.__stdout__, "do_calltip"
202 print >>sys.__stdout__, "do_calltip"
203 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
203 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
204 symbol = self.input_buffer
204 symbol = self.input_buffer
205 symbol_string = separators.split(symbol)[-1]
205 symbol_string = separators.split(symbol)[-1]
206 base_symbol_string = symbol_string.split('.')[0]
206 base_symbol_string = symbol_string.split('.')[0]
207 if base_symbol_string in self.shell.user_ns:
207 if base_symbol_string in self.shell.user_ns:
208 symbol = self.shell.user_ns[base_symbol_string]
208 symbol = self.shell.user_ns[base_symbol_string]
209 elif base_symbol_string in self.shell.user_global_ns:
209 elif base_symbol_string in self.shell.user_global_ns:
210 symbol = self.shell.user_global_ns[base_symbol_string]
210 symbol = self.shell.user_global_ns[base_symbol_string]
211 elif base_symbol_string in __builtin__.__dict__:
211 elif base_symbol_string in __builtin__.__dict__:
212 symbol = __builtin__.__dict__[base_symbol_string]
212 symbol = __builtin__.__dict__[base_symbol_string]
213 else:
213 else:
214 return False
214 return False
215 for name in symbol_string.split('.')[1:] + ['__doc__']:
215 for name in symbol_string.split('.')[1:] + ['__doc__']:
216 symbol = getattr(symbol, name)
216 symbol = getattr(symbol, name)
217 try:
217 try:
218 self.AutoCompCancel()
218 self.AutoCompCancel()
219 wx.Yield()
219 wx.Yield()
220 self.CallTipShow(self.GetCurrentPos(), symbol)
220 self.CallTipShow(self.GetCurrentPos(), symbol)
221 except:
221 except:
222 # The retrieve symbol couldn't be converted to a string
222 # The retrieve symbol couldn't be converted to a string
223 pass
223 pass
224
224
225
225
226 def _popup_completion(self, create=False):
226 def _popup_completion(self, create=False):
227 """ Updates the popup completion menu if it exists. If create is
227 """ Updates the popup completion menu if it exists. If create is
228 true, open the menu.
228 true, open the menu.
229 """
229 """
230 if self.debug:
230 if self.debug:
231 print >>sys.__stdout__, "_popup_completion",
231 print >>sys.__stdout__, "_popup_completion",
232 line = self.input_buffer
232 line = self.input_buffer
233 if (self.AutoCompActive() and not line[-1] == '.') \
233 if (self.AutoCompActive() and not line[-1] == '.') \
234 or create==True:
234 or create==True:
235 suggestion, completions = self.complete(line)
235 suggestion, completions = self.complete(line)
236 offset=0
236 offset=0
237 if completions:
237 if completions:
238 complete_sep = re.compile('[\s\{\}\[\]\(\)\= ,:]')
238 complete_sep = re.compile('[\s\{\}\[\]\(\)\= ,:]')
239 residual = complete_sep.split(line)[-1]
239 residual = complete_sep.split(line)[-1]
240 offset = len(residual)
240 offset = len(residual)
241 self.pop_completion(completions, offset=offset)
241 self.pop_completion(completions, offset=offset)
242 if self.debug:
242 if self.debug:
243 print >>sys.__stdout__, completions
243 print >>sys.__stdout__, completions
244
244
245
245
246 def buffered_write(self, text):
246 def buffered_write(self, text):
247 """ A write method for streams, that caches the stream in order
247 """ A write method for streams, that caches the stream in order
248 to avoid flooding the event loop.
248 to avoid flooding the event loop.
249
249
250 This can be called outside of the main loop, in separate
250 This can be called outside of the main loop, in separate
251 threads.
251 threads.
252 """
252 """
253 self._out_buffer_lock.acquire()
253 self._out_buffer_lock.acquire()
254 self._out_buffer.append(text)
254 self._out_buffer.append(text)
255 self._out_buffer_lock.release()
255 self._out_buffer_lock.release()
256 if not self._buffer_flush_timer.IsRunning():
256 if not self._buffer_flush_timer.IsRunning():
257 wx.CallAfter(self._buffer_flush_timer.Start, 100) # milliseconds
257 wx.CallAfter(self._buffer_flush_timer.Start, 100) # milliseconds
258
258
259
259
260 #--------------------------------------------------------------------------
260 #--------------------------------------------------------------------------
261 # LineFrontEnd interface
261 # LineFrontEnd interface
262 #--------------------------------------------------------------------------
262 #--------------------------------------------------------------------------
263
263
264 def execute(self, python_string, raw_string=None):
264 def execute(self, python_string, raw_string=None):
265 self._input_state = 'buffering'
265 self._input_state = 'buffering'
266 self.CallTipCancel()
266 self.CallTipCancel()
267 self._cursor = wx.BusyCursor()
267 self._cursor = wx.BusyCursor()
268 if raw_string is None:
268 if raw_string is None:
269 raw_string = python_string
269 raw_string = python_string
270 end_line = self.current_prompt_line \
270 end_line = self.current_prompt_line \
271 + max(1, len(raw_string.split('\n'))-1)
271 + max(1, len(raw_string.split('\n'))-1)
272 for i in range(self.current_prompt_line, end_line):
272 for i in range(self.current_prompt_line, end_line):
273 if i in self._markers:
273 if i in self._markers:
274 self.MarkerDeleteHandle(self._markers[i])
274 self.MarkerDeleteHandle(self._markers[i])
275 self._markers[i] = self.MarkerAdd(i, _COMPLETE_BUFFER_MARKER)
275 self._markers[i] = self.MarkerAdd(i, _COMPLETE_BUFFER_MARKER)
276 # Update the display:
276 # Update the display:
277 wx.Yield()
277 wx.Yield()
278 self.GotoPos(self.GetLength())
278 self.GotoPos(self.GetLength())
279 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
279 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
280
280
281 def save_output_hooks(self):
281 def save_output_hooks(self):
282 self.__old_raw_input = __builtin__.raw_input
282 self.__old_raw_input = __builtin__.raw_input
283 PrefilterFrontEnd.save_output_hooks(self)
283 PrefilterFrontEnd.save_output_hooks(self)
284
284
285 def capture_output(self):
285 def capture_output(self):
286 __builtin__.raw_input = self.raw_input
286 __builtin__.raw_input = self.raw_input
287 PrefilterFrontEnd.capture_output(self)
287 PrefilterFrontEnd.capture_output(self)
288
288
289
289
290 def release_output(self):
290 def release_output(self):
291 __builtin__.raw_input = self.__old_raw_input
291 __builtin__.raw_input = self.__old_raw_input
292 PrefilterFrontEnd.release_output(self)
292 PrefilterFrontEnd.release_output(self)
293
293
294
294
295 def after_execute(self):
295 def after_execute(self):
296 PrefilterFrontEnd.after_execute(self)
296 PrefilterFrontEnd.after_execute(self)
297 # Clear the wait cursor
297 # Clear the wait cursor
298 if hasattr(self, '_cursor'):
298 if hasattr(self, '_cursor'):
299 del self._cursor
299 del self._cursor
300
300
301
301
302 def show_traceback(self):
302 def show_traceback(self):
303 start_line = self.GetCurrentLine()
303 start_line = self.GetCurrentLine()
304 PrefilterFrontEnd.show_traceback(self)
304 PrefilterFrontEnd.show_traceback(self)
305 wx.Yield()
305 wx.Yield()
306 for i in range(start_line, self.GetCurrentLine()):
306 for i in range(start_line, self.GetCurrentLine()):
307 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
307 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
308
308
309
309
310 #--------------------------------------------------------------------------
310 #--------------------------------------------------------------------------
311 # ConsoleWidget interface
311 # ConsoleWidget interface
312 #--------------------------------------------------------------------------
312 #--------------------------------------------------------------------------
313
313
314 def new_prompt(self, prompt):
314 def new_prompt(self, prompt):
315 """ Display a new prompt, and start a new input buffer.
315 """ Display a new prompt, and start a new input buffer.
316 """
316 """
317 self._input_state = 'readline'
317 self._input_state = 'readline'
318 ConsoleWidget.new_prompt(self, prompt)
318 ConsoleWidget.new_prompt(self, prompt)
319 i = self.current_prompt_line
319 i = self.current_prompt_line
320 self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
320 self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
321
321
322
322
323 def write(self, *args, **kwargs):
323 def write(self, *args, **kwargs):
324 # Avoid multiple inheritence, be explicit about which
324 # Avoid multiple inheritence, be explicit about which
325 # parent method class gets called
325 # parent method class gets called
326 ConsoleWidget.write(self, *args, **kwargs)
326 ConsoleWidget.write(self, *args, **kwargs)
327
327
328
328
329 def _on_key_down(self, event, skip=True):
329 def _on_key_down(self, event, skip=True):
330 """ Capture the character events, let the parent
330 """ Capture the character events, let the parent
331 widget handle them, and put our logic afterward.
331 widget handle them, and put our logic afterward.
332 """
332 """
333 # FIXME: This method needs to be broken down in smaller ones.
333 # FIXME: This method needs to be broken down in smaller ones.
334 current_line_number = self.GetCurrentLine()
334 current_line_number = self.GetCurrentLine()
335 if event.KeyCode in (ord('c'), ord('C')) and event.ControlDown():
335 if event.KeyCode in (ord('c'), ord('C')) and event.ControlDown():
336 # Capture Control-C
336 # Capture Control-C
337 if self._input_state == 'subprocess':
337 if self._input_state == 'subprocess':
338 if self.debug:
338 if self.debug:
339 print >>sys.__stderr__, 'Killing running process'
339 print >>sys.__stderr__, 'Killing running process'
340 self._running_process.process.kill()
340 self._running_process.process.kill()
341 elif self._input_state == 'buffering':
341 elif self._input_state == 'buffering':
342 if self.debug:
342 if self.debug:
343 print >>sys.__stderr__, 'Raising KeyboardInterrupt'
343 print >>sys.__stderr__, 'Raising KeyboardInterrupt'
344 raise KeyboardInterrupt
344 raise KeyboardInterrupt
345 # XXX: We need to make really sure we
345 # XXX: We need to make really sure we
346 # get back to a prompt.
346 # get back to a prompt.
347 elif self._input_state == 'subprocess' and (
347 elif self._input_state == 'subprocess' and (
348 ( event.KeyCode<256 and
348 ( event.KeyCode<256 and
349 not event.ControlDown() )
349 not event.ControlDown() )
350 or
350 or
351 ( event.KeyCode in (ord('d'), ord('D')) and
351 ( event.KeyCode in (ord('d'), ord('D')) and
352 event.ControlDown())):
352 event.ControlDown())):
353 # We are running a process, we redirect keys.
353 # We are running a process, we redirect keys.
354 ConsoleWidget._on_key_down(self, event, skip=skip)
354 ConsoleWidget._on_key_down(self, event, skip=skip)
355 char = chr(event.KeyCode)
355 char = chr(event.KeyCode)
356 # Deal with some inconsistency in wx keycodes:
356 # Deal with some inconsistency in wx keycodes:
357 if char == '\r':
357 if char == '\r':
358 char = '\n'
358 char = '\n'
359 elif not event.ShiftDown():
359 elif not event.ShiftDown():
360 char = char.lower()
360 char = char.lower()
361 if event.ControlDown() and event.KeyCode in (ord('d'), ord('D')):
361 if event.ControlDown() and event.KeyCode in (ord('d'), ord('D')):
362 char = '\04'
362 char = '\04'
363 self._running_process.process.stdin.write(char)
363 self._running_process.process.stdin.write(char)
364 self._running_process.process.stdin.flush()
364 self._running_process.process.stdin.flush()
365 elif event.KeyCode in (ord('('), 57):
365 elif event.KeyCode in (ord('('), 57):
366 # Calltips
366 # Calltips
367 event.Skip()
367 event.Skip()
368 self.do_calltip()
368 self.do_calltip()
369 elif self.AutoCompActive():
369 elif self.AutoCompActive():
370 event.Skip()
370 event.Skip()
371 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
371 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
372 wx.CallAfter(self._popup_completion, create=True)
372 wx.CallAfter(self._popup_completion, create=True)
373 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
373 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
374 wx.WXK_RIGHT):
374 wx.WXK_RIGHT):
375 wx.CallAfter(self._popup_completion)
375 wx.CallAfter(self._popup_completion)
376 else:
376 else:
377 # Up history
377 # Up history
378 if event.KeyCode == wx.WXK_UP and (
378 if event.KeyCode == wx.WXK_UP and (
379 ( current_line_number == self.current_prompt_line and
379 ( current_line_number == self.current_prompt_line and
380 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
380 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
381 or event.ControlDown() ):
381 or event.ControlDown() ):
382 new_buffer = self.get_history_previous(
382 new_buffer = self.get_history_previous(
383 self.input_buffer)
383 self.input_buffer)
384 if new_buffer is not None:
384 if new_buffer is not None:
385 self.input_buffer = new_buffer
385 self.input_buffer = new_buffer
386 if self.GetCurrentLine() > self.current_prompt_line:
386 if self.GetCurrentLine() > self.current_prompt_line:
387 # Go to first line, for seemless history up.
387 # Go to first line, for seemless history up.
388 self.GotoPos(self.current_prompt_pos)
388 self.GotoPos(self.current_prompt_pos)
389 # Down history
389 # Down history
390 elif event.KeyCode == wx.WXK_DOWN and (
390 elif event.KeyCode == wx.WXK_DOWN and (
391 ( current_line_number == self.LineCount -1 and
391 ( current_line_number == self.LineCount -1 and
392 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
392 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
393 or event.ControlDown() ):
393 or event.ControlDown() ):
394 new_buffer = self.get_history_next()
394 new_buffer = self.get_history_next()
395 if new_buffer is not None:
395 if new_buffer is not None:
396 self.input_buffer = new_buffer
396 self.input_buffer = new_buffer
397 # Tab-completion
397 # Tab-completion
398 elif event.KeyCode == ord('\t'):
398 elif event.KeyCode == ord('\t'):
399 last_line = self.input_buffer.split('\n')[-1]
399 last_line = self.input_buffer.split('\n')[-1]
400 if not re.match(r'^\s*$', last_line):
400 if not re.match(r'^\s*$', last_line):
401 self.complete_current_input()
401 self.complete_current_input()
402 else:
402 else:
403 event.Skip()
403 event.Skip()
404 else:
404 else:
405 ConsoleWidget._on_key_down(self, event, skip=skip)
405 ConsoleWidget._on_key_down(self, event, skip=skip)
406
406
407
407
408 def _on_key_up(self, event, skip=True):
408 def _on_key_up(self, event, skip=True):
409 """ Called when any key is released.
409 """ Called when any key is released.
410 """
410 """
411 if event.KeyCode in (59, ord('.')):
411 if event.KeyCode in (59, ord('.')):
412 # Intercepting '.'
412 # Intercepting '.'
413 event.Skip()
413 event.Skip()
414 self._popup_completion(create=True)
414 self._popup_completion(create=True)
415 else:
415 else:
416 ConsoleWidget._on_key_up(self, event, skip=skip)
416 ConsoleWidget._on_key_up(self, event, skip=skip)
417
417
418
418
419 def _on_enter(self):
419 def _on_enter(self):
420 """ Called on return key down, in readline input_state.
420 """ Called on return key down, in readline input_state.
421 """
421 """
422 if self.debug:
422 if self.debug:
423 print >>sys.__stdout__, repr(self.input_buffer)
423 print >>sys.__stdout__, repr(self.input_buffer)
424 PrefilterFrontEnd._on_enter(self)
424 PrefilterFrontEnd._on_enter(self)
425
425
426
426
427 #--------------------------------------------------------------------------
427 #--------------------------------------------------------------------------
428 # Private API
428 # Private API
429 #--------------------------------------------------------------------------
429 #--------------------------------------------------------------------------
430
430
431 def _end_system_call(self):
431 def _end_system_call(self):
432 """ Called at the end of a system call.
432 """ Called at the end of a system call.
433 """
433 """
434 self._input_state = 'buffering'
434 self._input_state = 'buffering'
435 self._running_process = False
435 self._running_process = False
436
436
437
437
438 def _buffer_flush(self, event):
438 def _buffer_flush(self, event):
439 """ Called by the timer to flush the write buffer.
439 """ Called by the timer to flush the write buffer.
440
440
441 This is always called in the mainloop, by the wx timer.
441 This is always called in the mainloop, by the wx timer.
442 """
442 """
443 self._out_buffer_lock.acquire()
443 self._out_buffer_lock.acquire()
444 _out_buffer = self._out_buffer
444 _out_buffer = self._out_buffer
445 self._out_buffer = []
445 self._out_buffer = []
446 self._out_buffer_lock.release()
446 self._out_buffer_lock.release()
447 self.write(''.join(_out_buffer), refresh=False)
447 self.write(''.join(_out_buffer), refresh=False)
448 self._buffer_flush_timer.Stop()
448 self._buffer_flush_timer.Stop()
449
449
450 def _colorize_input_buffer(self):
450 def _colorize_input_buffer(self):
451 """ Keep the input buffer lines at a bright color.
451 """ Keep the input buffer lines at a bright color.
452 """
452 """
453 if not self._input_state == 'readline':
453 if not self._input_state == 'readline':
454 return
454 return
455 end_line = self.GetCurrentLine() + 1
455 end_line = self.GetCurrentLine()
456 if not sys.platform == 'win32':
457 end_line += 1
456 for i in range(self.current_prompt_line, end_line):
458 for i in range(self.current_prompt_line, end_line):
457 if i in self._markers:
459 if i in self._markers:
458 self.MarkerDeleteHandle(self._markers[i])
460 self.MarkerDeleteHandle(self._markers[i])
459 self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
461 self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
460
462
461
463
462 if __name__ == '__main__':
464 if __name__ == '__main__':
463 class MainWindow(wx.Frame):
465 class MainWindow(wx.Frame):
464 def __init__(self, parent, id, title):
466 def __init__(self, parent, id, title):
465 wx.Frame.__init__(self, parent, id, title, size=(300,250))
467 wx.Frame.__init__(self, parent, id, title, size=(300,250))
466 self._sizer = wx.BoxSizer(wx.VERTICAL)
468 self._sizer = wx.BoxSizer(wx.VERTICAL)
467 self.shell = WxController(self)
469 self.shell = WxController(self)
468 self._sizer.Add(self.shell, 1, wx.EXPAND)
470 self._sizer.Add(self.shell, 1, wx.EXPAND)
469 self.SetSizer(self._sizer)
471 self.SetSizer(self._sizer)
470 self.SetAutoLayout(1)
472 self.SetAutoLayout(1)
471 self.Show(True)
473 self.Show(True)
472
474
473 app = wx.PySimpleApp()
475 app = wx.PySimpleApp()
474 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
476 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
475 frame.shell.SetFocus()
477 frame.shell.SetFocus()
476 frame.SetSize((680, 460))
478 frame.SetSize((680, 460))
477 self = frame.shell
479 self = frame.shell
478
480
479 app.MainLoop()
481 app.MainLoop()
480
482
General Comments 0
You need to be logged in to leave comments. Login now