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