##// END OF EJS Templates
merge, fix crlf
Ville M. Vainio -
r1112:bc7ad023 merge
parent child Browse files
Show More
@@ -0,0 +1,453 b''
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
3 '''
4 Provides IPython remote instance.
5
6 @author: Laurent Dufrechou
7 laurent.dufrechou _at_ gmail.com
8 @license: BSD
9
10 All rights reserved. This program and the accompanying materials are made
11 available under the terms of the BSD which accompanies this distribution, and
12 is available at U{http://www.opensource.org/licenses/bsd-license.php}
13 '''
14
15 __version__ = 0.9
16 __author__ = "Laurent Dufrechou"
17 __email__ = "laurent.dufrechou _at_ gmail.com"
18 __license__ = "BSD"
19
20 import re
21 import sys
22 import os
23 import locale
24 import time
25 import pydoc,__builtin__,site
26 from thread_ex import ThreadEx
27 from StringIO import StringIO
28
29 try:
30 import IPython
31 except Exception,e:
32 raise "Error importing IPython (%s)" % str(e)
33
34 ##############################################################################
35 class _Helper(object):
36 """Redefine the built-in 'help'.
37 This is a wrapper around pydoc.help (with a twist).
38 """
39
40 def __init__(self,pager):
41 self._pager = pager
42
43 def __repr__(self):
44 return "Type help() for interactive help, " \
45 "or help(object) for help about object."
46
47 def __call__(self, *args, **kwds):
48 class DummyWriter(object):
49 def __init__(self,pager):
50 self._pager = pager
51
52 def write(self,data):
53 self._pager(data)
54
55 import pydoc
56 pydoc.help.output = DummyWriter(self._pager)
57 pydoc.help.interact = lambda :1
58
59 return pydoc.help(*args, **kwds)
60
61
62 ##############################################################################
63 class _CodeExecutor(ThreadEx):
64
65 def __init__(self, instance, after):
66 ThreadEx.__init__(self)
67 self.instance = instance
68 self._afterExecute=after
69
70 def run(self):
71 try:
72 self.instance._doc_text = None
73 self.instance._help_text = None
74 self.instance._execute()
75 # used for uper class to generate event after execution
76 self._afterExecute()
77
78 except KeyboardInterrupt:
79 pass
80
81
82 ##############################################################################
83 class NonBlockingIPShell(object):
84 '''
85 Create an IPython instance, running the commands in a separate,
86 non-blocking thread.
87 This allows embedding in any GUI without blockage.
88
89 Note: The ThreadEx class supports asynchroneous function call
90 via raise_exc()
91 '''
92
93 def __init__(self,argv=[],user_ns={},user_global_ns=None,
94 cin=None, cout=None, cerr=None,
95 ask_exit_handler=None):
96 '''
97 @param argv: Command line options for IPython
98 @type argv: list
99 @param user_ns: User namespace.
100 @type user_ns: dictionary
101 @param user_global_ns: User global namespace.
102 @type user_global_ns: dictionary.
103 @param cin: Console standard input.
104 @type cin: IO stream
105 @param cout: Console standard output.
106 @type cout: IO stream
107 @param cerr: Console standard error.
108 @type cerr: IO stream
109 @param exit_handler: Replacement for builtin exit() function
110 @type exit_handler: function
111 @param time_loop: Define the sleep time between two thread's loop
112 @type int
113 '''
114 #ipython0 initialisation
115 self.initIpython0(argv, user_ns, user_global_ns,
116 cin, cout, cerr,
117 ask_exit_handler)
118
119 #vars used by _execute
120 self._iter_more = 0
121 self._history_level = 0
122 self._complete_sep = re.compile('[\s\{\}\[\]\(\)]')
123 self._prompt = str(self._IP.outputcache.prompt1).strip()
124
125 #thread working vars
126 self._line_to_execute = ''
127
128 #vars that will be checked by GUI loop to handle thread states...
129 #will be replaced later by PostEvent GUI funtions...
130 self._doc_text = None
131 self._help_text = None
132 self._add_button = None
133
134 def initIpython0(self, argv=[], user_ns={}, user_global_ns=None,
135 cin=None, cout=None, cerr=None,
136 ask_exit_handler=None):
137 #first we redefine in/out/error functions of IPython
138 if cin:
139 IPython.Shell.Term.cin = cin
140 if cout:
141 IPython.Shell.Term.cout = cout
142 if cerr:
143 IPython.Shell.Term.cerr = cerr
144
145 # This is to get rid of the blockage that accurs during
146 # IPython.Shell.InteractiveShell.user_setup()
147 IPython.iplib.raw_input = lambda x: None
148
149 self._term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
150
151 excepthook = sys.excepthook
152
153 self._IP = IPython.Shell.make_IPython(
154 argv,user_ns=user_ns,
155 user_global_ns=user_global_ns,
156 embedded=True,
157 shell_class=IPython.Shell.InteractiveShell)
158
159 #we replace IPython default encoding by wx locale encoding
160 loc = locale.getpreferredencoding()
161 if loc:
162 self._IP.stdin_encoding = loc
163 #we replace the ipython default pager by our pager
164 self._IP.set_hook('show_in_pager',self._pager)
165
166 #we replace the ipython default shell command caller by our shell handler
167 self._IP.set_hook('shell_hook',self._shell)
168
169 #we replace the ipython default input command caller by our method
170 IPython.iplib.raw_input_original = self._raw_input
171 #we replace the ipython default exit command by our method
172 self._IP.exit = ask_exit_handler
173 #we replace the help command
174 self._IP.user_ns['help'] = _Helper(self._pager_help)
175
176 sys.excepthook = excepthook
177
178 #----------------------- Thread management section ----------------------
179 def doExecute(self,line):
180 """
181 Tell the thread to process the 'line' command
182 """
183
184 self._line_to_execute = line
185 #we launch the ipython line execution in a thread to make it interruptible
186 self.ce = _CodeExecutor(self,self._afterExecute)
187 self.ce.start()
188
189 #----------------------- IPython management section ----------------------
190 def getDocText(self):
191 """
192 Returns the output of the processing that need to be paged (if any)
193
194 @return: The std output string.
195 @rtype: string
196 """
197 return self._doc_text
198
199 def getHelpText(self):
200 """
201 Returns the output of the processing that need to be paged via help pager(if any)
202
203 @return: The std output string.
204 @rtype: string
205 """
206 return self._help_text
207
208 def getBanner(self):
209 """
210 Returns the IPython banner for useful info on IPython instance
211
212 @return: The banner string.
213 @rtype: string
214 """
215 return self._IP.BANNER
216
217 def getPromptCount(self):
218 """
219 Returns the prompt number.
220 Each time a user execute a line in the IPython shell the prompt count is increased
221
222 @return: The prompt number
223 @rtype: int
224 """
225 return self._IP.outputcache.prompt_count
226
227 def getPrompt(self):
228 """
229 Returns current prompt inside IPython instance
230 (Can be In [...]: ot ...:)
231
232 @return: The current prompt.
233 @rtype: string
234 """
235 return self._prompt
236
237 def getIndentation(self):
238 """
239 Returns the current indentation level
240 Usefull to put the caret at the good start position if we want to do autoindentation.
241
242 @return: The indentation level.
243 @rtype: int
244 """
245 return self._IP.indent_current_nsp
246
247 def updateNamespace(self, ns_dict):
248 '''
249 Add the current dictionary to the shell namespace.
250
251 @param ns_dict: A dictionary of symbol-values.
252 @type ns_dict: dictionary
253 '''
254 self._IP.user_ns.update(ns_dict)
255
256 def complete(self, line):
257 '''
258 Returns an auto completed line and/or posibilities for completion.
259
260 @param line: Given line so far.
261 @type line: string
262
263 @return: Line completed as for as possible,
264 and possible further completions.
265 @rtype: tuple
266 '''
267 split_line = self._complete_sep.split(line)
268 possibilities = self._IP.complete(split_line[-1])
269 if possibilities:
270
271 def _commonPrefix(str1, str2):
272 '''
273 Reduction function. returns common prefix of two given strings.
274
275 @param str1: First string.
276 @type str1: string
277 @param str2: Second string
278 @type str2: string
279
280 @return: Common prefix to both strings.
281 @rtype: string
282 '''
283 for i in range(len(str1)):
284 if not str2.startswith(str1[:i+1]):
285 return str1[:i]
286 return str1
287 common_prefix = reduce(_commonPrefix, possibilities)
288 completed = line[:-len(split_line[-1])]+common_prefix
289 else:
290 completed = line
291 return completed, possibilities
292
293 def historyBack(self):
294 '''
295 Provides one history command back.
296
297 @return: The command string.
298 @rtype: string
299 '''
300 history = ''
301 #the below while loop is used to suppress empty history lines
302 while((history == '' or history == '\n') and self._history_level >0):
303 if self._history_level>=1:
304 self._history_level -= 1
305 history = self._getHistory()
306 return history
307
308 def historyForward(self):
309 '''
310 Provides one history command forward.
311
312 @return: The command string.
313 @rtype: string
314 '''
315 history = ''
316 #the below while loop is used to suppress empty history lines
317 while((history == '' or history == '\n') and self._history_level <= self._getHistoryMaxIndex()):
318 if self._history_level < self._getHistoryMaxIndex():
319 self._history_level += 1
320 history = self._getHistory()
321 else:
322 if self._history_level == self._getHistoryMaxIndex():
323 history = self._getHistory()
324 self._history_level += 1
325 else:
326 history = ''
327 return history
328
329 def initHistoryIndex(self):
330 '''
331 set history to last command entered
332 '''
333 self._history_level = self._getHistoryMaxIndex()+1
334
335 #----------------------- IPython PRIVATE management section --------------
336 def _afterExecute(self):
337 '''
338 Can be redefined to generate post event after excution is done
339 '''
340 pass
341
342 #def _askExit(self):
343 # '''
344 # Can be redefined to generate post event to exit the Ipython shell
345 # '''
346 # pass
347
348 def _getHistoryMaxIndex(self):
349 '''
350 returns the max length of the history buffer
351
352 @return: history length
353 @rtype: int
354 '''
355 return len(self._IP.input_hist_raw)-1
356
357 def _getHistory(self):
358 '''
359 Get's the command string of the current history level.
360
361 @return: Historic command stri
362 @rtype: string
363 '''
364 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
365 return rv
366
367 def _pager_help(self,text):
368 '''
369 This function is used as a callback replacment to IPython help pager function
370
371 It puts the 'text' value inside the self._help_text string that can be retrived via getHelpText
372 function.
373 '''
374 if self._help_text == None:
375 self._help_text = text
376 else:
377 self._help_text += text
378
379 def _pager(self,IP,text):
380 '''
381 This function is used as a callback replacment to IPython pager function
382
383 It puts the 'text' value inside the self._doc_text string that can be retrived via getDocText
384 function.
385 '''
386 self._doc_text = text
387
388 def _raw_input(self, prompt=''):
389 '''
390 Custom raw_input() replacement. Get's current line from console buffer.
391
392 @param prompt: Prompt to print. Here for compatability as replacement.
393 @type prompt: string
394
395 @return: The current command line text.
396 @rtype: string
397 '''
398 return self._line_to_execute
399
400 def _execute(self):
401 '''
402 Executes the current line provided by the shell object.
403 '''
404 orig_stdout = sys.stdout
405 sys.stdout = IPython.Shell.Term.cout
406
407 try:
408 line = self._IP.raw_input(None, self._iter_more)
409 if self._IP.autoindent:
410 self._IP.readline_startup_hook(None)
411
412 except KeyboardInterrupt:
413 self._IP.write('\nKeyboardInterrupt\n')
414 self._IP.resetbuffer()
415 # keep cache in sync with the prompt counter:
416 self._IP.outputcache.prompt_count -= 1
417
418 if self._IP.autoindent:
419 self._IP.indent_current_nsp = 0
420 self._iter_more = 0
421 except:
422 self._IP.showtraceback()
423 else:
424 self._iter_more = self._IP.push(line)
425 if (self._IP.SyntaxTB.last_syntax_error and
426 self._IP.rc.autoedit_syntax):
427 self._IP.edit_syntax_error()
428 if self._iter_more:
429 self._prompt = str(self._IP.outputcache.prompt2).strip()
430 if self._IP.autoindent:
431 self._IP.readline_startup_hook(self._IP.pre_readline)
432 else:
433 self._prompt = str(self._IP.outputcache.prompt1).strip()
434 self._IP.indent_current_nsp = 0 #we set indentation to 0
435 sys.stdout = orig_stdout
436
437 def _shell(self, ip, cmd):
438 '''
439 Replacement method to allow shell commands without them blocking.
440
441 @param ip: Ipython instance, same as self._IP
442 @type cmd: Ipython instance
443 @param cmd: Shell command to execute.
444 @type cmd: string
445 '''
446 stdin, stdout = os.popen4(cmd)
447 result = stdout.read().decode('cp437').encode(locale.getpreferredencoding())
448 #we use print command because the shell command is called inside IPython instance and thus is
449 #redirected to thread cout
450 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
451 print "\x01\x1b[1;36m\x02"+result
452 stdout.close()
453 stdin.close()
@@ -70,8 +70,8 b' class IPythonHistoryPanel(wx.Panel):'
70 add = False
70 add = False
71 if self.filter_magic.GetValue() == True and history_line[0] == '%':
71 if self.filter_magic.GetValue() == True and history_line[0] == '%':
72 add = False
72 add = False
73 if add:
73 if add:
74 self.text_ctrl.AppendText(history_line+'\n')
74 self.text_ctrl.AppendText(history_line+'\n')
75
75
76
76
77 #----------------------------------------------------------------------
77 #----------------------------------------------------------------------
This diff has been collapsed as it changes many lines, (691 lines changed) Show them Hide them
@@ -1,7 +1,7 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 widget.
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
@@ -30,428 +30,85 b' import wx.lib.newevent'
30
30
31 import re
31 import re
32 import sys
32 import sys
33 import os
34 import locale
33 import locale
35 import time
36 from ThreadEx import Thread
37 from StringIO import StringIO
34 from StringIO import StringIO
38
39 try:
35 try:
40 import IPython
36 import IPython
41 except Exception,e:
37 except Exception,e:
42 raise "Error importing IPython (%s)" % str(e)
38 raise "Error importing IPython (%s)" % str(e)
43
39
44 class IterableIPShell(Thread):
40 from ipshell_nonblocking import NonBlockingIPShell
41
42
43 class WxNonBlockingIPShell(NonBlockingIPShell):
45 '''
44 '''
46 Create an IPython instance inside a dedicated thread.
45 An NonBlockingIPShell Thread that is WX dependent.
47 Does not start a blocking event loop, instead allow single iterations.
48 This allows embedding in any GUI without blockage.
49 The thread is a slave one, in that it doesn't interact directly with the GUI.
50 Note Thread class comes from ThreadEx that supports asynchroneous function call
51 via raise_exc()
52 '''
46 '''
53
47 def __init__(self, parent,
54 def __init__(self,argv=[],user_ns=None,user_global_ns=None,
48 argv=[],user_ns={},user_global_ns=None,
55 cin=None, cout=None, cerr=None,
49 cin=None, cout=None, cerr=None,
56 exit_handler=None,time_loop = 0.1):
50 ask_exit_handler=None):
57 '''
58 @param argv: Command line options for IPython
59 @type argv: list
60 @param user_ns: User namespace.
61 @type user_ns: dictionary
62 @param user_global_ns: User global namespace.
63 @type user_global_ns: dictionary.
64 @param cin: Console standard input.
65 @type cin: IO stream
66 @param cout: Console standard output.
67 @type cout: IO stream
68 @param cerr: Console standard error.
69 @type cerr: IO stream
70 @param exit_handler: Replacement for builtin exit() function
71 @type exit_handler: function
72 @param time_loop: Define the sleep time between two thread's loop
73 @type int
74 '''
75 Thread.__init__(self)
76
77 #first we redefine in/out/error functions of IPython
78 if cin:
79 IPython.Shell.Term.cin = cin
80 if cout:
81 IPython.Shell.Term.cout = cout
82 if cerr:
83 IPython.Shell.Term.cerr = cerr
84
85 # This is to get rid of the blockage that accurs during
86 # IPython.Shell.InteractiveShell.user_setup()
87 IPython.iplib.raw_input = lambda x: None
88
89 self._term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
90
91 excepthook = sys.excepthook
92 self._IP = IPython.Shell.make_IPython(
93 argv,user_ns=user_ns,
94 user_global_ns=user_global_ns,
95 embedded=True,
96 shell_class=IPython.Shell.InteractiveShell)
97
98 #we replace IPython default encoding by wx locale encoding
99 loc = locale.getpreferredencoding()
100 if loc:
101 self._IP.stdin_encoding = loc
102 #we replace the ipython default pager by our pager
103 self._IP.set_hook('show_in_pager',self._pager)
104
105 #we replace the ipython default shell command caller by our shell handler
106 self._IP.set_hook('shell_hook',self._shell)
107
108 #we replace the ipython default input command caller by our method
109 IPython.iplib.raw_input_original = self._raw_input
110 #we replace the ipython default exit command by our method
111 self._IP.exit = self._setAskExit
112
113 sys.excepthook = excepthook
114
115 self._iter_more = 0
116 self._history_level = 0
117 self._complete_sep = re.compile('[\s\{\}\[\]\(\)]')
118 self._prompt = str(self._IP.outputcache.prompt1).strip()
119
120 #thread working vars
121 self._terminate = False
122 self._time_loop = time_loop
123 self._has_doc = False
124 self._do_execute = False
125 self._line_to_execute = ''
126 self._doc_text = None
127 self._ask_exit = False
128
129 #----------------------- Thread management section ----------------------
130 def run (self):
131 """
132 Thread main loop
133 The thread will run until self._terminate will be set to True via shutdown() function
134 Command processing can be interrupted with Instance.raise_exc(KeyboardInterrupt) call in the
135 GUI thread.
136 """
137 while(not self._terminate):
138 try:
139 if self._do_execute:
140 self._doc_text = None
141 self._execute()
142 self._do_execute = False
143
144 except KeyboardInterrupt:
145 pass
146
147 time.sleep(self._time_loop)
148
149 def shutdown(self):
150 """
151 Shutdown the tread
152 """
153 self._terminate = True
154
155 def doExecute(self,line):
156 """
157 Tell the thread to process the 'line' command
158 """
159 self._do_execute = True
160 self._line_to_execute = line
161
162 def isExecuteDone(self):
163 """
164 Returns the processing state
165 """
166 return not self._do_execute
167
168 #----------------------- IPython management section ----------------------
169 def getAskExit(self):
170 '''
171 returns the _ask_exit variable that can be checked by GUI to see if
172 IPython request an exit handling
173 '''
174 return self._ask_exit
175
176 def clearAskExit(self):
177 '''
178 clear the _ask_exit var when GUI as handled the request.
179 '''
180 self._ask_exit = False
181
182 def getDocText(self):
183 """
184 Returns the output of the processing that need to be paged (if any)
185
186 @return: The std output string.
187 @rtype: string
188 """
189 return self._doc_text
190
191 def getBanner(self):
192 """
193 Returns the IPython banner for useful info on IPython instance
194
195 @return: The banner string.
196 @rtype: string
197 """
198 return self._IP.BANNER
199
200 def getPromptCount(self):
201 """
202 Returns the prompt number.
203 Each time a user execute a line in the IPython shell the prompt count is increased
204
205 @return: The prompt number
206 @rtype: int
207 """
208 return self._IP.outputcache.prompt_count
209
210 def getPrompt(self):
211 """
212 Returns current prompt inside IPython instance
213 (Can be In [...]: ot ...:)
214
215 @return: The current prompt.
216 @rtype: string
217 """
218 return self._prompt
219
220 def getIndentation(self):
221 """
222 Returns the current indentation level
223 Usefull to put the caret at the good start position if we want to do autoindentation.
224
225 @return: The indentation level.
226 @rtype: int
227 """
228 return self._IP.indent_current_nsp
229
230 def updateNamespace(self, ns_dict):
231 '''
232 Add the current dictionary to the shell namespace.
233
234 @param ns_dict: A dictionary of symbol-values.
235 @type ns_dict: dictionary
236 '''
237 self._IP.user_ns.update(ns_dict)
238
239 def complete(self, line):
240 '''
241 Returns an auto completed line and/or posibilities for completion.
242
243 @param line: Given line so far.
244 @type line: string
245
246 @return: Line completed as for as possible,
247 and possible further completions.
248 @rtype: tuple
249 '''
250 split_line = self._complete_sep.split(line)
251 possibilities = self._IP.complete(split_line[-1])
252 if possibilities:
253
254 def _commonPrefix(str1, str2):
255 '''
256 Reduction function. returns common prefix of two given strings.
257
258 @param str1: First string.
259 @type str1: string
260 @param str2: Second string
261 @type str2: string
262
263 @return: Common prefix to both strings.
264 @rtype: string
265 '''
266 for i in range(len(str1)):
267 if not str2.startswith(str1[:i+1]):
268 return str1[:i]
269 return str1
270 common_prefix = reduce(_commonPrefix, possibilities)
271 completed = line[:-len(split_line[-1])]+common_prefix
272 else:
273 completed = line
274 return completed, possibilities
275
276 def historyBack(self):
277 '''
278 Provides one history command back.
279
280 @return: The command string.
281 @rtype: string
282 '''
283 history = ''
284 #the below while loop is used to suppress empty history lines
285 while((history == '' or history == '\n') and self._history_level >0):
286 if self._history_level>=1:
287 self._history_level -= 1
288 history = self._getHistory()
289 return history
290
291 def historyForward(self):
292 '''
293 Provides one history command forward.
294
295 @return: The command string.
296 @rtype: string
297 '''
298 history = ''
299 #the below while loop is used to suppress empty history lines
300 while((history == '' or history == '\n') and self._history_level <= self._getHistoryMaxIndex()):
301 if self._history_level < self._getHistoryMaxIndex():
302 self._history_level += 1
303 history = self._getHistory()
304 else:
305 if self._history_level == self._getHistoryMaxIndex():
306 history = self._getHistory()
307 self._history_level += 1
308 else:
309 history = ''
310 return history
311
312 def initHistoryIndex(self):
313 '''
314 set history to last command entered
315 '''
316 self._history_level = self._getHistoryMaxIndex()+1
317
318 #----------------------- IPython PRIVATE management section ----------------------
319 def _setAskExit(self):
320 '''
321 set the _ask_exit variable that can be cjhecked by GUI to see if
322 IPython request an exit handling
323 '''
324 self._ask_exit = True
325
326 def _getHistoryMaxIndex(self):
327 '''
328 returns the max length of the history buffer
329
330 @return: history length
331 @rtype: int
332 '''
333 return len(self._IP.input_hist_raw)-1
334
51
335 def _getHistory(self):
52 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
336 '''
53 cin, cout, cerr,
337 Get's the command string of the current history level.
54 ask_exit_handler)
338
55
339 @return: Historic command string.
56 self.parent = parent
340 @rtype: string
341 '''
342 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
343 return rv
344
57
345 def _pager(self,IP,text):
58 self.ask_exit_callback = ask_exit_handler
346 '''
59 self._IP.exit = self._askExit
347 This function is used as a callback replacment to IPython pager function
348
60
349 It puts the 'text' value inside the self._doc_text string that can be retrived via getDocText
61 def addGUIShortcut(self,text,func):
350 function.
62 wx.CallAfter(self.parent.add_button_handler,
351 '''
63 button_info={ 'text':text,
352 self._doc_text = text
64 'func':self.parent.doExecuteLine(func)})
353
354 def _raw_input(self, prompt=''):
355 '''
356 Custom raw_input() replacement. Get's current line from console buffer.
357
65
358 @param prompt: Prompt to print. Here for compatability as replacement.
66 def _askExit(self):
359 @type prompt: string
67 wx.CallAfter(self.ask_exit_callback, ())
360
68
361 @return: The current command line text.
69 def _afterExecute(self):
362 @rtype: string
70 wx.CallAfter(self.parent.evtStateExecuteDone, ())
363 '''
364 return self._line_to_execute
365
71
366 def _execute(self):
367 '''
368 Executes the current line provided by the shell object.
369 '''
370 orig_stdout = sys.stdout
371 sys.stdout = IPython.Shell.Term.cout
372
72
373 try:
374 line = self._IP.raw_input(None, self._iter_more)
375 if self._IP.autoindent:
376 self._IP.readline_startup_hook(None)
377
378 except KeyboardInterrupt:
379 self._IP.write('\nKeyboardInterrupt\n')
380 self._IP.resetbuffer()
381 # keep cache in sync with the prompt counter:
382 self._IP.outputcache.prompt_count -= 1
383
384 if self._IP.autoindent:
385 self._IP.indent_current_nsp = 0
386 self._iter_more = 0
387 except:
388 self._IP.showtraceback()
389 else:
390 self._iter_more = self._IP.push(line)
391 if (self._IP.SyntaxTB.last_syntax_error and
392 self._IP.rc.autoedit_syntax):
393 self._IP.edit_syntax_error()
394 if self._iter_more:
395 self._prompt = str(self._IP.outputcache.prompt2).strip()
396 if self._IP.autoindent:
397 self._IP.readline_startup_hook(self._IP.pre_readline)
398 else:
399 self._prompt = str(self._IP.outputcache.prompt1).strip()
400 self._IP.indent_current_nsp = 0 #we set indentation to 0
401 sys.stdout = orig_stdout
402
403 def _shell(self, ip, cmd):
404 '''
405 Replacement method to allow shell commands without them blocking.
406
407 @param ip: Ipython instance, same as self._IP
408 @type cmd: Ipython instance
409 @param cmd: Shell command to execute.
410 @type cmd: string
411 '''
412 stdin, stdout = os.popen4(cmd)
413 result = stdout.read().decode('cp437').encode(locale.getpreferredencoding())
414 #we use print command because the shell command is called inside IPython instance and thus is
415 #redirected to thread cout
416 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
417 print "\x01\x1b[1;36m\x02"+result
418 stdout.close()
419 stdin.close()
420
421 class WxConsoleView(stc.StyledTextCtrl):
73 class WxConsoleView(stc.StyledTextCtrl):
422 '''
74 '''
423 Specialized styled text control view for console-like workflow.
75 Specialized styled text control view for console-like workflow.
424 We use here a scintilla frontend thus it can be reused in any GUI taht supports
76 We use here a scintilla frontend thus it can be reused in any GUI that
425 scintilla with less work.
77 supports scintilla with less work.
426
78
427 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.(with Black background)
79 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
80 (with Black background)
428 @type ANSI_COLORS_BLACK: dictionary
81 @type ANSI_COLORS_BLACK: dictionary
429
82
430 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.(with White background)
83 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
84 (with White background)
431 @type ANSI_COLORS_WHITE: dictionary
85 @type ANSI_COLORS_WHITE: dictionary
432
86
433 @ivar color_pat: Regex of terminal color pattern
87 @ivar color_pat: Regex of terminal color pattern
434 @type color_pat: _sre.SRE_Pattern
88 @type color_pat: _sre.SRE_Pattern
435 '''
89 '''
436 ANSI_STYLES_BLACK ={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
90 ANSI_STYLES_BLACK={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
437 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
91 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
438 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
92 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
439 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
93 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
440 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
94 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
441 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
95 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
442 '1;34': [12,'LIGHT BLUE'], '1;35': [13,'MEDIUM VIOLET RED'],
96 '1;34': [12,'LIGHT BLUE'], '1;35':
443 '1;36': [14,'LIGHT STEEL BLUE'], '1;37': [15,'YELLOW']}
97 [13,'MEDIUM VIOLET RED'],
444
98 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
445 ANSI_STYLES_WHITE ={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
99
446 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
100 ANSI_STYLES_WHITE={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
447 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
101 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
448 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
102 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
449 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
103 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
450 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
104 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
451 '1;34': [12,'LIGHT BLUE'], '1;35': [13,'MEDIUM VIOLET RED'],
105 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
452 '1;36': [14,'LIGHT STEEL BLUE'], '1;37': [15,'YELLOW']}
106 '1;34': [12,'LIGHT BLUE'], '1;35':
453
107 [13,'MEDIUM VIOLET RED'],
454 def __init__(self,parent,prompt,intro="",background_color="BLACK",pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
108 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
109
110 def __init__(self,parent,prompt,intro="",background_color="BLACK",
111 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
455 style=0):
112 style=0):
456 '''
113 '''
457 Initialize console view.
114 Initialize console view.
@@ -467,9 +124,10 b' class WxConsoleView(stc.StyledTextCtrl):'
467 '''
124 '''
468 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
125 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
469
126
470 ####### Scintilla configuration ##################################################
127 ####### Scintilla configuration ###################################
471
128
472 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside the widget
129 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
130 # the widget
473 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
131 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
474 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
132 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
475
133
@@ -531,12 +189,16 b' class WxConsoleView(stc.StyledTextCtrl):'
531 self.SetCaretForeground("WHITE")
189 self.SetCaretForeground("WHITE")
532 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
190 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
533
191
534 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "fore:%s,back:%s,size:%d,face:%s" % (self.ANSI_STYLES['0;30'][1],
192 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
535 self.background_color,
193 "fore:%s,back:%s,size:%d,face:%s"
536 faces['size'], faces['mono']))
194 % (self.ANSI_STYLES['0;30'][1],
195 self.background_color,
196 faces['size'], faces['mono']))
537 self.StyleClearAll()
197 self.StyleClearAll()
538 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FF0000,back:#0000FF,bold")
198 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
539 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
199 "fore:#FF0000,back:#0000FF,bold")
200 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
201 "fore:#000000,back:#FF0000,bold")
540
202
541 for style in self.ANSI_STYLES.values():
203 for style in self.ANSI_STYLES.values():
542 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
204 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
@@ -552,7 +214,6 b' class WxConsoleView(stc.StyledTextCtrl):'
552 self.showPrompt()
214 self.showPrompt()
553
215
554 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
216 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
555 #self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
556
217
557 def write(self, text):
218 def write(self, text):
558 '''
219 '''
@@ -720,7 +381,7 b' class WxConsoleView(stc.StyledTextCtrl):'
720 @return: Return True if event as been catched.
381 @return: Return True if event as been catched.
721 @rtype: boolean
382 @rtype: boolean
722 '''
383 '''
723
384
724 if event.GetKeyCode() == wx.WXK_HOME:
385 if event.GetKeyCode() == wx.WXK_HOME:
725 if event.Modifiers == wx.MOD_NONE:
386 if event.Modifiers == wx.MOD_NONE:
726 self.moveCursorOnNewValidKey()
387 self.moveCursorOnNewValidKey()
@@ -744,9 +405,9 b' class WxConsoleView(stc.StyledTextCtrl):'
744
405
745 elif event.GetKeyCode() == wx.WXK_BACK:
406 elif event.GetKeyCode() == wx.WXK_BACK:
746 self.moveCursorOnNewValidKey()
407 self.moveCursorOnNewValidKey()
747 if self.getCursorPos() > self.getCurrentPromptStart():
408 if self.getCursorPos() > self.getCurrentPromptStart():
748 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
409 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
749 return True
410 return True
750
411
751 if skip:
412 if skip:
752 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
413 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
@@ -791,15 +452,20 b' class WxConsoleView(stc.StyledTextCtrl):'
791 #print pt
452 #print pt
792 #self.Refresh(False)
453 #self.Refresh(False)
793
454
794 class WxIPythonViewPanel(wx.Panel):
455 class IPShellWidget(wx.Panel):
795 '''
456 '''
796 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
457 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
797 If you want to port this to any other GUI toolkit, just replace the WxConsoleView
458 If you want to port this to any other GUI toolkit, just replace the
798 by YOURGUIConsoleView and make YOURGUIIPythonView derivate from whatever container you want.
459 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
799 I've choosed to derivate from a wx.Panel because it seems to be ore usefull
460 from whatever container you want. I've choosed to derivate from a wx.Panel
800 Any idea to make it more 'genric' welcomed.
461 because it seems to be more useful
462 Any idea to make it more 'generic' welcomed.
801 '''
463 '''
802 def __init__(self,parent,exit_handler=None,intro=None,background_color="BLACK"):
464
465 def __init__(self, parent, ask_exit_handler=None, intro=None,
466 background_color="BLACK", add_button_handler=None,
467 wx_ip_shell=None,
468 ):
803 '''
469 '''
804 Initialize.
470 Initialize.
805 Instanciate an IPython thread.
471 Instanciate an IPython thread.
@@ -808,16 +474,23 b' class WxIPythonViewPanel(wx.Panel):'
808 '''
474 '''
809 wx.Panel.__init__(self,parent,-1)
475 wx.Panel.__init__(self,parent,-1)
810
476
811 ### IPython thread instanciation ###
477 ### IPython non blocking shell instanciation ###
812 self.cout = StringIO()
478 self.cout = StringIO()
813 self.IP = IterableIPShell(cout=self.cout,cerr=self.cout,
479
814 exit_handler = exit_handler,
480 self.add_button_handler = add_button_handler
815 time_loop = 0.1)
481 self.ask_exit_handler = ask_exit_handler
816 self.IP.start()
482
817
483 if wx_ip_shell is not None:
484 self.IP = wx_ip_shell
485 else:
486 self.IP = WxNonBlockingIPShell(self,
487 cout=self.cout,cerr=self.cout,
488 ask_exit_handler = ask_exit_handler)
489
818 ### IPython wx console view instanciation ###
490 ### IPython wx console view instanciation ###
819 #If user didn't defined an intro text, we create one for him
491 #If user didn't defined an intro text, we create one for him
820 #If you really wnat an empty intrp just call wxIPythonViewPanel with intro=''
492 #If you really wnat an empty intrp just call wxIPythonViewPanel
493 #with intro=''
821 if intro == None:
494 if intro == None:
822 welcome_text = "Welcome to WxIPython Shell.\n\n"
495 welcome_text = "Welcome to WxIPython Shell.\n\n"
823 welcome_text+= self.IP.getBanner()
496 welcome_text+= self.IP.getBanner()
@@ -841,99 +514,69 b' class WxIPythonViewPanel(wx.Panel):'
841 #and we focus on the widget :)
514 #and we focus on the widget :)
842 self.SetFocus()
515 self.SetFocus()
843
516
844 ### below are the thread communication variable ###
517 #widget state management (for key handling different cases)
845 # the IPython thread is managed via unidirectional communication.
518 self.setCurrentState('IDLE')
846 # It's a thread slave that can't interact by itself with the GUI.
519 self.pager_state = 'DONE'
847 # When the GUI event loop is done runStateMachine() is called and the thread sate is then
520
848 # managed.
521 #---------------------- IPython Thread Management ------------------------
849
522 def stateDoExecuteLine(self):
850 #Initialize the state machine #kept for information
523 #print >>sys.__stdout__,"command:",self.getCurrentLine()
851 #self.states = ['IDLE',
524 line=self.text_ctrl.getCurrentLine()
852 # 'DO_EXECUTE_LINE',
525 self.IP.doExecute(line.replace('\t',' '*4))
853 # 'WAIT_END_OF_EXECUTION',
526 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
854 # 'SHOW_DOC',
527 self.setCurrentState('WAIT_END_OF_EXECUTION')
855 # 'SHOW_PROMPT']
528
856
529 def evtStateExecuteDone(self,evt):
857 self.cur_state = 'IDLE'
530 self.doc = self.IP.getDocText()
858 self.pager_state = 'DONE'
531 self.help = self.IP.getHelpText()
859 #wx.CallAfter(self.runStateMachine)
532 if self.doc:
860
533 self.pager_lines = self.doc[7:].split('\n')
861 # This creates a new Event class and a EVT binder function
534 self.pager_state = 'INIT'
862 (self.AskExitEvent, EVT_ASK_EXIT) = wx.lib.newevent.NewEvent()
535 self.setCurrentState('SHOW_DOC')
863
536 self.pager(self.doc)
864 self.Bind(wx.EVT_IDLE, self.runStateMachine)
537 elif self.help:
865 self.Bind(EVT_ASK_EXIT, exit_handler)
538 self.pager_lines = self.help.split('\n')
866
539 self.pager_state = 'INIT'
867 def __del__(self):
540 self.setCurrentState('SHOW_DOC')
868 self.IP.shutdown()
541 self.pager(self.help)
869 self.IP.join()
542 else:
870 WxConsoleView.__del__()
543 self.stateShowPrompt()
871
544
872 #---------------------------- IPython Thread Management ---------------------------------------
545 def stateShowPrompt(self):
873 def runStateMachine(self,event):
546 self.setCurrentState('SHOW_PROMPT')
874 #print >>self.sys_stdout,"state:",self.cur_state
547 self.text_ctrl.setPrompt(self.IP.getPrompt())
548 self.text_ctrl.setIndentation(self.IP.getIndentation())
549 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
550 rv = self.cout.getvalue()
551 if rv: rv = rv.strip('\n')
552 self.text_ctrl.showReturned(rv)
553 self.cout.truncate(0)
554 self.IP.initHistoryIndex()
555 self.setCurrentState('IDLE')
556
557 def setCurrentState(self, state):
558 self.cur_state = state
875 self.updateStatusTracker(self.cur_state)
559 self.updateStatusTracker(self.cur_state)
876
560
877 if self.cur_state == 'DO_EXECUTE_LINE':
878 #print >>self.sys_stdout,"command:",self.getCurrentLine()
879 self.IP.doExecute(self.text_ctrl.getCurrentLine().replace('\t',' '*4))
880 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
881 self.cur_state = 'WAIT_END_OF_EXECUTION'
882
883 if self.cur_state == 'WAIT_END_OF_EXECUTION':
884 if self.IP.isExecuteDone():
885 self.doc = self.IP.getDocText()
886 if self.IP.getAskExit():
887 evt = self.AskExitEvent()
888 wx.PostEvent(self, evt)
889 self.IP.clearAskExit()
890 if self.doc:
891 self.pager_state = 'INIT'
892 self.cur_state = 'SHOW_DOC'
893 else:
894 self.cur_state = 'SHOW_PROMPT'
895
896 if self.cur_state == 'SHOW_PROMPT':
897 self.text_ctrl.setPrompt(self.IP.getPrompt())
898 self.text_ctrl.setIndentation(self.IP.getIndentation())
899 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
900 rv = self.cout.getvalue()
901 if rv: rv = rv.strip('\n')
902 self.text_ctrl.showReturned(rv)
903 self.cout.truncate(0)
904 self.IP.initHistoryIndex()
905 self.cur_state = 'IDLE'
906
907 if self.cur_state == 'SHOW_DOC':
908 self.pager(self.doc)
909 if self.pager_state == 'DONE':
910 self.cur_state = 'SHOW_PROMPT'
911
912 event.Skip()
913
914 #---------------------------- IPython pager ---------------------------------------
561 #---------------------------- IPython pager ---------------------------------------
915 def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
562 def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
916 if self.pager_state == 'WAITING':
563
917 #print >>self.sys_stdout,"PAGER waiting"
564 if self.pager_state == 'INIT':
918 return
565 #print >>sys.__stdout__,"PAGER state:",self.pager_state
919
566 self.pager_nb_lines = len(self.pager_lines)
920 if self.pager_state == 'INIT':
921 #print >>self.sys_stdout,"PAGER state:",self.pager_state
922 self.pager_lines = text[7:].split('\n')
923 self.pager_nb_lines = len(self.pager_lines)
924 self.pager_index = 0
567 self.pager_index = 0
925 self.pager_do_remove = False
568 self.pager_do_remove = False
926 self.text_ctrl.write('\n')
569 self.text_ctrl.write('\n')
927 self.pager_state = 'PROCESS_LINES'
570 self.pager_state = 'PROCESS_LINES'
928
571
929 if self.pager_state == 'PROCESS_LINES':
572 if self.pager_state == 'PROCESS_LINES':
930 #print >>self.sys_stdout,"PAGER state:",self.pager_state
573 #print >>sys.__stdout__,"PAGER state:",self.pager_state
931 if self.pager_do_remove == True:
574 if self.pager_do_remove == True:
932 self.text_ctrl.removeCurrentLine()
575 self.text_ctrl.removeCurrentLine()
933 self.pager_do_remove = False
576 self.pager_do_remove = False
934
577
935 if self.pager_nb_lines > 10:
578 if self.pager_nb_lines > 10:
936 #print >>self.sys_stdout,"PAGER processing 10 lines"
579 #print >>sys.__stdout__,"PAGER processing 10 lines"
937 if self.pager_index > 0:
580 if self.pager_index > 0:
938 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
581 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
939 else:
582 else:
@@ -948,7 +591,7 b' class WxIPythonViewPanel(wx.Panel):'
948 self.pager_state = 'WAITING'
591 self.pager_state = 'WAITING'
949 return
592 return
950 else:
593 else:
951 #print >>self.sys_stdout,"PAGER processing last lines"
594 #print >>sys.__stdout__,"PAGER processing last lines"
952 if self.pager_nb_lines > 0:
595 if self.pager_nb_lines > 0:
953 if self.pager_index > 0:
596 if self.pager_index > 0:
954 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
597 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
@@ -957,42 +600,46 b' class WxIPythonViewPanel(wx.Panel):'
957
600
958 self.pager_index += 1
601 self.pager_index += 1
959 self.pager_nb_lines -= 1
602 self.pager_nb_lines -= 1
960 if self.pager_nb_lines > 0:
603 if self.pager_nb_lines > 0:
961 for line in self.pager_lines[self.pager_index:]:
604 for line in self.pager_lines[self.pager_index:]:
962 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
605 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
963 self.pager_nb_lines = 0
606 self.pager_nb_lines = 0
964 self.pager_state = 'DONE'
607 self.pager_state = 'DONE'
608 self.stateShowPrompt()
965
609
966 #---------------------------- Key Handler --------------------------------------------
610 #------------------------ Key Handler ------------------------------------
967 def keyPress(self, event):
611 def keyPress(self, event):
968 '''
612 '''
969 Key press callback with plenty of shell goodness, like history,
613 Key press callback with plenty of shell goodness, like history,
970 autocompletions, etc.
614 autocompletions, etc.
971 '''
615 '''
972
616
973 if event.GetKeyCode() == ord('C'):
617 if event.GetKeyCode() == ord('C'):
974 if event.Modifiers == wx.MOD_CONTROL:
618 if event.Modifiers == wx.MOD_CONTROL:
975 if self.cur_state == 'WAIT_END_OF_EXECUTION':
619 if self.cur_state == 'WAIT_END_OF_EXECUTION':
976 #we raise an exception inside the IPython thread container
620 #we raise an exception inside the IPython thread container
977 self.IP.raise_exc(KeyboardInterrupt)
621 self.IP.ce.raise_exc(KeyboardInterrupt)
978 return
622 return
979
623
980 if event.KeyCode == wx.WXK_RETURN:
624 if event.KeyCode == wx.WXK_RETURN:
981 if self.cur_state == 'IDLE':
625 if self.cur_state == 'IDLE':
982 #we change the state ot the state machine
626 #we change the state ot the state machine
983 self.cur_state = 'DO_EXECUTE_LINE'
627 self.setCurrentState('DO_EXECUTE_LINE')
628 self.stateDoExecuteLine()
984 return
629 return
985 if self.pager_state == 'WAITING':
630 if self.pager_state == 'WAITING':
986 self.pager_state = 'PROCESS_LINES'
631 self.pager_state = 'PROCESS_LINES'
632 self.pager(self.doc)
987 return
633 return
988
634
989 if event.GetKeyCode() in [ord('q'),ord('Q')]:
635 if event.GetKeyCode() in [ord('q'),ord('Q')]:
990 if self.pager_state == 'WAITING':
636 if self.pager_state == 'WAITING':
991 self.pager_state = 'DONE'
637 self.pager_state = 'DONE'
638 self.stateShowPrompt()
992 return
639 return
993
640
994 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
641 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
995 if self.cur_state == 'IDLE':
642 if self.cur_state == 'IDLE':
996 if event.KeyCode == wx.WXK_UP:
643 if event.KeyCode == wx.WXK_UP:
997 history = self.IP.historyBack()
644 history = self.IP.historyBack()
998 self.text_ctrl.writeHistory(history)
645 self.text_ctrl.writeHistory(history)
@@ -1019,8 +666,8 b' class WxIPythonViewPanel(wx.Panel):'
1019
666
1020 return
667 return
1021 event.Skip()
668 event.Skip()
1022
669
1023 #---------------------------- Hook Section --------------------------------------------
670 #------------------------ Hook Section -----------------------------------
1024 def updateHistoryTracker(self,command_line):
671 def updateHistoryTracker(self,command_line):
1025 '''
672 '''
1026 Default history tracker (does nothing)
673 Default history tracker (does nothing)
@@ -1032,6 +679,7 b' class WxIPythonViewPanel(wx.Panel):'
1032 Define a new history tracker
679 Define a new history tracker
1033 '''
680 '''
1034 self.updateHistoryTracker = func
681 self.updateHistoryTracker = func
682
1035 def updateStatusTracker(self,status):
683 def updateStatusTracker(self,status):
1036 '''
684 '''
1037 Default status tracker (does nothing)
685 Default status tracker (does nothing)
@@ -1043,4 +691,25 b' class WxIPythonViewPanel(wx.Panel):'
1043 Define a new status tracker
691 Define a new status tracker
1044 '''
692 '''
1045 self.updateStatusTracker = func
693 self.updateStatusTracker = func
1046
694
695
696 if __name__ == '__main__':
697 # Some simple code to test the shell widget.
698 class MainWindow(wx.Frame):
699 def __init__(self, parent, id, title):
700 wx.Frame.__init__(self, parent, id, title, size=(300,250))
701 self._sizer = wx.BoxSizer(wx.VERTICAL)
702 self.shell = IPShellWidget(self)
703 self._sizer.Add(self.shell, 1, wx.EXPAND)
704 self.SetSizer(self._sizer)
705 self.SetAutoLayout(1)
706 self.Show(True)
707
708 app = wx.PySimpleApp()
709 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
710 frame.SetSize((780, 460))
711 shell = frame.shell
712
713 app.MainLoop()
714
715
@@ -1,3 +1,8 b''
1 """
2 Thread subclass that can deal with asynchronously function calls via
3 raise_exc.
4 """
5
1 import threading
6 import threading
2 import inspect
7 import inspect
3 import ctypes
8 import ctypes
@@ -17,7 +22,7 b' def _async_raise(tid, exctype):'
17 raise SystemError("PyThreadState_SetAsyncExc failed")
22 raise SystemError("PyThreadState_SetAsyncExc failed")
18
23
19
24
20 class Thread(threading.Thread):
25 class ThreadEx(threading.Thread):
21 def _get_my_tid(self):
26 def _get_my_tid(self):
22 """determines this (self's) thread id"""
27 """determines this (self's) thread id"""
23 if not self.isAlive():
28 if not self.isAlive():
@@ -2,11 +2,13 b''
2 # -*- coding: iso-8859-15 -*-
2 # -*- coding: iso-8859-15 -*-
3
3
4 import wx.aui
4 import wx.aui
5 import wx.py
5
6 #used for about dialog
6 from wx.lib.wordwrap import wordwrap
7 from wx.lib.wordwrap import wordwrap
7
8
8 from ipython_view import *
9 #used for ipython GUI objects
9 from ipython_history import *
10 from IPython.gui.wx.ipython_view import IPShellWidget
11 from IPython.gui.wx.ipython_history import IPythonHistoryPanel
10
12
11 __version__ = 0.8
13 __version__ = 0.8
12 __author__ = "Laurent Dufrechou"
14 __author__ = "Laurent Dufrechou"
@@ -20,7 +22,8 b' __license__ = "BSD"'
20 class MyFrame(wx.Frame):
22 class MyFrame(wx.Frame):
21 """Creating one main frame for our
23 """Creating one main frame for our
22 application with movables windows"""
24 application with movables windows"""
23 def __init__(self, parent=None, id=-1, title="WxIPython", pos=wx.DefaultPosition,
25 def __init__(self, parent=None, id=-1, title="WxIPython",
26 pos=wx.DefaultPosition,
24 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
27 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
25 wx.Frame.__init__(self, parent, id, title, pos, size, style)
28 wx.Frame.__init__(self, parent, id, title, pos, size, style)
26 self._mgr = wx.aui.AuiManager()
29 self._mgr = wx.aui.AuiManager()
@@ -31,15 +34,15 b' class MyFrame(wx.Frame):'
31 #create differents panels and make them persistant
34 #create differents panels and make them persistant
32 self.history_panel = IPythonHistoryPanel(self)
35 self.history_panel = IPythonHistoryPanel(self)
33
36
34 self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
37 self.ipython_panel = IPShellWidget(self,self.OnExitDlg,
35 background_color = "BLACK")
38 background_color = "BLACK")
36
39
37 #self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
40 #self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
38 # background_color = "WHITE")
41 # background_color = "WHITE")
39
42
40 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
43 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
41 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
44 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
42
45
43 self.statusbar = self.createStatus()
46 self.statusbar = self.createStatus()
44 self.createMenu()
47 self.createMenu()
45
48
@@ -48,13 +51,11 b' class MyFrame(wx.Frame):'
48 # main panels
51 # main panels
49 self._mgr.AddPane(self.ipython_panel , wx.CENTER, "IPython Shell")
52 self._mgr.AddPane(self.ipython_panel , wx.CENTER, "IPython Shell")
50 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
53 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
51
54
52 # now we specify some panel characteristics
55 # now we specify some panel characteristics
53 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
56 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
54 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
57 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
55 self._mgr.GetPane(self.history_panel).MinSize((200,400));
58 self._mgr.GetPane(self.history_panel).MinSize((200,400));
56
57
58
59
59 # tell the manager to "commit" all the changes just made
60 # tell the manager to "commit" all the changes just made
60 self._mgr.Update()
61 self._mgr.Update()
General Comments 0
You need to be logged in to leave comments. Login now