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