##// END OF EJS Templates
Merged the work with gael
ldufrechou -
r1109:2bff973c merge
parent child Browse files
Show More
@@ -1,454 +1,453 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 def __init__(self,argv
94 =[],user_ns={},user_global_ns=None,
93 def __init__(self,argv=[],user_ns={},user_global_ns=None,
95 94 cin=None, cout=None, cerr=None,
96 95 ask_exit_handler=None):
97 96 '''
98 97 @param argv: Command line options for IPython
99 98 @type argv: list
100 99 @param user_ns: User namespace.
101 100 @type user_ns: dictionary
102 101 @param user_global_ns: User global namespace.
103 102 @type user_global_ns: dictionary.
104 103 @param cin: Console standard input.
105 104 @type cin: IO stream
106 105 @param cout: Console standard output.
107 106 @type cout: IO stream
108 107 @param cerr: Console standard error.
109 108 @type cerr: IO stream
110 109 @param exit_handler: Replacement for builtin exit() function
111 110 @type exit_handler: function
112 111 @param time_loop: Define the sleep time between two thread's loop
113 112 @type int
114 113 '''
115 114 #ipython0 initialisation
116 115 self.initIpython0(argv, user_ns, user_global_ns,
117 116 cin, cout, cerr,
118 117 ask_exit_handler)
119 118
120 119 #vars used by _execute
121 120 self._iter_more = 0
122 121 self._history_level = 0
123 122 self._complete_sep = re.compile('[\s\{\}\[\]\(\)]')
124 123 self._prompt = str(self._IP.outputcache.prompt1).strip()
125 124
126 125 #thread working vars
127 126 self._line_to_execute = ''
128 127
129 128 #vars that will be checked by GUI loop to handle thread states...
130 129 #will be replaced later by PostEvent GUI funtions...
131 130 self._doc_text = None
132 131 self._help_text = None
133 132 self._add_button = None
134 133
135 134 def initIpython0(self, argv=[], user_ns={}, user_global_ns=None,
136 135 cin=None, cout=None, cerr=None,
137 136 ask_exit_handler=None):
138 137 #first we redefine in/out/error functions of IPython
139 138 if cin:
140 139 IPython.Shell.Term.cin = cin
141 140 if cout:
142 141 IPython.Shell.Term.cout = cout
143 142 if cerr:
144 143 IPython.Shell.Term.cerr = cerr
145 144
146 145 # This is to get rid of the blockage that accurs during
147 146 # IPython.Shell.InteractiveShell.user_setup()
148 147 IPython.iplib.raw_input = lambda x: None
149 148
150 149 self._term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
151 150
152 151 excepthook = sys.excepthook
153 152
154 153 self._IP = IPython.Shell.make_IPython(
155 154 argv,user_ns=user_ns,
156 155 user_global_ns=user_global_ns,
157 156 embedded=True,
158 157 shell_class=IPython.Shell.InteractiveShell)
159 158
160 159 #we replace IPython default encoding by wx locale encoding
161 loc = locale.getpreferredencoding()
162 if loc:
163 self._IP.stdin_encoding = loc
160 loc = locale.getpreferredencoding()
161 if loc:
162 self._IP.stdin_encoding = loc
164 163 #we replace the ipython default pager by our pager
165 164 self._IP.set_hook('show_in_pager',self._pager)
166 165
167 166 #we replace the ipython default shell command caller by our shell handler
168 self._IP.set_hook('shell_hook',self._shell)
167 self._IP.set_hook('shell_hook',self._shell)
169 168
170 169 #we replace the ipython default input command caller by our method
171 170 IPython.iplib.raw_input_original = self._raw_input
172 171 #we replace the ipython default exit command by our method
173 172 self._IP.exit = ask_exit_handler
174 173 #we replace the help command
175 174 self._IP.user_ns['help'] = _Helper(self._pager_help)
176 175
177 176 sys.excepthook = excepthook
178 177
179 178 #----------------------- Thread management section ----------------------
180 179 def doExecute(self,line):
181 180 """
182 181 Tell the thread to process the 'line' command
183 182 """
184 183
185 184 self._line_to_execute = line
186 185 #we launch the ipython line execution in a thread to make it interruptible
187 186 self.ce = _CodeExecutor(self,self._afterExecute)
188 187 self.ce.start()
189 188
190 189 #----------------------- IPython management section ----------------------
191 190 def getDocText(self):
192 191 """
193 192 Returns the output of the processing that need to be paged (if any)
194 193
195 194 @return: The std output string.
196 195 @rtype: string
197 196 """
198 197 return self._doc_text
199 198
200 199 def getHelpText(self):
201 200 """
202 201 Returns the output of the processing that need to be paged via help pager(if any)
203 202
204 203 @return: The std output string.
205 204 @rtype: string
206 205 """
207 206 return self._help_text
208 207
209 208 def getBanner(self):
210 209 """
211 210 Returns the IPython banner for useful info on IPython instance
212 211
213 212 @return: The banner string.
214 213 @rtype: string
215 214 """
216 215 return self._IP.BANNER
217 216
218 217 def getPromptCount(self):
219 218 """
220 219 Returns the prompt number.
221 220 Each time a user execute a line in the IPython shell the prompt count is increased
222 221
223 222 @return: The prompt number
224 223 @rtype: int
225 224 """
226 225 return self._IP.outputcache.prompt_count
227 226
228 227 def getPrompt(self):
229 228 """
230 229 Returns current prompt inside IPython instance
231 230 (Can be In [...]: ot ...:)
232 231
233 232 @return: The current prompt.
234 233 @rtype: string
235 234 """
236 235 return self._prompt
237 236
238 237 def getIndentation(self):
239 238 """
240 239 Returns the current indentation level
241 240 Usefull to put the caret at the good start position if we want to do autoindentation.
242 241
243 242 @return: The indentation level.
244 243 @rtype: int
245 244 """
246 245 return self._IP.indent_current_nsp
247 246
248 247 def updateNamespace(self, ns_dict):
249 248 '''
250 249 Add the current dictionary to the shell namespace.
251 250
252 251 @param ns_dict: A dictionary of symbol-values.
253 252 @type ns_dict: dictionary
254 253 '''
255 254 self._IP.user_ns.update(ns_dict)
256 255
257 256 def complete(self, line):
258 257 '''
259 258 Returns an auto completed line and/or posibilities for completion.
260 259
261 260 @param line: Given line so far.
262 261 @type line: string
263 262
264 263 @return: Line completed as for as possible,
265 264 and possible further completions.
266 265 @rtype: tuple
267 266 '''
268 267 split_line = self._complete_sep.split(line)
269 268 possibilities = self._IP.complete(split_line[-1])
270 269 if possibilities:
271 270
272 271 def _commonPrefix(str1, str2):
273 272 '''
274 273 Reduction function. returns common prefix of two given strings.
275 274
276 275 @param str1: First string.
277 276 @type str1: string
278 277 @param str2: Second string
279 278 @type str2: string
280 279
281 280 @return: Common prefix to both strings.
282 281 @rtype: string
283 282 '''
284 283 for i in range(len(str1)):
285 284 if not str2.startswith(str1[:i+1]):
286 285 return str1[:i]
287 286 return str1
288 287 common_prefix = reduce(_commonPrefix, possibilities)
289 288 completed = line[:-len(split_line[-1])]+common_prefix
290 289 else:
291 290 completed = line
292 291 return completed, possibilities
293 292
294 293 def historyBack(self):
295 294 '''
296 295 Provides one history command back.
297 296
298 297 @return: The command string.
299 298 @rtype: string
300 299 '''
301 300 history = ''
302 301 #the below while loop is used to suppress empty history lines
303 while((history == '' or history == '\n') and self._history_level >0):
304 if self._history_level>=1:
305 self._history_level -= 1
306 history = self._getHistory()
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()
307 306 return history
308 307
309 308 def historyForward(self):
310 309 '''
311 310 Provides one history command forward.
312 311
313 312 @return: The command string.
314 313 @rtype: string
315 314 '''
316 history = ''
317 #the below while loop is used to suppress empty history lines
318 while((history == '' or history == '\n') and self._history_level <= self._getHistoryMaxIndex()):
319 if self._history_level < self._getHistoryMaxIndex():
320 self._history_level += 1
321 history = self._getHistory()
322 else:
323 if self._history_level == self._getHistoryMaxIndex():
324 history = self._getHistory()
325 self._history_level += 1
326 else:
327 history = ''
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 = ''
328 327 return history
329 328
330 329 def initHistoryIndex(self):
331 330 '''
332 331 set history to last command entered
333 332 '''
334 333 self._history_level = self._getHistoryMaxIndex()+1
335 334
336 335 #----------------------- IPython PRIVATE management section --------------
337 336 def _afterExecute(self):
338 337 '''
339 338 Can be redefined to generate post event after excution is done
340 339 '''
341 340 pass
342 341
343 342 #def _askExit(self):
344 343 # '''
345 344 # Can be redefined to generate post event to exit the Ipython shell
346 345 # '''
347 346 # pass
348 347
349 348 def _getHistoryMaxIndex(self):
350 349 '''
351 350 returns the max length of the history buffer
352 351
353 352 @return: history length
354 353 @rtype: int
355 354 '''
356 355 return len(self._IP.input_hist_raw)-1
357 356
358 357 def _getHistory(self):
359 358 '''
360 359 Get's the command string of the current history level.
361 360
362 361 @return: Historic command stri
363 362 @rtype: string
364 363 '''
365 364 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
366 365 return rv
367 366
368 367 def _pager_help(self,text):
369 368 '''
370 369 This function is used as a callback replacment to IPython help pager function
371 370
372 371 It puts the 'text' value inside the self._help_text string that can be retrived via getHelpText
373 372 function.
374 373 '''
375 374 if self._help_text == None:
376 375 self._help_text = text
377 376 else:
378 377 self._help_text += text
379 378
380 379 def _pager(self,IP,text):
381 380 '''
382 381 This function is used as a callback replacment to IPython pager function
383 382
384 383 It puts the 'text' value inside the self._doc_text string that can be retrived via getDocText
385 384 function.
386 385 '''
387 386 self._doc_text = text
388 387
389 388 def _raw_input(self, prompt=''):
390 389 '''
391 390 Custom raw_input() replacement. Get's current line from console buffer.
392 391
393 392 @param prompt: Prompt to print. Here for compatability as replacement.
394 393 @type prompt: string
395 394
396 395 @return: The current command line text.
397 396 @rtype: string
398 397 '''
399 398 return self._line_to_execute
400 399
401 400 def _execute(self):
402 401 '''
403 402 Executes the current line provided by the shell object.
404 403 '''
405 404 orig_stdout = sys.stdout
406 405 sys.stdout = IPython.Shell.Term.cout
407 406
408 407 try:
409 408 line = self._IP.raw_input(None, self._iter_more)
410 409 if self._IP.autoindent:
411 410 self._IP.readline_startup_hook(None)
412 411
413 412 except KeyboardInterrupt:
414 413 self._IP.write('\nKeyboardInterrupt\n')
415 414 self._IP.resetbuffer()
416 415 # keep cache in sync with the prompt counter:
417 416 self._IP.outputcache.prompt_count -= 1
418 417
419 418 if self._IP.autoindent:
420 419 self._IP.indent_current_nsp = 0
421 420 self._iter_more = 0
422 421 except:
423 422 self._IP.showtraceback()
424 423 else:
425 424 self._iter_more = self._IP.push(line)
426 425 if (self._IP.SyntaxTB.last_syntax_error and
427 426 self._IP.rc.autoedit_syntax):
428 427 self._IP.edit_syntax_error()
429 428 if self._iter_more:
430 429 self._prompt = str(self._IP.outputcache.prompt2).strip()
431 430 if self._IP.autoindent:
432 431 self._IP.readline_startup_hook(self._IP.pre_readline)
433 432 else:
434 433 self._prompt = str(self._IP.outputcache.prompt1).strip()
435 434 self._IP.indent_current_nsp = 0 #we set indentation to 0
436 435 sys.stdout = orig_stdout
437 436
438 437 def _shell(self, ip, cmd):
439 438 '''
440 439 Replacement method to allow shell commands without them blocking.
441 440
442 441 @param ip: Ipython instance, same as self._IP
443 442 @type cmd: Ipython instance
444 443 @param cmd: Shell command to execute.
445 444 @type cmd: string
446 445 '''
447 446 stdin, stdout = os.popen4(cmd)
448 447 result = stdout.read().decode('cp437').encode(locale.getpreferredencoding())
449 448 #we use print command because the shell command is called inside IPython instance and thus is
450 449 #redirected to thread cout
451 450 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
452 451 print "\x01\x1b[1;36m\x02"+result
453 452 stdout.close()
454 453 stdin.close()
@@ -1,411 +1,411 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3 import wx
4 4 import wx.stc as stc
5 5 import keyword
6 6
7 7 #-----------------------------------------
8 8 # History widget for IPython
9 9 __version__ = 0.5
10 10 __author__ = "Laurent Dufrechou"
11 11 __email__ = "laurent.dufrechou _at_ gmail.com"
12 12 __license__ = "BSD"
13 13 #-----------------------------------------
14 14 class IPythonHistoryPanel(wx.Panel):
15 15
16 16 def __init__(self, parent,flt_empty=True,
17 17 flt_doc=True,flt_cmd=True,flt_magic=True):
18 18
19 19 wx.Panel.__init__(self,parent,-1)
20 20 #text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
21 21 text_ctrl = PythonSTC(self, -1)
22 22
23 23
24 24 st_filt = wx.StaticText(self, -1, " Filter:")
25 25
26 26 self.filter_empty = wx.CheckBox(self, -1, "Empty commands")
27 27 self.filter_doc = wx.CheckBox(self, -1, "?: Doc commands")
28 28 self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
29 29 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
30 30
31 31 self.filter_empty.SetValue(flt_empty)
32 32 self.filter_doc.SetValue(flt_doc)
33 33 self.filter_cmd.SetValue(flt_cmd)
34 34 self.filter_magic.SetValue(flt_magic)
35 35
36 36 sizer = wx.BoxSizer(wx.VERTICAL)
37 37
38 38 sizer.Add(text_ctrl, 1, wx.EXPAND)
39 39 sizer.AddMany( [(5,5),
40 40 st_filt,
41 41 (10,10),
42 42 self.filter_empty,
43 43 self.filter_doc,
44 44 self.filter_cmd,
45 45 self.filter_magic,
46 46 (10,10),
47 47 ])
48 48 self.SetAutoLayout(True)
49 49 sizer.Fit(self)
50 50 sizer.SetSizeHints(self)
51 51 self.SetSizer(sizer)
52 52 self.text_ctrl=text_ctrl
53 53 #text_ctrl.SetText(demoText + open('Main.py').read())
54 54 text_ctrl.EmptyUndoBuffer()
55 55 text_ctrl.Colourise(0, -1)
56 56
57 57 # line numbers in the margin
58 58 text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER)
59 59 text_ctrl.SetMarginWidth(1, 15)
60 60
61 61
62 62 def write(self,history_line):
63 63 add = True
64 64 if self.filter_empty.GetValue() == True and history_line == '':
65 65 add = False
66 66 if len(history_line)>0:
67 67 if self.filter_doc.GetValue() == True and history_line[-1:] == '?':
68 68 add = False
69 69 if self.filter_cmd.GetValue() == True and history_line[0] == '!':
70 70 add = False
71 71 if self.filter_magic.GetValue() == True and history_line[0] == '%':
72 72 add = False
73 if add:
74 self.text_ctrl.AppendText(history_line+'\n')
73 if add:
74 self.text_ctrl.AppendText(history_line+'\n')
75 75
76 76
77 77 #----------------------------------------------------------------------
78 78 # Font definition for Styled Text Control
79 79
80 80 if wx.Platform == '__WXMSW__':
81 81 faces = { 'times': 'Times New Roman',
82 82 'mono' : 'Courier New',
83 83 'helv' : 'Arial',
84 84 'other': 'Comic Sans MS',
85 85 'size' : 8,
86 86 'size2': 6,
87 87 }
88 88 elif wx.Platform == '__WXMAC__':
89 89 faces = { 'times': 'Times New Roman',
90 90 'mono' : 'Monaco',
91 91 'helv' : 'Arial',
92 92 'other': 'Comic Sans MS',
93 93 'size' : 8,
94 94 'size2': 6,
95 95 }
96 96 else:
97 97 faces = { 'times': 'Times',
98 98 'mono' : 'Courier',
99 99 'helv' : 'Helvetica',
100 100 'other': 'new century schoolbook',
101 101 'size' : 8,
102 102 'size2': 6,
103 103 }
104 104
105 105
106 106 #----------------------------------------------------------------------
107 107
108 108 class PythonSTC(stc.StyledTextCtrl):
109 109
110 110 fold_symbols = 3
111 111
112 112 def __init__(self, parent, ID,
113 113 pos=wx.DefaultPosition, size=wx.DefaultSize,
114 114 style=0):
115 115 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
116 116 #self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
117 117 #self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
118 118
119 119 self.SetLexer(stc.STC_LEX_PYTHON)
120 120 self.SetKeyWords(0, " ".join(keyword.kwlist))
121 121
122 122 #self.SetProperty("fold", "1")
123 123 #self.SetProperty("tab.timmy.whinge.level", "1")
124 124 #self.SetMargins(0,0)
125 125
126 126 #self.SetViewWhiteSpace(False)
127 127 #self.SetBufferedDraw(False)
128 128 #self.SetViewEOL(True)
129 129 self.SetEOLMode(stc.STC_EOL_CRLF)
130 130 #self.SetUseAntiAliasing(True)
131 131
132 132 self.SetEdgeMode(stc.STC_EDGE_LINE)
133 133 self.SetEdgeColumn(80)
134 134 self.SetEdgeColour(wx.LIGHT_GREY)
135 135 self.SetLayoutCache(stc.STC_CACHE_PAGE)
136 136
137 137 # Setup a margin to hold fold markers
138 138 #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
139 139 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
140 140 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
141 141 self.SetMarginSensitive(2, True)
142 142 self.SetMarginWidth(2, 12)
143 143
144 144 if self.fold_symbols == 0:
145 145 # Arrow pointing right for contracted folders, arrow pointing down for expanded
146 146 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black")
147 147 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black")
148 148 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black")
149 149 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black")
150 150 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
151 151 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
152 152 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
153 153
154 154 elif self.fold_symbols == 1:
155 155 # Plus for contracted folders, minus for expanded
156 156 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black")
157 157 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black")
158 158 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black")
159 159 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black")
160 160 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black")
161 161 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
162 162 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
163 163
164 164 elif self.fold_symbols == 2:
165 165 # Like a flattened tree control using circular headers and curved joins
166 166 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
167 167 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
168 168 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040")
169 169 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040")
170 170 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
171 171 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
172 172 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040")
173 173
174 174 elif self.fold_symbols == 3:
175 175 # Like a flattened tree control using square headers
176 176 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080")
177 177 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080")
178 178 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080")
179 179 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080")
180 180 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
181 181 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
182 182 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080")
183 183
184 184
185 185 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
186 186 self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
187 187 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
188 188
189 189 # Make some styles, The lexer defines what each style is used for, we
190 190 # just have to define what each style looks like. This set is adapted from
191 191 # Scintilla sample property files.
192 192
193 193 # Global default styles for all languages
194 194 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
195 195 self.StyleClearAll() # Reset all to be like the default
196 196
197 197 # Global default styles for all languages
198 198 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
199 199 self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
200 200 self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
201 201 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
202 202 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
203 203
204 204 # Python styles
205 205 # Default
206 206 self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
207 207 # Comments
208 208 self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
209 209 # Number
210 210 self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
211 211 # String
212 212 self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
213 213 # Single quoted string
214 214 self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
215 215 # Keyword
216 216 self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
217 217 # Triple quotes
218 218 self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
219 219 # Triple double quotes
220 220 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
221 221 # Class name definition
222 222 self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
223 223 # Function or method name definition
224 224 self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
225 225 # Operators
226 226 self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces)
227 227 # Identifiers
228 228 self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
229 229 # Comment-blocks
230 230 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
231 231 # End of line where string is not closed
232 232 self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
233 233
234 234 self.SetCaretForeground("BLUE")
235 235
236 236
237 237 # register some images for use in the AutoComplete box.
238 238 #self.RegisterImage(1, images.getSmilesBitmap())
239 239 #self.RegisterImage(2,
240 240 # wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
241 241 #self.RegisterImage(3,
242 242 # wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
243 243
244 244
245 245 def OnKeyPressed(self, event):
246 246 if self.CallTipActive():
247 247 self.CallTipCancel()
248 248 key = event.GetKeyCode()
249 249
250 250 if key == 32 and event.ControlDown():
251 251 pos = self.GetCurrentPos()
252 252
253 253 # Tips
254 254 if event.ShiftDown():
255 255 self.CallTipSetBackground("yellow")
256 256 self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
257 257 'show some suff, maybe parameters..\n\n'
258 258 'fubar(param1, param2)')
259 259 # Code completion
260 260 else:
261 261 #lst = []
262 262 #for x in range(50000):
263 263 # lst.append('%05d' % x)
264 264 #st = " ".join(lst)
265 265 #print len(st)
266 266 #self.AutoCompShow(0, st)
267 267
268 268 kw = keyword.kwlist[:]
269 269
270 270 kw.sort() # Python sorts are case sensitive
271 271 self.AutoCompSetIgnoreCase(False) # so this needs to match
272 272
273 273 # Images are specified with a appended "?type"
274 274 for i in range(len(kw)):
275 275 if kw[i] in keyword.kwlist:
276 276 kw[i] = kw[i]# + "?1"
277 277
278 278 self.AutoCompShow(0, " ".join(kw))
279 279 else:
280 280 event.Skip()
281 281
282 282
283 283 def OnUpdateUI(self, evt):
284 284 # check for matching braces
285 285 braceAtCaret = -1
286 286 braceOpposite = -1
287 287 charBefore = None
288 288 caretPos = self.GetCurrentPos()
289 289
290 290 if caretPos > 0:
291 291 charBefore = self.GetCharAt(caretPos - 1)
292 292 styleBefore = self.GetStyleAt(caretPos - 1)
293 293
294 294 # check before
295 295 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
296 296 braceAtCaret = caretPos - 1
297 297
298 298 # check after
299 299 if braceAtCaret < 0:
300 300 charAfter = self.GetCharAt(caretPos)
301 301 styleAfter = self.GetStyleAt(caretPos)
302 302
303 303 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
304 304 braceAtCaret = caretPos
305 305
306 306 if braceAtCaret >= 0:
307 307 braceOpposite = self.BraceMatch(braceAtCaret)
308 308
309 309 if braceAtCaret != -1 and braceOpposite == -1:
310 310 self.BraceBadLight(braceAtCaret)
311 311 else:
312 312 self.BraceHighlight(braceAtCaret, braceOpposite)
313 313 #pt = self.PointFromPosition(braceOpposite)
314 314 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
315 315 #print pt
316 316 #self.Refresh(False)
317 317
318 318
319 319 def OnMarginClick(self, evt):
320 320 # fold and unfold as needed
321 321 if evt.GetMargin() == 2:
322 322 if evt.GetShift() and evt.GetControl():
323 323 self.FoldAll()
324 324 else:
325 325 lineClicked = self.LineFromPosition(evt.GetPosition())
326 326
327 327 if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
328 328 if evt.GetShift():
329 329 self.SetFoldExpanded(lineClicked, True)
330 330 self.Expand(lineClicked, True, True, 1)
331 331 elif evt.GetControl():
332 332 if self.GetFoldExpanded(lineClicked):
333 333 self.SetFoldExpanded(lineClicked, False)
334 334 self.Expand(lineClicked, False, True, 0)
335 335 else:
336 336 self.SetFoldExpanded(lineClicked, True)
337 337 self.Expand(lineClicked, True, True, 100)
338 338 else:
339 339 self.ToggleFold(lineClicked)
340 340
341 341
342 342 def FoldAll(self):
343 343 lineCount = self.GetLineCount()
344 344 expanding = True
345 345
346 346 # find out if we are folding or unfolding
347 347 for lineNum in range(lineCount):
348 348 if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
349 349 expanding = not self.GetFoldExpanded(lineNum)
350 350 break
351 351
352 352 lineNum = 0
353 353
354 354 while lineNum < lineCount:
355 355 level = self.GetFoldLevel(lineNum)
356 356 if level & stc.STC_FOLDLEVELHEADERFLAG and \
357 357 (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
358 358
359 359 if expanding:
360 360 self.SetFoldExpanded(lineNum, True)
361 361 lineNum = self.Expand(lineNum, True)
362 362 lineNum = lineNum - 1
363 363 else:
364 364 lastChild = self.GetLastChild(lineNum, -1)
365 365 self.SetFoldExpanded(lineNum, False)
366 366
367 367 if lastChild > lineNum:
368 368 self.HideLines(lineNum+1, lastChild)
369 369
370 370 lineNum = lineNum + 1
371 371
372 372
373 373
374 374 def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
375 375 lastChild = self.GetLastChild(line, level)
376 376 line = line + 1
377 377
378 378 while line <= lastChild:
379 379 if force:
380 380 if visLevels > 0:
381 381 self.ShowLines(line, line)
382 382 else:
383 383 self.HideLines(line, line)
384 384 else:
385 385 if doExpand:
386 386 self.ShowLines(line, line)
387 387
388 388 if level == -1:
389 389 level = self.GetFoldLevel(line)
390 390
391 391 if level & stc.STC_FOLDLEVELHEADERFLAG:
392 392 if force:
393 393 if visLevels > 1:
394 394 self.SetFoldExpanded(line, True)
395 395 else:
396 396 self.SetFoldExpanded(line, False)
397 397
398 398 line = self.Expand(line, doExpand, force, visLevels-1)
399 399
400 400 else:
401 401 if doExpand and self.GetFoldExpanded(line):
402 402 line = self.Expand(line, True, force, visLevels-1)
403 403 else:
404 404 line = self.Expand(line, False, force, visLevels-1)
405 405 else:
406 406 line = line + 1
407 407
408 408 return line
409 409
410 410
411 411 #----------------------------------------------------------------------
@@ -1,702 +1,694 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 os
34 34 import locale
35 35 import time
36 36 from StringIO import StringIO
37 37 try:
38 38 import IPython
39 39 except Exception,e:
40 40 raise "Error importing IPython (%s)" % str(e)
41 41
42
43 42 from ipshell_nonblocking import NonBlockingIPShell
44 43
44
45 45 class WxNonBlockingIPShell(NonBlockingIPShell):
46 46 '''
47 47 An NonBlockingIPShell Thread that is WX dependent.
48 Thus it permits direct interaction with a WX GUI without OnIdle event state machine trick...
49 48 '''
50 def __init__(self,wx_instance,
49 def __init__(self, parent,
51 50 argv=[],user_ns={},user_global_ns=None,
52 51 cin=None, cout=None, cerr=None,
53 52 ask_exit_handler=None):
54 53
55 #user_ns['addGUIShortcut'] = self.addGUIShortcut
56 54 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
57 55 cin, cout, cerr,
58 56 ask_exit_handler)
59 57
60 # This creates a new Event class and a EVT binder function
61 (self.IPythonAskExitEvent, EVT_IP_ASK_EXIT) = wx.lib.newevent.NewEvent()
62 #(self.IPythonAddButtonEvent, EVT_IP_ADD_BUTTON_EXIT) = \
63 # wx.lib.newevent.NewEvent()
64 (self.IPythonExecuteDoneEvent, EVT_IP_EXECUTE_DONE) = \
65 wx.lib.newevent.NewEvent()
58 self.parent = parent
66 59
67 wx_instance.Bind(EVT_IP_ASK_EXIT, wx_instance.ask_exit_handler)
68 #wx_instance.Bind(EVT_IP_ADD_BUTTON_EXIT, wx_instance.add_button_handler)
69 wx_instance.Bind(EVT_IP_EXECUTE_DONE, wx_instance.evtStateExecuteDone)
70
71 self.wx_instance = wx_instance
72 self._IP.ask_exit = self._askExit
60 self.ask_exit_callback = ask_exit_handler
73 61 self._IP.exit = self._askExit
74
75 #def addGUIShortcut(self,text,func):
76 # evt = self.IPythonAddButtonEvent(
77 # button_info={ 'text':text,
78 # 'func':self.wx_instance.doExecuteLine(func)})
79 # wx.PostEvent(self.wx_instance, evt)
80
62
63 def addGUIShortcut(self,text,func):
64 wx.CallAfter(self.parent.add_button_handler,
65 button_info={ 'text':text,
66 'func':self.parent.doExecuteLine(func)})
67
81 68 def _askExit(self):
82 evt = self.IPythonAskExitEvent()
83 wx.PostEvent(self.wx_instance, evt)
69 wx.CallAfter(self.ask_exit_callback, ())
84 70
85 71 def _afterExecute(self):
86 evt = self.IPythonExecuteDoneEvent()
87 wx.PostEvent(self.wx_instance, evt)
72 wx.CallAfter(self.parent.evtStateExecuteDone, ())
88 73
89 74
90 75 class WxConsoleView(stc.StyledTextCtrl):
91 76 '''
92 77 Specialized styled text control view for console-like workflow.
93 78 We use here a scintilla frontend thus it can be reused in any GUI taht supports
94 79 scintilla with less work.
95 80
96 81 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.(with Black background)
97 82 @type ANSI_COLORS_BLACK: dictionary
98 83
99 84 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.(with White background)
100 85 @type ANSI_COLORS_WHITE: dictionary
101 86
102 87 @ivar color_pat: Regex of terminal color pattern
103 88 @type color_pat: _sre.SRE_Pattern
104 89 '''
105 90 ANSI_STYLES_BLACK ={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
106 91 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
107 92 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
108 93 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
109 94 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
110 95 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
111 96 '1;34': [12,'LIGHT BLUE'], '1;35': [13,'MEDIUM VIOLET RED'],
112 97 '1;36': [14,'LIGHT STEEL BLUE'], '1;37': [15,'YELLOW']}
113 98
114 99 ANSI_STYLES_WHITE ={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
115 100 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
116 101 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
117 102 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
118 103 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
119 104 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
120 105 '1;34': [12,'LIGHT BLUE'], '1;35': [13,'MEDIUM VIOLET RED'],
121 106 '1;36': [14,'LIGHT STEEL BLUE'], '1;37': [15,'YELLOW']}
122 107
123 def __init__(self,parent,prompt,intro="",background_color="BLACK",pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
108 def __init__(self,parent,prompt,intro="",background_color="BLACK",
109 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
124 110 style=0):
125 111 '''
126 112 Initialize console view.
127 113
128 114 @param parent: Parent widget
129 115 @param prompt: User specified prompt
130 116 @type intro: string
131 117 @param intro: User specified startup introduction string
132 118 @type intro: string
133 119 @param background_color: Can be BLACK or WHITE
134 120 @type background_color: string
135 121 @param other: init param of styledTextControl (can be used as-is)
136 122 '''
137 123 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
138 124
139 ####### Scintilla configuration ##################################################
125 ####### Scintilla configuration ###################################
140 126
141 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside the widget
127 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
128 # the widget
142 129 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
143 130 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
144 131
145 132 #we define platform specific fonts
146 133 if wx.Platform == '__WXMSW__':
147 134 faces = { 'times': 'Times New Roman',
148 135 'mono' : 'Courier New',
149 136 'helv' : 'Arial',
150 137 'other': 'Comic Sans MS',
151 138 'size' : 10,
152 139 'size2': 8,
153 140 }
154 141 elif wx.Platform == '__WXMAC__':
155 142 faces = { 'times': 'Times New Roman',
156 143 'mono' : 'Monaco',
157 144 'helv' : 'Arial',
158 145 'other': 'Comic Sans MS',
159 146 'size' : 10,
160 147 'size2': 8,
161 148 }
162 149 else:
163 150 faces = { 'times': 'Times',
164 151 'mono' : 'Courier',
165 152 'helv' : 'Helvetica',
166 153 'other': 'new century schoolbook',
167 154 'size' : 10,
168 155 'size2': 8,
169 156 }
170 157
171 158 #We draw a line at position 80
172 159 self.SetEdgeMode(stc.STC_EDGE_LINE)
173 160 self.SetEdgeColumn(80)
174 161 self.SetEdgeColour(wx.LIGHT_GREY)
175 162
176 163 #self.SetViewWhiteSpace(True)
177 164 #self.SetViewEOL(True)
178 165 self.SetEOLMode(stc.STC_EOL_CRLF)
179 166 #self.SetWrapMode(stc.STC_WRAP_CHAR)
180 167 #self.SetWrapMode(stc.STC_WRAP_WORD)
181 168 self.SetBufferedDraw(True)
182 169 #self.SetUseAntiAliasing(True)
183 170 self.SetLayoutCache(stc.STC_CACHE_PAGE)
184 171
185 172 self.EnsureCaretVisible()
186 173
187 174 self.SetMargins(3,3) #text is moved away from border with 3px
188 175 # Suppressing Scintilla margins
189 176 self.SetMarginWidth(0,0)
190 177 self.SetMarginWidth(1,0)
191 178 self.SetMarginWidth(2,0)
192 179
193 180 # make some styles
194 181 if background_color != "BLACK":
195 182 self.background_color = "WHITE"
196 183 self.SetCaretForeground("BLACK")
197 184 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
198 185 else:
199 186 self.background_color = background_color
200 187 self.SetCaretForeground("WHITE")
201 188 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
202 189
203 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "fore:%s,back:%s,size:%d,face:%s" % (self.ANSI_STYLES['0;30'][1],
204 self.background_color,
205 faces['size'], faces['mono']))
190 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
191 "fore:%s,back:%s,size:%d,face:%s"
192 % (self.ANSI_STYLES['0;30'][1],
193 self.background_color,
194 faces['size'], faces['mono']))
206 195 self.StyleClearAll()
207 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FF0000,back:#0000FF,bold")
208 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
196 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
197 "fore:#FF0000,back:#0000FF,bold")
198 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
199 "fore:#000000,back:#FF0000,bold")
209 200
210 201 for style in self.ANSI_STYLES.values():
211 202 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
212 203
213 204 #######################################################################
214 205
215 206 self.indent = 0
216 207 self.prompt_count = 0
217 208 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
218 209
219 210 self.write(intro)
220 211 self.setPrompt(prompt)
221 212 self.showPrompt()
222 213
223 214 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
224 #self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
225 215
226 216 def write(self, text):
227 217 '''
228 218 Write given text to buffer.
229 219
230 220 @param text: Text to append.
231 221 @type text: string
232 222 '''
233 223 segments = self.color_pat.split(text)
234 224 segment = segments.pop(0)
235 225 self.StartStyling(self.getCurrentLineEnd(),0xFF)
236 226 self.AppendText(segment)
237 227
238 228 if segments:
239 229 ansi_tags = self.color_pat.findall(text)
240 230
241 231 for tag in ansi_tags:
242 232 i = segments.index(tag)
243 233 self.StartStyling(self.getCurrentLineEnd(),0xFF)
244 234 self.AppendText(segments[i+1])
245 235
246 236 if tag != '0':
247 237 self.SetStyling(len(segments[i+1]),self.ANSI_STYLES[tag][0])
248 238
249 239 segments.pop(i)
250 240
251 241 self.moveCursor(self.getCurrentLineEnd())
252 242
253 243 def getPromptLen(self):
254 244 '''
255 245 Return the length of current prompt
256 246 '''
257 247 return len(str(self.prompt_count)) + 7
258 248
259 249 def setPrompt(self,prompt):
260 250 self.prompt = prompt
261 251
262 252 def setIndentation(self,indentation):
263 253 self.indent = indentation
264 254
265 255 def setPromptCount(self,count):
266 256 self.prompt_count = count
267 257
268 258 def showPrompt(self):
269 259 '''
270 260 Prints prompt at start of line.
271 261
272 262 @param prompt: Prompt to print.
273 263 @type prompt: string
274 264 '''
275 265 self.write(self.prompt)
276 266 #now we update the position of end of prompt
277 267 self.current_start = self.getCurrentLineEnd()
278 268
279 269 autoindent = self.indent*' '
280 270 autoindent = autoindent.replace(' ','\t')
281 271 self.write(autoindent)
282 272
283 273 def changeLine(self, text):
284 274 '''
285 275 Replace currently entered command line with given text.
286 276
287 277 @param text: Text to use as replacement.
288 278 @type text: string
289 279 '''
290 280 self.SetSelection(self.getCurrentPromptStart(),self.getCurrentLineEnd())
291 281 self.ReplaceSelection(text)
292 282 self.moveCursor(self.getCurrentLineEnd())
293 283
294 284 def getCurrentPromptStart(self):
295 285 return self.current_start
296 286
297 287 def getCurrentLineStart(self):
298 288 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
299 289
300 290 def getCurrentLineEnd(self):
301 291 return self.GetLength()
302 292
303 293 def getCurrentLine(self):
304 294 '''
305 295 Get text in current command line.
306 296
307 297 @return: Text of current command line.
308 298 @rtype: string
309 299 '''
310 300 return self.GetTextRange(self.getCurrentPromptStart(),
311 301 self.getCurrentLineEnd())
312 302
313 303 def showReturned(self, text):
314 304 '''
315 305 Show returned text from last command and print new prompt.
316 306
317 307 @param text: Text to show.
318 308 @type text: string
319 309 '''
320 310 self.write('\n'+text)
321 311 if text:
322 312 self.write('\n')
323 313 self.showPrompt()
324 314
325 315 def moveCursorOnNewValidKey(self):
326 316 #If cursor is at wrong position put it at last line...
327 317 if self.GetCurrentPos() < self.getCurrentPromptStart():
328 318 self.GotoPos(self.getCurrentPromptStart())
329 319
330 320 def removeFromTo(self,from_pos,to_pos):
331 321 if from_pos < to_pos:
332 322 self.SetSelection(from_pos,to_pos)
333 323 self.DeleteBack()
334 324
335 325 def removeCurrentLine(self):
336 326 self.LineDelete()
337 327
338 328 def moveCursor(self,position):
339 329 self.GotoPos(position)
340 330
341 331 def getCursorPos(self):
342 332 return self.GetCurrentPos()
343 333
344 334 def selectFromTo(self,from_pos,to_pos):
345 335 self.SetSelectionStart(from_pos)
346 336 self.SetSelectionEnd(to_pos)
347 337
348 338 def writeHistory(self,history):
349 339 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
350 340 self.changeLine(history)
351 341
352 342 def writeCompletion(self, possibilities):
353 343 max_len = len(max(possibilities,key=len))
354 344 max_symbol =' '*max_len
355 345
356 346 #now we check how much symbol we can put on a line...
357 347 cursor_pos = self.getCursorPos()
358 348 test_buffer = max_symbol + ' '*4
359 349 current_lines = self.GetLineCount()
360 350
361 351 allowed_symbols = 80/len(test_buffer)
362 352 if allowed_symbols == 0:
363 353 allowed_symbols = 1
364 354
365 355 pos = 1
366 356 buf = ''
367 357 for symbol in possibilities:
368 358 #buf += symbol+'\n'#*spaces)
369 359 if pos<allowed_symbols:
370 360 spaces = max_len - len(symbol) + 4
371 361 buf += symbol+' '*spaces
372 362 pos += 1
373 363 else:
374 364 buf+=symbol+'\n'
375 365 pos = 1
376 366 self.write(buf)
377 367
378 368 def _onKeypress(self, event, skip=True):
379 369 '''
380 370 Key press callback used for correcting behavior for console-like
381 371 interfaces. For example 'home' should go to prompt, not to begining of
382 372 line.
383 373
384 374 @param widget: Widget that key press accored in.
385 375 @type widget: gtk.Widget
386 376 @param event: Event object
387 377 @type event: gtk.gdk.Event
388 378
389 379 @return: Return True if event as been catched.
390 380 @rtype: boolean
391 381 '''
392
382
393 383 if event.GetKeyCode() == wx.WXK_HOME:
394 384 if event.Modifiers == wx.MOD_NONE:
395 385 self.moveCursorOnNewValidKey()
396 386 self.moveCursor(self.getCurrentPromptStart())
397 387 return True
398 388 elif event.Modifiers == wx.MOD_SHIFT:
399 389 self.moveCursorOnNewValidKey()
400 390 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
401 391 return True
402 392 else:
403 393 return False
404 394
405 395 elif event.GetKeyCode() == wx.WXK_LEFT:
406 396 if event.Modifiers == wx.MOD_NONE:
407 397 self.moveCursorOnNewValidKey()
408 398
409 399 self.moveCursor(self.getCursorPos()-1)
410 400 if self.getCursorPos() < self.getCurrentPromptStart():
411 401 self.moveCursor(self.getCurrentPromptStart())
412 402 return True
413 403
414 404 elif event.GetKeyCode() == wx.WXK_BACK:
415 405 self.moveCursorOnNewValidKey()
416 if self.getCursorPos() > self.getCurrentPromptStart():
406 if self.getCursorPos() > self.getCurrentPromptStart():
417 407 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
418 return True
408 return True
419 409
420 410 if skip:
421 411 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
422 412 self.moveCursorOnNewValidKey()
423 413
424 414 event.Skip()
425 415 return True
426 416 return False
427 417
428 418 def OnUpdateUI(self, evt):
429 419 # check for matching braces
430 420 braceAtCaret = -1
431 421 braceOpposite = -1
432 422 charBefore = None
433 423 caretPos = self.GetCurrentPos()
434 424
435 425 if caretPos > 0:
436 426 charBefore = self.GetCharAt(caretPos - 1)
437 427 styleBefore = self.GetStyleAt(caretPos - 1)
438 428
439 429 # check before
440 430 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
441 431 braceAtCaret = caretPos - 1
442 432
443 433 # check after
444 434 if braceAtCaret < 0:
445 435 charAfter = self.GetCharAt(caretPos)
446 436 styleAfter = self.GetStyleAt(caretPos)
447 437
448 438 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
449 439 braceAtCaret = caretPos
450 440
451 441 if braceAtCaret >= 0:
452 442 braceOpposite = self.BraceMatch(braceAtCaret)
453 443
454 444 if braceAtCaret != -1 and braceOpposite == -1:
455 445 self.BraceBadLight(braceAtCaret)
456 446 else:
457 447 self.BraceHighlight(braceAtCaret, braceOpposite)
458 448 #pt = self.PointFromPosition(braceOpposite)
459 449 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
460 450 #print pt
461 451 #self.Refresh(False)
462 452
463 453 class WxIPythonViewPanel(wx.Panel):
464 454 '''
465 455 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
466 456 If you want to port this to any other GUI toolkit, just replace the WxConsoleView
467 457 by YOURGUIConsoleView and make YOURGUIIPythonView derivate from whatever container you want.
468 458 I've choosed to derivate from a wx.Panel because it seems to be ore usefull
469 459 Any idea to make it more 'genric' welcomed.
470 460 '''
471 461
472 462 def __init__(self, parent, ask_exit_handler=None, intro=None,
473 463 background_color="BLACK", add_button_handler=None,
474 464 wx_ip_shell=None,
475 465 ):
476 466 '''
477 467 Initialize.
478 468 Instanciate an IPython thread.
479 469 Instanciate a WxConsoleView.
480 470 Redirect I/O to console.
481 471 '''
482 472 wx.Panel.__init__(self,parent,-1)
483 473
484 474 ### IPython non blocking shell instanciation ###
485 475 self.cout = StringIO()
486 476
487 477 self.add_button_handler = add_button_handler
488 478 self.ask_exit_handler = ask_exit_handler
489 479
490 480 if wx_ip_shell is not None:
491 481 self.IP = wx_ip_shell
492 482 else:
493 483 self.IP = WxNonBlockingIPShell(self,
494 484 cout=self.cout,cerr=self.cout,
495 485 ask_exit_handler = ask_exit_handler)
496 486
497 487 ### IPython wx console view instanciation ###
498 488 #If user didn't defined an intro text, we create one for him
499 #If you really wnat an empty intrp just call wxIPythonViewPanel with intro=''
489 #If you really wnat an empty intrp just call wxIPythonViewPanel
490 #with intro=''
500 491 if intro == None:
501 492 welcome_text = "Welcome to WxIPython Shell.\n\n"
502 493 welcome_text+= self.IP.getBanner()
503 494 welcome_text+= "!command -> Execute command in shell\n"
504 495 welcome_text+= "TAB -> Autocompletion\n"
505 496
506 497 self.text_ctrl = WxConsoleView(self,
507 498 self.IP.getPrompt(),
508 499 intro=welcome_text,
509 500 background_color=background_color)
510 501
511 502 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl)
512 503
513 504 ### making the layout of the panel ###
514 505 sizer = wx.BoxSizer(wx.VERTICAL)
515 506 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
516 507 self.SetAutoLayout(True)
517 508 sizer.Fit(self)
518 509 sizer.SetSizeHints(self)
519 510 self.SetSizer(sizer)
520 511 #and we focus on the widget :)
521 512 self.SetFocus()
522 513
523 514 #widget state management (for key handling different cases)
524 515 self.setCurrentState('IDLE')
525 516 self.pager_state = 'DONE'
526
517
527 518 def __del__(self):
528 519 WxConsoleView.__del__()
529 520
530 #---------------------------- IPython Thread Management ---------------------------------------
521 #---------------------- IPython Thread Management ------------------------
531 522 def stateDoExecuteLine(self):
532 523 #print >>sys.__stdout__,"command:",self.getCurrentLine()
533 524 line=self.text_ctrl.getCurrentLine()
534 525 self.IP.doExecute(line.replace('\t',' '*4))
535 526 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
536 527 self.setCurrentState('WAIT_END_OF_EXECUTION')
537 528
538 529 def evtStateExecuteDone(self,evt):
539 530 self.doc = self.IP.getDocText()
540 531 self.help = self.IP.getHelpText()
541 532 if self.doc:
542 533 self.pager_lines = self.doc[7:].split('\n')
543 534 self.pager_state = 'INIT'
544 535 self.setCurrentState('SHOW_DOC')
545 536 self.pager(self.doc)
546 537 elif self.help:
547 538 self.pager_lines = self.help.split('\n')
548 539 self.pager_state = 'INIT'
549 540 self.setCurrentState('SHOW_DOC')
550 541 self.pager(self.help)
551 542 else:
552 543 self.stateShowPrompt()
553 544
554 545 def stateShowPrompt(self):
555 546 self.setCurrentState('SHOW_PROMPT')
556 547 self.text_ctrl.setPrompt(self.IP.getPrompt())
557 548 self.text_ctrl.setIndentation(self.IP.getIndentation())
558 549 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
559 550 rv = self.cout.getvalue()
560 551 if rv: rv = rv.strip('\n')
561 552 self.text_ctrl.showReturned(rv)
562 553 self.cout.truncate(0)
563 554 self.IP.initHistoryIndex()
564 555 self.setCurrentState('IDLE')
565 556
566 557 def setCurrentState(self, state):
567 558 self.cur_state = state
568 559 self.updateStatusTracker(self.cur_state)
569 560
570 561 #---------------------------- IPython pager ---------------------------------------
571 562 def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
572 563
573 564 if self.pager_state == 'INIT':
574 565 #print >>sys.__stdout__,"PAGER state:",self.pager_state
575 566 self.pager_nb_lines = len(self.pager_lines)
576 567 self.pager_index = 0
577 568 self.pager_do_remove = False
578 569 self.text_ctrl.write('\n')
579 570 self.pager_state = 'PROCESS_LINES'
580 571
581 572 if self.pager_state == 'PROCESS_LINES':
582 573 #print >>sys.__stdout__,"PAGER state:",self.pager_state
583 574 if self.pager_do_remove == True:
584 575 self.text_ctrl.removeCurrentLine()
585 576 self.pager_do_remove = False
586 577
587 578 if self.pager_nb_lines > 10:
588 579 #print >>sys.__stdout__,"PAGER processing 10 lines"
589 580 if self.pager_index > 0:
590 581 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
591 582 else:
592 583 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
593 584
594 585 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
595 586 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
596 587 self.pager_index += 10
597 588 self.pager_nb_lines -= 10
598 589 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
599 590 self.pager_do_remove = True
600 591 self.pager_state = 'WAITING'
601 592 return
602 593 else:
603 594 #print >>sys.__stdout__,"PAGER processing last lines"
604 595 if self.pager_nb_lines > 0:
605 596 if self.pager_index > 0:
606 597 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
607 598 else:
608 599 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
609 600
610 601 self.pager_index += 1
611 602 self.pager_nb_lines -= 1
612 if self.pager_nb_lines > 0:
613 for line in self.pager_lines[self.pager_index:]:
614 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
615 self.pager_nb_lines = 0
616 self.pager_state = 'DONE'
617 self.stateShowPrompt()
603 if self.pager_nb_lines > 0:
604 for line in self.pager_lines[self.pager_index:]:
605 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
606 self.pager_nb_lines = 0
607 self.pager_state = 'DONE'
608 self.stateShowPrompt()
618 609
619 #---------------------------- Key Handler --------------------------------------------
610 #------------------------ Key Handler ------------------------------------
620 611 def keyPress(self, event):
621 612 '''
622 613 Key press callback with plenty of shell goodness, like history,
623 614 autocompletions, etc.
624 615 '''
625
616
626 617 if event.GetKeyCode() == ord('C'):
627 618 if event.Modifiers == wx.MOD_CONTROL:
628 619 if self.cur_state == 'WAIT_END_OF_EXECUTION':
629 620 #we raise an exception inside the IPython thread container
630 621 self.IP.ce.raise_exc(KeyboardInterrupt)
631 622 return
632 623
633 624 if event.KeyCode == wx.WXK_RETURN:
634 625 if self.cur_state == 'IDLE':
635 626 #we change the state ot the state machine
636 627 self.setCurrentState('DO_EXECUTE_LINE')
637 628 self.stateDoExecuteLine()
638 629 return
639 630 if self.pager_state == 'WAITING':
640 631 self.pager_state = 'PROCESS_LINES'
641 632 self.pager(self.doc)
642 633 return
643 634
644 635 if event.GetKeyCode() in [ord('q'),ord('Q')]:
645 636 if self.pager_state == 'WAITING':
646 637 self.pager_state = 'DONE'
647 638 self.stateShowPrompt()
648 639 return
649 640
650 641 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
651 if self.cur_state == 'IDLE':
642 if self.cur_state == 'IDLE':
652 643 if event.KeyCode == wx.WXK_UP:
653 644 history = self.IP.historyBack()
654 645 self.text_ctrl.writeHistory(history)
655 646 return
656 647 if event.KeyCode == wx.WXK_DOWN:
657 648 history = self.IP.historyForward()
658 649 self.text_ctrl.writeHistory(history)
659 650 return
660 651 if event.KeyCode == wx.WXK_TAB:
661 652 #if line empty we disable tab completion
662 653 if not self.text_ctrl.getCurrentLine().strip():
663 654 self.text_ctrl.write('\t')
664 655 return
665 656 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
666 657 if len(possibilities) > 1:
667 658 cur_slice = self.text_ctrl.getCurrentLine()
668 659 self.text_ctrl.write('\n')
669 660 self.text_ctrl.writeCompletion(possibilities)
670 661 self.text_ctrl.write('\n')
671 662
672 663 self.text_ctrl.showPrompt()
673 664 self.text_ctrl.write(cur_slice)
674 665 self.text_ctrl.changeLine(completed or cur_slice)
675 666
676 667 return
677 668 event.Skip()
678
679 #---------------------------- Hook Section --------------------------------------------
669
670 #------------------------ Hook Section -----------------------------------
680 671 def updateHistoryTracker(self,command_line):
681 672 '''
682 673 Default history tracker (does nothing)
683 674 '''
684 675 pass
685 676
686 677 def setHistoryTrackerHook(self,func):
687 678 '''
688 679 Define a new history tracker
689 680 '''
690 681 self.updateHistoryTracker = func
682
691 683 def updateStatusTracker(self,status):
692 684 '''
693 685 Default status tracker (does nothing)
694 686 '''
695 687 pass
696 688
697 689 def setStatusTrackerHook(self,func):
698 690 '''
699 691 Define a new status tracker
700 692 '''
701 693 self.updateStatusTracker = func
702 694
@@ -1,201 +1,201 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 WxIPythonViewPanel
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", pos=wx.DefaultPosition,
26 26 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
27 27 wx.Frame.__init__(self, parent, id, title, pos, size, style)
28 28 self._mgr = wx.aui.AuiManager()
29 29
30 30 # notify PyAUI which frame to use
31 31 self._mgr.SetManagedWindow(self)
32 32
33 33 #create differents panels and make them persistant
34 34 self.history_panel = IPythonHistoryPanel(self)
35 35
36 36 self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
37 37 background_color = "BLACK")
38 38
39 39 #self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
40 40 # background_color = "WHITE")
41 41
42 42 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
43 43 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
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 124 'SHOW_DOC':'Showing doc',
125 125 'SHOW_PROMPT':'Showing prompt'}
126 126 self.statusbar.SetStatusText(states[text], 0)
127 127
128 128 def OnClose(self, event):
129 129 """#event used to close program """
130 130 # deinitialize the frame manager
131 131 self._mgr.UnInit()
132 132 self.Destroy()
133 133 event.Skip()
134 134
135 135 def OnExitDlg(self, event):
136 136 dlg = wx.MessageDialog(self, 'Are you sure you want to quit WxIPython',
137 137 'WxIPython exit',
138 138 wx.ICON_QUESTION |
139 139 wx.YES_NO | wx.NO_DEFAULT
140 140 )
141 141 if dlg.ShowModal() == wx.ID_YES:
142 142 dlg.Destroy()
143 143 self._mgr.UnInit()
144 144 self.Destroy()
145 145 dlg.Destroy()
146 146
147 147 #event to display IPython pannel
148 148 def OnShowIPythonPanel(self,event):
149 149 """ #event to display Boxpannel """
150 150 self._mgr.GetPane(self.ipython_panel).Show(True)
151 151 self._mgr.Update()
152 152 #event to display History pannel
153 153 def OnShowHistoryPanel(self,event):
154 154 self._mgr.GetPane(self.history_panel).Show(True)
155 155 self._mgr.Update()
156 156
157 157 def OnShowAllPanel(self,event):
158 158 """#event to display all Pannels"""
159 159 self._mgr.GetPane(self.ipython_panel).Show(True)
160 160 self._mgr.GetPane(self.history_panel).Show(True)
161 161 self._mgr.Update()
162 162
163 163 def OnShowAbout(self, event):
164 164 # First we create and fill the info object
165 165 info = wx.AboutDialogInfo()
166 166 info.Name = "WxIPython"
167 167 info.Version = str(__version__)
168 168 info.Copyright = "(C) 2007 Laurent Dufrechou"
169 169 info.Description = wordwrap(
170 170 "A Gui that embbed a multithreaded IPython Shell",
171 171 350, wx.ClientDC(self))
172 172 info.WebSite = ("http://ipython.scipy.org/", "IPython home page")
173 173 info.Developers = [ "Laurent Dufrechou" ]
174 174 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 175 info.License = wordwrap(licenseText, 500, wx.ClientDC(self))
176 176
177 177 # Then we call wx.AboutBox giving it that info object
178 178 wx.AboutBox(info)
179 179
180 180 #-----------------------------------------
181 181 #Creating our application
182 182 #-----------------------------------------
183 183 class MyApp(wx.PySimpleApp):
184 184 """Creating our application"""
185 185 def __init__(self):
186 186 wx.PySimpleApp.__init__(self)
187 187
188 188 self.frame = MyFrame()
189 189 self.frame.Show()
190 190
191 191 #-----------------------------------------
192 192 #Main loop
193 193 #-----------------------------------------
194 194 def main():
195 195 app = MyApp()
196 196 app.SetTopWindow(app.frame)
197 197 app.MainLoop()
198 198
199 199 #if launched as main program run this
200 200 if __name__ == '__main__':
201 201 main()
General Comments 0
You need to be logged in to leave comments. Login now