##// END OF EJS Templates
pager cleanup
ldufrechou -
Show More
@@ -1,705 +1,702 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 elif self.help:
546 elif self.help:
547 self.pager_lines = self.help.split('\n')
547 self.pager_lines = self.help.split('\n')
548 self.pager_state = 'INIT'
548 self.pager_state = 'INIT'
549 self.setCurrentState('SHOW_DOC')
549 self.setCurrentState('SHOW_DOC')
550 self.pager(self.help)
550 self.pager(self.help)
551 else:
551 else:
552 self.stateShowPrompt()
552 self.stateShowPrompt()
553
553
554 def stateShowPrompt(self):
554 def stateShowPrompt(self):
555 self.setCurrentState('SHOW_PROMPT')
555 self.setCurrentState('SHOW_PROMPT')
556 self.text_ctrl.setPrompt(self.IP.getPrompt())
556 self.text_ctrl.setPrompt(self.IP.getPrompt())
557 self.text_ctrl.setIndentation(self.IP.getIndentation())
557 self.text_ctrl.setIndentation(self.IP.getIndentation())
558 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
558 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
559 rv = self.cout.getvalue()
559 rv = self.cout.getvalue()
560 if rv: rv = rv.strip('\n')
560 if rv: rv = rv.strip('\n')
561 self.text_ctrl.showReturned(rv)
561 self.text_ctrl.showReturned(rv)
562 self.cout.truncate(0)
562 self.cout.truncate(0)
563 self.IP.initHistoryIndex()
563 self.IP.initHistoryIndex()
564 self.setCurrentState('IDLE')
564 self.setCurrentState('IDLE')
565
565
566 def setCurrentState(self, state):
566 def setCurrentState(self, state):
567 self.cur_state = state
567 self.cur_state = state
568 self.updateStatusTracker(self.cur_state)
568 self.updateStatusTracker(self.cur_state)
569
569
570 #---------------------------- IPython pager ---------------------------------------
570 #---------------------------- IPython pager ---------------------------------------
571 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):
572 if self.pager_state == 'WAITING':
572
573 #print >>sys.__stdout__,"PAGER waiting"
573 if self.pager_state == 'INIT':
574 return
575
576 if self.pager_state == 'INIT':
577 #print >>sys.__stdout__,"PAGER state:",self.pager_state
574 #print >>sys.__stdout__,"PAGER state:",self.pager_state
578 self.pager_nb_lines = len(self.pager_lines)
575 self.pager_nb_lines = len(self.pager_lines)
579 self.pager_index = 0
576 self.pager_index = 0
580 self.pager_do_remove = False
577 self.pager_do_remove = False
581 self.text_ctrl.write('\n')
578 self.text_ctrl.write('\n')
582 self.pager_state = 'PROCESS_LINES'
579 self.pager_state = 'PROCESS_LINES'
583
580
584 if self.pager_state == 'PROCESS_LINES':
581 if self.pager_state == 'PROCESS_LINES':
585 #print >>sys.__stdout__,"PAGER state:",self.pager_state
582 #print >>sys.__stdout__,"PAGER state:",self.pager_state
586 if self.pager_do_remove == True:
583 if self.pager_do_remove == True:
587 self.text_ctrl.removeCurrentLine()
584 self.text_ctrl.removeCurrentLine()
588 self.pager_do_remove = False
585 self.pager_do_remove = False
589
586
590 if self.pager_nb_lines > 10:
587 if self.pager_nb_lines > 10:
591 #print >>sys.__stdout__,"PAGER processing 10 lines"
588 #print >>sys.__stdout__,"PAGER processing 10 lines"
592 if self.pager_index > 0:
589 if self.pager_index > 0:
593 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
590 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
594 else:
591 else:
595 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
592 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
596
593
597 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
594 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
598 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
595 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
599 self.pager_index += 10
596 self.pager_index += 10
600 self.pager_nb_lines -= 10
597 self.pager_nb_lines -= 10
601 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
598 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
602 self.pager_do_remove = True
599 self.pager_do_remove = True
603 self.pager_state = 'WAITING'
600 self.pager_state = 'WAITING'
604 return
601 return
605 else:
602 else:
606 #print >>sys.__stdout__,"PAGER processing last lines"
603 #print >>sys.__stdout__,"PAGER processing last lines"
607 if self.pager_nb_lines > 0:
604 if self.pager_nb_lines > 0:
608 if self.pager_index > 0:
605 if self.pager_index > 0:
609 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
606 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
610 else:
607 else:
611 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
608 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
612
609
613 self.pager_index += 1
610 self.pager_index += 1
614 self.pager_nb_lines -= 1
611 self.pager_nb_lines -= 1
615 if self.pager_nb_lines > 0:
612 if self.pager_nb_lines > 0:
616 for line in self.pager_lines[self.pager_index:]:
613 for line in self.pager_lines[self.pager_index:]:
617 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
614 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
618 self.pager_nb_lines = 0
615 self.pager_nb_lines = 0
619 self.pager_state = 'DONE'
616 self.pager_state = 'DONE'
620 self.stateShowPrompt()
617 self.stateShowPrompt()
621
618
622 #---------------------------- Key Handler --------------------------------------------
619 #---------------------------- Key Handler --------------------------------------------
623 def keyPress(self, event):
620 def keyPress(self, event):
624 '''
621 '''
625 Key press callback with plenty of shell goodness, like history,
622 Key press callback with plenty of shell goodness, like history,
626 autocompletions, etc.
623 autocompletions, etc.
627 '''
624 '''
628
625
629 if event.GetKeyCode() == ord('C'):
626 if event.GetKeyCode() == ord('C'):
630 if event.Modifiers == wx.MOD_CONTROL:
627 if event.Modifiers == wx.MOD_CONTROL:
631 if self.cur_state == 'WAIT_END_OF_EXECUTION':
628 if self.cur_state == 'WAIT_END_OF_EXECUTION':
632 #we raise an exception inside the IPython thread container
629 #we raise an exception inside the IPython thread container
633 self.IP.ce.raise_exc(KeyboardInterrupt)
630 self.IP.ce.raise_exc(KeyboardInterrupt)
634 return
631 return
635
632
636 if event.KeyCode == wx.WXK_RETURN:
633 if event.KeyCode == wx.WXK_RETURN:
637 if self.cur_state == 'IDLE':
634 if self.cur_state == 'IDLE':
638 #we change the state ot the state machine
635 #we change the state ot the state machine
639 self.setCurrentState('DO_EXECUTE_LINE')
636 self.setCurrentState('DO_EXECUTE_LINE')
640 self.stateDoExecuteLine()
637 self.stateDoExecuteLine()
641 return
638 return
642 if self.pager_state == 'WAITING':
639 if self.pager_state == 'WAITING':
643 self.pager_state = 'PROCESS_LINES'
640 self.pager_state = 'PROCESS_LINES'
644 self.pager(self.doc)
641 self.pager(self.doc)
645 return
642 return
646
643
647 if event.GetKeyCode() in [ord('q'),ord('Q')]:
644 if event.GetKeyCode() in [ord('q'),ord('Q')]:
648 if self.pager_state == 'WAITING':
645 if self.pager_state == 'WAITING':
649 self.pager_state = 'DONE'
646 self.pager_state = 'DONE'
650 self.stateShowPrompt()
647 self.stateShowPrompt()
651 return
648 return
652
649
653 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
650 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
654 if self.cur_state == 'IDLE':
651 if self.cur_state == 'IDLE':
655 if event.KeyCode == wx.WXK_UP:
652 if event.KeyCode == wx.WXK_UP:
656 history = self.IP.historyBack()
653 history = self.IP.historyBack()
657 self.text_ctrl.writeHistory(history)
654 self.text_ctrl.writeHistory(history)
658 return
655 return
659 if event.KeyCode == wx.WXK_DOWN:
656 if event.KeyCode == wx.WXK_DOWN:
660 history = self.IP.historyForward()
657 history = self.IP.historyForward()
661 self.text_ctrl.writeHistory(history)
658 self.text_ctrl.writeHistory(history)
662 return
659 return
663 if event.KeyCode == wx.WXK_TAB:
660 if event.KeyCode == wx.WXK_TAB:
664 #if line empty we disable tab completion
661 #if line empty we disable tab completion
665 if not self.text_ctrl.getCurrentLine().strip():
662 if not self.text_ctrl.getCurrentLine().strip():
666 self.text_ctrl.write('\t')
663 self.text_ctrl.write('\t')
667 return
664 return
668 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
665 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
669 if len(possibilities) > 1:
666 if len(possibilities) > 1:
670 cur_slice = self.text_ctrl.getCurrentLine()
667 cur_slice = self.text_ctrl.getCurrentLine()
671 self.text_ctrl.write('\n')
668 self.text_ctrl.write('\n')
672 self.text_ctrl.writeCompletion(possibilities)
669 self.text_ctrl.writeCompletion(possibilities)
673 self.text_ctrl.write('\n')
670 self.text_ctrl.write('\n')
674
671
675 self.text_ctrl.showPrompt()
672 self.text_ctrl.showPrompt()
676 self.text_ctrl.write(cur_slice)
673 self.text_ctrl.write(cur_slice)
677 self.text_ctrl.changeLine(completed or cur_slice)
674 self.text_ctrl.changeLine(completed or cur_slice)
678
675
679 return
676 return
680 event.Skip()
677 event.Skip()
681
678
682 #---------------------------- Hook Section --------------------------------------------
679 #---------------------------- Hook Section --------------------------------------------
683 def updateHistoryTracker(self,command_line):
680 def updateHistoryTracker(self,command_line):
684 '''
681 '''
685 Default history tracker (does nothing)
682 Default history tracker (does nothing)
686 '''
683 '''
687 pass
684 pass
688
685
689 def setHistoryTrackerHook(self,func):
686 def setHistoryTrackerHook(self,func):
690 '''
687 '''
691 Define a new history tracker
688 Define a new history tracker
692 '''
689 '''
693 self.updateHistoryTracker = func
690 self.updateHistoryTracker = func
694 def updateStatusTracker(self,status):
691 def updateStatusTracker(self,status):
695 '''
692 '''
696 Default status tracker (does nothing)
693 Default status tracker (does nothing)
697 '''
694 '''
698 pass
695 pass
699
696
700 def setStatusTrackerHook(self,func):
697 def setStatusTrackerHook(self,func):
701 '''
698 '''
702 Define a new status tracker
699 Define a new status tracker
703 '''
700 '''
704 self.updateStatusTracker = func
701 self.updateStatusTracker = func
705
702
General Comments 0
You need to be logged in to leave comments. Login now