##// END OF EJS Templates
Correct erroneous behaviour when doing:...
ldufrechou -
Show More
@@ -1,1 +1,2 b''
1 [LF]
1 *.py
2 *.py
@@ -1,715 +1,715 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 import wx.lib.newevent
29 import wx.lib.newevent
30
30
31 import re
31 import re
32 import sys
32 import sys
33 import locale
33 import locale
34 from StringIO import StringIO
34 from StringIO import StringIO
35 try:
35 try:
36 import IPython
36 import IPython
37 except Exception,e:
37 except Exception,e:
38 raise "Error importing IPython (%s)" % str(e)
38 raise "Error importing IPython (%s)" % str(e)
39
39
40 from ipshell_nonblocking import NonBlockingIPShell
40 from ipshell_nonblocking import NonBlockingIPShell
41
41
42
42
43 class WxNonBlockingIPShell(NonBlockingIPShell):
43 class WxNonBlockingIPShell(NonBlockingIPShell):
44 '''
44 '''
45 An NonBlockingIPShell Thread that is WX dependent.
45 An NonBlockingIPShell Thread that is WX dependent.
46 '''
46 '''
47 def __init__(self, parent,
47 def __init__(self, parent,
48 argv=[],user_ns={},user_global_ns=None,
48 argv=[],user_ns={},user_global_ns=None,
49 cin=None, cout=None, cerr=None,
49 cin=None, cout=None, cerr=None,
50 ask_exit_handler=None):
50 ask_exit_handler=None):
51
51
52 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
52 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
53 cin, cout, cerr,
53 cin, cout, cerr,
54 ask_exit_handler)
54 ask_exit_handler)
55
55
56 self.parent = parent
56 self.parent = parent
57
57
58 self.ask_exit_callback = ask_exit_handler
58 self.ask_exit_callback = ask_exit_handler
59 self._IP.exit = self._askExit
59 self._IP.exit = self._askExit
60
60
61 def addGUIShortcut(self,text,func):
61 def addGUIShortcut(self,text,func):
62 wx.CallAfter(self.parent.add_button_handler,
62 wx.CallAfter(self.parent.add_button_handler,
63 button_info={ 'text':text,
63 button_info={ 'text':text,
64 'func':self.parent.doExecuteLine(func)})
64 'func':self.parent.doExecuteLine(func)})
65
65
66 def _askExit(self):
66 def _askExit(self):
67 wx.CallAfter(self.ask_exit_callback, ())
67 wx.CallAfter(self.ask_exit_callback, ())
68
68
69 def _afterExecute(self):
69 def _afterExecute(self):
70 wx.CallAfter(self.parent.evtStateExecuteDone, ())
70 wx.CallAfter(self.parent.evtStateExecuteDone, ())
71
71
72
72
73 class WxConsoleView(stc.StyledTextCtrl):
73 class WxConsoleView(stc.StyledTextCtrl):
74 '''
74 '''
75 Specialized styled text control view for console-like workflow.
75 Specialized styled text control view for console-like workflow.
76 We use here a scintilla frontend thus it can be reused in any GUI that
76 We use here a scintilla frontend thus it can be reused in any GUI that
77 supports scintilla with less work.
77 supports scintilla with less work.
78
78
79 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
79 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
80 (with Black background)
80 (with Black background)
81 @type ANSI_COLORS_BLACK: dictionary
81 @type ANSI_COLORS_BLACK: dictionary
82
82
83 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
83 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
84 (with White background)
84 (with White background)
85 @type ANSI_COLORS_WHITE: dictionary
85 @type ANSI_COLORS_WHITE: dictionary
86
86
87 @ivar color_pat: Regex of terminal color pattern
87 @ivar color_pat: Regex of terminal color pattern
88 @type color_pat: _sre.SRE_Pattern
88 @type color_pat: _sre.SRE_Pattern
89 '''
89 '''
90 ANSI_STYLES_BLACK={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
90 ANSI_STYLES_BLACK={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
91 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
91 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
92 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
92 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
93 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
93 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
94 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
94 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
95 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
95 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
96 '1;34': [12,'LIGHT BLUE'], '1;35':
96 '1;34': [12,'LIGHT BLUE'], '1;35':
97 [13,'MEDIUM VIOLET RED'],
97 [13,'MEDIUM VIOLET RED'],
98 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
98 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
99
99
100 ANSI_STYLES_WHITE={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
100 ANSI_STYLES_WHITE={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
101 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
101 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
102 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
102 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
103 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
103 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
104 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
104 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
105 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
105 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
106 '1;34': [12,'LIGHT BLUE'], '1;35':
106 '1;34': [12,'LIGHT BLUE'], '1;35':
107 [13,'MEDIUM VIOLET RED'],
107 [13,'MEDIUM VIOLET RED'],
108 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
108 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
109
109
110 def __init__(self,parent,prompt,intro="",background_color="BLACK",
110 def __init__(self,parent,prompt,intro="",background_color="BLACK",
111 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
111 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
112 style=0):
112 style=0):
113 '''
113 '''
114 Initialize console view.
114 Initialize console view.
115
115
116 @param parent: Parent widget
116 @param parent: Parent widget
117 @param prompt: User specified prompt
117 @param prompt: User specified prompt
118 @type intro: string
118 @type intro: string
119 @param intro: User specified startup introduction string
119 @param intro: User specified startup introduction string
120 @type intro: string
120 @type intro: string
121 @param background_color: Can be BLACK or WHITE
121 @param background_color: Can be BLACK or WHITE
122 @type background_color: string
122 @type background_color: string
123 @param other: init param of styledTextControl (can be used as-is)
123 @param other: init param of styledTextControl (can be used as-is)
124 '''
124 '''
125 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
125 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
126
126
127 ####### Scintilla configuration ###################################
127 ####### Scintilla configuration ###################################
128
128
129 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
129 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
130 # the widget
130 # the widget
131 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
131 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
132 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
132 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
133
133
134 #we define platform specific fonts
134 #we define platform specific fonts
135 if wx.Platform == '__WXMSW__':
135 if wx.Platform == '__WXMSW__':
136 faces = { 'times': 'Times New Roman',
136 faces = { 'times': 'Times New Roman',
137 'mono' : 'Courier New',
137 'mono' : 'Courier New',
138 'helv' : 'Arial',
138 'helv' : 'Arial',
139 'other': 'Comic Sans MS',
139 'other': 'Comic Sans MS',
140 'size' : 10,
140 'size' : 10,
141 'size2': 8,
141 'size2': 8,
142 }
142 }
143 elif wx.Platform == '__WXMAC__':
143 elif wx.Platform == '__WXMAC__':
144 faces = { 'times': 'Times New Roman',
144 faces = { 'times': 'Times New Roman',
145 'mono' : 'Monaco',
145 'mono' : 'Monaco',
146 'helv' : 'Arial',
146 'helv' : 'Arial',
147 'other': 'Comic Sans MS',
147 'other': 'Comic Sans MS',
148 'size' : 10,
148 'size' : 10,
149 'size2': 8,
149 'size2': 8,
150 }
150 }
151 else:
151 else:
152 faces = { 'times': 'Times',
152 faces = { 'times': 'Times',
153 'mono' : 'Courier',
153 'mono' : 'Courier',
154 'helv' : 'Helvetica',
154 'helv' : 'Helvetica',
155 'other': 'new century schoolbook',
155 'other': 'new century schoolbook',
156 'size' : 10,
156 'size' : 10,
157 'size2': 8,
157 'size2': 8,
158 }
158 }
159
159
160 #We draw a line at position 80
160 #We draw a line at position 80
161 self.SetEdgeMode(stc.STC_EDGE_LINE)
161 self.SetEdgeMode(stc.STC_EDGE_LINE)
162 self.SetEdgeColumn(80)
162 self.SetEdgeColumn(80)
163 self.SetEdgeColour(wx.LIGHT_GREY)
163 self.SetEdgeColour(wx.LIGHT_GREY)
164
164
165 #self.SetViewWhiteSpace(True)
165 #self.SetViewWhiteSpace(True)
166 #self.SetViewEOL(True)
166 #self.SetViewEOL(True)
167 self.SetEOLMode(stc.STC_EOL_CRLF)
167 self.SetEOLMode(stc.STC_EOL_CRLF)
168 #self.SetWrapMode(stc.STC_WRAP_CHAR)
168 #self.SetWrapMode(stc.STC_WRAP_CHAR)
169 #self.SetWrapMode(stc.STC_WRAP_WORD)
169 #self.SetWrapMode(stc.STC_WRAP_WORD)
170 self.SetBufferedDraw(True)
170 self.SetBufferedDraw(True)
171 #self.SetUseAntiAliasing(True)
171 #self.SetUseAntiAliasing(True)
172 self.SetLayoutCache(stc.STC_CACHE_PAGE)
172 self.SetLayoutCache(stc.STC_CACHE_PAGE)
173
173
174 self.EnsureCaretVisible()
174 self.EnsureCaretVisible()
175
175
176 self.SetMargins(3,3) #text is moved away from border with 3px
176 self.SetMargins(3,3) #text is moved away from border with 3px
177 # Suppressing Scintilla margins
177 # Suppressing Scintilla margins
178 self.SetMarginWidth(0,0)
178 self.SetMarginWidth(0,0)
179 self.SetMarginWidth(1,0)
179 self.SetMarginWidth(1,0)
180 self.SetMarginWidth(2,0)
180 self.SetMarginWidth(2,0)
181
181
182 # make some styles
182 # make some styles
183 if background_color != "BLACK":
183 if background_color != "BLACK":
184 self.background_color = "WHITE"
184 self.background_color = "WHITE"
185 self.SetCaretForeground("BLACK")
185 self.SetCaretForeground("BLACK")
186 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
186 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
187 else:
187 else:
188 self.background_color = background_color
188 self.background_color = background_color
189 self.SetCaretForeground("WHITE")
189 self.SetCaretForeground("WHITE")
190 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
190 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
191
191
192 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
192 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
193 "fore:%s,back:%s,size:%d,face:%s"
193 "fore:%s,back:%s,size:%d,face:%s"
194 % (self.ANSI_STYLES['0;30'][1],
194 % (self.ANSI_STYLES['0;30'][1],
195 self.background_color,
195 self.background_color,
196 faces['size'], faces['mono']))
196 faces['size'], faces['mono']))
197 self.StyleClearAll()
197 self.StyleClearAll()
198 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
198 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
199 "fore:#FF0000,back:#0000FF,bold")
199 "fore:#FF0000,back:#0000FF,bold")
200 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
200 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
201 "fore:#000000,back:#FF0000,bold")
201 "fore:#000000,back:#FF0000,bold")
202
202
203 for style in self.ANSI_STYLES.values():
203 for style in self.ANSI_STYLES.values():
204 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
204 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
205
205
206 #######################################################################
206 #######################################################################
207
207
208 self.indent = 0
208 self.indent = 0
209 self.prompt_count = 0
209 self.prompt_count = 0
210 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
210 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
211
211
212 self.write(intro)
212 self.write(intro)
213 self.setPrompt(prompt)
213 self.setPrompt(prompt)
214 self.showPrompt()
214 self.showPrompt()
215
215
216 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
216 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
217
217
218 def write(self, text):
218 def write(self, text):
219 '''
219 '''
220 Write given text to buffer.
220 Write given text to buffer.
221
221
222 @param text: Text to append.
222 @param text: Text to append.
223 @type text: string
223 @type text: string
224 '''
224 '''
225 segments = self.color_pat.split(text)
225 segments = self.color_pat.split(text)
226 segment = segments.pop(0)
226 segment = segments.pop(0)
227 self.StartStyling(self.getCurrentLineEnd(),0xFF)
227 self.StartStyling(self.getCurrentLineEnd(),0xFF)
228 self.AppendText(segment)
228 self.AppendText(segment)
229
229
230 if segments:
230 if segments:
231 ansi_tags = self.color_pat.findall(text)
231 ansi_tags = self.color_pat.findall(text)
232
232
233 for tag in ansi_tags:
233 for tag in ansi_tags:
234 i = segments.index(tag)
234 i = segments.index(tag)
235 self.StartStyling(self.getCurrentLineEnd(),0xFF)
235 self.StartStyling(self.getCurrentLineEnd(),0xFF)
236 self.AppendText(segments[i+1])
236 self.AppendText(segments[i+1])
237
237
238 if tag != '0':
238 if tag != '0':
239 self.SetStyling(len(segments[i+1]),self.ANSI_STYLES[tag][0])
239 self.SetStyling(len(segments[i+1]),self.ANSI_STYLES[tag][0])
240
240
241 segments.pop(i)
241 segments.pop(i)
242
242
243 self.moveCursor(self.getCurrentLineEnd())
243 self.moveCursor(self.getCurrentLineEnd())
244
244
245 def getPromptLen(self):
245 def getPromptLen(self):
246 '''
246 '''
247 Return the length of current prompt
247 Return the length of current prompt
248 '''
248 '''
249 return len(str(self.prompt_count)) + 7
249 return len(str(self.prompt_count)) + 7
250
250
251 def setPrompt(self,prompt):
251 def setPrompt(self,prompt):
252 self.prompt = prompt
252 self.prompt = prompt
253
253
254 def setIndentation(self,indentation):
254 def setIndentation(self,indentation):
255 self.indent = indentation
255 self.indent = indentation
256
256
257 def setPromptCount(self,count):
257 def setPromptCount(self,count):
258 self.prompt_count = count
258 self.prompt_count = count
259
259
260 def showPrompt(self):
260 def showPrompt(self):
261 '''
261 '''
262 Prints prompt at start of line.
262 Prints prompt at start of line.
263
263
264 @param prompt: Prompt to print.
264 @param prompt: Prompt to print.
265 @type prompt: string
265 @type prompt: string
266 '''
266 '''
267 self.write(self.prompt)
267 self.write(self.prompt)
268 #now we update the position of end of prompt
268 #now we update the position of end of prompt
269 self.current_start = self.getCurrentLineEnd()
269 self.current_start = self.getCurrentLineEnd()
270
270
271 autoindent = self.indent*' '
271 autoindent = self.indent*' '
272 autoindent = autoindent.replace(' ','\t')
272 autoindent = autoindent.replace(' ','\t')
273 self.write(autoindent)
273 self.write(autoindent)
274
274
275 def changeLine(self, text):
275 def changeLine(self, text):
276 '''
276 '''
277 Replace currently entered command line with given text.
277 Replace currently entered command line with given text.
278
278
279 @param text: Text to use as replacement.
279 @param text: Text to use as replacement.
280 @type text: string
280 @type text: string
281 '''
281 '''
282 self.SetSelection(self.getCurrentPromptStart(),self.getCurrentLineEnd())
282 self.SetSelection(self.getCurrentPromptStart(),self.getCurrentLineEnd())
283 self.ReplaceSelection(text)
283 self.ReplaceSelection(text)
284 self.moveCursor(self.getCurrentLineEnd())
284 self.moveCursor(self.getCurrentLineEnd())
285
285
286 def getCurrentPromptStart(self):
286 def getCurrentPromptStart(self):
287 return self.current_start
287 return self.current_start
288
288
289 def getCurrentLineStart(self):
289 def getCurrentLineStart(self):
290 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
290 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
291
291
292 def getCurrentLineEnd(self):
292 def getCurrentLineEnd(self):
293 return self.GetLength()
293 return self.GetLength()
294
294
295 def getCurrentLine(self):
295 def getCurrentLine(self):
296 '''
296 '''
297 Get text in current command line.
297 Get text in current command line.
298
298
299 @return: Text of current command line.
299 @return: Text of current command line.
300 @rtype: string
300 @rtype: string
301 '''
301 '''
302 return self.GetTextRange(self.getCurrentPromptStart(),
302 return self.GetTextRange(self.getCurrentPromptStart(),
303 self.getCurrentLineEnd())
303 self.getCurrentLineEnd())
304
304
305 def showReturned(self, text):
305 def showReturned(self, text):
306 '''
306 '''
307 Show returned text from last command and print new prompt.
307 Show returned text from last command and print new prompt.
308
308
309 @param text: Text to show.
309 @param text: Text to show.
310 @type text: string
310 @type text: string
311 '''
311 '''
312 self.write('\n'+text)
312 self.write('\n'+text)
313 if text:
313 if text:
314 self.write('\n')
314 self.write('\n')
315 self.showPrompt()
315 self.showPrompt()
316
316
317 def moveCursorOnNewValidKey(self):
317 def moveCursorOnNewValidKey(self):
318 #If cursor is at wrong position put it at last line...
318 #If cursor is at wrong position put it at last line...
319 if self.GetCurrentPos() < self.getCurrentPromptStart():
319 if self.GetCurrentPos() < self.getCurrentPromptStart():
320 self.GotoPos(self.getCurrentPromptStart())
320 self.GotoPos(self.getCurrentPromptStart())
321
321
322 def removeFromTo(self,from_pos,to_pos):
322 def removeFromTo(self,from_pos,to_pos):
323 if from_pos < to_pos:
323 if from_pos < to_pos:
324 self.SetSelection(from_pos,to_pos)
324 self.SetSelection(from_pos,to_pos)
325 self.DeleteBack()
325 self.DeleteBack()
326
326
327 def removeCurrentLine(self):
327 def removeCurrentLine(self):
328 self.LineDelete()
328 self.LineDelete()
329
329
330 def moveCursor(self,position):
330 def moveCursor(self,position):
331 self.GotoPos(position)
331 self.GotoPos(position)
332
332
333 def getCursorPos(self):
333 def getCursorPos(self):
334 return self.GetCurrentPos()
334 return self.GetCurrentPos()
335
335
336 def selectFromTo(self,from_pos,to_pos):
336 def selectFromTo(self,from_pos,to_pos):
337 self.SetSelectionStart(from_pos)
337 self.SetSelectionStart(from_pos)
338 self.SetSelectionEnd(to_pos)
338 self.SetSelectionEnd(to_pos)
339
339
340 def writeHistory(self,history):
340 def writeHistory(self,history):
341 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
341 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
342 self.changeLine(history)
342 self.changeLine(history)
343
343
344 def writeCompletion(self, possibilities):
344 def writeCompletion(self, possibilities):
345 max_len = len(max(possibilities,key=len))
345 max_len = len(max(possibilities,key=len))
346 max_symbol =' '*max_len
346 max_symbol =' '*max_len
347
347
348 #now we check how much symbol we can put on a line...
348 #now we check how much symbol we can put on a line...
349 cursor_pos = self.getCursorPos()
349 cursor_pos = self.getCursorPos()
350 test_buffer = max_symbol + ' '*4
350 test_buffer = max_symbol + ' '*4
351 current_lines = self.GetLineCount()
351 current_lines = self.GetLineCount()
352
352
353 allowed_symbols = 80/len(test_buffer)
353 allowed_symbols = 80/len(test_buffer)
354 if allowed_symbols == 0:
354 if allowed_symbols == 0:
355 allowed_symbols = 1
355 allowed_symbols = 1
356
356
357 pos = 1
357 pos = 1
358 buf = ''
358 buf = ''
359 for symbol in possibilities:
359 for symbol in possibilities:
360 #buf += symbol+'\n'#*spaces)
360 #buf += symbol+'\n'#*spaces)
361 if pos<allowed_symbols:
361 if pos<allowed_symbols:
362 spaces = max_len - len(symbol) + 4
362 spaces = max_len - len(symbol) + 4
363 buf += symbol+' '*spaces
363 buf += symbol+' '*spaces
364 pos += 1
364 pos += 1
365 else:
365 else:
366 buf+=symbol+'\n'
366 buf+=symbol+'\n'
367 pos = 1
367 pos = 1
368 self.write(buf)
368 self.write(buf)
369
369
370 def _onKeypress(self, event, skip=True):
370 def _onKeypress(self, event, skip=True):
371 '''
371 '''
372 Key press callback used for correcting behavior for console-like
372 Key press callback used for correcting behavior for console-like
373 interfaces. For example 'home' should go to prompt, not to begining of
373 interfaces. For example 'home' should go to prompt, not to begining of
374 line.
374 line.
375
375
376 @param widget: Widget that key press accored in.
376 @param widget: Widget that key press accored in.
377 @type widget: gtk.Widget
377 @type widget: gtk.Widget
378 @param event: Event object
378 @param event: Event object
379 @type event: gtk.gdk.Event
379 @type event: gtk.gdk.Event
380
380
381 @return: Return True if event as been catched.
381 @return: Return True if event as been catched.
382 @rtype: boolean
382 @rtype: boolean
383 '''
383 '''
384
384
385 if event.GetKeyCode() == wx.WXK_HOME:
385 if event.GetKeyCode() == wx.WXK_HOME:
386 if event.Modifiers == wx.MOD_NONE:
386 if event.Modifiers == wx.MOD_NONE:
387 self.moveCursorOnNewValidKey()
387 self.moveCursorOnNewValidKey()
388 self.moveCursor(self.getCurrentPromptStart())
388 self.moveCursor(self.getCurrentPromptStart())
389 return True
389 return True
390 elif event.Modifiers == wx.MOD_SHIFT:
390 elif event.Modifiers == wx.MOD_SHIFT:
391 self.moveCursorOnNewValidKey()
391 self.moveCursorOnNewValidKey()
392 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
392 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
393 return True
393 return True
394 else:
394 else:
395 return False
395 return False
396
396
397 elif event.GetKeyCode() == wx.WXK_LEFT:
397 elif event.GetKeyCode() == wx.WXK_LEFT:
398 if event.Modifiers == wx.MOD_NONE:
398 if event.Modifiers == wx.MOD_NONE:
399 self.moveCursorOnNewValidKey()
399 self.moveCursorOnNewValidKey()
400
400
401 self.moveCursor(self.getCursorPos()-1)
401 self.moveCursor(self.getCursorPos()-1)
402 if self.getCursorPos() < self.getCurrentPromptStart():
402 if self.getCursorPos() < self.getCurrentPromptStart():
403 self.moveCursor(self.getCurrentPromptStart())
403 self.moveCursor(self.getCurrentPromptStart())
404 return True
404 return True
405
405
406 elif event.GetKeyCode() == wx.WXK_BACK:
406 elif event.GetKeyCode() == wx.WXK_BACK:
407 self.moveCursorOnNewValidKey()
407 self.moveCursorOnNewValidKey()
408 if self.getCursorPos() > self.getCurrentPromptStart():
408 if self.getCursorPos() > self.getCurrentPromptStart():
409 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
409 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
410 return True
410 return True
411
411
412 if skip:
412 if skip:
413 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
413 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
414 self.moveCursorOnNewValidKey()
414 self.moveCursorOnNewValidKey()
415
415
416 event.Skip()
416 event.Skip()
417 return True
417 return True
418 return False
418 return False
419
419
420 def OnUpdateUI(self, evt):
420 def OnUpdateUI(self, evt):
421 # check for matching braces
421 # check for matching braces
422 braceAtCaret = -1
422 braceAtCaret = -1
423 braceOpposite = -1
423 braceOpposite = -1
424 charBefore = None
424 charBefore = None
425 caretPos = self.GetCurrentPos()
425 caretPos = self.GetCurrentPos()
426
426
427 if caretPos > 0:
427 if caretPos > 0:
428 charBefore = self.GetCharAt(caretPos - 1)
428 charBefore = self.GetCharAt(caretPos - 1)
429 styleBefore = self.GetStyleAt(caretPos - 1)
429 styleBefore = self.GetStyleAt(caretPos - 1)
430
430
431 # check before
431 # check before
432 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
432 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
433 braceAtCaret = caretPos - 1
433 braceAtCaret = caretPos - 1
434
434
435 # check after
435 # check after
436 if braceAtCaret < 0:
436 if braceAtCaret < 0:
437 charAfter = self.GetCharAt(caretPos)
437 charAfter = self.GetCharAt(caretPos)
438 styleAfter = self.GetStyleAt(caretPos)
438 styleAfter = self.GetStyleAt(caretPos)
439
439
440 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
440 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
441 braceAtCaret = caretPos
441 braceAtCaret = caretPos
442
442
443 if braceAtCaret >= 0:
443 if braceAtCaret >= 0:
444 braceOpposite = self.BraceMatch(braceAtCaret)
444 braceOpposite = self.BraceMatch(braceAtCaret)
445
445
446 if braceAtCaret != -1 and braceOpposite == -1:
446 if braceAtCaret != -1 and braceOpposite == -1:
447 self.BraceBadLight(braceAtCaret)
447 self.BraceBadLight(braceAtCaret)
448 else:
448 else:
449 self.BraceHighlight(braceAtCaret, braceOpposite)
449 self.BraceHighlight(braceAtCaret, braceOpposite)
450 #pt = self.PointFromPosition(braceOpposite)
450 #pt = self.PointFromPosition(braceOpposite)
451 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
451 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
452 #print pt
452 #print pt
453 #self.Refresh(False)
453 #self.Refresh(False)
454
454
455 class IPShellWidget(wx.Panel):
455 class IPShellWidget(wx.Panel):
456 '''
456 '''
457 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
457 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
458 If you want to port this to any other GUI toolkit, just replace the
458 If you want to port this to any other GUI toolkit, just replace the
459 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
459 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
460 from whatever container you want. I've choosed to derivate from a wx.Panel
460 from whatever container you want. I've choosed to derivate from a wx.Panel
461 because it seems to be more useful
461 because it seems to be more useful
462 Any idea to make it more 'generic' welcomed.
462 Any idea to make it more 'generic' welcomed.
463 '''
463 '''
464
464
465 def __init__(self, parent, ask_exit_handler=None, intro=None,
465 def __init__(self, parent, ask_exit_handler=None, intro=None,
466 background_color="BLACK", add_button_handler=None,
466 background_color="BLACK", add_button_handler=None,
467 wx_ip_shell=None,
467 wx_ip_shell=None,
468 ):
468 ):
469 '''
469 '''
470 Initialize.
470 Initialize.
471 Instanciate an IPython thread.
471 Instanciate an IPython thread.
472 Instanciate a WxConsoleView.
472 Instanciate a WxConsoleView.
473 Redirect I/O to console.
473 Redirect I/O to console.
474 '''
474 '''
475 wx.Panel.__init__(self,parent,-1)
475 wx.Panel.__init__(self,parent,-1)
476
476
477 ### IPython non blocking shell instanciation ###
477 ### IPython non blocking shell instanciation ###
478 self.cout = StringIO()
478 self.cout = StringIO()
479
479
480 self.add_button_handler = add_button_handler
480 self.add_button_handler = add_button_handler
481 self.ask_exit_handler = ask_exit_handler
481 self.ask_exit_handler = ask_exit_handler
482
482
483 if wx_ip_shell is not None:
483 if wx_ip_shell is not None:
484 self.IP = wx_ip_shell
484 self.IP = wx_ip_shell
485 else:
485 else:
486 self.IP = WxNonBlockingIPShell(self,
486 self.IP = WxNonBlockingIPShell(self,
487 cout=self.cout,cerr=self.cout,
487 cout=self.cout,cerr=self.cout,
488 ask_exit_handler = ask_exit_handler)
488 ask_exit_handler = ask_exit_handler)
489
489
490 ### IPython wx console view instanciation ###
490 ### IPython wx console view instanciation ###
491 #If user didn't defined an intro text, we create one for him
491 #If user didn't defined an intro text, we create one for him
492 #If you really wnat an empty intrp just call wxIPythonViewPanel
492 #If you really wnat an empty intrp just call wxIPythonViewPanel
493 #with intro=''
493 #with intro=''
494 if intro == None:
494 if intro == None:
495 welcome_text = "Welcome to WxIPython Shell.\n\n"
495 welcome_text = "Welcome to WxIPython Shell.\n\n"
496 welcome_text+= self.IP.getBanner()
496 welcome_text+= self.IP.getBanner()
497 welcome_text+= "!command -> Execute command in shell\n"
497 welcome_text+= "!command -> Execute command in shell\n"
498 welcome_text+= "TAB -> Autocompletion\n"
498 welcome_text+= "TAB -> Autocompletion\n"
499
499
500 self.text_ctrl = WxConsoleView(self,
500 self.text_ctrl = WxConsoleView(self,
501 self.IP.getPrompt(),
501 self.IP.getPrompt(),
502 intro=welcome_text,
502 intro=welcome_text,
503 background_color=background_color)
503 background_color=background_color)
504
504
505 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl)
505 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl)
506
506
507 ### making the layout of the panel ###
507 ### making the layout of the panel ###
508 sizer = wx.BoxSizer(wx.VERTICAL)
508 sizer = wx.BoxSizer(wx.VERTICAL)
509 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
509 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
510 self.SetAutoLayout(True)
510 self.SetAutoLayout(True)
511 sizer.Fit(self)
511 sizer.Fit(self)
512 sizer.SetSizeHints(self)
512 sizer.SetSizeHints(self)
513 self.SetSizer(sizer)
513 self.SetSizer(sizer)
514 #and we focus on the widget :)
514 #and we focus on the widget :)
515 self.SetFocus()
515 self.SetFocus()
516
516
517 #widget state management (for key handling different cases)
517 #widget state management (for key handling different cases)
518 self.setCurrentState('IDLE')
518 self.setCurrentState('IDLE')
519 self.pager_state = 'DONE'
519 self.pager_state = 'DONE'
520
520
521 #---------------------- IPython Thread Management ------------------------
521 #---------------------- IPython Thread Management ------------------------
522 def stateDoExecuteLine(self):
522 def stateDoExecuteLine(self):
523 #print >>sys.__stdout__,"command:",self.getCurrentLine()
523 #print >>sys.__stdout__,"command:",self.getCurrentLine()
524 line=self.text_ctrl.getCurrentLine()
524 line=self.text_ctrl.getCurrentLine()
525 self.IP.doExecute(line.replace('\t',' '*4))
525 self.IP.doExecute((line.replace('\t',' '*4)).encode('cp1252'))
526 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
526 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
527 self.setCurrentState('WAIT_END_OF_EXECUTION')
527 self.setCurrentState('WAIT_END_OF_EXECUTION')
528
528
529 def evtStateExecuteDone(self,evt):
529 def evtStateExecuteDone(self,evt):
530 self.doc = self.IP.getDocText()
530 self.doc = self.IP.getDocText()
531 self.help = self.IP.getHelpText()
531 self.help = self.IP.getHelpText()
532 if self.doc:
532 if self.doc:
533 self.pager_lines = self.doc[7:].split('\n')
533 self.pager_lines = self.doc[7:].split('\n')
534 self.pager_state = 'INIT'
534 self.pager_state = 'INIT'
535 self.setCurrentState('SHOW_DOC')
535 self.setCurrentState('SHOW_DOC')
536 self.pager(self.doc)
536 self.pager(self.doc)
537 elif self.help:
537 elif self.help:
538 self.pager_lines = self.help.split('\n')
538 self.pager_lines = self.help.split('\n')
539 self.pager_state = 'INIT'
539 self.pager_state = 'INIT'
540 self.setCurrentState('SHOW_DOC')
540 self.setCurrentState('SHOW_DOC')
541 self.pager(self.help)
541 self.pager(self.help)
542 else:
542 else:
543 self.stateShowPrompt()
543 self.stateShowPrompt()
544
544
545 def stateShowPrompt(self):
545 def stateShowPrompt(self):
546 self.setCurrentState('SHOW_PROMPT')
546 self.setCurrentState('SHOW_PROMPT')
547 self.text_ctrl.setPrompt(self.IP.getPrompt())
547 self.text_ctrl.setPrompt(self.IP.getPrompt())
548 self.text_ctrl.setIndentation(self.IP.getIndentation())
548 self.text_ctrl.setIndentation(self.IP.getIndentation())
549 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
549 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
550 rv = self.cout.getvalue()
550 rv = self.cout.getvalue()
551 if rv: rv = rv.strip('\n')
551 if rv: rv = rv.strip('\n')
552 self.text_ctrl.showReturned(rv)
552 self.text_ctrl.showReturned(rv)
553 self.cout.truncate(0)
553 self.cout.truncate(0)
554 self.IP.initHistoryIndex()
554 self.IP.initHistoryIndex()
555 self.setCurrentState('IDLE')
555 self.setCurrentState('IDLE')
556
556
557 def setCurrentState(self, state):
557 def setCurrentState(self, state):
558 self.cur_state = state
558 self.cur_state = state
559 self.updateStatusTracker(self.cur_state)
559 self.updateStatusTracker(self.cur_state)
560
560
561 #---------------------------- IPython pager ---------------------------------------
561 #---------------------------- IPython pager ---------------------------------------
562 def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
562 def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
563
563
564 if self.pager_state == 'INIT':
564 if self.pager_state == 'INIT':
565 #print >>sys.__stdout__,"PAGER state:",self.pager_state
565 #print >>sys.__stdout__,"PAGER state:",self.pager_state
566 self.pager_nb_lines = len(self.pager_lines)
566 self.pager_nb_lines = len(self.pager_lines)
567 self.pager_index = 0
567 self.pager_index = 0
568 self.pager_do_remove = False
568 self.pager_do_remove = False
569 self.text_ctrl.write('\n')
569 self.text_ctrl.write('\n')
570 self.pager_state = 'PROCESS_LINES'
570 self.pager_state = 'PROCESS_LINES'
571
571
572 if self.pager_state == 'PROCESS_LINES':
572 if self.pager_state == 'PROCESS_LINES':
573 #print >>sys.__stdout__,"PAGER state:",self.pager_state
573 #print >>sys.__stdout__,"PAGER state:",self.pager_state
574 if self.pager_do_remove == True:
574 if self.pager_do_remove == True:
575 self.text_ctrl.removeCurrentLine()
575 self.text_ctrl.removeCurrentLine()
576 self.pager_do_remove = False
576 self.pager_do_remove = False
577
577
578 if self.pager_nb_lines > 10:
578 if self.pager_nb_lines > 10:
579 #print >>sys.__stdout__,"PAGER processing 10 lines"
579 #print >>sys.__stdout__,"PAGER processing 10 lines"
580 if self.pager_index > 0:
580 if self.pager_index > 0:
581 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
581 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
582 else:
582 else:
583 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
583 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
584
584
585 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
585 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
586 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
586 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
587 self.pager_index += 10
587 self.pager_index += 10
588 self.pager_nb_lines -= 10
588 self.pager_nb_lines -= 10
589 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
589 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
590 self.pager_do_remove = True
590 self.pager_do_remove = True
591 self.pager_state = 'WAITING'
591 self.pager_state = 'WAITING'
592 return
592 return
593 else:
593 else:
594 #print >>sys.__stdout__,"PAGER processing last lines"
594 #print >>sys.__stdout__,"PAGER processing last lines"
595 if self.pager_nb_lines > 0:
595 if self.pager_nb_lines > 0:
596 if self.pager_index > 0:
596 if self.pager_index > 0:
597 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
597 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
598 else:
598 else:
599 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
599 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
600
600
601 self.pager_index += 1
601 self.pager_index += 1
602 self.pager_nb_lines -= 1
602 self.pager_nb_lines -= 1
603 if self.pager_nb_lines > 0:
603 if self.pager_nb_lines > 0:
604 for line in self.pager_lines[self.pager_index:]:
604 for line in self.pager_lines[self.pager_index:]:
605 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
605 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
606 self.pager_nb_lines = 0
606 self.pager_nb_lines = 0
607 self.pager_state = 'DONE'
607 self.pager_state = 'DONE'
608 self.stateShowPrompt()
608 self.stateShowPrompt()
609
609
610 #------------------------ Key Handler ------------------------------------
610 #------------------------ Key Handler ------------------------------------
611 def keyPress(self, event):
611 def keyPress(self, event):
612 '''
612 '''
613 Key press callback with plenty of shell goodness, like history,
613 Key press callback with plenty of shell goodness, like history,
614 autocompletions, etc.
614 autocompletions, etc.
615 '''
615 '''
616
616
617 if event.GetKeyCode() == ord('C'):
617 if event.GetKeyCode() == ord('C'):
618 if event.Modifiers == wx.MOD_CONTROL:
618 if event.Modifiers == wx.MOD_CONTROL:
619 if self.cur_state == 'WAIT_END_OF_EXECUTION':
619 if self.cur_state == 'WAIT_END_OF_EXECUTION':
620 #we raise an exception inside the IPython thread container
620 #we raise an exception inside the IPython thread container
621 self.IP.ce.raise_exc(KeyboardInterrupt)
621 self.IP.ce.raise_exc(KeyboardInterrupt)
622 return
622 return
623
623
624 if event.KeyCode == wx.WXK_RETURN:
624 if event.KeyCode == wx.WXK_RETURN:
625 if self.cur_state == 'IDLE':
625 if self.cur_state == 'IDLE':
626 #we change the state ot the state machine
626 #we change the state ot the state machine
627 self.setCurrentState('DO_EXECUTE_LINE')
627 self.setCurrentState('DO_EXECUTE_LINE')
628 self.stateDoExecuteLine()
628 self.stateDoExecuteLine()
629 return
629 return
630 if self.pager_state == 'WAITING':
630 if self.pager_state == 'WAITING':
631 self.pager_state = 'PROCESS_LINES'
631 self.pager_state = 'PROCESS_LINES'
632 self.pager(self.doc)
632 self.pager(self.doc)
633 return
633 return
634
634
635 if event.GetKeyCode() in [ord('q'),ord('Q')]:
635 if event.GetKeyCode() in [ord('q'),ord('Q')]:
636 if self.pager_state == 'WAITING':
636 if self.pager_state == 'WAITING':
637 self.pager_state = 'DONE'
637 self.pager_state = 'DONE'
638 self.stateShowPrompt()
638 self.stateShowPrompt()
639 return
639 return
640
640
641 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
641 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
642 if self.cur_state == 'IDLE':
642 if self.cur_state == 'IDLE':
643 if event.KeyCode == wx.WXK_UP:
643 if event.KeyCode == wx.WXK_UP:
644 history = self.IP.historyBack()
644 history = self.IP.historyBack()
645 self.text_ctrl.writeHistory(history)
645 self.text_ctrl.writeHistory(history)
646 return
646 return
647 if event.KeyCode == wx.WXK_DOWN:
647 if event.KeyCode == wx.WXK_DOWN:
648 history = self.IP.historyForward()
648 history = self.IP.historyForward()
649 self.text_ctrl.writeHistory(history)
649 self.text_ctrl.writeHistory(history)
650 return
650 return
651 if event.KeyCode == wx.WXK_TAB:
651 if event.KeyCode == wx.WXK_TAB:
652 #if line empty we disable tab completion
652 #if line empty we disable tab completion
653 if not self.text_ctrl.getCurrentLine().strip():
653 if not self.text_ctrl.getCurrentLine().strip():
654 self.text_ctrl.write('\t')
654 self.text_ctrl.write('\t')
655 return
655 return
656 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
656 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
657 if len(possibilities) > 1:
657 if len(possibilities) > 1:
658 cur_slice = self.text_ctrl.getCurrentLine()
658 cur_slice = self.text_ctrl.getCurrentLine()
659 self.text_ctrl.write('\n')
659 self.text_ctrl.write('\n')
660 self.text_ctrl.writeCompletion(possibilities)
660 self.text_ctrl.writeCompletion(possibilities)
661 self.text_ctrl.write('\n')
661 self.text_ctrl.write('\n')
662
662
663 self.text_ctrl.showPrompt()
663 self.text_ctrl.showPrompt()
664 self.text_ctrl.write(cur_slice)
664 self.text_ctrl.write(cur_slice)
665 self.text_ctrl.changeLine(completed or cur_slice)
665 self.text_ctrl.changeLine(completed or cur_slice)
666
666
667 return
667 return
668 event.Skip()
668 event.Skip()
669
669
670 #------------------------ Hook Section -----------------------------------
670 #------------------------ Hook Section -----------------------------------
671 def updateHistoryTracker(self,command_line):
671 def updateHistoryTracker(self,command_line):
672 '''
672 '''
673 Default history tracker (does nothing)
673 Default history tracker (does nothing)
674 '''
674 '''
675 pass
675 pass
676
676
677 def setHistoryTrackerHook(self,func):
677 def setHistoryTrackerHook(self,func):
678 '''
678 '''
679 Define a new history tracker
679 Define a new history tracker
680 '''
680 '''
681 self.updateHistoryTracker = func
681 self.updateHistoryTracker = func
682
682
683 def updateStatusTracker(self,status):
683 def updateStatusTracker(self,status):
684 '''
684 '''
685 Default status tracker (does nothing)
685 Default status tracker (does nothing)
686 '''
686 '''
687 pass
687 pass
688
688
689 def setStatusTrackerHook(self,func):
689 def setStatusTrackerHook(self,func):
690 '''
690 '''
691 Define a new status tracker
691 Define a new status tracker
692 '''
692 '''
693 self.updateStatusTracker = func
693 self.updateStatusTracker = func
694
694
695
695
696 if __name__ == '__main__':
696 if __name__ == '__main__':
697 # Some simple code to test the shell widget.
697 # Some simple code to test the shell widget.
698 class MainWindow(wx.Frame):
698 class MainWindow(wx.Frame):
699 def __init__(self, parent, id, title):
699 def __init__(self, parent, id, title):
700 wx.Frame.__init__(self, parent, id, title, size=(300,250))
700 wx.Frame.__init__(self, parent, id, title, size=(300,250))
701 self._sizer = wx.BoxSizer(wx.VERTICAL)
701 self._sizer = wx.BoxSizer(wx.VERTICAL)
702 self.shell = IPShellWidget(self)
702 self.shell = IPShellWidget(self)
703 self._sizer.Add(self.shell, 1, wx.EXPAND)
703 self._sizer.Add(self.shell, 1, wx.EXPAND)
704 self.SetSizer(self._sizer)
704 self.SetSizer(self._sizer)
705 self.SetAutoLayout(1)
705 self.SetAutoLayout(1)
706 self.Show(True)
706 self.Show(True)
707
707
708 app = wx.PySimpleApp()
708 app = wx.PySimpleApp()
709 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
709 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
710 frame.SetSize((780, 460))
710 frame.SetSize((780, 460))
711 shell = frame.shell
711 shell = frame.shell
712
712
713 app.MainLoop()
713 app.MainLoop()
714
714
715
715
General Comments 0
You need to be logged in to leave comments. Login now