##// END OF EJS Templates
Merging Laurent's WX branch, reviewed by Gael....
Fernando Perez -
r1862:321357e1 merge
parent child Browse files
Show More
@@ -62,11 +62,10 b' class _Helper(object):'
62 ##############################################################################
62 ##############################################################################
63 class _CodeExecutor(ThreadEx):
63 class _CodeExecutor(ThreadEx):
64 ''' Thread that execute ipython code '''
64 ''' Thread that execute ipython code '''
65 def __init__(self, instance, after):
65 def __init__(self, instance):
66 ThreadEx.__init__(self)
66 ThreadEx.__init__(self)
67 self.instance = instance
67 self.instance = instance
68 self._afterExecute = after
68
69
70 def run(self):
69 def run(self):
71 '''Thread main loop'''
70 '''Thread main loop'''
72 try:
71 try:
@@ -74,7 +73,7 b' class _CodeExecutor(ThreadEx):'
74 self.instance._help_text = None
73 self.instance._help_text = None
75 self.instance._execute()
74 self.instance._execute()
76 # used for uper class to generate event after execution
75 # used for uper class to generate event after execution
77 self._afterExecute()
76 self.instance._after_execute()
78
77
79 except KeyboardInterrupt:
78 except KeyboardInterrupt:
80 pass
79 pass
@@ -114,8 +113,7 b' class NonBlockingIPShell(object):'
114 '''
113 '''
115 #ipython0 initialisation
114 #ipython0 initialisation
116 self._IP = None
115 self._IP = None
117 self._term = None
116 self.init_ipython0(argv, user_ns, user_global_ns,
118 self.initIpython0(argv, user_ns, user_global_ns,
119 cin, cout, cerr,
117 cin, cout, cerr,
120 ask_exit_handler)
118 ask_exit_handler)
121
119
@@ -127,33 +125,32 b' class NonBlockingIPShell(object):'
127
125
128 #thread working vars
126 #thread working vars
129 self._line_to_execute = ''
127 self._line_to_execute = ''
130
128 self._threading = True
129
131 #vars that will be checked by GUI loop to handle thread states...
130 #vars that will be checked by GUI loop to handle thread states...
132 #will be replaced later by PostEvent GUI funtions...
131 #will be replaced later by PostEvent GUI funtions...
133 self._doc_text = None
132 self._doc_text = None
134 self._help_text = None
133 self._help_text = None
135 self._add_button = None
134 self._add_button = None
136
135
137 def initIpython0(self, argv=[], user_ns={}, user_global_ns=None,
136 def init_ipython0(self, argv=[], user_ns={}, user_global_ns=None,
138 cin=None, cout=None, cerr=None,
137 cin=None, cout=None, cerr=None,
139 ask_exit_handler=None):
138 ask_exit_handler=None):
140 ''' Initialize an ithon0 instance '''
139 ''' Initialize an ipython0 instance '''
141
140
142 #first we redefine in/out/error functions of IPython
141 #first we redefine in/out/error functions of IPython
142 #BUG: we've got a limitation form ipython0 there
143 #only one instance can be instanciated else tehre will be
144 #cin/cout/cerr clash...
143 if cin:
145 if cin:
144 IPython.Shell.Term.cin = cin
146 IPython.genutils.Term.cin = cin
145 if cout:
147 if cout:
146 IPython.Shell.Term.cout = cout
148 IPython.genutils.Term.cout = cout
147 if cerr:
149 if cerr:
148 IPython.Shell.Term.cerr = cerr
150 IPython.genutils.Term.cerr = cerr
149
151
150 # This is to get rid of the blockage that accurs during
151 # IPython.Shell.InteractiveShell.user_setup()
152 IPython.iplib.raw_input = lambda x: None
153
154 self._term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
155
156 excepthook = sys.excepthook
152 excepthook = sys.excepthook
153
157 #Hack to save sys.displayhook, because ipython seems to overwrite it...
154 #Hack to save sys.displayhook, because ipython seems to overwrite it...
158 self.sys_displayhook_ori = sys.displayhook
155 self.sys_displayhook_ori = sys.displayhook
159
156
@@ -163,7 +160,8 b' class NonBlockingIPShell(object):'
163 embedded=True,
160 embedded=True,
164 shell_class=IPython.Shell.InteractiveShell)
161 shell_class=IPython.Shell.InteractiveShell)
165
162
166 #we restore sys.displayhook
163 #we save ipython0 displayhook and we restore sys.displayhook
164 self.displayhook = sys.displayhook
167 sys.displayhook = self.sys_displayhook_ori
165 sys.displayhook = self.sys_displayhook_ori
168
166
169 #we replace IPython default encoding by wx locale encoding
167 #we replace IPython default encoding by wx locale encoding
@@ -173,11 +171,12 b' class NonBlockingIPShell(object):'
173 #we replace the ipython default pager by our pager
171 #we replace the ipython default pager by our pager
174 self._IP.set_hook('show_in_pager', self._pager)
172 self._IP.set_hook('show_in_pager', self._pager)
175
173
176 #we replace the ipython default shell command caller by our shell handler
174 #we replace the ipython default shell command caller
175 #by our shell handler
177 self._IP.set_hook('shell_hook', self._shell)
176 self._IP.set_hook('shell_hook', self._shell)
178
177
179 #we replace the ipython default input command caller by our method
178 #we replace the ipython default input command caller by our method
180 IPython.iplib.raw_input_original = self._raw_input
179 IPython.iplib.raw_input_original = self._raw_input_original
181 #we replace the ipython default exit command by our method
180 #we replace the ipython default exit command by our method
182 self._IP.exit = ask_exit_handler
181 self._IP.exit = ask_exit_handler
183 #we replace the help command
182 #we replace the help command
@@ -186,26 +185,68 b' class NonBlockingIPShell(object):'
186 #we disable cpase magic... until we found a way to use it properly.
185 #we disable cpase magic... until we found a way to use it properly.
187 #import IPython.ipapi
186 #import IPython.ipapi
188 ip = IPython.ipapi.get()
187 ip = IPython.ipapi.get()
189 def bypassMagic(self, arg):
188 def bypass_magic(self, arg):
190 print '%this magic is currently disabled.'
189 print '%this magic is currently disabled.'
191 ip.expose_magic('cpaste', bypassMagic)
190 ip.expose_magic('cpaste', bypass_magic)
191
192 import __builtin__
193 __builtin__.raw_input = self._raw_input
192
194
193 sys.excepthook = excepthook
195 sys.excepthook = excepthook
194
196
195 #----------------------- Thread management section ----------------------
197 #----------------------- Thread management section ----------------------
196 def doExecute(self, line):
198 def do_execute(self, line):
197 """
199 """
198 Tell the thread to process the 'line' command
200 Tell the thread to process the 'line' command
199 """
201 """
200
202
201 self._line_to_execute = line
203 self._line_to_execute = line
202 #we launch the ipython line execution in a thread to make it interruptible
204
203 #with include it in self namespace to be able to call ce.raise_exc(KeyboardInterrupt)
205 if self._threading:
204 self.ce = _CodeExecutor(self, self._afterExecute)
206 #we launch the ipython line execution in a thread to make it
205 self.ce.start()
207 #interruptible with include it in self namespace to be able
206
208 #to call ce.raise_exc(KeyboardInterrupt)
207 #----------------------- IPython management section ----------------------
209 self.ce = _CodeExecutor(self)
208 def getDocText(self):
210 self.ce.start()
211 else:
212 try:
213 self._doc_text = None
214 self._help_text = None
215 self._execute()
216 # used for uper class to generate event after execution
217 self._after_execute()
218
219 except KeyboardInterrupt:
220 pass
221
222 #----------------------- IPython management section ----------------------
223 def get_threading(self):
224 """
225 Returns threading status, is set to True, then each command sent to
226 the interpreter will be executed in a separated thread allowing,
227 for example, breaking a long running commands.
228 Disallowing it, permits better compatibilty with instance that is embedding
229 IPython instance.
230
231 @return: Execution method
232 @rtype: bool
233 """
234 return self._threading
235
236 def set_threading(self, state):
237 """
238 Sets threading state, if set to True, then each command sent to
239 the interpreter will be executed in a separated thread allowing,
240 for example, breaking a long running commands.
241 Disallowing it, permits better compatibilty with instance that is embedding
242 IPython instance.
243
244 @param state: Sets threading state
245 @type bool
246 """
247 self._threading = state
248
249 def get_doc_text(self):
209 """
250 """
210 Returns the output of the processing that need to be paged (if any)
251 Returns the output of the processing that need to be paged (if any)
211
252
@@ -214,7 +255,7 b' class NonBlockingIPShell(object):'
214 """
255 """
215 return self._doc_text
256 return self._doc_text
216
257
217 def getHelpText(self):
258 def get_help_text(self):
218 """
259 """
219 Returns the output of the processing that need to be paged via help pager(if any)
260 Returns the output of the processing that need to be paged via help pager(if any)
220
261
@@ -223,7 +264,7 b' class NonBlockingIPShell(object):'
223 """
264 """
224 return self._help_text
265 return self._help_text
225
266
226 def getBanner(self):
267 def get_banner(self):
227 """
268 """
228 Returns the IPython banner for useful info on IPython instance
269 Returns the IPython banner for useful info on IPython instance
229
270
@@ -232,7 +273,7 b' class NonBlockingIPShell(object):'
232 """
273 """
233 return self._IP.BANNER
274 return self._IP.BANNER
234
275
235 def getPromptCount(self):
276 def get_prompt_count(self):
236 """
277 """
237 Returns the prompt number.
278 Returns the prompt number.
238 Each time a user execute a line in the IPython shell the prompt count is increased
279 Each time a user execute a line in the IPython shell the prompt count is increased
@@ -242,7 +283,7 b' class NonBlockingIPShell(object):'
242 """
283 """
243 return self._IP.outputcache.prompt_count
284 return self._IP.outputcache.prompt_count
244
285
245 def getPrompt(self):
286 def get_prompt(self):
246 """
287 """
247 Returns current prompt inside IPython instance
288 Returns current prompt inside IPython instance
248 (Can be In [...]: ot ...:)
289 (Can be In [...]: ot ...:)
@@ -252,7 +293,7 b' class NonBlockingIPShell(object):'
252 """
293 """
253 return self._prompt
294 return self._prompt
254
295
255 def getIndentation(self):
296 def get_indentation(self):
256 """
297 """
257 Returns the current indentation level
298 Returns the current indentation level
258 Usefull to put the caret at the good start position if we want to do autoindentation.
299 Usefull to put the caret at the good start position if we want to do autoindentation.
@@ -262,7 +303,7 b' class NonBlockingIPShell(object):'
262 """
303 """
263 return self._IP.indent_current_nsp
304 return self._IP.indent_current_nsp
264
305
265 def updateNamespace(self, ns_dict):
306 def update_namespace(self, ns_dict):
266 '''
307 '''
267 Add the current dictionary to the shell namespace.
308 Add the current dictionary to the shell namespace.
268
309
@@ -286,7 +327,7 b' class NonBlockingIPShell(object):'
286 possibilities = self._IP.complete(split_line[-1])
327 possibilities = self._IP.complete(split_line[-1])
287 if possibilities:
328 if possibilities:
288
329
289 def _commonPrefix(str1, str2):
330 def _common_prefix(str1, str2):
290 '''
331 '''
291 Reduction function. returns common prefix of two given strings.
332 Reduction function. returns common prefix of two given strings.
292
333
@@ -302,13 +343,13 b' class NonBlockingIPShell(object):'
302 if not str2.startswith(str1[:i+1]):
343 if not str2.startswith(str1[:i+1]):
303 return str1[:i]
344 return str1[:i]
304 return str1
345 return str1
305 common_prefix = reduce(_commonPrefix, possibilities)
346 common_prefix = reduce(_common_prefix, possibilities)
306 completed = line[:-len(split_line[-1])]+common_prefix
347 completed = line[:-len(split_line[-1])]+common_prefix
307 else:
348 else:
308 completed = line
349 completed = line
309 return completed, possibilities
350 return completed, possibilities
310
351
311 def historyBack(self):
352 def history_back(self):
312 '''
353 '''
313 Provides one history command back.
354 Provides one history command back.
314
355
@@ -320,10 +361,10 b' class NonBlockingIPShell(object):'
320 while((history == '' or history == '\n') and self._history_level >0):
361 while((history == '' or history == '\n') and self._history_level >0):
321 if self._history_level >= 1:
362 if self._history_level >= 1:
322 self._history_level -= 1
363 self._history_level -= 1
323 history = self._getHistory()
364 history = self._get_history()
324 return history
365 return history
325
366
326 def historyForward(self):
367 def history_forward(self):
327 '''
368 '''
328 Provides one history command forward.
369 Provides one history command forward.
329
370
@@ -333,38 +374,38 b' class NonBlockingIPShell(object):'
333 history = ''
374 history = ''
334 #the below while loop is used to suppress empty history lines
375 #the below while loop is used to suppress empty history lines
335 while((history == '' or history == '\n') \
376 while((history == '' or history == '\n') \
336 and self._history_level <= self._getHistoryMaxIndex()):
377 and self._history_level <= self._get_history_max_index()):
337 if self._history_level < self._getHistoryMaxIndex():
378 if self._history_level < self._get_history_max_index():
338 self._history_level += 1
379 self._history_level += 1
339 history = self._getHistory()
380 history = self._get_history()
340 else:
381 else:
341 if self._history_level == self._getHistoryMaxIndex():
382 if self._history_level == self._get_history_max_index():
342 history = self._getHistory()
383 history = self._get_history()
343 self._history_level += 1
384 self._history_level += 1
344 else:
385 else:
345 history = ''
386 history = ''
346 return history
387 return history
347
388
348 def initHistoryIndex(self):
389 def init_history_index(self):
349 '''
390 '''
350 set history to last command entered
391 set history to last command entered
351 '''
392 '''
352 self._history_level = self._getHistoryMaxIndex()+1
393 self._history_level = self._get_history_max_index()+1
353
394
354 #----------------------- IPython PRIVATE management section --------------
395 #----------------------- IPython PRIVATE management section --------------
355 def _afterExecute(self):
396 def _after_execute(self):
356 '''
397 '''
357 Can be redefined to generate post event after excution is done
398 Can be redefined to generate post event after excution is done
358 '''
399 '''
359 pass
400 pass
360
401
361 #def _askExit(self):
402 def _ask_exit(self):
362 # '''
403 '''
363 # Can be redefined to generate post event to exit the Ipython shell
404 Can be redefined to generate post event to exit the Ipython shell
364 # '''
405 '''
365 # pass
406 pass
366
407
367 def _getHistoryMaxIndex(self):
408 def _get_history_max_index(self):
368 '''
409 '''
369 returns the max length of the history buffer
410 returns the max length of the history buffer
370
411
@@ -373,7 +414,7 b' class NonBlockingIPShell(object):'
373 '''
414 '''
374 return len(self._IP.input_hist_raw)-1
415 return len(self._IP.input_hist_raw)-1
375
416
376 def _getHistory(self):
417 def _get_history(self):
377 '''
418 '''
378 Get's the command string of the current history level.
419 Get's the command string of the current history level.
379
420
@@ -388,7 +429,7 b' class NonBlockingIPShell(object):'
388 This function is used as a callback replacment to IPython help pager function
429 This function is used as a callback replacment to IPython help pager function
389
430
390 It puts the 'text' value inside the self._help_text string that can be retrived via
431 It puts the 'text' value inside the self._help_text string that can be retrived via
391 getHelpText function.
432 get_help_text function.
392 '''
433 '''
393 if self._help_text == None:
434 if self._help_text == None:
394 self._help_text = text
435 self._help_text = text
@@ -400,11 +441,11 b' class NonBlockingIPShell(object):'
400 This function is used as a callback replacment to IPython pager function
441 This function is used as a callback replacment to IPython pager function
401
442
402 It puts the 'text' value inside the self._doc_text string that can be retrived via
443 It puts the 'text' value inside the self._doc_text string that can be retrived via
403 getDocText function.
444 get_doc_text function.
404 '''
445 '''
405 self._doc_text = text
446 self._doc_text = text
406
447
407 def _raw_input(self, prompt=''):
448 def _raw_input_original(self, prompt=''):
408 '''
449 '''
409 Custom raw_input() replacement. Get's current line from console buffer.
450 Custom raw_input() replacement. Get's current line from console buffer.
410
451
@@ -416,13 +457,21 b' class NonBlockingIPShell(object):'
416 '''
457 '''
417 return self._line_to_execute
458 return self._line_to_execute
418
459
460 def _raw_input(self, prompt=''):
461 """ A replacement from python's raw_input.
462 """
463 raise NotImplementedError
464
419 def _execute(self):
465 def _execute(self):
420 '''
466 '''
421 Executes the current line provided by the shell object.
467 Executes the current line provided by the shell object.
422 '''
468 '''
469
423 orig_stdout = sys.stdout
470 orig_stdout = sys.stdout
424 sys.stdout = IPython.Shell.Term.cout
471 sys.stdout = IPython.Shell.Term.cout
425
472 #self.sys_displayhook_ori = sys.displayhook
473 #sys.displayhook = self.displayhook
474
426 try:
475 try:
427 line = self._IP.raw_input(None, self._iter_more)
476 line = self._IP.raw_input(None, self._iter_more)
428 if self._IP.autoindent:
477 if self._IP.autoindent:
@@ -440,8 +489,10 b' class NonBlockingIPShell(object):'
440 except:
489 except:
441 self._IP.showtraceback()
490 self._IP.showtraceback()
442 else:
491 else:
492 self._IP.write(str(self._IP.outputcache.prompt_out).strip())
443 self._iter_more = self._IP.push(line)
493 self._iter_more = self._IP.push(line)
444 if (self._IP.SyntaxTB.last_syntax_error and self._IP.rc.autoedit_syntax):
494 if (self._IP.SyntaxTB.last_syntax_error and \
495 self._IP.rc.autoedit_syntax):
445 self._IP.edit_syntax_error()
496 self._IP.edit_syntax_error()
446 if self._iter_more:
497 if self._iter_more:
447 self._prompt = str(self._IP.outputcache.prompt2).strip()
498 self._prompt = str(self._IP.outputcache.prompt2).strip()
@@ -450,8 +501,10 b' class NonBlockingIPShell(object):'
450 else:
501 else:
451 self._prompt = str(self._IP.outputcache.prompt1).strip()
502 self._prompt = str(self._IP.outputcache.prompt1).strip()
452 self._IP.indent_current_nsp = 0 #we set indentation to 0
503 self._IP.indent_current_nsp = 0 #we set indentation to 0
504
453 sys.stdout = orig_stdout
505 sys.stdout = orig_stdout
454
506 #sys.displayhook = self.sys_displayhook_ori
507
455 def _shell(self, ip, cmd):
508 def _shell(self, ip, cmd):
456 '''
509 '''
457 Replacement method to allow shell commands without them blocking.
510 Replacement method to allow shell commands without them blocking.
@@ -462,7 +515,8 b' class NonBlockingIPShell(object):'
462 @type cmd: string
515 @type cmd: string
463 '''
516 '''
464 stdin, stdout = os.popen4(cmd)
517 stdin, stdout = os.popen4(cmd)
465 result = stdout.read().decode('cp437').encode(locale.getpreferredencoding())
518 result = stdout.read().decode('cp437').\
519 encode(locale.getpreferredencoding())
466 #we use print command because the shell command is called
520 #we use print command because the shell command is called
467 #inside IPython instance and thus is redirected to thread cout
521 #inside IPython instance and thus is redirected to thread cout
468 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
522 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
@@ -29,17 +29,21 b' class IPythonHistoryPanel(wx.Panel):'
29 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
29 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
30
30
31 self.options={'filter_empty':{'value':'True',
31 self.options={'filter_empty':{'value':'True',
32 'checkbox':self.filter_empty,'True':True,'False':False,
32 'checkbox':self.filter_empty, \
33 'setfunc':lambda x:None},
33 'True':True,'False':False,
34 'setfunc':lambda x:None},
34 'filter_doc':{'value':'True',
35 'filter_doc':{'value':'True',
35 'checkbox':self.filter_doc,'True':True,'False':False,
36 'checkbox':self.filter_doc, \
36 'setfunc':lambda x:None},
37 'True':True,'False':False,
38 'setfunc':lambda x:None},
37 'filter_cmd':{'value':'True',
39 'filter_cmd':{'value':'True',
38 'checkbox':self.filter_cmd,'True':True,'False':False,
40 'checkbox':self.filter_cmd, \
39 'setfunc':lambda x:None},
41 'True':True,'False':False,
42 'setfunc':lambda x:None},
40 'filter_magic':{'value':'True',
43 'filter_magic':{'value':'True',
41 'checkbox':self.filter_magic,'True':True,'False':False,
44 'checkbox':self.filter_magic, \
42 'setfunc':lambda x:None},
45 'True':True,'False':False,
46 'setfunc':lambda x:None},
43 }
47 }
44 self.reloadOptions(self.options)
48 self.reloadOptions(self.options)
45
49
@@ -199,51 +203,81 b' class PythonSTC(stc.StyledTextCtrl):'
199 self.SetLayoutCache(stc.STC_CACHE_PAGE)
203 self.SetLayoutCache(stc.STC_CACHE_PAGE)
200
204
201 # Setup a margin to hold fold markers
205 # Setup a margin to hold fold markers
202 #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
206 #self.SetFoldFlags(16)
207 ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
203 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
208 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
204 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
209 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
205 self.SetMarginSensitive(2, True)
210 self.SetMarginSensitive(2, True)
206 self.SetMarginWidth(2, 12)
211 self.SetMarginWidth(2, 12)
207
212
208 if self.fold_symbols == 0:
213 if self.fold_symbols == 0:
209 # Arrow pointing right for contracted folders, arrow pointing down for expanded
214 # Arrow pointing right for contracted folders,
210 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black")
215 # arrow pointing down for expanded
211 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black")
216 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
212 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black")
217 stc.STC_MARK_ARROWDOWN, "black", "black")
213 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black")
218 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
214 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
219 stc.STC_MARK_ARROW, "black", "black")
215 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
220 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
216 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
221 stc.STC_MARK_EMPTY, "black", "black")
222 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
223 stc.STC_MARK_EMPTY, "black", "black")
224 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
225 stc.STC_MARK_EMPTY, "white", "black")
226 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
227 stc.STC_MARK_EMPTY, "white", "black")
228 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
229 stc.STC_MARK_EMPTY, "white", "black")
217
230
218 elif self.fold_symbols == 1:
231 elif self.fold_symbols == 1:
219 # Plus for contracted folders, minus for expanded
232 # Plus for contracted folders, minus for expanded
220 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black")
233 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
221 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black")
234 stc.STC_MARK_MINUS, "white", "black")
222 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black")
235 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
223 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black")
236 stc.STC_MARK_PLUS, "white", "black")
224 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
237 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
225 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
238 stc.STC_MARK_EMPTY, "white", "black")
226 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
239 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
240 stc.STC_MARK_EMPTY, "white", "black")
241 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
242 stc.STC_MARK_EMPTY, "white", "black")
243 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
244 stc.STC_MARK_EMPTY, "white", "black")
245 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
246 stc.STC_MARK_EMPTY, "white", "black")
227
247
228 elif self.fold_symbols == 2:
248 elif self.fold_symbols == 2:
229 # Like a flattened tree control using circular headers and curved joins
249 # Like a flattened tree control using circular headers and curved joins
230 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
250 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
231 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
251 stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
232 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040")
252 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
233 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040")
253 stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
234 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
254 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
235 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
255 stc.STC_MARK_VLINE, "white", "#404040")
236 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040")
256 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
257 stc.STC_MARK_LCORNERCURVE, "white", "#404040")
258 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
259 stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
260 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
261 stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
262 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
263 stc.STC_MARK_TCORNERCURVE, "white", "#404040")
237
264
238 elif self.fold_symbols == 3:
265 elif self.fold_symbols == 3:
239 # Like a flattened tree control using square headers
266 # Like a flattened tree control using square headers
240 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080")
267 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
241 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080")
268 stc.STC_MARK_BOXMINUS, "white", "#808080")
242 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080")
269 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
243 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080")
270 stc.STC_MARK_BOXPLUS, "white", "#808080")
244 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
271 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
245 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
272 stc.STC_MARK_VLINE, "white", "#808080")
246 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080")
273 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
274 stc.STC_MARK_LCORNER, "white", "#808080")
275 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
276 stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
277 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
278 stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
279 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
280 stc.STC_MARK_TCORNER, "white", "#808080")
247
281
248
282
249 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
283 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
@@ -363,7 +397,7 b' class PythonSTC(stc.StyledTextCtrl):'
363 if braceAtCaret < 0:
397 if braceAtCaret < 0:
364 charAfter = self.GetCharAt(caretPos)
398 charAfter = self.GetCharAt(caretPos)
365 styleAfter = self.GetStyleAt(caretPos)
399 styleAfter = self.GetStyleAt(caretPos)
366
400
367 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
401 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
368 braceAtCaret = caretPos
402 braceAtCaret = caretPos
369
403
This diff has been collapsed as it changes many lines, (1829 lines changed) Show them Hide them
@@ -1,885 +1,944 b''
1 #!/usr/bin/python
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
2 # -*- coding: iso-8859-15 -*-
3 '''
3 '''
4 Provides IPython WX console widgets.
4 Provides IPython WX console widgets.
5
5
6 @author: Laurent Dufrechou
6 @author: Laurent Dufrechou
7 laurent.dufrechou _at_ gmail.com
7 laurent.dufrechou _at_ gmail.com
8 This WX widget is based on the original work of Eitan Isaacson
8 This WX widget is based on the original work of Eitan Isaacson
9 that provided the console for the GTK toolkit.
9 that provided the console for the GTK toolkit.
10
10
11 Original work from:
11 Original work from:
12 @author: Eitan Isaacson
12 @author: Eitan Isaacson
13 @organization: IBM Corporation
13 @organization: IBM Corporation
14 @copyright: Copyright (c) 2007 IBM Corporation
14 @copyright: Copyright (c) 2007 IBM Corporation
15 @license: BSD
15 @license: BSD
16
16
17 All rights reserved. This program and the accompanying materials are made
17 All rights reserved. This program and the accompanying materials are made
18 available under the terms of the BSD which accompanies this distribution, and
18 available under the terms of the BSD which accompanies this distribution, and
19 is available at U{http://www.opensource.org/licenses/bsd-license.php}
19 is available at U{http://www.opensource.org/licenses/bsd-license.php}
20 '''
20 '''
21
21
22 __version__ = 0.8
22 __version__ = 0.9
23 __author__ = "Laurent Dufrechou"
23 __author__ = "Laurent Dufrechou"
24 __email__ = "laurent.dufrechou _at_ gmail.com"
24 __email__ = "laurent.dufrechou _at_ gmail.com"
25 __license__ = "BSD"
25 __license__ = "BSD"
26
26
27 import wx
27 import wx
28 import wx.stc as stc
28 import wx.stc as stc
29
29
30 import re
30 import re
31 from StringIO import StringIO
31 from StringIO import StringIO
32
32
33 import sys
33 import sys
34 import codecs
34 import codecs
35 import locale
35 import locale
36 for enc in (locale.getpreferredencoding(),
36 import time
37 sys.getfilesystemencoding(),
37
38 sys.getdefaultencoding()):
38 for enc in (locale.getpreferredencoding(),
39 try:
39 sys.getfilesystemencoding(),
40 codecs.lookup(enc)
40 sys.getdefaultencoding()):
41 ENCODING = enc
41 try:
42 break
42 codecs.lookup(enc)
43 except LookupError:
43 ENCODING = enc
44 pass
44 break
45 else:
45 except LookupError:
46 ENCODING = 'utf-8'
46 pass
47
47 else:
48 from ipshell_nonblocking import NonBlockingIPShell
48 ENCODING = 'utf-8'
49
49
50 class WxNonBlockingIPShell(NonBlockingIPShell):
50 from ipshell_nonblocking import NonBlockingIPShell
51 '''
51
52 An NonBlockingIPShell Thread that is WX dependent.
52 class WxNonBlockingIPShell(NonBlockingIPShell):
53 '''
53 '''
54 def __init__(self, parent,
54 An NonBlockingIPShell Thread that is WX dependent.
55 argv=[],user_ns={},user_global_ns=None,
55 '''
56 cin=None, cout=None, cerr=None,
56 def __init__(self, parent,
57 ask_exit_handler=None):
57 argv=[],user_ns={},user_global_ns=None,
58
58 cin=None, cout=None, cerr=None,
59 NonBlockingIPShell.__init__(self, argv, user_ns, user_global_ns,
59 ask_exit_handler=None):
60 cin, cout, cerr,
60
61 ask_exit_handler)
61 NonBlockingIPShell.__init__(self, argv, user_ns, user_global_ns,
62
62 cin, cout, cerr,
63 self.parent = parent
63 ask_exit_handler)
64
64
65 self.ask_exit_callback = ask_exit_handler
65 self.parent = parent
66 self._IP.exit = self._askExit
66
67
67 self.ask_exit_callback = ask_exit_handler
68 def addGUIShortcut(self, text, func):
68 self._IP.exit = self._ask_exit
69 wx.CallAfter(self.parent.add_button_handler,
69
70 button_info={ 'text':text,
70 def addGUIShortcut(self, text, func):
71 'func':self.parent.doExecuteLine(func)})
71 wx.CallAfter(self.parent.add_button_handler,
72
72 button_info={ 'text':text,
73 def _askExit(self):
73 'func':self.parent.doExecuteLine(func)})
74 wx.CallAfter(self.ask_exit_callback, ())
74
75
75 def _raw_input(self, prompt=''):
76 def _afterExecute(self):
76 """ A replacement from python's raw_input.
77 wx.CallAfter(self.parent.evtStateExecuteDone, ())
77 """
78
78 self.answer = None
79
79 if(self._threading == True):
80 class WxConsoleView(stc.StyledTextCtrl):
80 wx.CallAfter(self._yesNoBox, prompt)
81 '''
81 while self.answer is None:
82 Specialized styled text control view for console-like workflow.
82 time.sleep(.1)
83 We use here a scintilla frontend thus it can be reused in any GUI that
83 else:
84 supports scintilla with less work.
84 self._yesNoBox(prompt)
85
85 return self.answer
86 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
86
87 (with Black background)
87 def _yesNoBox(self, prompt):
88 @type ANSI_COLORS_BLACK: dictionary
88 """ yes/no box managed with wx.CallAfter jsut in case caler is executed in a thread"""
89
89 dlg = wx.TextEntryDialog(
90 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
90 self.parent, prompt,
91 (with White background)
91 'Input requested', 'Python')
92 @type ANSI_COLORS_WHITE: dictionary
92 dlg.SetValue("")
93
93
94 @ivar color_pat: Regex of terminal color pattern
94 answer = ''
95 @type color_pat: _sre.SRE_Pattern
95 if dlg.ShowModal() == wx.ID_OK:
96 '''
96 answer = dlg.GetValue()
97 ANSI_STYLES_BLACK = {'0;30': [0, 'WHITE'], '0;31': [1, 'RED'],
97
98 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
98 dlg.Destroy()
99 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
99 self.answer = answer
100 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
100
101 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
101 def _ask_exit(self):
102 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
102 wx.CallAfter(self.ask_exit_callback, ())
103 '1;34': [12, 'LIGHT BLUE'], '1;35':
103
104 [13, 'MEDIUM VIOLET RED'],
104 def _after_execute(self):
105 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
105 wx.CallAfter(self.parent.evtStateExecuteDone, ())
106
106
107 ANSI_STYLES_WHITE = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
107
108 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
108 class WxConsoleView(stc.StyledTextCtrl):
109 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
109 '''
110 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
110 Specialized styled text control view for console-like workflow.
111 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
111 We use here a scintilla frontend thus it can be reused in any GUI that
112 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
112 supports scintilla with less work.
113 '1;34': [12, 'LIGHT BLUE'], '1;35':
113
114 [13, 'MEDIUM VIOLET RED'],
114 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
115 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
115 (with Black background)
116
116 @type ANSI_COLORS_BLACK: dictionary
117 def __init__(self, parent, prompt, intro="", background_color="BLACK",
117
118 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
118 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
119 style=0, autocomplete_mode = 'IPYTHON'):
119 (with White background)
120 '''
120 @type ANSI_COLORS_WHITE: dictionary
121 Initialize console view.
121
122
122 @ivar color_pat: Regex of terminal color pattern
123 @param parent: Parent widget
123 @type color_pat: _sre.SRE_Pattern
124 @param prompt: User specified prompt
124 '''
125 @type intro: string
125 ANSI_STYLES_BLACK = {'0;30': [0, 'WHITE'], '0;31': [1, 'RED'],
126 @param intro: User specified startup introduction string
126 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
127 @type intro: string
127 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
128 @param background_color: Can be BLACK or WHITE
128 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
129 @type background_color: string
129 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
130 @param other: init param of styledTextControl (can be used as-is)
130 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
131 @param autocomplete_mode: Can be 'IPYTHON' or 'STC'
131 '1;34': [12, 'LIGHT BLUE'], '1;35':
132 'IPYTHON' show autocompletion the ipython way
132 [13, 'MEDIUM VIOLET RED'],
133 'STC" show it scintilla text control way
133 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
134 '''
134
135 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
135 ANSI_STYLES_WHITE = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
136
136 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
137 ####### Scintilla configuration ###################################
137 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
138
138 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
139 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
139 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
140 # the widget
140 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
141 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
141 '1;34': [12, 'LIGHT BLUE'], '1;35':
142 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
142 [13, 'MEDIUM VIOLET RED'],
143
143 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
144 #We draw a line at position 80
144
145 self.SetEdgeMode(stc.STC_EDGE_LINE)
145 def __init__(self, parent, prompt, intro="", background_color="BLACK",
146 self.SetEdgeColumn(80)
146 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
147 self.SetEdgeColour(wx.LIGHT_GREY)
147 style=0, autocomplete_mode = 'IPYTHON'):
148
148 '''
149 #self.SetViewWhiteSpace(True)
149 Initialize console view.
150 #self.SetViewEOL(True)
150
151 self.SetEOLMode(stc.STC_EOL_CRLF)
151 @param parent: Parent widget
152 #self.SetWrapMode(stc.STC_WRAP_CHAR)
152 @param prompt: User specified prompt
153 #self.SetWrapMode(stc.STC_WRAP_WORD)
153 @type intro: string
154 self.SetBufferedDraw(True)
154 @param intro: User specified startup introduction string
155 #self.SetUseAntiAliasing(True)
155 @type intro: string
156 self.SetLayoutCache(stc.STC_CACHE_PAGE)
156 @param background_color: Can be BLACK or WHITE
157 self.SetUndoCollection(False)
157 @type background_color: string
158 self.SetUseTabs(True)
158 @param other: init param of styledTextControl (can be used as-is)
159 self.SetIndent(4)
159 @param autocomplete_mode: Can be 'IPYTHON' or 'STC'
160 self.SetTabWidth(4)
160 'IPYTHON' show autocompletion the ipython way
161
161 'STC" show it scintilla text control way
162 self.EnsureCaretVisible()
162 '''
163
163 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
164 self.SetMargins(3, 3) #text is moved away from border with 3px
164
165 # Suppressing Scintilla margins
165 ####### Scintilla configuration ###################################
166 self.SetMarginWidth(0, 0)
166
167 self.SetMarginWidth(1, 0)
167 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
168 self.SetMarginWidth(2, 0)
168 # the widget
169
169 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
170 self.background_color = background_color
170 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
171 self.buildStyles()
171
172
172 #We draw a line at position 80
173 self.indent = 0
173 self.SetEdgeMode(stc.STC_EDGE_LINE)
174 self.prompt_count = 0
174 self.SetEdgeColumn(80)
175 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
175 self.SetEdgeColour(wx.LIGHT_GREY)
176
176
177 self.write(intro)
177 #self.SetViewWhiteSpace(True)
178 self.setPrompt(prompt)
178 #self.SetViewEOL(True)
179 self.showPrompt()
179 self.SetEOLMode(stc.STC_EOL_CRLF)
180
180 #self.SetWrapMode(stc.STC_WRAP_CHAR)
181 self.autocomplete_mode = autocomplete_mode
181 #self.SetWrapMode(stc.STC_WRAP_WORD)
182
182 self.SetBufferedDraw(True)
183 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress)
183 #self.SetUseAntiAliasing(True)
184
184 self.SetLayoutCache(stc.STC_CACHE_PAGE)
185 def buildStyles(self):
185 self.SetUndoCollection(False)
186 #we define platform specific fonts
186 self.SetUseTabs(True)
187 if wx.Platform == '__WXMSW__':
187 self.SetIndent(4)
188 faces = { 'times': 'Times New Roman',
188 self.SetTabWidth(4)
189 'mono' : 'Courier New',
189
190 'helv' : 'Arial',
190 self.EnsureCaretVisible()
191 'other': 'Comic Sans MS',
191
192 'size' : 10,
192 self.SetMargins(3, 3) #text is moved away from border with 3px
193 'size2': 8,
193 # Suppressing Scintilla margins
194 }
194 self.SetMarginWidth(0, 0)
195 elif wx.Platform == '__WXMAC__':
195 self.SetMarginWidth(1, 0)
196 faces = { 'times': 'Times New Roman',
196 self.SetMarginWidth(2, 0)
197 'mono' : 'Monaco',
197
198 'helv' : 'Arial',
198 self.background_color = background_color
199 'other': 'Comic Sans MS',
199 self.buildStyles()
200 'size' : 10,
200
201 'size2': 8,
201 self.indent = 0
202 }
202 self.prompt_count = 0
203 else:
203 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
204 faces = { 'times': 'Times',
204
205 'mono' : 'Courier',
205 self.write(intro)
206 'helv' : 'Helvetica',
206 self.setPrompt(prompt)
207 'other': 'new century schoolbook',
207 self.showPrompt()
208 'size' : 10,
208
209 'size2': 8,
209 self.autocomplete_mode = autocomplete_mode
210 }
210
211
211 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress)
212 # make some styles
212
213 if self.background_color != "BLACK":
213 def buildStyles(self):
214 self.background_color = "WHITE"
214 #we define platform specific fonts
215 self.SetCaretForeground("BLACK")
215 if wx.Platform == '__WXMSW__':
216 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
216 faces = { 'times': 'Times New Roman',
217 else:
217 'mono' : 'Courier New',
218 self.SetCaretForeground("WHITE")
218 'helv' : 'Arial',
219 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
219 'other': 'Comic Sans MS',
220
220 'size' : 10,
221 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
221 'size2': 8,
222 "fore:%s,back:%s,size:%d,face:%s"
222 }
223 % (self.ANSI_STYLES['0;30'][1],
223 elif wx.Platform == '__WXMAC__':
224 self.background_color,
224 faces = { 'times': 'Times New Roman',
225 faces['size'], faces['mono']))
225 'mono' : 'Monaco',
226 self.StyleClearAll()
226 'helv' : 'Arial',
227 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
227 'other': 'Comic Sans MS',
228 "fore:#FF0000,back:#0000FF,bold")
228 'size' : 10,
229 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
229 'size2': 8,
230 "fore:#000000,back:#FF0000,bold")
230 }
231
231 else:
232 for style in self.ANSI_STYLES.values():
232 faces = { 'times': 'Times',
233 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
233 'mono' : 'Courier',
234
234 'helv' : 'Helvetica',
235 #######################################################################
235 'other': 'new century schoolbook',
236
236 'size' : 10,
237 def setBackgroundColor(self, color):
237 'size2': 8,
238 self.background_color = color
238 }
239 self.buildStyles()
239
240
240 # make some styles
241 def getBackgroundColor(self, color):
241 if self.background_color != "BLACK":
242 return self.background_color
242 self.background_color = "WHITE"
243
243 self.SetCaretForeground("BLACK")
244 def asyncWrite(self, text):
244 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
245 '''
245 else:
246 Write given text to buffer in an asynchroneous way.
246 self.SetCaretForeground("WHITE")
247 It is used from another thread to be able to acces the GUI.
247 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
248 @param text: Text to append
248
249 @type text: string
249 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
250 '''
250 "fore:%s,back:%s,size:%d,face:%s"
251 try:
251 % (self.ANSI_STYLES['0;30'][1],
252 #print >>sys.__stdout__,'entering'
252 self.background_color,
253 wx.MutexGuiEnter()
253 faces['size'], faces['mono']))
254 #print >>sys.__stdout__,'locking the GUI'
254 self.StyleClearAll()
255
255 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
256 #be sure not to be interrutpted before the MutexGuiLeave!
256 "fore:#FF0000,back:#0000FF,bold")
257 self.write(text)
257 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
258
258 "fore:#000000,back:#FF0000,bold")
259 #print >>sys.__stdout__,'done'
259
260
260 for style in self.ANSI_STYLES.values():
261 except KeyboardInterrupt:
261 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
262 #print >>sys.__stdout__,'got keyboard interrupt'
262
263 wx.MutexGuiLeave()
263 #######################################################################
264 #print >>sys.__stdout__,'interrupt unlock the GUI'
264
265 raise KeyboardInterrupt
265 def setBackgroundColor(self, color):
266 wx.MutexGuiLeave()
266 self.background_color = color
267 #print >>sys.__stdout__,'normal unlock the GUI'
267 self.buildStyles()
268
268
269
269 def getBackgroundColor(self, color):
270 def write(self, text):
270 return self.background_color
271 '''
271
272 Write given text to buffer.
272 def asyncWrite(self, text):
273
273 '''
274 @param text: Text to append.
274 Write given text to buffer in an asynchroneous way.
275 @type text: string
275 It is used from another thread to be able to acces the GUI.
276 '''
276 @param text: Text to append
277 segments = self.color_pat.split(text)
277 @type text: string
278 segment = segments.pop(0)
278 '''
279 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
279 try:
280 self.AppendText(segment)
280 wx.MutexGuiEnter()
281
281
282 if segments:
282 #be sure not to be interrutpted before the MutexGuiLeave!
283 ansi_tags = self.color_pat.findall(text)
283 self.write(text)
284
284
285 for tag in ansi_tags:
285 except KeyboardInterrupt:
286 i = segments.index(tag)
286 wx.MutexGuiLeave()
287 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
287 raise KeyboardInterrupt
288 self.AppendText(segments[i+1])
288 wx.MutexGuiLeave()
289
289
290 if tag != '0':
290
291 self.SetStyling(len(segments[i+1]), self.ANSI_STYLES[tag][0])
291 def write(self, text):
292
292 '''
293 segments.pop(i)
293 Write given text to buffer.
294
294
295 self.moveCursor(self.getCurrentLineEnd())
295 @param text: Text to append.
296
296 @type text: string
297 def getPromptLen(self):
297 '''
298 '''
298 segments = self.color_pat.split(text)
299 Return the length of current prompt
299 segment = segments.pop(0)
300 '''
300 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
301 return len(str(self.prompt_count)) + 7
301 self.AppendText(segment)
302
302
303 def setPrompt(self, prompt):
303 if segments:
304 self.prompt = prompt
304 ansi_tags = self.color_pat.findall(text)
305
305
306 def setIndentation(self, indentation):
306 for tag in ansi_tags:
307 self.indent = indentation
307 i = segments.index(tag)
308
308 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
309 def setPromptCount(self, count):
309 self.AppendText(segments[i+1])
310 self.prompt_count = count
310
311
311 if tag != '0':
312 def showPrompt(self):
312 self.SetStyling(len(segments[i+1]), self.ANSI_STYLES[tag][0])
313 '''
313
314 Prints prompt at start of line.
314 segments.pop(i)
315
315
316 @param prompt: Prompt to print.
316 self.moveCursor(self.getCurrentLineEnd())
317 @type prompt: string
317
318 '''
318 def getPromptLen(self):
319 self.write(self.prompt)
319 '''
320 #now we update the position of end of prompt
320 Return the length of current prompt
321 self.current_start = self.getCurrentLineEnd()
321 '''
322
322 return len(str(self.prompt_count)) + 7
323 autoindent = self.indent*' '
323
324 autoindent = autoindent.replace(' ','\t')
324 def setPrompt(self, prompt):
325 self.write(autoindent)
325 self.prompt = prompt
326
326
327 def changeLine(self, text):
327 def setIndentation(self, indentation):
328 '''
328 self.indent = indentation
329 Replace currently entered command line with given text.
329
330
330 def setPromptCount(self, count):
331 @param text: Text to use as replacement.
331 self.prompt_count = count
332 @type text: string
332
333 '''
333 def showPrompt(self):
334 self.SetSelection(self.getCurrentPromptStart(), self.getCurrentLineEnd())
334 '''
335 self.ReplaceSelection(text)
335 Prints prompt at start of line.
336 self.moveCursor(self.getCurrentLineEnd())
336
337
337 @param prompt: Prompt to print.
338 def getCurrentPromptStart(self):
338 @type prompt: string
339 return self.current_start
339 '''
340
340 self.write(self.prompt)
341 def getCurrentLineStart(self):
341 #now we update the position of end of prompt
342 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
342 self.current_start = self.getCurrentLineEnd()
343
343
344 def getCurrentLineEnd(self):
344 autoindent = self.indent*' '
345 return self.GetLength()
345 autoindent = autoindent.replace(' ','\t')
346
346 self.write(autoindent)
347 def getCurrentLine(self):
347
348 '''
348 def changeLine(self, text):
349 Get text in current command line.
349 '''
350
350 Replace currently entered command line with given text.
351 @return: Text of current command line.
351
352 @rtype: string
352 @param text: Text to use as replacement.
353 '''
353 @type text: string
354 return self.GetTextRange(self.getCurrentPromptStart(),
354 '''
355 self.getCurrentLineEnd())
355 self.SetSelection(self.getCurrentPromptStart(), self.getCurrentLineEnd())
356
356 self.ReplaceSelection(text)
357 def moveCursorOnNewValidKey(self):
357 self.moveCursor(self.getCurrentLineEnd())
358 #If cursor is at wrong position put it at last line...
358
359 if self.GetCurrentPos() < self.getCurrentPromptStart():
359 def getCurrentPromptStart(self):
360 self.GotoPos(self.getCurrentPromptStart())
360 return self.current_start
361
361
362 def removeFromTo(self, from_pos, to_pos):
362 def getCurrentLineStart(self):
363 if from_pos < to_pos:
363 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
364 self.SetSelection(from_pos, to_pos)
364
365 self.DeleteBack()
365 def getCurrentLineEnd(self):
366
366 return self.GetLength()
367 def removeCurrentLine(self):
367
368 self.LineDelete()
368 def getCurrentLine(self):
369
369 '''
370 def moveCursor(self, position):
370 Get text in current command line.
371 self.GotoPos(position)
371
372
372 @return: Text of current command line.
373 def getCursorPos(self):
373 @rtype: string
374 return self.GetCurrentPos()
374 '''
375
375 return self.GetTextRange(self.getCurrentPromptStart(),
376 def selectFromTo(self, from_pos, to_pos):
376 self.getCurrentLineEnd())
377 self.SetSelectionStart(from_pos)
377
378 self.SetSelectionEnd(to_pos)
378 def moveCursorOnNewValidKey(self):
379
379 #If cursor is at wrong position put it at last line...
380 def writeHistory(self, history):
380 if self.GetCurrentPos() < self.getCurrentPromptStart():
381 self.removeFromTo(self.getCurrentPromptStart(), self.getCurrentLineEnd())
381 self.GotoPos(self.getCurrentPromptStart())
382 self.changeLine(history)
382
383
383 def removeFromTo(self, from_pos, to_pos):
384 def setCompletionMethod(self, completion):
384 if from_pos < to_pos:
385 if completion in ['IPYTHON', 'STC']:
385 self.SetSelection(from_pos, to_pos)
386 self.autocomplete_mode = completion
386 self.DeleteBack()
387 else:
387
388 raise AttributeError
388 def removeCurrentLine(self):
389
389 self.LineDelete()
390 def getCompletionMethod(self, completion):
390
391 return self.autocomplete_mode
391 def moveCursor(self, position):
392
392 self.GotoPos(position)
393 def writeCompletion(self, possibilities):
393
394 if self.autocomplete_mode == 'IPYTHON':
394 def getCursorPos(self):
395 max_len = len(max(possibilities, key=len))
395 return self.GetCurrentPos()
396 max_symbol = ' '*max_len
396
397
397 def selectFromTo(self, from_pos, to_pos):
398 #now we check how much symbol we can put on a line...
398 self.SetSelectionStart(from_pos)
399 test_buffer = max_symbol + ' '*4
399 self.SetSelectionEnd(to_pos)
400
400
401 allowed_symbols = 80/len(test_buffer)
401 def writeHistory(self, history):
402 if allowed_symbols == 0:
402 self.removeFromTo(self.getCurrentPromptStart(), self.getCurrentLineEnd())
403 allowed_symbols = 1
403 self.changeLine(history)
404
404
405 pos = 1
405 def setCompletionMethod(self, completion):
406 buf = ''
406 if completion in ['IPYTHON', 'STC']:
407 for symbol in possibilities:
407 self.autocomplete_mode = completion
408 #buf += symbol+'\n'#*spaces)
408 else:
409 if pos < allowed_symbols:
409 raise AttributeError
410 spaces = max_len - len(symbol) + 4
410
411 buf += symbol+' '*spaces
411 def getCompletionMethod(self, completion):
412 pos += 1
412 return self.autocomplete_mode
413 else:
413
414 buf += symbol+'\n'
414 def writeCompletion(self, possibilities):
415 pos = 1
415 if self.autocomplete_mode == 'IPYTHON':
416 self.write(buf)
416 max_len = len(max(possibilities, key=len))
417 else:
417 max_symbol = ' '*max_len
418 possibilities.sort() # Python sorts are case sensitive
418
419 self.AutoCompSetIgnoreCase(False)
419 #now we check how much symbol we can put on a line...
420 self.AutoCompSetAutoHide(False)
420 test_buffer = max_symbol + ' '*4
421 #let compute the length ot last word
421
422 splitter = [' ', '(', '[', '{']
422 allowed_symbols = 80/len(test_buffer)
423 last_word = self.getCurrentLine()
423 if allowed_symbols == 0:
424 for breaker in splitter:
424 allowed_symbols = 1
425 last_word = last_word.split(breaker)[-1]
425
426 self.AutoCompShow(len(last_word), " ".join(possibilities))
426 pos = 1
427
427 buf = ''
428 def _onKeypress(self, event, skip=True):
428 for symbol in possibilities:
429 '''
429 #buf += symbol+'\n'#*spaces)
430 Key press callback used for correcting behavior for console-like
430 if pos < allowed_symbols:
431 interfaces. For example 'home' should go to prompt, not to begining of
431 spaces = max_len - len(symbol) + 4
432 line.
432 buf += symbol+' '*spaces
433
433 pos += 1
434 @param widget: Widget that key press accored in.
434 else:
435 @type widget: gtk.Widget
435 buf += symbol+'\n'
436 @param event: Event object
436 pos = 1
437 @type event: gtk.gdk.Event
437 self.write(buf)
438
438 else:
439 @return: Return True if event as been catched.
439 possibilities.sort() # Python sorts are case sensitive
440 @rtype: boolean
440 self.AutoCompSetIgnoreCase(False)
441 '''
441 self.AutoCompSetAutoHide(False)
442
442 #let compute the length ot last word
443 if not self.AutoCompActive():
443 splitter = [' ', '(', '[', '{','=']
444 if event.GetKeyCode() == wx.WXK_HOME:
444 last_word = self.getCurrentLine()
445 if event.Modifiers == wx.MOD_NONE:
445 for breaker in splitter:
446 self.moveCursorOnNewValidKey()
446 last_word = last_word.split(breaker)[-1]
447 self.moveCursor(self.getCurrentPromptStart())
447 self.AutoCompShow(len(last_word), " ".join(possibilities))
448 return True
448
449 elif event.Modifiers == wx.MOD_SHIFT:
449 def _onKeypress(self, event, skip=True):
450 self.moveCursorOnNewValidKey()
450 '''
451 self.selectFromTo(self.getCurrentPromptStart(), self.getCursorPos())
451 Key press callback used for correcting behavior for console-like
452 return True
452 interfaces. For example 'home' should go to prompt, not to begining of
453 else:
453 line.
454 return False
454
455
455 @param widget: Widget that key press accored in.
456 elif event.GetKeyCode() == wx.WXK_LEFT:
456 @type widget: gtk.Widget
457 if event.Modifiers == wx.MOD_NONE:
457 @param event: Event object
458 self.moveCursorOnNewValidKey()
458 @type event: gtk.gdk.Event
459
459
460 self.moveCursor(self.getCursorPos()-1)
460 @return: Return True if event as been catched.
461 if self.getCursorPos() < self.getCurrentPromptStart():
461 @rtype: boolean
462 self.moveCursor(self.getCurrentPromptStart())
462 '''
463 return True
463 if not self.AutoCompActive():
464
464 if event.GetKeyCode() == wx.WXK_HOME:
465 elif event.GetKeyCode() == wx.WXK_BACK:
465 if event.Modifiers == wx.MOD_NONE:
466 self.moveCursorOnNewValidKey()
466 self.moveCursorOnNewValidKey()
467 if self.getCursorPos() > self.getCurrentPromptStart():
467 self.moveCursor(self.getCurrentPromptStart())
468 event.Skip()
468 return True
469 return True
469 elif event.Modifiers == wx.MOD_SHIFT:
470
470 self.moveCursorOnNewValidKey()
471 if skip:
471 self.selectFromTo(self.getCurrentPromptStart(), self.getCursorPos())
472 if event.GetKeyCode() not in [wx.WXK_PAGEUP, wx.WXK_PAGEDOWN]\
472 return True
473 and event.Modifiers == wx.MOD_NONE:
473 else:
474 self.moveCursorOnNewValidKey()
474 return False
475
475
476 event.Skip()
476 elif event.GetKeyCode() == wx.WXK_LEFT:
477 return True
477 if event.Modifiers == wx.MOD_NONE:
478 return False
478 self.moveCursorOnNewValidKey()
479 else:
479
480 event.Skip()
480 self.moveCursor(self.getCursorPos()-1)
481
481 if self.getCursorPos() < self.getCurrentPromptStart():
482 def OnUpdateUI(self, evt):
482 self.moveCursor(self.getCurrentPromptStart())
483 # check for matching braces
483 return True
484 braceAtCaret = -1
484
485 braceOpposite = -1
485 elif event.GetKeyCode() == wx.WXK_BACK:
486 charBefore = None
486 self.moveCursorOnNewValidKey()
487 caretPos = self.GetCurrentPos()
487 if self.getCursorPos() > self.getCurrentPromptStart():
488
488 event.Skip()
489 if caretPos > 0:
489 return True
490 charBefore = self.GetCharAt(caretPos - 1)
490
491 styleBefore = self.GetStyleAt(caretPos - 1)
491 if skip:
492
492 if event.GetKeyCode() not in [wx.WXK_PAGEUP, wx.WXK_PAGEDOWN]\
493 # check before
493 and event.Modifiers == wx.MOD_NONE:
494 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
494 self.moveCursorOnNewValidKey()
495 braceAtCaret = caretPos - 1
495
496
496 event.Skip()
497 # check after
497 return True
498 if braceAtCaret < 0:
498 return False
499 charAfter = self.GetCharAt(caretPos)
499 else:
500 styleAfter = self.GetStyleAt(caretPos)
500 event.Skip()
501
501
502 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
502 def OnUpdateUI(self, evt):
503 braceAtCaret = caretPos
503 # check for matching braces
504
504 braceAtCaret = -1
505 if braceAtCaret >= 0:
505 braceOpposite = -1
506 braceOpposite = self.BraceMatch(braceAtCaret)
506 charBefore = None
507
507 caretPos = self.GetCurrentPos()
508 if braceAtCaret != -1 and braceOpposite == -1:
508
509 self.BraceBadLight(braceAtCaret)
509 if caretPos > 0:
510 else:
510 charBefore = self.GetCharAt(caretPos - 1)
511 self.BraceHighlight(braceAtCaret, braceOpposite)
511 styleBefore = self.GetStyleAt(caretPos - 1)
512 #pt = self.PointFromPosition(braceOpposite)
512
513 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
513 # check before
514 #print pt
514 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
515 #self.Refresh(False)
515 braceAtCaret = caretPos - 1
516
516
517 class IPShellWidget(wx.Panel):
517 # check after
518 '''
518 if braceAtCaret < 0:
519 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
519 charAfter = self.GetCharAt(caretPos)
520 If you want to port this to any other GUI toolkit, just replace the
520 styleAfter = self.GetStyleAt(caretPos)
521 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
521
522 from whatever container you want. I've choosed to derivate from a wx.Panel
522 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
523 because it seems to be more useful
523 braceAtCaret = caretPos
524 Any idea to make it more 'generic' welcomed.
524
525 '''
525 if braceAtCaret >= 0:
526
526 braceOpposite = self.BraceMatch(braceAtCaret)
527 def __init__(self, parent, intro=None,
527
528 background_color="BLACK", add_button_handler=None,
528 if braceAtCaret != -1 and braceOpposite == -1:
529 wx_ip_shell=None, user_ns={},user_global_ns=None,
529 self.BraceBadLight(braceAtCaret)
530 ):
530 else:
531 '''
531 self.BraceHighlight(braceAtCaret, braceOpposite)
532 Initialize.
532 #pt = self.PointFromPosition(braceOpposite)
533 Instanciate an IPython thread.
533 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
534 Instanciate a WxConsoleView.
534 #print pt
535 Redirect I/O to console.
535 #self.Refresh(False)
536 '''
536
537 wx.Panel.__init__(self,parent,wx.ID_ANY)
537 class IPShellWidget(wx.Panel):
538
538 '''
539 self.parent = parent
539 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
540 ### IPython non blocking shell instanciation ###
540 If you want to port this to any other GUI toolkit, just replace the
541 self.cout = StringIO()
541 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
542 self.add_button_handler = add_button_handler
542 from whatever container you want. I've choosed to derivate from a wx.Panel
543
543 because it seems to be more useful
544 if wx_ip_shell is not None:
544 Any idea to make it more 'generic' welcomed.
545 self.IP = wx_ip_shell
545 '''
546 else:
546
547 self.IP = WxNonBlockingIPShell(self,
547 def __init__(self, parent, intro=None,
548 cout = self.cout, cerr = self.cout,
548 background_color="BLACK", add_button_handler=None,
549 ask_exit_handler = self.askExitCallback)
549 wx_ip_shell=None, user_ns={},user_global_ns=None,
550
550 ):
551 ### IPython wx console view instanciation ###
551 '''
552 #If user didn't defined an intro text, we create one for him
552 Initialize.
553 #If you really wnat an empty intro just call wxIPythonViewPanel
553 Instanciate an IPython thread.
554 #with intro=''
554 Instanciate a WxConsoleView.
555 if intro is None:
555 Redirect I/O to console.
556 welcome_text = "Welcome to WxIPython Shell.\n\n"
556 '''
557 welcome_text+= self.IP.getBanner()
557 wx.Panel.__init__(self,parent,wx.ID_ANY)
558 welcome_text+= "!command -> Execute command in shell\n"
558
559 welcome_text+= "TAB -> Autocompletion\n"
559 self.parent = parent
560 else:
560 ### IPython non blocking shell instanciation ###
561 welcome_text = intro
561 self.cout = StringIO()
562
562 self.add_button_handler = add_button_handler
563 self.text_ctrl = WxConsoleView(self,
563
564 self.IP.getPrompt(),
564 if wx_ip_shell is not None:
565 intro=welcome_text,
565 self.IP = wx_ip_shell
566 background_color=background_color)
566 else:
567
567 self.IP = WxNonBlockingIPShell(self,
568 self.cout.write = self.text_ctrl.asyncWrite
568 cout = self.cout, cerr = self.cout,
569
569 ask_exit_handler = self.askExitCallback)
570 option_text = wx.StaticText(self, -1, "Options:")
570
571 self.completion_option = wx.CheckBox(self, -1, "Scintilla Completion")
571 ### IPython wx console view instanciation ###
572 #self.completion_option.SetValue(False)
572 #If user didn't defined an intro text, we create one for him
573 self.background_option = wx.CheckBox(self, -1, "White Background")
573 #If you really wnat an empty intro just call wxIPythonViewPanel
574 #self.background_option.SetValue(False)
574 #with intro=''
575
575 if intro is None:
576 self.options={'completion':{'value':'IPYTHON',
576 welcome_text = "Welcome to WxIPython Shell.\n\n"
577 'checkbox':self.completion_option,'STC':True,'IPYTHON':False,
577 welcome_text+= self.IP.get_banner()
578 'setfunc':self.text_ctrl.setCompletionMethod},
578 welcome_text+= "!command -> Execute command in shell\n"
579 'background_color':{'value':'BLACK',
579 welcome_text+= "TAB -> Autocompletion\n"
580 'checkbox':self.background_option,'WHITE':True,'BLACK':False,
580 else:
581 'setfunc':self.text_ctrl.setBackgroundColor},
581 welcome_text = intro
582 }
582
583 self.reloadOptions(self.options)
583 self.text_ctrl = WxConsoleView(self,
584
584 self.IP.get_prompt(),
585 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress)
585 intro=welcome_text,
586 self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion)
586 background_color=background_color)
587 self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor)
587
588
588 option_text = wx.StaticText(self, -1, "Options:")
589 ### making the layout of the panel ###
589 self.completion_option = wx.CheckBox(self, -1, "Scintilla Completion")
590 sizer = wx.BoxSizer(wx.VERTICAL)
590 self.completion_option.SetToolTip(wx.ToolTip(
591 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
591 "Selects the completion type:\nEither Ipython default style or Scintilla one"))
592 option_sizer = wx.BoxSizer(wx.HORIZONTAL)
592 #self.completion_option.SetValue(False)
593 sizer.Add(option_sizer, 0)
593 self.background_option = wx.CheckBox(self, -1, "White Background")
594 option_sizer.AddMany([(10, 20),
594 self.background_option.SetToolTip(wx.ToolTip(
595 (option_text, 0, wx.ALIGN_CENTER_VERTICAL),
595 "Selects the back ground color: BLACK or WHITE"))
596 (5, 5),
596 #self.background_option.SetValue(False)
597 (self.completion_option, 0, wx.ALIGN_CENTER_VERTICAL),
597 self.threading_option = wx.CheckBox(self, -1, "Execute in thread")
598 (8, 8),
598 self.threading_option.SetToolTip(wx.ToolTip(
599 (self.background_option, 0, wx.ALIGN_CENTER_VERTICAL)
599 "Use threading: infinite loop don't freeze the GUI and commands can be breaked\nNo threading: maximum compatibility"))
600 ])
600 #self.threading_option.SetValue(False)
601 self.SetAutoLayout(True)
601
602 sizer.Fit(self)
602 self.options={'completion':{'value':'IPYTHON',
603 sizer.SetSizeHints(self)
603 'checkbox':self.completion_option,'STC':True,'IPYTHON':False,
604 self.SetSizer(sizer)
604 'setfunc':self.text_ctrl.setCompletionMethod},
605 #and we focus on the widget :)
605 'background_color':{'value':'BLACK',
606 self.SetFocus()
606 'checkbox':self.background_option,'WHITE':True,'BLACK':False,
607
607 'setfunc':self.text_ctrl.setBackgroundColor},
608 #widget state management (for key handling different cases)
608 'threading':{'value':'True',
609 self.setCurrentState('IDLE')
609 'checkbox':self.threading_option,'True':True,'False':False,
610 self.pager_state = 'DONE'
610 'setfunc':self.IP.set_threading},
611 self.raw_input_current_line = 0
611 }
612
612
613 def askExitCallback(self, event):
613 #self.cout.write dEfault option is asynchroneous because default sate is threading ON
614 self.askExitHandler(event)
614 self.cout.write = self.text_ctrl.asyncWrite
615
615 #we reloard options
616 #---------------------- IPython Thread Management ------------------------
616 self.reloadOptions(self.options)
617 def stateDoExecuteLine(self):
617
618 lines=self.text_ctrl.getCurrentLine()
618 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress)
619 self.text_ctrl.write('\n')
619 self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion)
620 lines_to_execute = lines.replace('\t',' '*4)
620 self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor)
621 lines_to_execute = lines_to_execute.replace('\r','')
621 self.threading_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionThreading)
622 self.IP.doExecute(lines_to_execute.encode(ENCODING))
622
623 self.updateHistoryTracker(lines)
623 ### making the layout of the panel ###
624 self.setCurrentState('WAIT_END_OF_EXECUTION')
624 sizer = wx.BoxSizer(wx.VERTICAL)
625
625 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
626 def evtStateExecuteDone(self,evt):
626 option_sizer = wx.BoxSizer(wx.HORIZONTAL)
627 self.doc = self.IP.getDocText()
627 sizer.Add(option_sizer, 0)
628 self.help = self.IP.getHelpText()
628 option_sizer.AddMany([(10, 20),
629 if self.doc:
629 (option_text, 0, wx.ALIGN_CENTER_VERTICAL),
630 self.pager_lines = self.doc[7:].split('\n')
630 (5, 5),
631 self.pager_state = 'INIT'
631 (self.completion_option, 0, wx.ALIGN_CENTER_VERTICAL),
632 self.setCurrentState('SHOW_DOC')
632 (8, 8),
633 self.pager(self.doc)
633 (self.background_option, 0, wx.ALIGN_CENTER_VERTICAL),
634 elif self.help:
634 (8, 8),
635 self.pager_lines = self.help.split('\n')
635 (self.threading_option, 0, wx.ALIGN_CENTER_VERTICAL)
636 self.pager_state = 'INIT'
636 ])
637 self.setCurrentState('SHOW_DOC')
637 self.SetAutoLayout(True)
638 self.pager(self.help)
638 sizer.Fit(self)
639 else:
639 sizer.SetSizeHints(self)
640 self.stateShowPrompt()
640 self.SetSizer(sizer)
641
641 #and we focus on the widget :)
642 def stateShowPrompt(self):
642 self.SetFocus()
643 self.setCurrentState('SHOW_PROMPT')
643
644 self.text_ctrl.setPrompt(self.IP.getPrompt())
644 #widget state management (for key handling different cases)
645 self.text_ctrl.setIndentation(self.IP.getIndentation())
645 self.setCurrentState('IDLE')
646 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
646 self.pager_state = 'DONE'
647 self.text_ctrl.showPrompt()
647 self.raw_input_current_line = 0
648 self.IP.initHistoryIndex()
648
649 self.setCurrentState('IDLE')
649 def askExitCallback(self, event):
650
650 self.askExitHandler(event)
651 def setCurrentState(self, state):
651
652 self.cur_state = state
652 #---------------------- IPython Thread Management ------------------------
653 self.updateStatusTracker(self.cur_state)
653 def stateDoExecuteLine(self):
654
654 lines=self.text_ctrl.getCurrentLine()
655 def pager(self,text):
655 self.text_ctrl.write('\n')
656
656 lines_to_execute = lines.replace('\t',' '*4)
657 if self.pager_state == 'INIT':
657 lines_to_execute = lines_to_execute.replace('\r','')
658 #print >>sys.__stdout__,"PAGER state:",self.pager_state
658 self.IP.do_execute(lines_to_execute.encode(ENCODING))
659 self.pager_nb_lines = len(self.pager_lines)
659 self.updateHistoryTracker(lines)
660 self.pager_index = 0
660 if(self.text_ctrl.getCursorPos()!=0):
661 self.pager_do_remove = False
661 self.text_ctrl.removeCurrentLine()
662 self.text_ctrl.write('\n')
662 self.setCurrentState('WAIT_END_OF_EXECUTION')
663 self.pager_state = 'PROCESS_LINES'
663
664
664 def evtStateExecuteDone(self,evt):
665 if self.pager_state == 'PROCESS_LINES':
665 self.doc = self.IP.get_doc_text()
666 #print >>sys.__stdout__,"PAGER state:",self.pager_state
666 self.help = self.IP.get_help_text()
667 if self.pager_do_remove == True:
667 if self.doc:
668 self.text_ctrl.removeCurrentLine()
668 self.pager_lines = self.doc[7:].split('\n')
669 self.pager_do_remove = False
669 self.pager_state = 'INIT'
670
670 self.setCurrentState('SHOW_DOC')
671 if self.pager_nb_lines > 10:
671 self.pager(self.doc)
672 #print >>sys.__stdout__,"PAGER processing 10 lines"
672 elif self.help:
673 if self.pager_index > 0:
673 self.pager_lines = self.help.split('\n')
674 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
674 self.pager_state = 'INIT'
675 else:
675 self.setCurrentState('SHOW_DOC')
676 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
676 self.pager(self.help)
677
677 else:
678 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
678 if(self.text_ctrl.getCursorPos()!=0):
679 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
679 self.text_ctrl.removeCurrentLine()
680 self.pager_index += 10
680 self.stateShowPrompt()
681 self.pager_nb_lines -= 10
681
682 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
682 def stateShowPrompt(self):
683 self.pager_do_remove = True
683 self.setCurrentState('SHOW_PROMPT')
684 self.pager_state = 'WAITING'
684 self.text_ctrl.setPrompt(self.IP.get_prompt())
685 return
685 self.text_ctrl.setIndentation(self.IP.get_indentation())
686 else:
686 self.text_ctrl.setPromptCount(self.IP.get_prompt_count())
687 #print >>sys.__stdout__,"PAGER processing last lines"
687 self.text_ctrl.showPrompt()
688 if self.pager_nb_lines > 0:
688 self.IP.init_history_index()
689 if self.pager_index > 0:
689 self.setCurrentState('IDLE')
690 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
690
691 else:
691 def setCurrentState(self, state):
692 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
692 self.cur_state = state
693
693 self.updateStatusTracker(self.cur_state)
694 self.pager_index += 1
694
695 self.pager_nb_lines -= 1
695 def pager(self,text):
696 if self.pager_nb_lines > 0:
696
697 for line in self.pager_lines[self.pager_index:]:
697 if self.pager_state == 'INIT':
698 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
698 #print >>sys.__stdout__,"PAGER state:",self.pager_state
699 self.pager_nb_lines = 0
699 self.pager_nb_lines = len(self.pager_lines)
700 self.pager_state = 'DONE'
700 self.pager_index = 0
701 self.stateShowPrompt()
701 self.pager_do_remove = False
702
702 self.text_ctrl.write('\n')
703 #------------------------ Key Handler ------------------------------------
703 self.pager_state = 'PROCESS_LINES'
704 def keyPress(self, event):
704
705 '''
705 if self.pager_state == 'PROCESS_LINES':
706 Key press callback with plenty of shell goodness, like history,
706 #print >>sys.__stdout__,"PAGER state:",self.pager_state
707 autocompletions, etc.
707 if self.pager_do_remove == True:
708 '''
708 self.text_ctrl.removeCurrentLine()
709 if event.GetKeyCode() == ord('C'):
709 self.pager_do_remove = False
710 if event.Modifiers == wx.MOD_CONTROL or event.Modifiers == wx.MOD_ALT:
710
711 if self.cur_state == 'WAIT_END_OF_EXECUTION':
711 if self.pager_nb_lines > 10:
712 #we raise an exception inside the IPython thread container
712 #print >>sys.__stdout__,"PAGER processing 10 lines"
713 self.IP.ce.raise_exc(KeyboardInterrupt)
713 if self.pager_index > 0:
714 return
714 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
715
715 else:
716 #let this before 'wx.WXK_RETURN' because we have to put 'IDLE'
716 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
717 #mode if AutoComp has been set as inactive
717
718 if self.cur_state == 'COMPLETING':
718 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
719 if not self.text_ctrl.AutoCompActive():
719 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
720 self.cur_state = 'IDLE'
720 self.pager_index += 10
721 else:
721 self.pager_nb_lines -= 10
722 event.Skip()
722 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
723
723 self.pager_do_remove = True
724 if event.KeyCode == wx.WXK_RETURN:
724 self.pager_state = 'WAITING'
725 if self.cur_state == 'IDLE':
725 return
726 #we change the state ot the state machine
726 else:
727 self.setCurrentState('DO_EXECUTE_LINE')
727 #print >>sys.__stdout__,"PAGER processing last lines"
728 self.stateDoExecuteLine()
728 if self.pager_nb_lines > 0:
729 return
729 if self.pager_index > 0:
730
730 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
731 if self.pager_state == 'WAITING':
731 else:
732 self.pager_state = 'PROCESS_LINES'
732 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
733 self.pager(self.doc)
733
734 return
734 self.pager_index += 1
735
735 self.pager_nb_lines -= 1
736 if self.cur_state == 'WAITING_USER_INPUT':
736 if self.pager_nb_lines > 0:
737 line=self.text_ctrl.getCurrentLine()
737 for line in self.pager_lines[self.pager_index:]:
738 self.text_ctrl.write('\n')
738 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
739 self.setCurrentState('WAIT_END_OF_EXECUTION')
739 self.pager_nb_lines = 0
740 return
740 self.pager_state = 'DONE'
741
741 self.stateShowPrompt()
742 if event.GetKeyCode() in [ord('q'),ord('Q')]:
742
743 if self.pager_state == 'WAITING':
743 #------------------------ Key Handler ------------------------------------
744 self.pager_state = 'DONE'
744 def keyPress(self, event):
745 self.text_ctrl.write('\n')
745 '''
746 self.stateShowPrompt()
746 Key press callback with plenty of shell goodness, like history,
747 return
747 autocompletions, etc.
748
748 '''
749 if self.cur_state == 'WAITING_USER_INPUT':
749 if event.GetKeyCode() == ord('C'):
750 event.Skip()
750 if event.Modifiers == wx.MOD_CONTROL or event.Modifiers == wx.MOD_ALT:
751
751 if self.cur_state == 'WAIT_END_OF_EXECUTION':
752 if self.cur_state == 'IDLE':
752 #we raise an exception inside the IPython thread container
753 if event.KeyCode == wx.WXK_UP:
753 self.IP.ce.raise_exc(KeyboardInterrupt)
754 history = self.IP.historyBack()
754 return
755 self.text_ctrl.writeHistory(history)
755
756 return
756 #let this before 'wx.WXK_RETURN' because we have to put 'IDLE'
757 if event.KeyCode == wx.WXK_DOWN:
757 #mode if AutoComp has been set as inactive
758 history = self.IP.historyForward()
758 if self.cur_state == 'COMPLETING':
759 self.text_ctrl.writeHistory(history)
759 if not self.text_ctrl.AutoCompActive():
760 return
760 self.cur_state = 'IDLE'
761 if event.KeyCode == wx.WXK_TAB:
761 else:
762 #if line empty we disable tab completion
762 event.Skip()
763 if not self.text_ctrl.getCurrentLine().strip():
763
764 self.text_ctrl.write('\t')
764 if event.KeyCode == wx.WXK_RETURN:
765 return
765 if self.cur_state == 'IDLE':
766 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
766 #we change the state ot the state machine
767 if len(possibilities) > 1:
767 self.setCurrentState('DO_EXECUTE_LINE')
768 if self.text_ctrl.autocomplete_mode == 'IPYTHON':
768 self.stateDoExecuteLine()
769 cur_slice = self.text_ctrl.getCurrentLine()
769 return
770 self.text_ctrl.write('\n')
770
771 self.text_ctrl.writeCompletion(possibilities)
771 if self.pager_state == 'WAITING':
772 self.text_ctrl.write('\n')
772 self.pager_state = 'PROCESS_LINES'
773
773 self.pager(self.doc)
774 self.text_ctrl.showPrompt()
774 return
775 self.text_ctrl.write(cur_slice)
775
776 self.text_ctrl.changeLine(completed or cur_slice)
776 if self.cur_state == 'WAITING_USER_INPUT':
777 else:
777 line=self.text_ctrl.getCurrentLine()
778 self.cur_state = 'COMPLETING'
778 self.text_ctrl.write('\n')
779 self.text_ctrl.writeCompletion(possibilities)
779 self.setCurrentState('WAIT_END_OF_EXECUTION')
780 else:
780 return
781 self.text_ctrl.changeLine(completed or cur_slice)
781
782 return
782 if event.GetKeyCode() in [ord('q'),ord('Q')]:
783 event.Skip()
783 if self.pager_state == 'WAITING':
784
784 self.pager_state = 'DONE'
785 #------------------------ Option Section ---------------------------------
785 self.text_ctrl.write('\n')
786 def evtCheckOptionCompletion(self, event):
786 self.stateShowPrompt()
787 if event.IsChecked():
787 return
788 self.options['completion']['value']='STC'
788
789 else:
789 if self.cur_state == 'WAITING_USER_INPUT':
790 self.options['completion']['value']='IPYTHON'
790 event.Skip()
791 self.text_ctrl.setCompletionMethod(self.options['completion']['value'])
791
792 self.updateOptionTracker('completion',
792 if self.cur_state == 'IDLE':
793 self.options['completion']['value'])
793 if event.KeyCode == wx.WXK_UP:
794 self.text_ctrl.SetFocus()
794 history = self.IP.history_back()
795
795 self.text_ctrl.writeHistory(history)
796 def evtCheckOptionBackgroundColor(self, event):
796 return
797 if event.IsChecked():
797 if event.KeyCode == wx.WXK_DOWN:
798 self.options['background_color']['value']='WHITE'
798 history = self.IP.history_forward()
799 else:
799 self.text_ctrl.writeHistory(history)
800 self.options['background_color']['value']='BLACK'
800 return
801 self.text_ctrl.setBackgroundColor(self.options['background_color']['value'])
801 if event.KeyCode == wx.WXK_TAB:
802 self.updateOptionTracker('background_color',
802 #if line empty we disable tab completion
803 self.options['background_color']['value'])
803 if not self.text_ctrl.getCurrentLine().strip():
804 self.text_ctrl.SetFocus()
804 self.text_ctrl.write('\t')
805
805 return
806 def getOptions(self):
806 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
807 return self.options
807 if len(possibilities) > 1:
808
808 if self.text_ctrl.autocomplete_mode == 'IPYTHON':
809 def reloadOptions(self,options):
809 cur_slice = self.text_ctrl.getCurrentLine()
810 self.options = options
810 self.text_ctrl.write('\n')
811 for key in self.options.keys():
811 self.text_ctrl.writeCompletion(possibilities)
812 value = self.options[key]['value']
812 self.text_ctrl.write('\n')
813 self.options[key]['checkbox'].SetValue(self.options[key][value])
813
814 self.options[key]['setfunc'](value)
814 self.text_ctrl.showPrompt()
815
815 self.text_ctrl.write(cur_slice)
816
816 self.text_ctrl.changeLine(completed or cur_slice)
817 #------------------------ Hook Section -----------------------------------
817 else:
818 def updateOptionTracker(self,name,value):
818 self.cur_state = 'COMPLETING'
819 '''
819 self.text_ctrl.writeCompletion(possibilities)
820 Default history tracker (does nothing)
820 else:
821 '''
821 self.text_ctrl.changeLine(completed or cur_slice)
822 pass
822 return
823
823 event.Skip()
824 def setOptionTrackerHook(self,func):
824
825 '''
825 #------------------------ Option Section ---------------------------------
826 Define a new history tracker
826 def evtCheckOptionCompletion(self, event):
827 '''
827 if event.IsChecked():
828 self.updateOptionTracker = func
828 self.options['completion']['value']='STC'
829
829 else:
830 def updateHistoryTracker(self,command_line):
830 self.options['completion']['value']='IPYTHON'
831 '''
831 self.text_ctrl.setCompletionMethod(self.options['completion']['value'])
832 Default history tracker (does nothing)
832 self.updateOptionTracker('completion',
833 '''
833 self.options['completion']['value'])
834 pass
834 self.text_ctrl.SetFocus()
835
835
836 def setHistoryTrackerHook(self,func):
836 def evtCheckOptionBackgroundColor(self, event):
837 '''
837 if event.IsChecked():
838 Define a new history tracker
838 self.options['background_color']['value']='WHITE'
839 '''
839 else:
840 self.updateHistoryTracker = func
840 self.options['background_color']['value']='BLACK'
841
841 self.text_ctrl.setBackgroundColor(self.options['background_color']['value'])
842 def updateStatusTracker(self,status):
842 self.updateOptionTracker('background_color',
843 '''
843 self.options['background_color']['value'])
844 Default status tracker (does nothing)
844 self.text_ctrl.SetFocus()
845 '''
845
846 pass
846 def evtCheckOptionThreading(self, event):
847
847 if event.IsChecked():
848 def setStatusTrackerHook(self,func):
848 self.options['threading']['value']='True'
849 '''
849 self.IP.set_threading(True)
850 Define a new status tracker
850 self.cout.write = self.text_ctrl.asyncWrite
851 '''
851 else:
852 self.updateStatusTracker = func
852 self.options['threading']['value']='False'
853
853 self.IP.set_threading(False)
854 def askExitHandler(self, event):
854 self.cout.write = self.text_ctrl.write
855 '''
855 self.updateOptionTracker('threading',
856 Default exit handler
856 self.options['threading']['value'])
857 '''
857 self.text_ctrl.SetFocus()
858 self.text_ctrl.write('\nExit callback has not been set.')
858
859
859 def getOptions(self):
860 def setAskExitHandler(self, func):
860 return self.options
861 '''
861
862 Define an exit handler
862 def reloadOptions(self,options):
863 '''
863 self.options = options
864 self.askExitHandler = func
864 for key in self.options.keys():
865
865 value = self.options[key]['value']
866 if __name__ == '__main__':
866 self.options[key]['checkbox'].SetValue(self.options[key][value])
867 # Some simple code to test the shell widget.
867 self.options[key]['setfunc'](value)
868 class MainWindow(wx.Frame):
868
869 def __init__(self, parent, id, title):
869 if self.options['threading']['value']=='True':
870 wx.Frame.__init__(self, parent, id, title, size=(300,250))
870 self.IP.set_threading(True)
871 self._sizer = wx.BoxSizer(wx.VERTICAL)
871 self.cout.write = self.text_ctrl.asyncWrite
872 self.shell = IPShellWidget(self)
872 else:
873 self._sizer.Add(self.shell, 1, wx.EXPAND)
873 self.IP.set_threading(False)
874 self.SetSizer(self._sizer)
874 self.cout.write = self.text_ctrl.write
875 self.SetAutoLayout(1)
875
876 self.Show(True)
876 #------------------------ Hook Section -----------------------------------
877
877 def updateOptionTracker(self,name,value):
878 app = wx.PySimpleApp()
878 '''
879 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
879 Default history tracker (does nothing)
880 frame.SetSize((780, 460))
880 '''
881 shell = frame.shell
881 pass
882
882
883 app.MainLoop()
883 def setOptionTrackerHook(self,func):
884
884 '''
885
885 Define a new history tracker
886 '''
887 self.updateOptionTracker = func
888
889 def updateHistoryTracker(self,command_line):
890 '''
891 Default history tracker (does nothing)
892 '''
893 pass
894
895 def setHistoryTrackerHook(self,func):
896 '''
897 Define a new history tracker
898 '''
899 self.updateHistoryTracker = func
900
901 def updateStatusTracker(self,status):
902 '''
903 Default status tracker (does nothing)
904 '''
905 pass
906
907 def setStatusTrackerHook(self,func):
908 '''
909 Define a new status tracker
910 '''
911 self.updateStatusTracker = func
912
913 def askExitHandler(self, event):
914 '''
915 Default exit handler
916 '''
917 self.text_ctrl.write('\nExit callback has not been set.')
918
919 def setAskExitHandler(self, func):
920 '''
921 Define an exit handler
922 '''
923 self.askExitHandler = func
924
925 if __name__ == '__main__':
926 # Some simple code to test the shell widget.
927 class MainWindow(wx.Frame):
928 def __init__(self, parent, id, title):
929 wx.Frame.__init__(self, parent, id, title, size=(300,250))
930 self._sizer = wx.BoxSizer(wx.VERTICAL)
931 self.shell = IPShellWidget(self)
932 self._sizer.Add(self.shell, 1, wx.EXPAND)
933 self.SetSizer(self._sizer)
934 self.SetAutoLayout(1)
935 self.Show(True)
936
937 app = wx.PySimpleApp()
938 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
939 frame.SetSize((780, 460))
940 shell = frame.shell
941
942 app.MainLoop()
943
944
@@ -10,10 +10,18 b' from wx.lib.wordwrap import wordwrap'
10 from IPython.gui.wx.ipython_view import IPShellWidget
10 from IPython.gui.wx.ipython_view import IPShellWidget
11 from IPython.gui.wx.ipython_history import IPythonHistoryPanel
11 from IPython.gui.wx.ipython_history import IPythonHistoryPanel
12
12
13 #used to invoke ipython1 wx implementation
14 ### FIXME ### temporary disabled due to interference with 'show_in_pager' hook
15 is_sync_frontend_ok = False
16 try:
17 from IPython.frontend.wx.ipythonx import IPythonXController
18 except ImportError:
19 is_sync_frontend_ok = False
20
13 #used to create options.conf file in user directory
21 #used to create options.conf file in user directory
14 from IPython.ipapi import get
22 from IPython.ipapi import get
15
23
16 __version__ = 0.8
24 __version__ = 0.91
17 __author__ = "Laurent Dufrechou"
25 __author__ = "Laurent Dufrechou"
18 __email__ = "laurent.dufrechou _at_ gmail.com"
26 __email__ = "laurent.dufrechou _at_ gmail.com"
19 __license__ = "BSD"
27 __license__ = "BSD"
@@ -27,7 +35,7 b' class MyFrame(wx.Frame):'
27 application with movables windows"""
35 application with movables windows"""
28 def __init__(self, parent=None, id=-1, title="WxIPython",
36 def __init__(self, parent=None, id=-1, title="WxIPython",
29 pos=wx.DefaultPosition,
37 pos=wx.DefaultPosition,
30 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
38 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE, sync_ok=False):
31 wx.Frame.__init__(self, parent, id, title, pos, size, style)
39 wx.Frame.__init__(self, parent, id, title, pos, size, style)
32 self._mgr = wx.aui.AuiManager()
40 self._mgr = wx.aui.AuiManager()
33
41
@@ -41,12 +49,18 b' class MyFrame(wx.Frame):'
41
49
42 self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
50 self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
43 #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
51 #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
44
52 if(sync_ok):
53 self.ipython_panel2 = IPythonXController(self)
54 else:
55 self.ipython_panel2 = None
45 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
56 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
46 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
57 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
47 self.ipython_panel.setAskExitHandler(self.OnExitDlg)
58 self.ipython_panel.setAskExitHandler(self.OnExitDlg)
48 self.ipython_panel.setOptionTrackerHook(self.optionSave)
59 self.ipython_panel.setOptionTrackerHook(self.optionSave)
49
60
61 #Create a notebook to display different IPython shell implementations
62 self.nb = wx.aui.AuiNotebook(self)
63
50 self.optionLoad()
64 self.optionLoad()
51
65
52 self.statusbar = self.createStatus()
66 self.statusbar = self.createStatus()
@@ -55,7 +69,11 b' class MyFrame(wx.Frame):'
55 ########################################################################
69 ########################################################################
56 ### add the panes to the manager
70 ### add the panes to the manager
57 # main panels
71 # main panels
58 self._mgr.AddPane(self.ipython_panel , wx.CENTER, "IPython Shell")
72 self._mgr.AddPane(self.nb , wx.CENTER, "IPython Shells")
73 self.nb.AddPage(self.ipython_panel , "IPython0 Shell")
74 if(sync_ok):
75 self.nb.AddPage(self.ipython_panel2, "IPython1 Synchroneous Shell")
76
59 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
77 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
60
78
61 # now we specify some panel characteristics
79 # now we specify some panel characteristics
@@ -77,7 +95,10 b' class MyFrame(wx.Frame):'
77 warn_text = 'Hello from IPython and wxPython.\n'
95 warn_text = 'Hello from IPython and wxPython.\n'
78 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
96 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
79 warn_text +='It does NOT emulate currently all the IPython functions.\n'
97 warn_text +='It does NOT emulate currently all the IPython functions.\n'
80
98 warn_text +="\nIf you use MATPLOTLIB with show() you'll need to deactivate the THREADING option.\n"
99 if(not sync_ok):
100 warn_text +="\n->No twisted package detected, IPython1 example deactivated."
101
81 dlg = wx.MessageDialog(self,
102 dlg = wx.MessageDialog(self,
82 warn_text,
103 warn_text,
83 'Warning Box',
104 'Warning Box',
@@ -146,13 +167,6 b' class MyFrame(wx.Frame):'
146 about_menu = wx.Menu()
167 about_menu = wx.Menu()
147 about_menu.Append(wx.ID_HIGHEST+3, "About")
168 about_menu.Append(wx.ID_HIGHEST+3, "About")
148
169
149 #view_menu.AppendSeparator()
150 #options_menu = wx.Menu()
151 #options_menu.AppendCheckItem(wx.ID_HIGHEST+7, "Allow Floating")
152 #options_menu.AppendCheckItem(wx.ID_HIGHEST+8, "Transparent Hint")
153 #options_menu.AppendCheckItem(wx.ID_HIGHEST+9, "Transparent Hint Fade-in")
154
155
156 mb.Append(file_menu, "File")
170 mb.Append(file_menu, "File")
157 mb.Append(view_menu, "View")
171 mb.Append(view_menu, "View")
158 mb.Append(about_menu, "About")
172 mb.Append(about_menu, "About")
@@ -233,17 +247,17 b' class MyFrame(wx.Frame):'
233 #-----------------------------------------
247 #-----------------------------------------
234 class MyApp(wx.PySimpleApp):
248 class MyApp(wx.PySimpleApp):
235 """Creating our application"""
249 """Creating our application"""
236 def __init__(self):
250 def __init__(self, sync_ok=False):
237 wx.PySimpleApp.__init__(self)
251 wx.PySimpleApp.__init__(self)
238
252
239 self.frame = MyFrame()
253 self.frame = MyFrame(sync_ok=sync_ok)
240 self.frame.Show()
254 self.frame.Show()
241
255
242 #-----------------------------------------
256 #-----------------------------------------
243 #Main loop
257 #Main loop
244 #-----------------------------------------
258 #-----------------------------------------
245 def main():
259 def main():
246 app = MyApp()
260 app = MyApp(is_sync_frontend_ok)
247 app.SetTopWindow(app.frame)
261 app.SetTopWindow(app.frame)
248 app.MainLoop()
262 app.MainLoop()
249
263
General Comments 0
You need to be logged in to leave comments. Login now