##// END OF EJS Templates
Support for true raw_input:...
ldufrechou -
Show More
@@ -1,453 +1,436 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3 '''
4 4 Provides IPython remote instance.
5 5
6 6 @author: Laurent Dufrechou
7 7 laurent.dufrechou _at_ gmail.com
8 8 @license: BSD
9 9
10 10 All rights reserved. This program and the accompanying materials are made
11 11 available under the terms of the BSD which accompanies this distribution, and
12 12 is available at U{http://www.opensource.org/licenses/bsd-license.php}
13 13 '''
14 14
15 15 __version__ = 0.9
16 16 __author__ = "Laurent Dufrechou"
17 17 __email__ = "laurent.dufrechou _at_ gmail.com"
18 18 __license__ = "BSD"
19 19
20 20 import re
21 21 import sys
22 22 import os
23 23 import locale
24 24 import time
25 25 import pydoc,__builtin__,site
26 26 from thread_ex import ThreadEx
27 27 from StringIO import StringIO
28 28
29 29 try:
30 30 import IPython
31 31 except Exception,e:
32 32 raise "Error importing IPython (%s)" % str(e)
33 33
34 34 ##############################################################################
35 35 class _Helper(object):
36 36 """Redefine the built-in 'help'.
37 37 This is a wrapper around pydoc.help (with a twist).
38 38 """
39 39
40 40 def __init__(self,pager):
41 41 self._pager = pager
42 42
43 43 def __repr__(self):
44 44 return "Type help() for interactive help, " \
45 45 "or help(object) for help about object."
46 46
47 47 def __call__(self, *args, **kwds):
48 48 class DummyWriter(object):
49 49 def __init__(self,pager):
50 50 self._pager = pager
51 51
52 52 def write(self,data):
53 53 self._pager(data)
54 54
55 55 import pydoc
56 56 pydoc.help.output = DummyWriter(self._pager)
57 57 pydoc.help.interact = lambda :1
58 58
59 59 return pydoc.help(*args, **kwds)
60 60
61 61
62 62 ##############################################################################
63 63 class _CodeExecutor(ThreadEx):
64 64
65 65 def __init__(self, instance, after):
66 66 ThreadEx.__init__(self)
67 67 self.instance = instance
68 68 self._afterExecute=after
69 69
70 70 def run(self):
71 71 try:
72 72 self.instance._doc_text = None
73 73 self.instance._help_text = None
74 74 self.instance._execute()
75 75 # used for uper class to generate event after execution
76 76 self._afterExecute()
77 77
78 78 except KeyboardInterrupt:
79 79 pass
80 80
81 81
82 82 ##############################################################################
83 83 class NonBlockingIPShell(object):
84 84 '''
85 85 Create an IPython instance, running the commands in a separate,
86 86 non-blocking thread.
87 87 This allows embedding in any GUI without blockage.
88 88
89 89 Note: The ThreadEx class supports asynchroneous function call
90 90 via raise_exc()
91 91 '''
92 92
93 93 def __init__(self,argv=[],user_ns={},user_global_ns=None,
94 94 cin=None, cout=None, cerr=None,
95 ask_exit_handler=None):
95 ask_exit_handler=None, rawinput=None):
96 96 '''
97 97 @param argv: Command line options for IPython
98 98 @type argv: list
99 99 @param user_ns: User namespace.
100 100 @type user_ns: dictionary
101 101 @param user_global_ns: User global namespace.
102 102 @type user_global_ns: dictionary.
103 103 @param cin: Console standard input.
104 104 @type cin: IO stream
105 105 @param cout: Console standard output.
106 106 @type cout: IO stream
107 107 @param cerr: Console standard error.
108 108 @type cerr: IO stream
109 109 @param exit_handler: Replacement for builtin exit() function
110 110 @type exit_handler: function
111 111 @param time_loop: Define the sleep time between two thread's loop
112 112 @type int
113 113 '''
114 114 #ipython0 initialisation
115 115 self.initIpython0(argv, user_ns, user_global_ns,
116 116 cin, cout, cerr,
117 ask_exit_handler)
117 ask_exit_handler, rawinput)
118 118
119 119 #vars used by _execute
120 120 self._iter_more = 0
121 121 self._history_level = 0
122 122 self._complete_sep = re.compile('[\s\{\}\[\]\(\)]')
123 123 self._prompt = str(self._IP.outputcache.prompt1).strip()
124 124
125 125 #thread working vars
126 126 self._line_to_execute = ''
127 127
128 128 #vars that will be checked by GUI loop to handle thread states...
129 129 #will be replaced later by PostEvent GUI funtions...
130 130 self._doc_text = None
131 131 self._help_text = None
132 132 self._add_button = None
133 133
134 134 def initIpython0(self, argv=[], user_ns={}, user_global_ns=None,
135 135 cin=None, cout=None, cerr=None,
136 ask_exit_handler=None):
136 ask_exit_handler=None, rawinput=None):
137 137 #first we redefine in/out/error functions of IPython
138 138 if cin:
139 139 IPython.Shell.Term.cin = cin
140 140 if cout:
141 141 IPython.Shell.Term.cout = cout
142 142 if cerr:
143 143 IPython.Shell.Term.cerr = cerr
144 144
145 145 # This is to get rid of the blockage that accurs during
146 146 # IPython.Shell.InteractiveShell.user_setup()
147 147 IPython.iplib.raw_input = lambda x: None
148 148
149 149 self._term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
150 150
151 151 excepthook = sys.excepthook
152 152
153 153 self._IP = IPython.Shell.make_IPython(
154 154 argv,user_ns=user_ns,
155 155 user_global_ns=user_global_ns,
156 156 embedded=True,
157 157 shell_class=IPython.Shell.InteractiveShell)
158 158
159 159 #we replace IPython default encoding by wx locale encoding
160 160 loc = locale.getpreferredencoding()
161 161 if loc:
162 162 self._IP.stdin_encoding = loc
163 163 #we replace the ipython default pager by our pager
164 164 self._IP.set_hook('show_in_pager',self._pager)
165 165
166 166 #we replace the ipython default shell command caller by our shell handler
167 167 self._IP.set_hook('shell_hook',self._shell)
168 168
169 169 #we replace the ipython default input command caller by our method
170 IPython.iplib.raw_input_original = self._raw_input
170 IPython.iplib.raw_input_original = rawinput
171
171 172 #we replace the ipython default exit command by our method
172 173 self._IP.exit = ask_exit_handler
173 174 #we replace the help command
174 175 self._IP.user_ns['help'] = _Helper(self._pager_help)
175 176
176 177 sys.excepthook = excepthook
177 178
178 179 #----------------------- Thread management section ----------------------
179 180 def doExecute(self,line):
180 181 """
181 182 Tell the thread to process the 'line' command
182 183 """
183 184
184 185 self._line_to_execute = line
185 186 #we launch the ipython line execution in a thread to make it interruptible
186 187 self.ce = _CodeExecutor(self,self._afterExecute)
187 188 self.ce.start()
188 189
189 190 #----------------------- IPython management section ----------------------
190 191 def getDocText(self):
191 192 """
192 193 Returns the output of the processing that need to be paged (if any)
193 194
194 195 @return: The std output string.
195 196 @rtype: string
196 197 """
197 198 return self._doc_text
198 199
199 200 def getHelpText(self):
200 201 """
201 202 Returns the output of the processing that need to be paged via help pager(if any)
202 203
203 204 @return: The std output string.
204 205 @rtype: string
205 206 """
206 207 return self._help_text
207 208
208 209 def getBanner(self):
209 210 """
210 211 Returns the IPython banner for useful info on IPython instance
211 212
212 213 @return: The banner string.
213 214 @rtype: string
214 215 """
215 216 return self._IP.BANNER
216 217
217 218 def getPromptCount(self):
218 219 """
219 220 Returns the prompt number.
220 221 Each time a user execute a line in the IPython shell the prompt count is increased
221 222
222 223 @return: The prompt number
223 224 @rtype: int
224 225 """
225 226 return self._IP.outputcache.prompt_count
226 227
227 228 def getPrompt(self):
228 229 """
229 230 Returns current prompt inside IPython instance
230 231 (Can be In [...]: ot ...:)
231 232
232 233 @return: The current prompt.
233 234 @rtype: string
234 235 """
235 236 return self._prompt
236 237
237 238 def getIndentation(self):
238 239 """
239 240 Returns the current indentation level
240 241 Usefull to put the caret at the good start position if we want to do autoindentation.
241 242
242 243 @return: The indentation level.
243 244 @rtype: int
244 245 """
245 246 return self._IP.indent_current_nsp
246 247
247 248 def updateNamespace(self, ns_dict):
248 249 '''
249 250 Add the current dictionary to the shell namespace.
250 251
251 252 @param ns_dict: A dictionary of symbol-values.
252 253 @type ns_dict: dictionary
253 254 '''
254 255 self._IP.user_ns.update(ns_dict)
255 256
256 257 def complete(self, line):
257 258 '''
258 259 Returns an auto completed line and/or posibilities for completion.
259 260
260 261 @param line: Given line so far.
261 262 @type line: string
262 263
263 264 @return: Line completed as for as possible,
264 265 and possible further completions.
265 266 @rtype: tuple
266 267 '''
267 268 split_line = self._complete_sep.split(line)
268 269 possibilities = self._IP.complete(split_line[-1])
269 270 if possibilities:
270 271
271 272 def _commonPrefix(str1, str2):
272 273 '''
273 274 Reduction function. returns common prefix of two given strings.
274 275
275 276 @param str1: First string.
276 277 @type str1: string
277 278 @param str2: Second string
278 279 @type str2: string
279 280
280 281 @return: Common prefix to both strings.
281 282 @rtype: string
282 283 '''
283 284 for i in range(len(str1)):
284 285 if not str2.startswith(str1[:i+1]):
285 286 return str1[:i]
286 287 return str1
287 288 common_prefix = reduce(_commonPrefix, possibilities)
288 289 completed = line[:-len(split_line[-1])]+common_prefix
289 290 else:
290 291 completed = line
291 292 return completed, possibilities
292 293
293 294 def historyBack(self):
294 295 '''
295 296 Provides one history command back.
296 297
297 298 @return: The command string.
298 299 @rtype: string
299 300 '''
300 301 history = ''
301 302 #the below while loop is used to suppress empty history lines
302 303 while((history == '' or history == '\n') and self._history_level >0):
303 304 if self._history_level>=1:
304 305 self._history_level -= 1
305 306 history = self._getHistory()
306 307 return history
307 308
308 309 def historyForward(self):
309 310 '''
310 311 Provides one history command forward.
311 312
312 313 @return: The command string.
313 314 @rtype: string
314 315 '''
315 316 history = ''
316 317 #the below while loop is used to suppress empty history lines
317 318 while((history == '' or history == '\n') and self._history_level <= self._getHistoryMaxIndex()):
318 319 if self._history_level < self._getHistoryMaxIndex():
319 320 self._history_level += 1
320 321 history = self._getHistory()
321 322 else:
322 323 if self._history_level == self._getHistoryMaxIndex():
323 324 history = self._getHistory()
324 325 self._history_level += 1
325 326 else:
326 327 history = ''
327 328 return history
328 329
329 330 def initHistoryIndex(self):
330 331 '''
331 332 set history to last command entered
332 333 '''
333 334 self._history_level = self._getHistoryMaxIndex()+1
334 335
335 336 #----------------------- IPython PRIVATE management section --------------
336 337 def _afterExecute(self):
337 338 '''
338 339 Can be redefined to generate post event after excution is done
339 340 '''
340 341 pass
341 342
342 #def _askExit(self):
343 # '''
344 # Can be redefined to generate post event to exit the Ipython shell
345 # '''
346 # pass
347
348 343 def _getHistoryMaxIndex(self):
349 344 '''
350 345 returns the max length of the history buffer
351 346
352 347 @return: history length
353 348 @rtype: int
354 349 '''
355 350 return len(self._IP.input_hist_raw)-1
356 351
357 352 def _getHistory(self):
358 353 '''
359 354 Get's the command string of the current history level.
360 355
361 356 @return: Historic command stri
362 357 @rtype: string
363 358 '''
364 359 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
365 360 return rv
366 361
367 362 def _pager_help(self,text):
368 363 '''
369 364 This function is used as a callback replacment to IPython help pager function
370 365
371 366 It puts the 'text' value inside the self._help_text string that can be retrived via getHelpText
372 367 function.
373 368 '''
374 369 if self._help_text == None:
375 370 self._help_text = text
376 371 else:
377 372 self._help_text += text
378 373
379 374 def _pager(self,IP,text):
380 375 '''
381 376 This function is used as a callback replacment to IPython pager function
382 377
383 378 It puts the 'text' value inside the self._doc_text string that can be retrived via getDocText
384 379 function.
385 380 '''
386 381 self._doc_text = text
387 382
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 383 def _execute(self):
401 384 '''
402 385 Executes the current line provided by the shell object.
403 386 '''
404 387 orig_stdout = sys.stdout
405 388 sys.stdout = IPython.Shell.Term.cout
406 389
407 390 try:
408 391 line = self._IP.raw_input(None, self._iter_more)
409 392 if self._IP.autoindent:
410 393 self._IP.readline_startup_hook(None)
411 394
412 395 except KeyboardInterrupt:
413 396 self._IP.write('\nKeyboardInterrupt\n')
414 397 self._IP.resetbuffer()
415 398 # keep cache in sync with the prompt counter:
416 399 self._IP.outputcache.prompt_count -= 1
417 400
418 401 if self._IP.autoindent:
419 402 self._IP.indent_current_nsp = 0
420 403 self._iter_more = 0
421 404 except:
422 405 self._IP.showtraceback()
423 406 else:
424 407 self._iter_more = self._IP.push(line)
425 408 if (self._IP.SyntaxTB.last_syntax_error and
426 409 self._IP.rc.autoedit_syntax):
427 410 self._IP.edit_syntax_error()
428 411 if self._iter_more:
429 412 self._prompt = str(self._IP.outputcache.prompt2).strip()
430 413 if self._IP.autoindent:
431 414 self._IP.readline_startup_hook(self._IP.pre_readline)
432 415 else:
433 416 self._prompt = str(self._IP.outputcache.prompt1).strip()
434 417 self._IP.indent_current_nsp = 0 #we set indentation to 0
435 418 sys.stdout = orig_stdout
436 419
437 420 def _shell(self, ip, cmd):
438 421 '''
439 422 Replacement method to allow shell commands without them blocking.
440 423
441 424 @param ip: Ipython instance, same as self._IP
442 425 @type cmd: Ipython instance
443 426 @param cmd: Shell command to execute.
444 427 @type cmd: string
445 428 '''
446 429 stdin, stdout = os.popen4(cmd)
447 430 result = stdout.read().decode('cp437').encode(locale.getpreferredencoding())
448 431 #we use print command because the shell command is called inside IPython instance and thus is
449 432 #redirected to thread cout
450 433 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
451 434 print "\x01\x1b[1;36m\x02"+result
452 435 stdout.close()
453 436 stdin.close()
@@ -1,720 +1,735 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3 '''
4 4 Provides IPython WX console widgets.
5 5
6 6 @author: Laurent Dufrechou
7 7 laurent.dufrechou _at_ gmail.com
8 8 This WX widget is based on the original work of Eitan Isaacson
9 9 that provided the console for the GTK toolkit.
10 10
11 11 Original work from:
12 12 @author: Eitan Isaacson
13 13 @organization: IBM Corporation
14 14 @copyright: Copyright (c) 2007 IBM Corporation
15 15 @license: BSD
16 16
17 17 All rights reserved. This program and the accompanying materials are made
18 18 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 22 __version__ = 0.8
23 23 __author__ = "Laurent Dufrechou"
24 24 __email__ = "laurent.dufrechou _at_ gmail.com"
25 25 __license__ = "BSD"
26 26
27 27 import wx
28 28 import wx.stc as stc
29 29 import wx.lib.newevent
30 30
31 31 import re
32 32 import sys
33 33 import locale
34 34 from StringIO import StringIO
35 35 try:
36 36 import IPython
37 37 except Exception,e:
38 38 raise "Error importing IPython (%s)" % str(e)
39 39
40 40 from ipshell_nonblocking import NonBlockingIPShell
41 41
42 42
43 43 class WxNonBlockingIPShell(NonBlockingIPShell):
44 44 '''
45 45 An NonBlockingIPShell Thread that is WX dependent.
46 46 '''
47 47 def __init__(self, parent,
48 48 argv=[],user_ns={},user_global_ns=None,
49 49 cin=None, cout=None, cerr=None,
50 ask_exit_handler=None):
50 ask_exit_handler=None, rawinput=None):
51 51
52 52 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
53 53 cin, cout, cerr,
54 ask_exit_handler)
54 ask_exit_handler,
55 rawinput)
55 56
56 57 self.parent = parent
57 58
58 59 self.ask_exit_callback = ask_exit_handler
59 60 self._IP.exit = self._askExit
60 61
61 62 def addGUIShortcut(self,text,func):
62 63 wx.CallAfter(self.parent.add_button_handler,
63 64 button_info={ 'text':text,
64 65 'func':self.parent.doExecuteLine(func)})
65 66
66 67 def _askExit(self):
67 68 wx.CallAfter(self.ask_exit_callback, ())
68 69
69 70 def _afterExecute(self):
70 71 wx.CallAfter(self.parent.evtStateExecuteDone, ())
71 72
72 73
73 74 class WxConsoleView(stc.StyledTextCtrl):
74 75 '''
75 76 Specialized styled text control view for console-like workflow.
76 77 We use here a scintilla frontend thus it can be reused in any GUI that
77 78 supports scintilla with less work.
78 79
79 80 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
80 81 (with Black background)
81 82 @type ANSI_COLORS_BLACK: dictionary
82 83
83 84 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
84 85 (with White background)
85 86 @type ANSI_COLORS_WHITE: dictionary
86 87
87 88 @ivar color_pat: Regex of terminal color pattern
88 89 @type color_pat: _sre.SRE_Pattern
89 90 '''
90 91 ANSI_STYLES_BLACK={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
91 92 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
92 93 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
93 94 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
94 95 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
95 96 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
96 97 '1;34': [12,'LIGHT BLUE'], '1;35':
97 98 [13,'MEDIUM VIOLET RED'],
98 99 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
99 100
100 101 ANSI_STYLES_WHITE={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
101 102 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
102 103 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
103 104 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
104 105 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
105 106 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
106 107 '1;34': [12,'LIGHT BLUE'], '1;35':
107 108 [13,'MEDIUM VIOLET RED'],
108 109 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
109 110
110 111 def __init__(self,parent,prompt,intro="",background_color="BLACK",
111 112 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
112 113 style=0):
113 114 '''
114 115 Initialize console view.
115 116
116 117 @param parent: Parent widget
117 118 @param prompt: User specified prompt
118 119 @type intro: string
119 120 @param intro: User specified startup introduction string
120 121 @type intro: string
121 122 @param background_color: Can be BLACK or WHITE
122 123 @type background_color: string
123 124 @param other: init param of styledTextControl (can be used as-is)
124 125 '''
125 126 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
126 127
127 128 ####### Scintilla configuration ###################################
128 129
129 130 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
130 131 # the widget
131 132 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
132 133 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
133 134
134 135 #we define platform specific fonts
135 136 if wx.Platform == '__WXMSW__':
136 137 faces = { 'times': 'Times New Roman',
137 138 'mono' : 'Courier New',
138 139 'helv' : 'Arial',
139 140 'other': 'Comic Sans MS',
140 141 'size' : 10,
141 142 'size2': 8,
142 143 }
143 144 elif wx.Platform == '__WXMAC__':
144 145 faces = { 'times': 'Times New Roman',
145 146 'mono' : 'Monaco',
146 147 'helv' : 'Arial',
147 148 'other': 'Comic Sans MS',
148 149 'size' : 10,
149 150 'size2': 8,
150 151 }
151 152 else:
152 153 faces = { 'times': 'Times',
153 154 'mono' : 'Courier',
154 155 'helv' : 'Helvetica',
155 156 'other': 'new century schoolbook',
156 157 'size' : 10,
157 158 'size2': 8,
158 159 }
159 160
160 161 #We draw a line at position 80
161 162 self.SetEdgeMode(stc.STC_EDGE_LINE)
162 163 self.SetEdgeColumn(80)
163 164 self.SetEdgeColour(wx.LIGHT_GREY)
164 165
165 166 #self.SetViewWhiteSpace(True)
166 167 #self.SetViewEOL(True)
167 168 self.SetEOLMode(stc.STC_EOL_CRLF)
168 169 #self.SetWrapMode(stc.STC_WRAP_CHAR)
169 170 #self.SetWrapMode(stc.STC_WRAP_WORD)
170 171 self.SetBufferedDraw(True)
171 172 #self.SetUseAntiAliasing(True)
172 173 self.SetLayoutCache(stc.STC_CACHE_PAGE)
173 174
174 175 self.EnsureCaretVisible()
175 176
176 177 self.SetMargins(3,3) #text is moved away from border with 3px
177 178 # Suppressing Scintilla margins
178 179 self.SetMarginWidth(0,0)
179 180 self.SetMarginWidth(1,0)
180 181 self.SetMarginWidth(2,0)
181 182
182 183 # make some styles
183 184 if background_color != "BLACK":
184 185 self.background_color = "WHITE"
185 186 self.SetCaretForeground("BLACK")
186 187 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
187 188 else:
188 189 self.background_color = background_color
189 190 self.SetCaretForeground("WHITE")
190 191 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
191 192
192 193 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
193 194 "fore:%s,back:%s,size:%d,face:%s"
194 195 % (self.ANSI_STYLES['0;30'][1],
195 196 self.background_color,
196 197 faces['size'], faces['mono']))
197 198 self.StyleClearAll()
198 199 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
199 200 "fore:#FF0000,back:#0000FF,bold")
200 201 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
201 202 "fore:#000000,back:#FF0000,bold")
202 203
203 204 for style in self.ANSI_STYLES.values():
204 205 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
205 206
206 207 #######################################################################
207 208
208 209 self.indent = 0
209 210 self.prompt_count = 0
210 211 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
211 212
212 213 self.write(intro)
213 214 self.setPrompt(prompt)
214 215 self.showPrompt()
215 216
216 217 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
217 218
218 219 def write(self, text):
219 220 '''
220 221 Write given text to buffer.
221 222
222 223 @param text: Text to append.
223 224 @type text: string
224 225 '''
225 226 segments = self.color_pat.split(text)
226 227 segment = segments.pop(0)
227 228 self.StartStyling(self.getCurrentLineEnd(),0xFF)
228 229 self.AppendText(segment)
229 230
230 231 if segments:
231 232 ansi_tags = self.color_pat.findall(text)
232 233
233 234 for tag in ansi_tags:
234 235 i = segments.index(tag)
235 236 self.StartStyling(self.getCurrentLineEnd(),0xFF)
236 237 self.AppendText(segments[i+1])
237 238
238 239 if tag != '0':
239 240 self.SetStyling(len(segments[i+1]),self.ANSI_STYLES[tag][0])
240 241
241 242 segments.pop(i)
242 243
243 244 self.moveCursor(self.getCurrentLineEnd())
244 245
245 246 def getPromptLen(self):
246 247 '''
247 248 Return the length of current prompt
248 249 '''
249 250 return len(str(self.prompt_count)) + 7
250 251
251 252 def setPrompt(self,prompt):
252 253 self.prompt = prompt
253 254
254 255 def setIndentation(self,indentation):
255 256 self.indent = indentation
256 257
257 258 def setPromptCount(self,count):
258 259 self.prompt_count = count
259 260
260 261 def showPrompt(self):
261 262 '''
262 263 Prints prompt at start of line.
263 264
264 265 @param prompt: Prompt to print.
265 266 @type prompt: string
266 267 '''
267 268 self.write(self.prompt)
268 269 #now we update the position of end of prompt
269 270 self.current_start = self.getCurrentLineEnd()
270 271
271 272 autoindent = self.indent*' '
272 273 autoindent = autoindent.replace(' ','\t')
273 274 self.write(autoindent)
274 275
275 276 def changeLine(self, text):
276 277 '''
277 278 Replace currently entered command line with given text.
278 279
279 280 @param text: Text to use as replacement.
280 281 @type text: string
281 282 '''
282 283 self.SetSelection(self.getCurrentPromptStart(),self.getCurrentLineEnd())
283 284 self.ReplaceSelection(text)
284 285 self.moveCursor(self.getCurrentLineEnd())
285 286
286 287 def getCurrentPromptStart(self):
287 288 return self.current_start
288 289
289 290 def getCurrentLineStart(self):
290 291 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
291 292
292 293 def getCurrentLineEnd(self):
293 294 return self.GetLength()
294 295
295 296 def getCurrentLine(self):
296 297 '''
297 298 Get text in current command line.
298 299
299 300 @return: Text of current command line.
300 301 @rtype: string
301 302 '''
302 303 return self.GetTextRange(self.getCurrentPromptStart(),
303 304 self.getCurrentLineEnd())
304 305
305 306 def moveCursorOnNewValidKey(self):
306 307 #If cursor is at wrong position put it at last line...
307 308 if self.GetCurrentPos() < self.getCurrentPromptStart():
308 309 self.GotoPos(self.getCurrentPromptStart())
309 310
310 311 def removeFromTo(self,from_pos,to_pos):
311 312 if from_pos < to_pos:
312 313 self.SetSelection(from_pos,to_pos)
313 314 self.DeleteBack()
314 315
315 316 def removeCurrentLine(self):
316 317 self.LineDelete()
317 318
318 319 def moveCursor(self,position):
319 320 self.GotoPos(position)
320 321
321 322 def getCursorPos(self):
322 323 return self.GetCurrentPos()
323 324
324 325 def selectFromTo(self,from_pos,to_pos):
325 326 self.SetSelectionStart(from_pos)
326 327 self.SetSelectionEnd(to_pos)
327 328
328 329 def writeHistory(self,history):
329 330 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
330 331 self.changeLine(history)
331 332
332 333 def writeCompletion(self, possibilities):
333 334 max_len = len(max(possibilities,key=len))
334 335 max_symbol =' '*max_len
335 336
336 337 #now we check how much symbol we can put on a line...
337 338 cursor_pos = self.getCursorPos()
338 339 test_buffer = max_symbol + ' '*4
339 340 current_lines = self.GetLineCount()
340 341
341 342 allowed_symbols = 80/len(test_buffer)
342 343 if allowed_symbols == 0:
343 344 allowed_symbols = 1
344 345
345 346 pos = 1
346 347 buf = ''
347 348 for symbol in possibilities:
348 349 #buf += symbol+'\n'#*spaces)
349 350 if pos<allowed_symbols:
350 351 spaces = max_len - len(symbol) + 4
351 352 buf += symbol+' '*spaces
352 353 pos += 1
353 354 else:
354 355 buf+=symbol+'\n'
355 356 pos = 1
356 357 self.write(buf)
357 358
358 359 def _onKeypress(self, event, skip=True):
359 360 '''
360 361 Key press callback used for correcting behavior for console-like
361 362 interfaces. For example 'home' should go to prompt, not to begining of
362 363 line.
363 364
364 365 @param widget: Widget that key press accored in.
365 366 @type widget: gtk.Widget
366 367 @param event: Event object
367 368 @type event: gtk.gdk.Event
368 369
369 370 @return: Return True if event as been catched.
370 371 @rtype: boolean
371 372 '''
372 373
373 374 if event.GetKeyCode() == wx.WXK_HOME:
374 375 if event.Modifiers == wx.MOD_NONE:
375 376 self.moveCursorOnNewValidKey()
376 377 self.moveCursor(self.getCurrentPromptStart())
377 378 return True
378 379 elif event.Modifiers == wx.MOD_SHIFT:
379 380 self.moveCursorOnNewValidKey()
380 381 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
381 382 return True
382 383 else:
383 384 return False
384 385
385 386 elif event.GetKeyCode() == wx.WXK_LEFT:
386 387 if event.Modifiers == wx.MOD_NONE:
387 388 self.moveCursorOnNewValidKey()
388 389
389 390 self.moveCursor(self.getCursorPos()-1)
390 391 if self.getCursorPos() < self.getCurrentPromptStart():
391 392 self.moveCursor(self.getCurrentPromptStart())
392 393 return True
393 394
394 395 elif event.GetKeyCode() == wx.WXK_BACK:
395 396 self.moveCursorOnNewValidKey()
396 397 if self.getCursorPos() > self.getCurrentPromptStart():
397 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
398 event.Skip()
398 399 return True
399 400
400 401 if skip:
401 402 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
402 403 self.moveCursorOnNewValidKey()
403 404
404 405 event.Skip()
405 406 return True
406 407 return False
407 408
408 409 def OnUpdateUI(self, evt):
409 410 # check for matching braces
410 411 braceAtCaret = -1
411 412 braceOpposite = -1
412 413 charBefore = None
413 414 caretPos = self.GetCurrentPos()
414 415
415 416 if caretPos > 0:
416 417 charBefore = self.GetCharAt(caretPos - 1)
417 418 styleBefore = self.GetStyleAt(caretPos - 1)
418 419
419 420 # check before
420 421 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
421 422 braceAtCaret = caretPos - 1
422 423
423 424 # check after
424 425 if braceAtCaret < 0:
425 426 charAfter = self.GetCharAt(caretPos)
426 427 styleAfter = self.GetStyleAt(caretPos)
427 428
428 429 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
429 430 braceAtCaret = caretPos
430 431
431 432 if braceAtCaret >= 0:
432 433 braceOpposite = self.BraceMatch(braceAtCaret)
433 434
434 435 if braceAtCaret != -1 and braceOpposite == -1:
435 436 self.BraceBadLight(braceAtCaret)
436 437 else:
437 438 self.BraceHighlight(braceAtCaret, braceOpposite)
438 439 #pt = self.PointFromPosition(braceOpposite)
439 440 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
440 441 #print pt
441 442 #self.Refresh(False)
442 443
443 444 class IPShellWidget(wx.Panel):
444 445 '''
445 446 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
446 447 If you want to port this to any other GUI toolkit, just replace the
447 448 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
448 449 from whatever container you want. I've choosed to derivate from a wx.Panel
449 450 because it seems to be more useful
450 451 Any idea to make it more 'generic' welcomed.
451 452 '''
452 453
453 454 def __init__(self, parent, intro=None,
454 455 background_color="BLACK", add_button_handler=None,
455 456 wx_ip_shell=None,
456 457 ):
457 458 '''
458 459 Initialize.
459 460 Instanciate an IPython thread.
460 461 Instanciate a WxConsoleView.
461 462 Redirect I/O to console.
462 463 '''
463 464 wx.Panel.__init__(self,parent,-1)
464 465
465 466 ### IPython non blocking shell instanciation ###
466 467 self.cout = StringIO()
467 468 self.add_button_handler = add_button_handler
468 469
469 470 if wx_ip_shell is not None:
470 471 self.IP = wx_ip_shell
471 472 else:
472 473 self.IP = WxNonBlockingIPShell(self,
473 cout = self.cout,cerr = self.cout,
474 ask_exit_handler = self.askExitCallback)
474 cout = self.cout, cerr = self.cout,
475 ask_exit_handler = self.askExitCallback,
476 rawinput = self.rawInput)
475 477
476 478 ### IPython wx console view instanciation ###
477 479 #If user didn't defined an intro text, we create one for him
478 480 #If you really wnat an empty intrp just call wxIPythonViewPanel
479 481 #with intro=''
480 482 if intro is None:
481 483 welcome_text = "Welcome to WxIPython Shell.\n\n"
482 484 welcome_text+= self.IP.getBanner()
483 485 welcome_text+= "!command -> Execute command in shell\n"
484 486 welcome_text+= "TAB -> Autocompletion\n"
485 487 else:
486 488 welcome_text = intro
487 489
488 490 self.text_ctrl = WxConsoleView(self,
489 491 self.IP.getPrompt(),
490 492 intro=welcome_text,
491 493 background_color=background_color)
492 494
493 495 self.cout.write = self.text_ctrl.write
494 496
495 497 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl)
496 498
497 499 ### making the layout of the panel ###
498 500 sizer = wx.BoxSizer(wx.VERTICAL)
499 501 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
500 502 self.SetAutoLayout(True)
501 503 sizer.Fit(self)
502 504 sizer.SetSizeHints(self)
503 505 self.SetSizer(sizer)
504 506 #and we focus on the widget :)
505 507 self.SetFocus()
506 508
507 509 #widget state management (for key handling different cases)
508 510 self.setCurrentState('IDLE')
509 511 self.pager_state = 'DONE'
510 512
511 513 def askExitCallback(self, event):
512 514 self.askExitHandler(event)
513 515
514 516 #---------------------- IPython Thread Management ------------------------
515 517 def stateDoExecuteLine(self):
516 518 #print >>sys.__stdout__,"command:",self.getCurrentLine()
517 519 line=self.text_ctrl.getCurrentLine()
518 520 self.text_ctrl.write('\n')
519 521 self.IP.doExecute((line.replace('\t',' '*4)).encode('cp1252'))
520 522 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
521 523 self.setCurrentState('WAIT_END_OF_EXECUTION')
522 524
523 525 def evtStateExecuteDone(self,evt):
524 526 self.doc = self.IP.getDocText()
525 527 self.help = self.IP.getHelpText()
526 528 if self.doc:
527 529 self.pager_lines = self.doc[7:].split('\n')
528 530 self.pager_state = 'INIT'
529 531 self.setCurrentState('SHOW_DOC')
530 532 self.pager(self.doc)
531 533 elif self.help:
532 534 self.pager_lines = self.help.split('\n')
533 535 self.pager_state = 'INIT'
534 536 self.setCurrentState('SHOW_DOC')
535 537 self.pager(self.help)
536 538 else:
537 539 self.stateShowPrompt()
538 540
539 541 def stateShowPrompt(self):
540 542 self.setCurrentState('SHOW_PROMPT')
541 543 self.text_ctrl.setPrompt(self.IP.getPrompt())
542 544 self.text_ctrl.setIndentation(self.IP.getIndentation())
543 545 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
544 546 self.text_ctrl.showPrompt()
545 547 self.IP.initHistoryIndex()
546 548 self.setCurrentState('IDLE')
547 549
548 550 def setCurrentState(self, state):
549 551 self.cur_state = state
550 552 self.updateStatusTracker(self.cur_state)
551
553 #---------------------------- Ipython raw_input -----------------------------------
554 def rawInput(self, prompt=''):
555 self.setCurrentState('WAITING_USER_INPUT')
556 while self.cur_state != 'WAIT_END_OF_EXECUTION':
557 pass
558 line = self.text_ctrl.getCurrentLine()
559 line = line.split('\n')
560 return line[-2]
561
552 562 #---------------------------- IPython pager ---------------------------------------
553 def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
563 def pager(self,text):
554 564
555 565 if self.pager_state == 'INIT':
556 566 #print >>sys.__stdout__,"PAGER state:",self.pager_state
557 567 self.pager_nb_lines = len(self.pager_lines)
558 568 self.pager_index = 0
559 569 self.pager_do_remove = False
560 570 self.text_ctrl.write('\n')
561 571 self.pager_state = 'PROCESS_LINES'
562 572
563 573 if self.pager_state == 'PROCESS_LINES':
564 574 #print >>sys.__stdout__,"PAGER state:",self.pager_state
565 575 if self.pager_do_remove == True:
566 576 self.text_ctrl.removeCurrentLine()
567 577 self.pager_do_remove = False
568 578
569 579 if self.pager_nb_lines > 10:
570 580 #print >>sys.__stdout__,"PAGER processing 10 lines"
571 581 if self.pager_index > 0:
572 582 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
573 583 else:
574 584 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
575 585
576 586 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
577 587 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
578 588 self.pager_index += 10
579 589 self.pager_nb_lines -= 10
580 590 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
581 591 self.pager_do_remove = True
582 592 self.pager_state = 'WAITING'
583 593 return
584 594 else:
585 595 #print >>sys.__stdout__,"PAGER processing last lines"
586 596 if self.pager_nb_lines > 0:
587 597 if self.pager_index > 0:
588 598 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
589 599 else:
590 600 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
591 601
592 602 self.pager_index += 1
593 603 self.pager_nb_lines -= 1
594 604 if self.pager_nb_lines > 0:
595 605 for line in self.pager_lines[self.pager_index:]:
596 606 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
597 607 self.pager_nb_lines = 0
598 608 self.pager_state = 'DONE'
599 609 self.stateShowPrompt()
600 610
601 611 #------------------------ Key Handler ------------------------------------
602 612 def keyPress(self, event):
603 613 '''
604 614 Key press callback with plenty of shell goodness, like history,
605 615 autocompletions, etc.
606 616 '''
607 617
608 618 if event.GetKeyCode() == ord('C'):
609 619 if event.Modifiers == wx.MOD_CONTROL:
610 620 if self.cur_state == 'WAIT_END_OF_EXECUTION':
611 621 #we raise an exception inside the IPython thread container
612 622 self.IP.ce.raise_exc(KeyboardInterrupt)
613 623 return
614 624
615 625 if event.KeyCode == wx.WXK_RETURN:
616 626 if self.cur_state == 'IDLE':
617 627 #we change the state ot the state machine
618 628 self.setCurrentState('DO_EXECUTE_LINE')
619 629 self.stateDoExecuteLine()
620 630 return
621 631 if self.pager_state == 'WAITING':
622 632 self.pager_state = 'PROCESS_LINES'
623 633 self.pager(self.doc)
624 634 return
625 635
636 if self.cur_state == 'WAITING_USER_INPUT':
637 line=self.text_ctrl.getCurrentLine()
638 self.text_ctrl.write('\n')
639 self.setCurrentState('WAIT_END_OF_EXECUTION')
640 return
641
626 642 if event.GetKeyCode() in [ord('q'),ord('Q')]:
627 643 if self.pager_state == 'WAITING':
628 644 self.pager_state = 'DONE'
629 645 self.stateShowPrompt()
630 646 return
631 647
632 # if self.cur_state == 'WAIT_END_OF_EXECUTION':
633 # print self.cur_state
634 # self.text_ctrl.write('.')
648 if self.cur_state == 'WAITING_USER_INPUT':
649 event.Skip()
635 650
636 651 if self.cur_state == 'IDLE':
637 652 if event.KeyCode == wx.WXK_UP:
638 653 history = self.IP.historyBack()
639 654 self.text_ctrl.writeHistory(history)
640 655 return
641 656 if event.KeyCode == wx.WXK_DOWN:
642 657 history = self.IP.historyForward()
643 658 self.text_ctrl.writeHistory(history)
644 659 return
645 660 if event.KeyCode == wx.WXK_TAB:
646 661 #if line empty we disable tab completion
647 662 if not self.text_ctrl.getCurrentLine().strip():
648 663 self.text_ctrl.write('\t')
649 664 return
650 665 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
651 666 if len(possibilities) > 1:
652 667 cur_slice = self.text_ctrl.getCurrentLine()
653 668 self.text_ctrl.write('\n')
654 669 self.text_ctrl.writeCompletion(possibilities)
655 670 self.text_ctrl.write('\n')
656 671
657 672 self.text_ctrl.showPrompt()
658 673 self.text_ctrl.write(cur_slice)
659 674 self.text_ctrl.changeLine(completed or cur_slice)
660 675
661 676 return
662 677 event.Skip()
663 678
664 679 #------------------------ Hook Section -----------------------------------
665 680 def updateHistoryTracker(self,command_line):
666 681 '''
667 682 Default history tracker (does nothing)
668 683 '''
669 684 pass
670 685
671 686 def setHistoryTrackerHook(self,func):
672 687 '''
673 688 Define a new history tracker
674 689 '''
675 690 self.updateHistoryTracker = func
676 691
677 692 def updateStatusTracker(self,status):
678 693 '''
679 694 Default status tracker (does nothing)
680 695 '''
681 696 pass
682 697
683 698 def setStatusTrackerHook(self,func):
684 699 '''
685 700 Define a new status tracker
686 701 '''
687 702 self.updateStatusTracker = func
688 703
689 704 def askExitHandler(self, event):
690 705 '''
691 706 Default exit handler
692 707 '''
693 708 self.text_ctrl.write('\nExit callback has not been set.')
694 709
695 710 def setAskExitHandler(self, func):
696 711 '''
697 712 Define an exit handler
698 713 '''
699 714 self.askExitHandler = func
700 715
701 716 if __name__ == '__main__':
702 717 # Some simple code to test the shell widget.
703 718 class MainWindow(wx.Frame):
704 719 def __init__(self, parent, id, title):
705 720 wx.Frame.__init__(self, parent, id, title, size=(300,250))
706 721 self._sizer = wx.BoxSizer(wx.VERTICAL)
707 722 self.shell = IPShellWidget(self)
708 723 self._sizer.Add(self.shell, 1, wx.EXPAND)
709 724 self.SetSizer(self._sizer)
710 725 self.SetAutoLayout(1)
711 726 self.Show(True)
712 727
713 728 app = wx.PySimpleApp()
714 729 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
715 730 frame.SetSize((780, 460))
716 731 shell = frame.shell
717 732
718 733 app.MainLoop()
719 734
720 735
@@ -1,201 +1,202 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3
4 4 import wx.aui
5 5
6 6 #used for about dialog
7 7 from wx.lib.wordwrap import wordwrap
8 8
9 9 #used for ipython GUI objects
10 10 from IPython.gui.wx.ipython_view import IPShellWidget
11 11 from IPython.gui.wx.ipython_history import IPythonHistoryPanel
12 12
13 13 __version__ = 0.8
14 14 __author__ = "Laurent Dufrechou"
15 15 __email__ = "laurent.dufrechou _at_ gmail.com"
16 16 __license__ = "BSD"
17 17
18 18 #-----------------------------------------
19 19 # Creating one main frame for our
20 20 # application with movables windows
21 21 #-----------------------------------------
22 22 class MyFrame(wx.Frame):
23 23 """Creating one main frame for our
24 24 application with movables windows"""
25 25 def __init__(self, parent=None, id=-1, title="WxIPython",
26 26 pos=wx.DefaultPosition,
27 27 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
28 28 wx.Frame.__init__(self, parent, id, title, pos, size, style)
29 29 self._mgr = wx.aui.AuiManager()
30 30
31 31 # notify PyAUI which frame to use
32 32 self._mgr.SetManagedWindow(self)
33 33
34 34 #create differents panels and make them persistant
35 35 self.history_panel = IPythonHistoryPanel(self)
36 36
37 37 self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
38 38
39 39 #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
40 40
41 41 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
42 42 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
43 43 self.ipython_panel.setAskExitHandler(self.OnExitDlg)
44 44
45 45 self.statusbar = self.createStatus()
46 46 self.createMenu()
47 47
48 48 ########################################################################
49 49 ### add the panes to the manager
50 50 # main panels
51 51 self._mgr.AddPane(self.ipython_panel , wx.CENTER, "IPython Shell")
52 52 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
53 53
54 54 # now we specify some panel characteristics
55 55 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
56 56 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
57 57 self._mgr.GetPane(self.history_panel).MinSize((200,400));
58 58
59 59 # tell the manager to "commit" all the changes just made
60 60 self._mgr.Update()
61 61
62 62 #global event handling
63 63 self.Bind(wx.EVT_CLOSE, self.OnClose)
64 64 self.Bind(wx.EVT_MENU, self.OnClose,id=wx.ID_EXIT)
65 65 self.Bind(wx.EVT_MENU, self.OnShowIPythonPanel,id=wx.ID_HIGHEST+1)
66 66 self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2)
67 67 self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3)
68 68 self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6)
69 69
70 70 warn_text = 'Hello from IPython and wxPython.\n'
71 71 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
72 72 warn_text +='It does NOT emulate currently all the IPython functions.\n'
73 73
74 74 dlg = wx.MessageDialog(self,
75 75 warn_text,
76 76 'Warning Box',
77 77 wx.OK | wx.ICON_INFORMATION
78 78 )
79 79 dlg.ShowModal()
80 80 dlg.Destroy()
81 81
82 82 def createMenu(self):
83 83 """local method used to create one menu bar"""
84 84
85 85 mb = wx.MenuBar()
86 86
87 87 file_menu = wx.Menu()
88 88 file_menu.Append(wx.ID_EXIT, "Exit")
89 89
90 90 view_menu = wx.Menu()
91 91 view_menu.Append(wx.ID_HIGHEST+1, "Show IPython Panel")
92 92 view_menu.Append(wx.ID_HIGHEST+2, "Show History Panel")
93 93 view_menu.AppendSeparator()
94 94 view_menu.Append(wx.ID_HIGHEST+6, "Show All")
95 95
96 96 about_menu = wx.Menu()
97 97 about_menu.Append(wx.ID_HIGHEST+3, "About")
98 98
99 99 #view_menu.AppendSeparator()
100 100 #options_menu = wx.Menu()
101 101 #options_menu.AppendCheckItem(wx.ID_HIGHEST+7, "Allow Floating")
102 102 #options_menu.AppendCheckItem(wx.ID_HIGHEST+8, "Transparent Hint")
103 103 #options_menu.AppendCheckItem(wx.ID_HIGHEST+9, "Transparent Hint Fade-in")
104 104
105 105
106 106 mb.Append(file_menu, "File")
107 107 mb.Append(view_menu, "View")
108 108 mb.Append(about_menu, "About")
109 109 #mb.Append(options_menu, "Options")
110 110
111 111 self.SetMenuBar(mb)
112 112
113 113 def createStatus(self):
114 114 statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
115 115 statusbar.SetStatusWidths([-2, -3])
116 116 statusbar.SetStatusText("Ready", 0)
117 117 statusbar.SetStatusText("WxIPython "+str(__version__), 1)
118 118 return statusbar
119 119
120 120 def updateStatus(self,text):
121 121 states = {'IDLE':'Idle',
122 122 'DO_EXECUTE_LINE':'Send command',
123 123 'WAIT_END_OF_EXECUTION':'Running command',
124 'WAITING_USER_INPUT':'Waiting user input',
124 125 'SHOW_DOC':'Showing doc',
125 126 'SHOW_PROMPT':'Showing prompt'}
126 127 self.statusbar.SetStatusText(states[text], 0)
127 128
128 129 def OnClose(self, event):
129 130 """#event used to close program """
130 131 # deinitialize the frame manager
131 132 self._mgr.UnInit()
132 133 self.Destroy()
133 134 event.Skip()
134 135
135 136 def OnExitDlg(self, event):
136 137 dlg = wx.MessageDialog(self, 'Are you sure you want to quit WxIPython',
137 138 'WxIPython exit',
138 139 wx.ICON_QUESTION |
139 140 wx.YES_NO | wx.NO_DEFAULT
140 141 )
141 142 if dlg.ShowModal() == wx.ID_YES:
142 143 dlg.Destroy()
143 144 self._mgr.UnInit()
144 145 self.Destroy()
145 146 dlg.Destroy()
146 147
147 148 #event to display IPython pannel
148 149 def OnShowIPythonPanel(self,event):
149 150 """ #event to display Boxpannel """
150 151 self._mgr.GetPane(self.ipython_panel).Show(True)
151 152 self._mgr.Update()
152 153 #event to display History pannel
153 154 def OnShowHistoryPanel(self,event):
154 155 self._mgr.GetPane(self.history_panel).Show(True)
155 156 self._mgr.Update()
156 157
157 158 def OnShowAllPanel(self,event):
158 159 """#event to display all Pannels"""
159 160 self._mgr.GetPane(self.ipython_panel).Show(True)
160 161 self._mgr.GetPane(self.history_panel).Show(True)
161 162 self._mgr.Update()
162 163
163 164 def OnShowAbout(self, event):
164 165 # First we create and fill the info object
165 166 info = wx.AboutDialogInfo()
166 167 info.Name = "WxIPython"
167 168 info.Version = str(__version__)
168 169 info.Copyright = "(C) 2007 Laurent Dufrechou"
169 170 info.Description = wordwrap(
170 171 "A Gui that embbed a multithreaded IPython Shell",
171 172 350, wx.ClientDC(self))
172 173 info.WebSite = ("http://ipython.scipy.org/", "IPython home page")
173 174 info.Developers = [ "Laurent Dufrechou" ]
174 175 licenseText="BSD License.\nAll rights reserved. This program and the accompanying materials are made available under the terms of the BSD which accompanies this distribution, and is available at http://www.opensource.org/licenses/bsd-license.php"
175 176 info.License = wordwrap(licenseText, 500, wx.ClientDC(self))
176 177
177 178 # Then we call wx.AboutBox giving it that info object
178 179 wx.AboutBox(info)
179 180
180 181 #-----------------------------------------
181 182 #Creating our application
182 183 #-----------------------------------------
183 184 class MyApp(wx.PySimpleApp):
184 185 """Creating our application"""
185 186 def __init__(self):
186 187 wx.PySimpleApp.__init__(self)
187 188
188 189 self.frame = MyFrame()
189 190 self.frame.Show()
190 191
191 192 #-----------------------------------------
192 193 #Main loop
193 194 #-----------------------------------------
194 195 def main():
195 196 app = MyApp()
196 197 app.SetTopWindow(app.frame)
197 198 app.MainLoop()
198 199
199 200 #if launched as main program run this
200 201 if __name__ == '__main__':
201 202 main()
General Comments 0
You need to be logged in to leave comments. Login now