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