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