##// END OF EJS Templates
fix crlf on ipy_winpdb
Ville M. Vainio -
r1137:be020659 merge
parent child Browse files
Show More
@@ -0,0 +1,73 b''
1 """ Debug a script (like %run -d) in IPython process, Using WinPdb
2
3 Usage:
4
5 %wdb test.py
6 run test.py, with a winpdb breakpoint at start of the file
7
8 %wdb pass
9 Change the password (e.g. if you have forgotten the old one)
10 """
11
12 import os
13
14 import IPython.ipapi
15 import rpdb2
16
17 ip = IPython.ipapi.get()
18
19 rpdb_started = False
20
21 def wdb_f(self, arg):
22 """ Debug a script (like %run -d) in IPython process, Using WinPdb
23
24 Usage:
25
26 %wdb test.py
27 run test.py, with a winpdb breakpoint at start of the file
28
29 %wdb pass
30 Change the password (e.g. if you have forgotten the old one)
31
32 Note that after the script has been run, you need to do "Go" (f5)
33 in WinPdb to resume normal IPython operation.
34 """
35
36 global rpdb_started
37 if not arg.strip():
38 print __doc__
39 return
40
41 if arg.strip() == 'pass':
42 passwd = raw_input('Enter new winpdb session password: ')
43 ip.db['winpdb_pass'] = passwd
44 print "Winpdb password changed"
45 if rpdb_started:
46 print "You need to restart IPython to use the new password"
47 return
48
49 path = os.path.abspath(arg)
50 if not os.path.isfile(path):
51 raise IPython.ipapi.UsageError("%%wdb: file %s does not exist" % path)
52 if not rpdb_started:
53 passwd = ip.db.get('winpdb_pass', None)
54 if passwd is None:
55 import textwrap
56 print textwrap.dedent("""\
57 Winpdb sessions need a password that you use for attaching the external
58 winpdb session. IPython will remember this. You can change the password later
59 by '%wpdb pass'
60 """)
61 passwd = raw_input('Enter new winpdb session password: ')
62 ip.db['winpdb_pass'] = passwd
63
64 print "Starting rpdb2 in IPython process"
65 rpdb2.start_embedded_debugger(passwd, timeout = 0)
66 rpdb_started = True
67
68 rpdb2.set_temp_breakpoint(path)
69 print 'It is time to attach with WinPdb (launch WinPdb if needed, File -> Attach)'
70 ip.magic('%run ' + arg)
71
72
73 ip.expose_magic('wdb', wdb_f)
@@ -1,100 +1,102 b''
1 1 """ User configuration file for IPython
2 2
3 3 This is a more flexible and safe way to configure ipython than *rc files
4 4 (ipythonrc, ipythonrc-pysh etc.)
5 5
6 6 This file is always imported on ipython startup. You can import the
7 7 ipython extensions you need here (see IPython/Extensions directory).
8 8
9 9 Feel free to edit this file to customize your ipython experience.
10 10
11 11 Note that as such this file does nothing, for backwards compatibility.
12 12 Consult e.g. file 'ipy_profile_sh.py' for an example of the things
13 13 you can do here.
14 14
15 15 See http://ipython.scipy.org/moin/IpythonExtensionApi for detailed
16 16 description on what you could do here.
17 17 """
18 18
19 19 # Most of your config files and extensions will probably start with this import
20 20
21 21 import IPython.ipapi
22 22 ip = IPython.ipapi.get()
23 23
24 24 # You probably want to uncomment this if you did %upgrade -nolegacy
25 25 # import ipy_defaults
26 26
27 27 import os
28 28
29 29 def main():
30 30
31 31 # uncomment if you want to get ipython -p sh behaviour
32 32 # without having to use command line switches
33 33 # import ipy_profile_sh
34 34
35 35 # Configure your favourite editor?
36 36 # Good idea e.g. for %edit os.path.isfile
37 37
38 38 #import ipy_editors
39 39
40 40 # Choose one of these:
41 41
42 42 #ipy_editors.scite()
43 43 #ipy_editors.scite('c:/opt/scite/scite.exe')
44 44 #ipy_editors.komodo()
45 45 #ipy_editors.idle()
46 46 # ... or many others, try 'ipy_editors??' after import to see them
47 47
48 48 # Or roll your own:
49 49 #ipy_editors.install_editor("c:/opt/jed +$line $file")
50 50
51 51
52 52 o = ip.options
53 53 # An example on how to set options
54 54 #o.autocall = 1
55 55 o.system_verbose = 0
56 56
57 57 #import_all("os sys")
58 58 #execf('~/_ipython/ns.py')
59 59
60 60
61 61 # -- prompt
62 62 # A different, more compact set of prompts from the default ones, that
63 63 # always show your current location in the filesystem:
64 64
65 65 #o.prompt_in1 = r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Normal\n\C_Green|\#>'
66 66 #o.prompt_in2 = r'.\D: '
67 67 #o.prompt_out = r'[\#] '
68 68
69 69 # Try one of these color settings if you can't read the text easily
70 70 # autoexec is a list of IPython commands to execute on startup
71 71 #o.autoexec.append('%colors LightBG')
72 72 #o.autoexec.append('%colors NoColor')
73 73 #o.autoexec.append('%colors Linux')
74 74
75 75 # for sane integer division that converts to float (1/2 == 0.5)
76 76 #o.autoexec.append('from __future__ import division')
77 77
78 78 # For %tasks and %kill
79 79 #import jobctrl
80 80
81 81 # For autoreloading of modules (%autoreload, %aimport)
82 82 #import ipy_autoreload
83 83
84 84 # For winpdb support (%wdb)
85 85 #import ipy_winpdb
86 86
87 87 # For bzr completer, requires bzrlib (the python installation of bzr)
88 88 #import ipy_bzr
89 89
90
91
90 92 # some config helper functions you can use
91 93 def import_all(modules):
92 94 """ Usage: import_all("os sys") """
93 95 for m in modules.split():
94 96 ip.ex("from %s import *" % m)
95 97
96 98 def execf(fname):
97 99 """ Execute a file in user namespace """
98 100 ip.ex('execfile("%s")' % os.path.expanduser(fname))
99 101
100 102 main()
@@ -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,729 +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 def showReturned(self, text):
306 '''
307 Show returned text from last command and print new prompt.
308
309 @param text: Text to show.
310 @type text: string
311 '''
312 self.write('\n'+text)
313 if text:
314 self.write('\n')
315 self.showPrompt()
316
317 306 def moveCursorOnNewValidKey(self):
318 307 #If cursor is at wrong position put it at last line...
319 308 if self.GetCurrentPos() < self.getCurrentPromptStart():
320 309 self.GotoPos(self.getCurrentPromptStart())
321 310
322 311 def removeFromTo(self,from_pos,to_pos):
323 312 if from_pos < to_pos:
324 313 self.SetSelection(from_pos,to_pos)
325 314 self.DeleteBack()
326 315
327 316 def removeCurrentLine(self):
328 317 self.LineDelete()
329 318
330 319 def moveCursor(self,position):
331 320 self.GotoPos(position)
332 321
333 322 def getCursorPos(self):
334 323 return self.GetCurrentPos()
335 324
336 325 def selectFromTo(self,from_pos,to_pos):
337 326 self.SetSelectionStart(from_pos)
338 327 self.SetSelectionEnd(to_pos)
339 328
340 329 def writeHistory(self,history):
341 330 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
342 331 self.changeLine(history)
343 332
344 333 def writeCompletion(self, possibilities):
345 334 max_len = len(max(possibilities,key=len))
346 335 max_symbol =' '*max_len
347 336
348 337 #now we check how much symbol we can put on a line...
349 338 cursor_pos = self.getCursorPos()
350 339 test_buffer = max_symbol + ' '*4
351 340 current_lines = self.GetLineCount()
352 341
353 342 allowed_symbols = 80/len(test_buffer)
354 343 if allowed_symbols == 0:
355 344 allowed_symbols = 1
356 345
357 346 pos = 1
358 347 buf = ''
359 348 for symbol in possibilities:
360 349 #buf += symbol+'\n'#*spaces)
361 350 if pos<allowed_symbols:
362 351 spaces = max_len - len(symbol) + 4
363 352 buf += symbol+' '*spaces
364 353 pos += 1
365 354 else:
366 355 buf+=symbol+'\n'
367 356 pos = 1
368 357 self.write(buf)
369 358
370 359 def _onKeypress(self, event, skip=True):
371 360 '''
372 361 Key press callback used for correcting behavior for console-like
373 362 interfaces. For example 'home' should go to prompt, not to begining of
374 363 line.
375 364
376 365 @param widget: Widget that key press accored in.
377 366 @type widget: gtk.Widget
378 367 @param event: Event object
379 368 @type event: gtk.gdk.Event
380 369
381 370 @return: Return True if event as been catched.
382 371 @rtype: boolean
383 372 '''
384 373
385 374 if event.GetKeyCode() == wx.WXK_HOME:
386 375 if event.Modifiers == wx.MOD_NONE:
387 376 self.moveCursorOnNewValidKey()
388 377 self.moveCursor(self.getCurrentPromptStart())
389 378 return True
390 379 elif event.Modifiers == wx.MOD_SHIFT:
391 380 self.moveCursorOnNewValidKey()
392 381 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
393 382 return True
394 383 else:
395 384 return False
396 385
397 386 elif event.GetKeyCode() == wx.WXK_LEFT:
398 387 if event.Modifiers == wx.MOD_NONE:
399 388 self.moveCursorOnNewValidKey()
400 389
401 390 self.moveCursor(self.getCursorPos()-1)
402 391 if self.getCursorPos() < self.getCurrentPromptStart():
403 392 self.moveCursor(self.getCurrentPromptStart())
404 393 return True
405 394
406 395 elif event.GetKeyCode() == wx.WXK_BACK:
407 396 self.moveCursorOnNewValidKey()
408 397 if self.getCursorPos() > self.getCurrentPromptStart():
409 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
398 event.Skip()
410 399 return True
411 400
412 401 if skip:
413 402 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
414 403 self.moveCursorOnNewValidKey()
415 404
416 405 event.Skip()
417 406 return True
418 407 return False
419 408
420 409 def OnUpdateUI(self, evt):
421 410 # check for matching braces
422 411 braceAtCaret = -1
423 412 braceOpposite = -1
424 413 charBefore = None
425 414 caretPos = self.GetCurrentPos()
426 415
427 416 if caretPos > 0:
428 417 charBefore = self.GetCharAt(caretPos - 1)
429 418 styleBefore = self.GetStyleAt(caretPos - 1)
430 419
431 420 # check before
432 421 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
433 422 braceAtCaret = caretPos - 1
434 423
435 424 # check after
436 425 if braceAtCaret < 0:
437 426 charAfter = self.GetCharAt(caretPos)
438 427 styleAfter = self.GetStyleAt(caretPos)
439 428
440 429 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
441 430 braceAtCaret = caretPos
442 431
443 432 if braceAtCaret >= 0:
444 433 braceOpposite = self.BraceMatch(braceAtCaret)
445 434
446 435 if braceAtCaret != -1 and braceOpposite == -1:
447 436 self.BraceBadLight(braceAtCaret)
448 437 else:
449 438 self.BraceHighlight(braceAtCaret, braceOpposite)
450 439 #pt = self.PointFromPosition(braceOpposite)
451 440 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
452 441 #print pt
453 442 #self.Refresh(False)
454 443
455 444 class IPShellWidget(wx.Panel):
456 445 '''
457 446 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
458 447 If you want to port this to any other GUI toolkit, just replace the
459 448 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
460 449 from whatever container you want. I've choosed to derivate from a wx.Panel
461 450 because it seems to be more useful
462 451 Any idea to make it more 'generic' welcomed.
463 452 '''
453
464 454 def __init__(self, parent, intro=None,
465 455 background_color="BLACK", add_button_handler=None,
466 456 wx_ip_shell=None,
467 457 ):
468 458 '''
469 459 Initialize.
470 460 Instanciate an IPython thread.
471 461 Instanciate a WxConsoleView.
472 462 Redirect I/O to console.
473 463 '''
474 464 wx.Panel.__init__(self,parent,-1)
475 465
476 466 ### IPython non blocking shell instanciation ###
477 467 self.cout = StringIO()
478
479 468 self.add_button_handler = add_button_handler
480 469
481 470 if wx_ip_shell is not None:
482 471 self.IP = wx_ip_shell
483 472 else:
484 473 self.IP = WxNonBlockingIPShell(self,
485 cout = self.cout,cerr = self.cout,
486 ask_exit_handler = self.askExitCallback)
474 cout = self.cout, cerr = self.cout,
475 ask_exit_handler = self.askExitCallback,
476 rawinput = self.rawInput)
487 477
488 478 ### IPython wx console view instanciation ###
489 479 #If user didn't defined an intro text, we create one for him
490 480 #If you really wnat an empty intrp just call wxIPythonViewPanel
491 481 #with intro=''
492 482 if intro is None:
493 483 welcome_text = "Welcome to WxIPython Shell.\n\n"
494 484 welcome_text+= self.IP.getBanner()
495 485 welcome_text+= "!command -> Execute command in shell\n"
496 486 welcome_text+= "TAB -> Autocompletion\n"
497 487 else:
498 488 welcome_text = intro
499 489
500 490 self.text_ctrl = WxConsoleView(self,
501 491 self.IP.getPrompt(),
502 492 intro=welcome_text,
503 493 background_color=background_color)
494
495 self.cout.write = self.text_ctrl.write
504 496
505 497 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl)
506
498
507 499 ### making the layout of the panel ###
508 500 sizer = wx.BoxSizer(wx.VERTICAL)
509 501 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
510 502 self.SetAutoLayout(True)
511 503 sizer.Fit(self)
512 504 sizer.SetSizeHints(self)
513 505 self.SetSizer(sizer)
514 506 #and we focus on the widget :)
515 507 self.SetFocus()
516 508
517 509 #widget state management (for key handling different cases)
518 510 self.setCurrentState('IDLE')
519 511 self.pager_state = 'DONE'
520 512
521 513 def askExitCallback(self, event):
522 514 self.askExitHandler(event)
523 515
524 516 #---------------------- IPython Thread Management ------------------------
525 517 def stateDoExecuteLine(self):
526 518 #print >>sys.__stdout__,"command:",self.getCurrentLine()
527 519 line=self.text_ctrl.getCurrentLine()
520 self.text_ctrl.write('\n')
528 521 self.IP.doExecute((line.replace('\t',' '*4)).encode('cp1252'))
529 522 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
530 523 self.setCurrentState('WAIT_END_OF_EXECUTION')
531 524
532 525 def evtStateExecuteDone(self,evt):
533 526 self.doc = self.IP.getDocText()
534 527 self.help = self.IP.getHelpText()
535 528 if self.doc:
536 529 self.pager_lines = self.doc[7:].split('\n')
537 530 self.pager_state = 'INIT'
538 531 self.setCurrentState('SHOW_DOC')
539 532 self.pager(self.doc)
540 533 elif self.help:
541 534 self.pager_lines = self.help.split('\n')
542 535 self.pager_state = 'INIT'
543 536 self.setCurrentState('SHOW_DOC')
544 537 self.pager(self.help)
545 538 else:
546 539 self.stateShowPrompt()
547 540
548 541 def stateShowPrompt(self):
549 542 self.setCurrentState('SHOW_PROMPT')
550 543 self.text_ctrl.setPrompt(self.IP.getPrompt())
551 544 self.text_ctrl.setIndentation(self.IP.getIndentation())
552 545 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
553 rv = self.cout.getvalue()
554 if rv: rv = rv.strip('\n')
555 self.text_ctrl.showReturned(rv)
556 self.cout.truncate(0)
546 self.text_ctrl.showPrompt()
557 547 self.IP.initHistoryIndex()
558 548 self.setCurrentState('IDLE')
559 549
560 550 def setCurrentState(self, state):
561 551 self.cur_state = state
562 552 self.updateStatusTracker(self.cur_state)
563
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
564 562 #---------------------------- IPython pager ---------------------------------------
565 def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
563 def pager(self,text):
566 564
567 565 if self.pager_state == 'INIT':
568 566 #print >>sys.__stdout__,"PAGER state:",self.pager_state
569 567 self.pager_nb_lines = len(self.pager_lines)
570 568 self.pager_index = 0
571 569 self.pager_do_remove = False
572 570 self.text_ctrl.write('\n')
573 571 self.pager_state = 'PROCESS_LINES'
574 572
575 573 if self.pager_state == 'PROCESS_LINES':
576 574 #print >>sys.__stdout__,"PAGER state:",self.pager_state
577 575 if self.pager_do_remove == True:
578 576 self.text_ctrl.removeCurrentLine()
579 577 self.pager_do_remove = False
580 578
581 579 if self.pager_nb_lines > 10:
582 580 #print >>sys.__stdout__,"PAGER processing 10 lines"
583 581 if self.pager_index > 0:
584 582 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
585 583 else:
586 584 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
587 585
588 586 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
589 587 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
590 588 self.pager_index += 10
591 589 self.pager_nb_lines -= 10
592 590 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
593 591 self.pager_do_remove = True
594 592 self.pager_state = 'WAITING'
595 593 return
596 594 else:
597 595 #print >>sys.__stdout__,"PAGER processing last lines"
598 596 if self.pager_nb_lines > 0:
599 597 if self.pager_index > 0:
600 598 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
601 599 else:
602 600 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
603 601
604 602 self.pager_index += 1
605 603 self.pager_nb_lines -= 1
606 604 if self.pager_nb_lines > 0:
607 605 for line in self.pager_lines[self.pager_index:]:
608 606 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
609 607 self.pager_nb_lines = 0
610 608 self.pager_state = 'DONE'
611 609 self.stateShowPrompt()
612 610
613 611 #------------------------ Key Handler ------------------------------------
614 612 def keyPress(self, event):
615 613 '''
616 614 Key press callback with plenty of shell goodness, like history,
617 615 autocompletions, etc.
618 616 '''
619 617
620 618 if event.GetKeyCode() == ord('C'):
621 619 if event.Modifiers == wx.MOD_CONTROL:
622 620 if self.cur_state == 'WAIT_END_OF_EXECUTION':
623 621 #we raise an exception inside the IPython thread container
624 622 self.IP.ce.raise_exc(KeyboardInterrupt)
625 623 return
626 624
627 625 if event.KeyCode == wx.WXK_RETURN:
628 626 if self.cur_state == 'IDLE':
629 627 #we change the state ot the state machine
630 628 self.setCurrentState('DO_EXECUTE_LINE')
631 629 self.stateDoExecuteLine()
632 630 return
633 631 if self.pager_state == 'WAITING':
634 632 self.pager_state = 'PROCESS_LINES'
635 633 self.pager(self.doc)
636 634 return
637 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
638 642 if event.GetKeyCode() in [ord('q'),ord('Q')]:
639 643 if self.pager_state == 'WAITING':
640 644 self.pager_state = 'DONE'
641 645 self.stateShowPrompt()
642 646 return
643
644 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
647
648 if self.cur_state == 'WAITING_USER_INPUT':
649 event.Skip()
650
645 651 if self.cur_state == 'IDLE':
646 652 if event.KeyCode == wx.WXK_UP:
647 653 history = self.IP.historyBack()
648 654 self.text_ctrl.writeHistory(history)
649 655 return
650 656 if event.KeyCode == wx.WXK_DOWN:
651 657 history = self.IP.historyForward()
652 658 self.text_ctrl.writeHistory(history)
653 659 return
654 660 if event.KeyCode == wx.WXK_TAB:
655 661 #if line empty we disable tab completion
656 662 if not self.text_ctrl.getCurrentLine().strip():
657 663 self.text_ctrl.write('\t')
658 664 return
659 665 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
660 666 if len(possibilities) > 1:
661 667 cur_slice = self.text_ctrl.getCurrentLine()
662 668 self.text_ctrl.write('\n')
663 669 self.text_ctrl.writeCompletion(possibilities)
664 670 self.text_ctrl.write('\n')
665 671
666 672 self.text_ctrl.showPrompt()
667 673 self.text_ctrl.write(cur_slice)
668 674 self.text_ctrl.changeLine(completed or cur_slice)
669 675
670 676 return
671 677 event.Skip()
672
678
673 679 #------------------------ Hook Section -----------------------------------
674 680 def updateHistoryTracker(self,command_line):
675 681 '''
676 682 Default history tracker (does nothing)
677 683 '''
678 684 pass
679 685
680 686 def setHistoryTrackerHook(self,func):
681 687 '''
682 688 Define a new history tracker
683 689 '''
684 690 self.updateHistoryTracker = func
685 691
686 692 def updateStatusTracker(self,status):
687 693 '''
688 694 Default status tracker (does nothing)
689 695 '''
690 696 pass
691 697
692 698 def setStatusTrackerHook(self,func):
693 699 '''
694 700 Define a new status tracker
695 701 '''
696 702 self.updateStatusTracker = func
697 703
698 704 def askExitHandler(self, event):
699 705 '''
700 706 Default exit handler
701 707 '''
702 708 self.text_ctrl.write('\nExit callback has not been set.')
703 709
704 710 def setAskExitHandler(self, func):
705 711 '''
706 712 Define an exit handler
707 713 '''
708 714 self.askExitHandler = func
709 715
710 716 if __name__ == '__main__':
711 717 # Some simple code to test the shell widget.
712 718 class MainWindow(wx.Frame):
713 719 def __init__(self, parent, id, title):
714 720 wx.Frame.__init__(self, parent, id, title, size=(300,250))
715 721 self._sizer = wx.BoxSizer(wx.VERTICAL)
716 722 self.shell = IPShellWidget(self)
717 723 self._sizer.Add(self.shell, 1, wx.EXPAND)
718 724 self.SetSizer(self._sizer)
719 725 self.SetAutoLayout(1)
720 726 self.Show(True)
721 727
722 728 app = wx.PySimpleApp()
723 729 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
724 730 frame.SetSize((780, 460))
725 731 shell = frame.shell
726 732
727 733 app.MainLoop()
728 734
729 735
@@ -1,202 +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 #self.ipython_panel = WxIPythonViewPanel(self,
40 # background_color = "WHITE")
39 #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
41 40
42 41 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
43 42 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
44 43 self.ipython_panel.setAskExitHandler(self.OnExitDlg)
45 44
46 45 self.statusbar = self.createStatus()
47 46 self.createMenu()
48 47
49 48 ########################################################################
50 49 ### add the panes to the manager
51 50 # main panels
52 51 self._mgr.AddPane(self.ipython_panel , wx.CENTER, "IPython Shell")
53 52 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
54 53
55 54 # now we specify some panel characteristics
56 55 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
57 56 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
58 57 self._mgr.GetPane(self.history_panel).MinSize((200,400));
59 58
60 59 # tell the manager to "commit" all the changes just made
61 60 self._mgr.Update()
62 61
63 62 #global event handling
64 63 self.Bind(wx.EVT_CLOSE, self.OnClose)
65 64 self.Bind(wx.EVT_MENU, self.OnClose,id=wx.ID_EXIT)
66 65 self.Bind(wx.EVT_MENU, self.OnShowIPythonPanel,id=wx.ID_HIGHEST+1)
67 66 self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2)
68 67 self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3)
69 68 self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6)
70 69
71 70 warn_text = 'Hello from IPython and wxPython.\n'
72 71 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
73 72 warn_text +='It does NOT emulate currently all the IPython functions.\n'
74 73
75 74 dlg = wx.MessageDialog(self,
76 75 warn_text,
77 76 'Warning Box',
78 77 wx.OK | wx.ICON_INFORMATION
79 78 )
80 79 dlg.ShowModal()
81 80 dlg.Destroy()
82 81
83 82 def createMenu(self):
84 83 """local method used to create one menu bar"""
85 84
86 85 mb = wx.MenuBar()
87 86
88 87 file_menu = wx.Menu()
89 88 file_menu.Append(wx.ID_EXIT, "Exit")
90 89
91 90 view_menu = wx.Menu()
92 91 view_menu.Append(wx.ID_HIGHEST+1, "Show IPython Panel")
93 92 view_menu.Append(wx.ID_HIGHEST+2, "Show History Panel")
94 93 view_menu.AppendSeparator()
95 94 view_menu.Append(wx.ID_HIGHEST+6, "Show All")
96 95
97 96 about_menu = wx.Menu()
98 97 about_menu.Append(wx.ID_HIGHEST+3, "About")
99 98
100 99 #view_menu.AppendSeparator()
101 100 #options_menu = wx.Menu()
102 101 #options_menu.AppendCheckItem(wx.ID_HIGHEST+7, "Allow Floating")
103 102 #options_menu.AppendCheckItem(wx.ID_HIGHEST+8, "Transparent Hint")
104 103 #options_menu.AppendCheckItem(wx.ID_HIGHEST+9, "Transparent Hint Fade-in")
105 104
106 105
107 106 mb.Append(file_menu, "File")
108 107 mb.Append(view_menu, "View")
109 108 mb.Append(about_menu, "About")
110 109 #mb.Append(options_menu, "Options")
111 110
112 111 self.SetMenuBar(mb)
113 112
114 113 def createStatus(self):
115 114 statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
116 115 statusbar.SetStatusWidths([-2, -3])
117 116 statusbar.SetStatusText("Ready", 0)
118 117 statusbar.SetStatusText("WxIPython "+str(__version__), 1)
119 118 return statusbar
120 119
121 120 def updateStatus(self,text):
122 121 states = {'IDLE':'Idle',
123 122 'DO_EXECUTE_LINE':'Send command',
124 123 'WAIT_END_OF_EXECUTION':'Running command',
124 'WAITING_USER_INPUT':'Waiting user input',
125 125 'SHOW_DOC':'Showing doc',
126 126 'SHOW_PROMPT':'Showing prompt'}
127 127 self.statusbar.SetStatusText(states[text], 0)
128 128
129 129 def OnClose(self, event):
130 130 """#event used to close program """
131 131 # deinitialize the frame manager
132 132 self._mgr.UnInit()
133 133 self.Destroy()
134 134 event.Skip()
135 135
136 136 def OnExitDlg(self, event):
137 137 dlg = wx.MessageDialog(self, 'Are you sure you want to quit WxIPython',
138 138 'WxIPython exit',
139 139 wx.ICON_QUESTION |
140 140 wx.YES_NO | wx.NO_DEFAULT
141 141 )
142 142 if dlg.ShowModal() == wx.ID_YES:
143 143 dlg.Destroy()
144 144 self._mgr.UnInit()
145 145 self.Destroy()
146 146 dlg.Destroy()
147 147
148 148 #event to display IPython pannel
149 149 def OnShowIPythonPanel(self,event):
150 150 """ #event to display Boxpannel """
151 151 self._mgr.GetPane(self.ipython_panel).Show(True)
152 152 self._mgr.Update()
153 153 #event to display History pannel
154 154 def OnShowHistoryPanel(self,event):
155 155 self._mgr.GetPane(self.history_panel).Show(True)
156 156 self._mgr.Update()
157 157
158 158 def OnShowAllPanel(self,event):
159 159 """#event to display all Pannels"""
160 160 self._mgr.GetPane(self.ipython_panel).Show(True)
161 161 self._mgr.GetPane(self.history_panel).Show(True)
162 162 self._mgr.Update()
163 163
164 164 def OnShowAbout(self, event):
165 165 # First we create and fill the info object
166 166 info = wx.AboutDialogInfo()
167 167 info.Name = "WxIPython"
168 168 info.Version = str(__version__)
169 169 info.Copyright = "(C) 2007 Laurent Dufrechou"
170 170 info.Description = wordwrap(
171 171 "A Gui that embbed a multithreaded IPython Shell",
172 172 350, wx.ClientDC(self))
173 173 info.WebSite = ("http://ipython.scipy.org/", "IPython home page")
174 174 info.Developers = [ "Laurent Dufrechou" ]
175 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"
176 176 info.License = wordwrap(licenseText, 500, wx.ClientDC(self))
177 177
178 178 # Then we call wx.AboutBox giving it that info object
179 179 wx.AboutBox(info)
180 180
181 181 #-----------------------------------------
182 182 #Creating our application
183 183 #-----------------------------------------
184 184 class MyApp(wx.PySimpleApp):
185 185 """Creating our application"""
186 186 def __init__(self):
187 187 wx.PySimpleApp.__init__(self)
188 188
189 189 self.frame = MyFrame()
190 190 self.frame.Show()
191 191
192 192 #-----------------------------------------
193 193 #Main loop
194 194 #-----------------------------------------
195 195 def main():
196 196 app = MyApp()
197 197 app.SetTopWindow(app.frame)
198 198 app.MainLoop()
199 199
200 200 #if launched as main program run this
201 201 if __name__ == '__main__':
202 202 main()
General Comments 0
You need to be logged in to leave comments. Login now