]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/shell.py
2 #----------------------------------------------------------------------
3 # 12/10/2003 - Jeff Grimmett (grimmtooth@softhome.net)
5 # o 2.5 compatability update.
6 # o Added deprecation warning.
9 """wxPython interactive shell
11 Copyright (c) 1999 SIA "ANK"
13 this module is free software. it may be used under same terms as Python itself
16 i would like to use command completion (see rlcompleter library module),
17 but i cannot load it because i don't have readline...
20 03-oct-1999 [als] created
21 04-oct-1999 [als] PyShellOutput.intro moved from __init__ parameters
22 to class attributes; html debug disabled
23 04-oct-1999 [als] fixed bug with class attributes
24 input prompts and output styles added to customized demo
26 04-oct-1999 [rpd] Changed to use the new sizers
27 05-oct-1999 [als] changes inspired by code.InteractiveInterpreter()
28 from Python Library. if i knew about this class earlier,
29 i would rather inherit from it.
30 renamed to wxPyShell.py since i've renounced the 8.3 scheme
32 8-10-2001 THIS MODULE IS NOW DEPRECATED. Please see the most excellent
33 PyCrust package instead.
36 __version__
="$Revision$"
49 ########################################\
50 # THIS MODULE IS NOW DEPRECATED |
52 # Please see the most excellent PyCrust |
54 ########################################/
58 warnings
.warn(warningmsg
, DeprecationWarning, stacklevel
=2)
60 #----------------------------------------------------------------------
62 class PyShellInput(wx
.Panel
):
63 """PyShell input window
66 PS1
=" Enter Command:"
68 def __init__(self
, parent
, shell
, id=-1):
69 """Create input window
71 shell must be a PyShell object.
72 it is used for exception handling, eval() namespaces,
73 and shell.output is used for output
74 (print's go to overridden stdout)
76 wx
.Panel
.__init
__(self
, parent
, id)
78 # make a private copy of class attrs
79 self
.PS1
=PyShellInput
.PS1
80 self
.PS2
=PyShellInput
.PS2
82 self
.label
=wx
.StaticText(self
, -1, self
.PS1
)
84 self
.entry
=wx
.TextCtrl(self
, tid
, style
= wx
.TE_MULTILINE
)
85 self
.entry
.Bind(wx
.EVT_CHAR
, self
.OnChar
)
86 self
.entry
.SetFont(wx
.Font(9, wx
.MODERN
, wx
.NORMAL
, wx
.NORMAL
, False))
87 sizer
=wx
.BoxSizer(wx
.VERTICAL
)
88 sizer
.AddMany([(self
.label
, 0, wx
.EXPAND
), (self
.entry
, 1, wx
.EXPAND
)])
90 self
.SetAutoLayout(True)
91 self
.Bind(wx
.EVT_SET_FOCUS
, self
.OnSetFocus
)
92 # when in "continuation" mode,
93 # two consecutive newlines are required
94 # to avoid execution of unfinished block
97 def OnSetFocus(self
, event
):
101 def Clear(self
, event
=None):
102 """reset input state"""
103 self
.label
.SetLabel(self
.PS1
)
105 self
.entry
.SetSelection(0, self
.entry
.GetLastPosition())
107 # self.entry.SetFocus()
109 def OnChar(self
, event
):
110 """called on CHARevent. executes input on newline"""
111 # print "On Char:", event.__dict__.keys()
112 if event
.KeyCode() !=wx
.WXK_RETURN
:
113 # not of our business
116 text
=self
.entry
.GetValue()
118 text
= text
.replace("\r\n", "\n")
119 # see if we've finished
120 if (not (self
.first_line
or text
[-1] =="\n") # in continuation mode
121 or (text
[-1] =="\\") # escaped newline
123 # XXX should escaped newline put myself i "continuation" mode?
126 # ok, we can try to execute this
127 rc
=self
.shell
.TryExec(text
)
129 # code is incomplete; continue input
131 self
.label
.SetLabel(self
.PS2
)
138 class PyShellOutput(wx
.Panel
):
139 """PyShell output window
141 for now, it is based on simple wxTextCtrl,
142 but i'm looking at HTML classes to provide colorized output
144 # attributes for for different (input, output, exception) display styles:
145 # begin tag, end tag, newline
146 in_style
=(" <font color=\"#000080\"><tt>>>> ",
147 "</tt></font><br>\n", "<br>\n... ")
148 out_style
=("<tt>", "</tt>\n", "<br>\n")
149 exc_style
=("<font color=\"#FF0000\"><tt>",
150 "</tt></font>\n", "<br>\n")
151 intro
="<H3>wxPython Interactive Shell</H3>\n"
154 erefs
=(("&", "&"), (">", ">"), ("<", "<"), (" ", " "))
155 def __init__(self
, parent
, id=-1):
156 wx
.Panel
.__init
__(self
, parent
, id)
157 # make a private copy of class attrs
158 self
.in_style
=PyShellOutput
.in_style
159 self
.out_style
=PyShellOutput
.out_style
160 self
.exc_style
=PyShellOutput
.exc_style
161 self
.intro
=PyShellOutput
.intro
162 self
.html_debug
=PyShellOutput
.html_debug
165 # this was used in html debugging,
166 # but i don't want to delete it; it's funny
167 splitter
=wx
.SplitterWindow(self
, -1)
168 self
.view
=wx
.TextCtrl(splitter
, -1,
169 style
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
)
170 self
.html
=wx
.html
.HtmlWindow(splitter
)
171 splitter
.SplitVertically(self
.view
, self
.html
)
172 splitter
.SetSashPosition(40)
173 splitter
.SetMinimumPaneSize(3)
174 self
.client
=splitter
177 self
.html
=wx
.html
.HtmlWindow(self
)
178 self
.client
=self
.html
# used in OnSize()
179 self
.text
=self
.intro
180 self
.html
.SetPage(self
.text
)
181 self
.html
.SetAutoLayout(True)
183 # refreshes are annoying
186 self
.Bind(wx
.EVT_SIZE
, self
.OnSize
)
187 self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
)
189 def OnSize(self
, event
):
190 self
.client
.SetSize(self
.GetClientSize())
192 def OnIdle(self
, event
):
193 """when there's nothing to do, we can update display"""
194 if self
.in_batch
and self
.dirty
: self
.UpdWindow()
196 def BeginBatch(self
):
197 """do not refresh display till EndBatch()"""
201 """end batch; start updating display immediately"""
203 if self
.dirty
: self
.UpdWindow()
206 """sync display with text buffer"""
208 html
.SetPage(self
.text
)
211 (x
,y
) =html
.GetVirtualSize()
214 def AddText(self
, text
, style
=None):
215 """write text to output window"""
216 # a trick needed to defer default from compile-time to execute-time
217 if style
==None: style
=self
.out_style
218 if 0 and __debug__
: sys
.__stdout
__.write(text
)
220 for (symbol
, eref
) in self
.erefs
:
221 text
= text
.replace(symbol
, eref
)
223 text
= text
.replace("\n", style
[2])
225 self
.text
=self
.text
+style
[0] +text
+style
[1]
226 if not self
.in_batch
: self
.UpdWindow()
229 # html debug output needn't to be too large
230 self
.view
.SetValue(self
.text
[-4096:])
232 def write(self
, str, style
=None):
233 """stdout-like interface"""
234 if style
==None: style
=self
.out_style
235 # do not process incomplete lines
237 # hm... what was i supposed to do?
240 self
.line_buffer
=self
.line_buffer
+str
242 self
.AddText(self
.line_buffer
+str, style
)
245 def flush(self
, style
=None):
246 """write out all that was left in line buffer"""
247 if style
==None: style
=self
.out_style
248 self
.AddText(self
.line_buffer
+"\n", style
)
250 def write_in(self
, str, style
=None):
251 """write text in "input" style"""
252 if style
==None: style
=self
.in_style
253 self
.AddText(str, style
)
255 def write_exc(self
, str, style
=None):
256 """write text in "exception" style"""
257 if style
==None: style
=self
.exc_style
258 self
.AddText(str, style
)
260 class PyShell(wx
.Panel
):
261 """interactive Python shell with wxPython interface
264 def __init__(self
, parent
, globals=globals(), locals={},
265 id=-1, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
266 style
=wx
.TAB_TRAVERSAL
, name
="shell"):
267 """create PyShell window"""
268 wx
.Panel
.__init
__(self
, parent
, id, pos
, size
, style
, name
)
269 self
.globals =globals
271 splitter
=wx
.SplitterWindow(self
, -1)
272 self
.output
=PyShellOutput(splitter
)
273 self
.input =PyShellInput(splitter
, self
)
274 self
.input.SetFocus()
275 splitter
.SplitHorizontally(self
.input, self
.output
)
276 splitter
.SetSashPosition(100)
277 splitter
.SetMinimumPaneSize(20)
278 self
.splitter
=splitter
279 self
.Bind(wx
.EVT_SET_FOCUS
, self
.OnSetFocus
)
280 self
.Bind(wx
.EVT_SIZE
, self
.OnSize
)
282 def OnSetFocus(self
, event
):
283 self
.input.SetFocus()
285 def TryExec(self
, source
, symbol
="single"):
286 """Compile and run some source in the interpreter.
288 borrowed from code.InteractiveInterpreter().runsource()
289 as i said above, i would rather like to inherit from that class
291 returns 1 if more input is required, or 0, otherwise
294 cc
= code
.compile_command(source
, symbol
=symbol
)
295 except (OverflowError, SyntaxError):
296 # [als] hm... never seen anything of that kind
297 self
.ShowSyntaxError()
300 # source is incomplete
302 # source is sucessfully compiled
304 # redirect system stdout to the output window
307 # begin printout batch (html updates are deferred until EndBatch())
311 exec cc
in self
.globals, self
.locals
313 # SystemExit is not handled and has to be re-raised
316 # all other exceptions produce traceback output
318 # switch back to saved stdout
325 def ShowException(self
):
326 """display the traceback for the latest exception"""
327 (etype
, value
, tb
) =sys
.exc_info()
328 # remove myself from traceback
329 tblist
=traceback
.extract_tb(tb
)[1:]
330 msg
= ' '.join(traceback
.format_exception_only(etype
, value
)
331 +traceback
.format_list(tblist
))
332 self
.output
.write_exc(msg
)
334 def ShowSyntaxError(self
):
335 """display message about syntax error (no traceback here)"""
336 (etype
, value
, tb
) =sys
.exc_info()
337 msg
= ' '.join(traceback
.format_exception_only(etype
, value
))
338 self
.output
.write_exc(msg
)
340 def OnSize(self
, event
):
341 self
.splitter
.SetSize(self
.GetClientSize())
343 #----------------------------------------------------------------------
344 if __name__
== '__main__':
345 class MyFrame(wx
.Frame
):
346 """Very standard Frame class. Nothing special here!"""
347 def __init__(self
, parent
=None, id =-1,
348 title
="wxPython Interactive Shell"):
349 wx
.Frame
.__init
__(self
, parent
, id, title
)
350 self
.shell
=PyShell(self
)
353 """Demonstrates usage of both default and customized shells"""
357 self
.SetTopWindow(frame
)
358 ## PyShellInput.PS1 =" let's get some work done..."
359 ## PyShellInput.PS2 =" ok, what do you really mean?"
360 ## PyShellOutput.in_style =(
361 ## "<I><font color=\"#008000\"><tt>>>> ",
362 ## "</tt></font></I><br>\n", "<br>\n... ")
363 ## PyShellOutput.out_style =(
364 ## "<font color=\"#000080\"><tt>",
365 ## "</tt></font><br>\n", "<br>\n")
366 ## PyShellOutput.exc_style =("<B><font color=\"#FF0000\"><tt>",
367 ## "</tt></font></B>\n", "<br>\n")
368 ## PyShellOutput.intro ="<I><B>Customized wxPython Shell</B>" \
369 ## "<br><-- move this sash to see html debug output</I><br>\n"
370 ## PyShellOutput.html_debug =1
371 ## frame = MyFrame(title="Customized wxPython Shell")