]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/lib/pyshell.py
Insure suitable choices of path/drive separator on OS/2.
[wxWidgets.git] / wxPython / wx / lib / pyshell.py
CommitLineData
d14a1e28
RD
1#----------------------------------------------------------------------
2# Name: wxPython.lib.pyshell
3# Purpose: A Python Interactive Interpreter running in a wxStyledTextCtrl
4# window.
5#
6# Author: Robin Dunn
7#
8# Created: 7-July-2000
9# RCS-ID: $Id$
10# Copyright: (c) 2000 by Total Control Software
11# Licence: wxWindows license
12#----------------------------------------------------------------------
13
14"""
15PyShellWindow is a class that provides an Interactive Interpreter running
16inside a wxStyledTextCtrl, similar to the Python shell windows found in
17IDLE and PythonWin.
18
19There is still much to be done to improve this class, such as line
20buffering/recall, autoindent, calltips, autocomplete, fixing the colourizer,
21etc... But it's a good start.
22
23
248-10-2001 THIS MODULE IS NOW DEPRECATED. Please see the most excellent
25 PyCrust package instead.
26
27"""
28
29
30from wxPython.wx import *
31from wxPython.stc import *
32
33import sys, keyword
34from code import InteractiveInterpreter
35
36#----------------------------------------------------------------------
37# default styles, etc. to use for the STC
38
39if wxPlatform == '__WXMSW__':
40 _defaultSize = 8
41else:
42 _defaultSize = 10
43
44
45_default_properties = {
46 'selMargin' : 0,
47 'marginWidth' : 1,
48 'ps1' : '>>> ',
49 'stdout' : 'fore:#0000FF',
50 'stderr' : 'fore:#007f00',
51 'trace' : 'fore:#FF0000',
52
53 'default' : 'size:%d' % _defaultSize,
54 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
55 'bracebad' : 'fore:#000000,back:#FF0000,bold',
56
57 # properties for the various Python lexer styles
58 'comment' : 'fore:#007F00',
59 'number' : 'fore:#007F7F',
60 'string' : 'fore:#7F007F,italic',
61 'char' : 'fore:#7F007F,italic',
62 'keyword' : 'fore:#00007F,bold',
63 'triple' : 'fore:#7F0000',
64 'tripledouble': 'fore:#7F0000',
65 'class' : 'fore:#0000FF,bold,underline',
66 'def' : 'fore:#007F7F,bold',
67 'operator' : 'bold',
68
69 }
70
71
72# new style numbers
73_stdout_style = 15
74_stderr_style = 16
75_trace_style = 17
76
77
78#----------------------------------------------------------------------
79
80class PyShellWindow(wxStyledTextCtrl, InteractiveInterpreter):
81 def __init__(self, parent, ID, pos=wxDefaultPosition,
82 size=wxDefaultSize, style=0,
83 locals=None, properties=None, banner=None):
84 wxStyledTextCtrl.__init__(self, parent, ID, pos, size, style)
85 InteractiveInterpreter.__init__(self, locals)
86
87 self.lastPromptPos = 0
88
89 # the line cache is used to cycle through previous commands
90 self.lines = []
91 self.lastUsedLine = self.curLine = 0
92
93 # set defaults and then deal with any user defined properties
94 self.props = {}
95 self.props.update(_default_properties)
96 if properties:
97 self.props.update(properties)
98 self.UpdateProperties()
99
100 # copyright/banner message
101 if banner is None:
102 self.write("Python %s on %s\n" % #%s\n(%s)\n" %
103 (sys.version, sys.platform,
104 #sys.copyright, self.__class__.__name__
105 ))
106 else:
107 self.write("%s\n" % banner)
108
109 # write the initial prompt
110 self.Prompt()
111
112 # Event handlers
113 EVT_KEY_DOWN(self, self.OnKey)
114 EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI)
115 #EVT_STC_STYLENEEDED(self, ID, self.OnStyle)
116
117
118 def GetLocals(self): return self.locals
119 def SetLocals(self, locals): self.locals = locals
120
121 def GetProperties(self): return self.props
122 def SetProperties(self, properties):
123 self.props.update(properties)
124 self.UpdateProperties()
125
126
127 def UpdateProperties(self):
128 """
129 Reset the editor and other settings based on the contents of the
130 current properties dictionary.
131 """
132 p = self.props
133
134 #self.SetEdgeMode(wxSTC_EDGE_LINE)
135 #self.SetEdgeColumn(80)
136
137
138 # set the selection margin and window margin
139 self.SetMarginWidth(1, p['selMargin'])
140 self.SetMargins(p['marginWidth'], p['marginWidth'])
141
142 # styles
143 self.StyleSetSpec(wxSTC_STYLE_DEFAULT, p['default'])
144 self.StyleClearAll()
145 self.StyleSetSpec(_stdout_style, p['stdout'])
146 self.StyleSetSpec(_stderr_style, p['stderr'])
147 self.StyleSetSpec(_trace_style, p['trace'])
148
149 self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, p['bracegood'])
150 self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, p['bracebad'])
151 self.StyleSetSpec(wxSTC_P_COMMENTLINE, p['comment'])
152 self.StyleSetSpec(wxSTC_P_NUMBER, p['number'])
153 self.StyleSetSpec(wxSTC_P_STRING, p['string'])
154 self.StyleSetSpec(wxSTC_P_CHARACTER, p['char'])
155 self.StyleSetSpec(wxSTC_P_WORD, p['keyword'])
156 self.StyleSetSpec(wxSTC_P_TRIPLE, p['triple'])
157 self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, p['tripledouble'])
158 self.StyleSetSpec(wxSTC_P_CLASSNAME, p['class'])
159 self.StyleSetSpec(wxSTC_P_DEFNAME, p['def'])
160 self.StyleSetSpec(wxSTC_P_OPERATOR, p['operator'])
161 self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, p['comment'])
162
163
164 # used for writing to stdout, etc.
165 def _write(self, text, style=_stdout_style):
166 self.lastPromptPos = 0
167 pos = self.GetCurrentPos()
168 self.AddText(text)
169 self.StartStyling(pos, 0xFF)
170 self.SetStyling(len(text), style)
171 self.EnsureCaretVisible()
172 wxYield()
173
174 write = _write
175
176 def writeTrace(self, text):
177 self._write(text, _trace_style)
178
179
180 def Prompt(self):
181 # is the current line non-empty?
182 text, pos = self.GetCurLine()
183 if pos != 0:
184 self.AddText('\n')
185 self.AddText(self.props['ps1'])
186 self.lastPromptPos = self.GetCurrentPos()
187 self.EnsureCaretVisible()
188 self.ScrollToColumn(0)
189
190
191 def PushLine(self, text):
192 # TODO: Add the text to the line cache, manage the cache so
193 # it doesn't get too big.
194 pass
195
196
197
198 def OnKey(self, evt):
199 key = evt.KeyCode()
200 if key == WXK_RETURN:
201 pos = self.GetCurrentPos()
202 lastPos = self.GetTextLength()
203
204 # if not on the last line, duplicate the current line
205 if self.GetLineCount()-1 != self.GetCurrentLine():
206 text, col = self.GetCurLine()
207 prompt = self.props['ps1']
208 lp = len(prompt)
209 if text[:lp] == prompt:
210 text = text[lp:]
211
212 self.SetSelection(self.lastPromptPos, lastPos)
213 self.ReplaceSelection(text[:-1])
214
215 else: # try to execute the text from the prompt to the end
216 if lastPos == self.lastPromptPos:
217 self.AddText('\n')
218 self.Prompt()
219 return
220
221 text = self.GetTextRange(self.lastPromptPos, lastPos)
222 self.AddText('\n')
223
224 more = self.runsource(text)
225 if not more:
226 self.PushLine(text)
227 self.Prompt()
228
229 # TODO: Add handlers for Alt-P and Alt-N to cycle through entries
230 # in the line cache
231
232 else:
233 evt.Skip()
234
235
236 def OnStyle(self, evt):
237 # Only style from the prompt pos to the end
238 lastPos = self.GetTextLength()
239 if self.lastPromptPos and self.lastPromptPos != lastPos:
240 self.SetLexer(wxSTC_LEX_PYTHON)
241 self.SetKeywords(0, ' '.join(keyword.kwlist))
242
243 self.Colourise(self.lastPromptPos, lastPos)
244
245 self.SetLexer(0)
246
247
248 def OnUpdateUI(self, evt):
249 # check for matching braces
250 braceAtCaret = -1
251 braceOpposite = -1
252 charBefore = None
253 caretPos = self.GetCurrentPos()
254 if caretPos > 0:
255 charBefore = self.GetCharAt(caretPos - 1)
256 styleBefore = self.GetStyleAt(caretPos - 1)
257
258 # check before
259 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == wxSTC_P_OPERATOR:
260 braceAtCaret = caretPos - 1
261
262 # check after
263 if braceAtCaret < 0:
264 charAfter = self.GetCharAt(caretPos)
265 styleAfter = self.GetStyleAt(caretPos)
266 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == wxSTC_P_OPERATOR:
267 braceAtCaret = caretPos
268
269 if braceAtCaret >= 0:
270 braceOpposite = self.BraceMatch(braceAtCaret)
271
272 if braceAtCaret != -1 and braceOpposite == -1:
273 self.BraceBadlight(braceAtCaret)
274 else:
275 self.BraceHighlight(braceAtCaret, braceOpposite)
276
277
278
279 #----------------------------------------------
280 # overloaded methods from InteractiveInterpreter
281 def runsource(self, source):
282 stdout, stderr = sys.stdout, sys.stderr
283 sys.stdout = FauxFile(self, _stdout_style)
284 sys.stderr = FauxFile(self, _stderr_style)
285
286 more = InteractiveInterpreter.runsource(self, source)
287
288 sys.stdout, sys.stderr = stdout, stderr
289 return more
290
291 def showsyntaxerror(self, filename=None):
292 self.write = self.writeTrace
293 InteractiveInterpreter.showsyntaxerror(self, filename)
294 self.write = self._write
295
296 def showtraceback(self):
297 self.write = self.writeTrace
298 InteractiveInterpreter.showtraceback(self)
299 self.write = self._write
300
301#----------------------------------------------------------------------
302
303class FauxFile:
304 def __init__(self, psw, style):
305 self.psw = psw
306 self.style = style
307
308 def write(self, text):
309 self.psw.write(text, self.style)
310
311 def writelines(self, lst):
312 map(self.write, lst)
313
314 def flush(self):
315 pass
316
317
318#----------------------------------------------------------------------
319# test code
320
321if __name__ == '__main__':
322 app = wxPyWidgetTester(size = (640, 480))
323 app.SetWidget(PyShellWindow, -1)
324 app.MainLoop()
325
326
327#----------------------------------------------------------------------
1fded56b 328
1fded56b 329