##// END OF EJS Templates
Merging Laurent's WX branch, reviewed by Gael....
Fernando Perez -
r1862:321357e1 merge
parent child Browse files
Show More
@@ -62,10 +62,9 class _Helper(object):
62 62 ##############################################################################
63 63 class _CodeExecutor(ThreadEx):
64 64 ''' Thread that execute ipython code '''
65 def __init__(self, instance, after):
65 def __init__(self, instance):
66 66 ThreadEx.__init__(self)
67 67 self.instance = instance
68 self._afterExecute = after
69 68
70 69 def run(self):
71 70 '''Thread main loop'''
@@ -74,7 +73,7 class _CodeExecutor(ThreadEx):
74 73 self.instance._help_text = None
75 74 self.instance._execute()
76 75 # used for uper class to generate event after execution
77 self._afterExecute()
76 self.instance._after_execute()
78 77
79 78 except KeyboardInterrupt:
80 79 pass
@@ -114,8 +113,7 class NonBlockingIPShell(object):
114 113 '''
115 114 #ipython0 initialisation
116 115 self._IP = None
117 self._term = None
118 self.initIpython0(argv, user_ns, user_global_ns,
116 self.init_ipython0(argv, user_ns, user_global_ns,
119 117 cin, cout, cerr,
120 118 ask_exit_handler)
121 119
@@ -127,6 +125,7 class NonBlockingIPShell(object):
127 125
128 126 #thread working vars
129 127 self._line_to_execute = ''
128 self._threading = True
130 129
131 130 #vars that will be checked by GUI loop to handle thread states...
132 131 #will be replaced later by PostEvent GUI funtions...
@@ -134,26 +133,24 class NonBlockingIPShell(object):
134 133 self._help_text = None
135 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 137 cin=None, cout=None, cerr=None,
139 138 ask_exit_handler=None):
140 ''' Initialize an ithon0 instance '''
139 ''' Initialize an ipython0 instance '''
141 140
142 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 145 if cin:
144 IPython.Shell.Term.cin = cin
146 IPython.genutils.Term.cin = cin
145 147 if cout:
146 IPython.Shell.Term.cout = cout
148 IPython.genutils.Term.cout = cout
147 149 if cerr:
148 IPython.Shell.Term.cerr = cerr
149
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)
150 IPython.genutils.Term.cerr = cerr
155 151
156 152 excepthook = sys.excepthook
153
157 154 #Hack to save sys.displayhook, because ipython seems to overwrite it...
158 155 self.sys_displayhook_ori = sys.displayhook
159 156
@@ -163,7 +160,8 class NonBlockingIPShell(object):
163 160 embedded=True,
164 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 165 sys.displayhook = self.sys_displayhook_ori
168 166
169 167 #we replace IPython default encoding by wx locale encoding
@@ -173,11 +171,12 class NonBlockingIPShell(object):
173 171 #we replace the ipython default pager by our pager
174 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 176 self._IP.set_hook('shell_hook', self._shell)
178 177
179 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 180 #we replace the ipython default exit command by our method
182 181 self._IP.exit = ask_exit_handler
183 182 #we replace the help command
@@ -186,26 +185,68 class NonBlockingIPShell(object):
186 185 #we disable cpase magic... until we found a way to use it properly.
187 186 #import IPython.ipapi
188 187 ip = IPython.ipapi.get()
189 def bypassMagic(self, arg):
188 def bypass_magic(self, arg):
190 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 195 sys.excepthook = excepthook
194 196
195 197 #----------------------- Thread management section ----------------------
196 def doExecute(self, line):
198 def do_execute(self, line):
197 199 """
198 200 Tell the thread to process the 'line' command
199 201 """
200 202
201 203 self._line_to_execute = line
202 #we launch the ipython line execution in a thread to make it interruptible
203 #with include it in self namespace to be able to call ce.raise_exc(KeyboardInterrupt)
204 self.ce = _CodeExecutor(self, self._afterExecute)
204
205 if self._threading:
206 #we launch the ipython line execution in a thread to make it
207 #interruptible with include it in self namespace to be able
208 #to call ce.raise_exc(KeyboardInterrupt)
209 self.ce = _CodeExecutor(self)
205 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
206 221
207 222 #----------------------- IPython management section ----------------------
208 def getDocText(self):
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 251 Returns the output of the processing that need to be paged (if any)
211 252
@@ -214,7 +255,7 class NonBlockingIPShell(object):
214 255 """
215 256 return self._doc_text
216 257
217 def getHelpText(self):
258 def get_help_text(self):
218 259 """
219 260 Returns the output of the processing that need to be paged via help pager(if any)
220 261
@@ -223,7 +264,7 class NonBlockingIPShell(object):
223 264 """
224 265 return self._help_text
225 266
226 def getBanner(self):
267 def get_banner(self):
227 268 """
228 269 Returns the IPython banner for useful info on IPython instance
229 270
@@ -232,7 +273,7 class NonBlockingIPShell(object):
232 273 """
233 274 return self._IP.BANNER
234 275
235 def getPromptCount(self):
276 def get_prompt_count(self):
236 277 """
237 278 Returns the prompt number.
238 279 Each time a user execute a line in the IPython shell the prompt count is increased
@@ -242,7 +283,7 class NonBlockingIPShell(object):
242 283 """
243 284 return self._IP.outputcache.prompt_count
244 285
245 def getPrompt(self):
286 def get_prompt(self):
246 287 """
247 288 Returns current prompt inside IPython instance
248 289 (Can be In [...]: ot ...:)
@@ -252,7 +293,7 class NonBlockingIPShell(object):
252 293 """
253 294 return self._prompt
254 295
255 def getIndentation(self):
296 def get_indentation(self):
256 297 """
257 298 Returns the current indentation level
258 299 Usefull to put the caret at the good start position if we want to do autoindentation.
@@ -262,7 +303,7 class NonBlockingIPShell(object):
262 303 """
263 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 308 Add the current dictionary to the shell namespace.
268 309
@@ -286,7 +327,7 class NonBlockingIPShell(object):
286 327 possibilities = self._IP.complete(split_line[-1])
287 328 if possibilities:
288 329
289 def _commonPrefix(str1, str2):
330 def _common_prefix(str1, str2):
290 331 '''
291 332 Reduction function. returns common prefix of two given strings.
292 333
@@ -302,13 +343,13 class NonBlockingIPShell(object):
302 343 if not str2.startswith(str1[:i+1]):
303 344 return str1[:i]
304 345 return str1
305 common_prefix = reduce(_commonPrefix, possibilities)
346 common_prefix = reduce(_common_prefix, possibilities)
306 347 completed = line[:-len(split_line[-1])]+common_prefix
307 348 else:
308 349 completed = line
309 350 return completed, possibilities
310 351
311 def historyBack(self):
352 def history_back(self):
312 353 '''
313 354 Provides one history command back.
314 355
@@ -320,10 +361,10 class NonBlockingIPShell(object):
320 361 while((history == '' or history == '\n') and self._history_level >0):
321 362 if self._history_level >= 1:
322 363 self._history_level -= 1
323 history = self._getHistory()
364 history = self._get_history()
324 365 return history
325 366
326 def historyForward(self):
367 def history_forward(self):
327 368 '''
328 369 Provides one history command forward.
329 370
@@ -333,38 +374,38 class NonBlockingIPShell(object):
333 374 history = ''
334 375 #the below while loop is used to suppress empty history lines
335 376 while((history == '' or history == '\n') \
336 and self._history_level <= self._getHistoryMaxIndex()):
337 if self._history_level < self._getHistoryMaxIndex():
377 and self._history_level <= self._get_history_max_index()):
378 if self._history_level < self._get_history_max_index():
338 379 self._history_level += 1
339 history = self._getHistory()
380 history = self._get_history()
340 381 else:
341 if self._history_level == self._getHistoryMaxIndex():
342 history = self._getHistory()
382 if self._history_level == self._get_history_max_index():
383 history = self._get_history()
343 384 self._history_level += 1
344 385 else:
345 386 history = ''
346 387 return history
347 388
348 def initHistoryIndex(self):
389 def init_history_index(self):
349 390 '''
350 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 395 #----------------------- IPython PRIVATE management section --------------
355 def _afterExecute(self):
396 def _after_execute(self):
356 397 '''
357 398 Can be redefined to generate post event after excution is done
358 399 '''
359 400 pass
360 401
361 #def _askExit(self):
362 # '''
363 # Can be redefined to generate post event to exit the Ipython shell
364 # '''
365 # pass
402 def _ask_exit(self):
403 '''
404 Can be redefined to generate post event to exit the Ipython shell
405 '''
406 pass
366 407
367 def _getHistoryMaxIndex(self):
408 def _get_history_max_index(self):
368 409 '''
369 410 returns the max length of the history buffer
370 411
@@ -373,7 +414,7 class NonBlockingIPShell(object):
373 414 '''
374 415 return len(self._IP.input_hist_raw)-1
375 416
376 def _getHistory(self):
417 def _get_history(self):
377 418 '''
378 419 Get's the command string of the current history level.
379 420
@@ -388,7 +429,7 class NonBlockingIPShell(object):
388 429 This function is used as a callback replacment to IPython help pager function
389 430
390 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 434 if self._help_text == None:
394 435 self._help_text = text
@@ -400,11 +441,11 class NonBlockingIPShell(object):
400 441 This function is used as a callback replacment to IPython pager function
401 442
402 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 446 self._doc_text = text
406 447
407 def _raw_input(self, prompt=''):
448 def _raw_input_original(self, prompt=''):
408 449 '''
409 450 Custom raw_input() replacement. Get's current line from console buffer.
410 451
@@ -416,12 +457,20 class NonBlockingIPShell(object):
416 457 '''
417 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 465 def _execute(self):
420 466 '''
421 467 Executes the current line provided by the shell object.
422 468 '''
469
423 470 orig_stdout = sys.stdout
424 471 sys.stdout = IPython.Shell.Term.cout
472 #self.sys_displayhook_ori = sys.displayhook
473 #sys.displayhook = self.displayhook
425 474
426 475 try:
427 476 line = self._IP.raw_input(None, self._iter_more)
@@ -440,8 +489,10 class NonBlockingIPShell(object):
440 489 except:
441 490 self._IP.showtraceback()
442 491 else:
492 self._IP.write(str(self._IP.outputcache.prompt_out).strip())
443 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 496 self._IP.edit_syntax_error()
446 497 if self._iter_more:
447 498 self._prompt = str(self._IP.outputcache.prompt2).strip()
@@ -450,7 +501,9 class NonBlockingIPShell(object):
450 501 else:
451 502 self._prompt = str(self._IP.outputcache.prompt1).strip()
452 503 self._IP.indent_current_nsp = 0 #we set indentation to 0
504
453 505 sys.stdout = orig_stdout
506 #sys.displayhook = self.sys_displayhook_ori
454 507
455 508 def _shell(self, ip, cmd):
456 509 '''
@@ -462,7 +515,8 class NonBlockingIPShell(object):
462 515 @type cmd: string
463 516 '''
464 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 520 #we use print command because the shell command is called
467 521 #inside IPython instance and thus is redirected to thread cout
468 522 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
@@ -29,16 +29,20 class IPythonHistoryPanel(wx.Panel):
29 29 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
30 30
31 31 self.options={'filter_empty':{'value':'True',
32 'checkbox':self.filter_empty,'True':True,'False':False,
32 'checkbox':self.filter_empty, \
33 'True':True,'False':False,
33 34 'setfunc':lambda x:None},
34 35 'filter_doc':{'value':'True',
35 'checkbox':self.filter_doc,'True':True,'False':False,
36 'checkbox':self.filter_doc, \
37 'True':True,'False':False,
36 38 'setfunc':lambda x:None},
37 39 'filter_cmd':{'value':'True',
38 'checkbox':self.filter_cmd,'True':True,'False':False,
40 'checkbox':self.filter_cmd, \
41 'True':True,'False':False,
39 42 'setfunc':lambda x:None},
40 43 'filter_magic':{'value':'True',
41 'checkbox':self.filter_magic,'True':True,'False':False,
44 'checkbox':self.filter_magic, \
45 'True':True,'False':False,
42 46 'setfunc':lambda x:None},
43 47 }
44 48 self.reloadOptions(self.options)
@@ -199,51 +203,81 class PythonSTC(stc.StyledTextCtrl):
199 203 self.SetLayoutCache(stc.STC_CACHE_PAGE)
200 204
201 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 208 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
204 209 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
205 210 self.SetMarginSensitive(2, True)
206 211 self.SetMarginWidth(2, 12)
207 212
208 213 if self.fold_symbols == 0:
209 # Arrow pointing right for contracted folders, arrow pointing down for expanded
210 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black")
211 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black")
212 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black")
213 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black")
214 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
215 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
216 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
214 # Arrow pointing right for contracted folders,
215 # arrow pointing down for expanded
216 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
217 stc.STC_MARK_ARROWDOWN, "black", "black")
218 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
219 stc.STC_MARK_ARROW, "black", "black")
220 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
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 231 elif self.fold_symbols == 1:
219 232 # Plus for contracted folders, minus for expanded
220 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black")
221 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black")
222 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black")
223 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black")
224 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
225 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
226 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
233 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
234 stc.STC_MARK_MINUS, "white", "black")
235 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
236 stc.STC_MARK_PLUS, "white", "black")
237 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
238 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 248 elif self.fold_symbols == 2:
229 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")
231 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
232 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040")
233 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040")
234 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
235 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
236 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040")
250 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
251 stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
252 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
253 stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
254 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
255 stc.STC_MARK_VLINE, "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 265 elif self.fold_symbols == 3:
239 266 # Like a flattened tree control using square headers
240 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080")
241 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080")
242 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080")
243 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080")
244 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
245 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
246 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080")
267 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
268 stc.STC_MARK_BOXMINUS, "white", "#808080")
269 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
270 stc.STC_MARK_BOXPLUS, "white", "#808080")
271 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
272 stc.STC_MARK_VLINE, "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 283 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
@@ -19,7 +19,7 available under the terms of the BSD which accompanies this distribution, and
19 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 23 __author__ = "Laurent Dufrechou"
24 24 __email__ = "laurent.dufrechou _at_ gmail.com"
25 25 __license__ = "BSD"
@@ -33,6 +33,8 from StringIO import StringIO
33 33 import sys
34 34 import codecs
35 35 import locale
36 import time
37
36 38 for enc in (locale.getpreferredencoding(),
37 39 sys.getfilesystemencoding(),
38 40 sys.getdefaultencoding()):
@@ -63,17 +65,43 class WxNonBlockingIPShell(NonBlockingIPShell):
63 65 self.parent = parent
64 66
65 67 self.ask_exit_callback = ask_exit_handler
66 self._IP.exit = self._askExit
68 self._IP.exit = self._ask_exit
67 69
68 70 def addGUIShortcut(self, text, func):
69 71 wx.CallAfter(self.parent.add_button_handler,
70 72 button_info={ 'text':text,
71 73 'func':self.parent.doExecuteLine(func)})
72 74
73 def _askExit(self):
75 def _raw_input(self, prompt=''):
76 """ A replacement from python's raw_input.
77 """
78 self.answer = None
79 if(self._threading == True):
80 wx.CallAfter(self._yesNoBox, prompt)
81 while self.answer is None:
82 time.sleep(.1)
83 else:
84 self._yesNoBox(prompt)
85 return self.answer
86
87 def _yesNoBox(self, prompt):
88 """ yes/no box managed with wx.CallAfter jsut in case caler is executed in a thread"""
89 dlg = wx.TextEntryDialog(
90 self.parent, prompt,
91 'Input requested', 'Python')
92 dlg.SetValue("")
93
94 answer = ''
95 if dlg.ShowModal() == wx.ID_OK:
96 answer = dlg.GetValue()
97
98 dlg.Destroy()
99 self.answer = answer
100
101 def _ask_exit(self):
74 102 wx.CallAfter(self.ask_exit_callback, ())
75 103
76 def _afterExecute(self):
104 def _after_execute(self):
77 105 wx.CallAfter(self.parent.evtStateExecuteDone, ())
78 106
79 107
@@ -249,22 +277,15 class WxConsoleView(stc.StyledTextCtrl):
249 277 @type text: string
250 278 '''
251 279 try:
252 #print >>sys.__stdout__,'entering'
253 280 wx.MutexGuiEnter()
254 #print >>sys.__stdout__,'locking the GUI'
255 281
256 282 #be sure not to be interrutpted before the MutexGuiLeave!
257 283 self.write(text)
258 284
259 #print >>sys.__stdout__,'done'
260
261 285 except KeyboardInterrupt:
262 #print >>sys.__stdout__,'got keyboard interrupt'
263 286 wx.MutexGuiLeave()
264 #print >>sys.__stdout__,'interrupt unlock the GUI'
265 287 raise KeyboardInterrupt
266 288 wx.MutexGuiLeave()
267 #print >>sys.__stdout__,'normal unlock the GUI'
268 289
269 290
270 291 def write(self, text):
@@ -419,7 +440,7 class WxConsoleView(stc.StyledTextCtrl):
419 440 self.AutoCompSetIgnoreCase(False)
420 441 self.AutoCompSetAutoHide(False)
421 442 #let compute the length ot last word
422 splitter = [' ', '(', '[', '{']
443 splitter = [' ', '(', '[', '{','=']
423 444 last_word = self.getCurrentLine()
424 445 for breaker in splitter:
425 446 last_word = last_word.split(breaker)[-1]
@@ -439,7 +460,6 class WxConsoleView(stc.StyledTextCtrl):
439 460 @return: Return True if event as been catched.
440 461 @rtype: boolean
441 462 '''
442
443 463 if not self.AutoCompActive():
444 464 if event.GetKeyCode() == wx.WXK_HOME:
445 465 if event.Modifiers == wx.MOD_NONE:
@@ -554,24 +574,30 class IPShellWidget(wx.Panel):
554 574 #with intro=''
555 575 if intro is None:
556 576 welcome_text = "Welcome to WxIPython Shell.\n\n"
557 welcome_text+= self.IP.getBanner()
577 welcome_text+= self.IP.get_banner()
558 578 welcome_text+= "!command -> Execute command in shell\n"
559 579 welcome_text+= "TAB -> Autocompletion\n"
560 580 else:
561 581 welcome_text = intro
562 582
563 583 self.text_ctrl = WxConsoleView(self,
564 self.IP.getPrompt(),
584 self.IP.get_prompt(),
565 585 intro=welcome_text,
566 586 background_color=background_color)
567 587
568 self.cout.write = self.text_ctrl.asyncWrite
569
570 588 option_text = wx.StaticText(self, -1, "Options:")
571 589 self.completion_option = wx.CheckBox(self, -1, "Scintilla Completion")
590 self.completion_option.SetToolTip(wx.ToolTip(
591 "Selects the completion type:\nEither Ipython default style or Scintilla one"))
572 592 #self.completion_option.SetValue(False)
573 593 self.background_option = wx.CheckBox(self, -1, "White Background")
594 self.background_option.SetToolTip(wx.ToolTip(
595 "Selects the back ground color: BLACK or WHITE"))
574 596 #self.background_option.SetValue(False)
597 self.threading_option = wx.CheckBox(self, -1, "Execute in thread")
598 self.threading_option.SetToolTip(wx.ToolTip(
599 "Use threading: infinite loop don't freeze the GUI and commands can be breaked\nNo threading: maximum compatibility"))
600 #self.threading_option.SetValue(False)
575 601
576 602 self.options={'completion':{'value':'IPYTHON',
577 603 'checkbox':self.completion_option,'STC':True,'IPYTHON':False,
@@ -579,12 +605,20 class IPShellWidget(wx.Panel):
579 605 'background_color':{'value':'BLACK',
580 606 'checkbox':self.background_option,'WHITE':True,'BLACK':False,
581 607 'setfunc':self.text_ctrl.setBackgroundColor},
608 'threading':{'value':'True',
609 'checkbox':self.threading_option,'True':True,'False':False,
610 'setfunc':self.IP.set_threading},
582 611 }
612
613 #self.cout.write dEfault option is asynchroneous because default sate is threading ON
614 self.cout.write = self.text_ctrl.asyncWrite
615 #we reloard options
583 616 self.reloadOptions(self.options)
584 617
585 618 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress)
586 619 self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion)
587 620 self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor)
621 self.threading_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionThreading)
588 622
589 623 ### making the layout of the panel ###
590 624 sizer = wx.BoxSizer(wx.VERTICAL)
@@ -596,7 +630,9 class IPShellWidget(wx.Panel):
596 630 (5, 5),
597 631 (self.completion_option, 0, wx.ALIGN_CENTER_VERTICAL),
598 632 (8, 8),
599 (self.background_option, 0, wx.ALIGN_CENTER_VERTICAL)
633 (self.background_option, 0, wx.ALIGN_CENTER_VERTICAL),
634 (8, 8),
635 (self.threading_option, 0, wx.ALIGN_CENTER_VERTICAL)
600 636 ])
601 637 self.SetAutoLayout(True)
602 638 sizer.Fit(self)
@@ -619,13 +655,15 class IPShellWidget(wx.Panel):
619 655 self.text_ctrl.write('\n')
620 656 lines_to_execute = lines.replace('\t',' '*4)
621 657 lines_to_execute = lines_to_execute.replace('\r','')
622 self.IP.doExecute(lines_to_execute.encode(ENCODING))
658 self.IP.do_execute(lines_to_execute.encode(ENCODING))
623 659 self.updateHistoryTracker(lines)
660 if(self.text_ctrl.getCursorPos()!=0):
661 self.text_ctrl.removeCurrentLine()
624 662 self.setCurrentState('WAIT_END_OF_EXECUTION')
625 663
626 664 def evtStateExecuteDone(self,evt):
627 self.doc = self.IP.getDocText()
628 self.help = self.IP.getHelpText()
665 self.doc = self.IP.get_doc_text()
666 self.help = self.IP.get_help_text()
629 667 if self.doc:
630 668 self.pager_lines = self.doc[7:].split('\n')
631 669 self.pager_state = 'INIT'
@@ -637,15 +675,17 class IPShellWidget(wx.Panel):
637 675 self.setCurrentState('SHOW_DOC')
638 676 self.pager(self.help)
639 677 else:
678 if(self.text_ctrl.getCursorPos()!=0):
679 self.text_ctrl.removeCurrentLine()
640 680 self.stateShowPrompt()
641 681
642 682 def stateShowPrompt(self):
643 683 self.setCurrentState('SHOW_PROMPT')
644 self.text_ctrl.setPrompt(self.IP.getPrompt())
645 self.text_ctrl.setIndentation(self.IP.getIndentation())
646 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
684 self.text_ctrl.setPrompt(self.IP.get_prompt())
685 self.text_ctrl.setIndentation(self.IP.get_indentation())
686 self.text_ctrl.setPromptCount(self.IP.get_prompt_count())
647 687 self.text_ctrl.showPrompt()
648 self.IP.initHistoryIndex()
688 self.IP.init_history_index()
649 689 self.setCurrentState('IDLE')
650 690
651 691 def setCurrentState(self, state):
@@ -751,11 +791,11 class IPShellWidget(wx.Panel):
751 791
752 792 if self.cur_state == 'IDLE':
753 793 if event.KeyCode == wx.WXK_UP:
754 history = self.IP.historyBack()
794 history = self.IP.history_back()
755 795 self.text_ctrl.writeHistory(history)
756 796 return
757 797 if event.KeyCode == wx.WXK_DOWN:
758 history = self.IP.historyForward()
798 history = self.IP.history_forward()
759 799 self.text_ctrl.writeHistory(history)
760 800 return
761 801 if event.KeyCode == wx.WXK_TAB:
@@ -803,6 +843,19 class IPShellWidget(wx.Panel):
803 843 self.options['background_color']['value'])
804 844 self.text_ctrl.SetFocus()
805 845
846 def evtCheckOptionThreading(self, event):
847 if event.IsChecked():
848 self.options['threading']['value']='True'
849 self.IP.set_threading(True)
850 self.cout.write = self.text_ctrl.asyncWrite
851 else:
852 self.options['threading']['value']='False'
853 self.IP.set_threading(False)
854 self.cout.write = self.text_ctrl.write
855 self.updateOptionTracker('threading',
856 self.options['threading']['value'])
857 self.text_ctrl.SetFocus()
858
806 859 def getOptions(self):
807 860 return self.options
808 861
@@ -813,6 +866,12 class IPShellWidget(wx.Panel):
813 866 self.options[key]['checkbox'].SetValue(self.options[key][value])
814 867 self.options[key]['setfunc'](value)
815 868
869 if self.options['threading']['value']=='True':
870 self.IP.set_threading(True)
871 self.cout.write = self.text_ctrl.asyncWrite
872 else:
873 self.IP.set_threading(False)
874 self.cout.write = self.text_ctrl.write
816 875
817 876 #------------------------ Hook Section -----------------------------------
818 877 def updateOptionTracker(self,name,value):
@@ -10,10 +10,18 from wx.lib.wordwrap import wordwrap
10 10 from IPython.gui.wx.ipython_view import IPShellWidget
11 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 21 #used to create options.conf file in user directory
14 22 from IPython.ipapi import get
15 23
16 __version__ = 0.8
24 __version__ = 0.91
17 25 __author__ = "Laurent Dufrechou"
18 26 __email__ = "laurent.dufrechou _at_ gmail.com"
19 27 __license__ = "BSD"
@@ -27,7 +35,7 class MyFrame(wx.Frame):
27 35 application with movables windows"""
28 36 def __init__(self, parent=None, id=-1, title="WxIPython",
29 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 39 wx.Frame.__init__(self, parent, id, title, pos, size, style)
32 40 self._mgr = wx.aui.AuiManager()
33 41
@@ -41,12 +49,18 class MyFrame(wx.Frame):
41 49
42 50 self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
43 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 56 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
46 57 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
47 58 self.ipython_panel.setAskExitHandler(self.OnExitDlg)
48 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 64 self.optionLoad()
51 65
52 66 self.statusbar = self.createStatus()
@@ -55,7 +69,11 class MyFrame(wx.Frame):
55 69 ########################################################################
56 70 ### add the panes to the manager
57 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 77 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
60 78
61 79 # now we specify some panel characteristics
@@ -77,6 +95,9 class MyFrame(wx.Frame):
77 95 warn_text = 'Hello from IPython and wxPython.\n'
78 96 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
79 97 warn_text +='It does NOT emulate currently all the IPython functions.\n'
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."
80 101
81 102 dlg = wx.MessageDialog(self,
82 103 warn_text,
@@ -146,13 +167,6 class MyFrame(wx.Frame):
146 167 about_menu = wx.Menu()
147 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 170 mb.Append(file_menu, "File")
157 171 mb.Append(view_menu, "View")
158 172 mb.Append(about_menu, "About")
@@ -233,17 +247,17 class MyFrame(wx.Frame):
233 247 #-----------------------------------------
234 248 class MyApp(wx.PySimpleApp):
235 249 """Creating our application"""
236 def __init__(self):
250 def __init__(self, sync_ok=False):
237 251 wx.PySimpleApp.__init__(self)
238 252
239 self.frame = MyFrame()
253 self.frame = MyFrame(sync_ok=sync_ok)
240 254 self.frame.Show()
241 255
242 256 #-----------------------------------------
243 257 #Main loop
244 258 #-----------------------------------------
245 259 def main():
246 app = MyApp()
260 app = MyApp(is_sync_frontend_ok)
247 261 app.SetTopWindow(app.frame)
248 262 app.MainLoop()
249 263
General Comments 0
You need to be logged in to leave comments. Login now