blob: f83ee0c653a328f9234a8697296482e0454f0235 [file] [log] [blame]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00001#! /usr/bin/env python
2
3import os
4import sys
5import string
Guido van Rossum80d132d1998-10-16 16:12:11 +00006import getopt
Guido van Rossum5af7a721998-10-12 23:59:27 +00007import re
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00008
9import linecache
10from code import InteractiveInterpreter
11
12from Tkinter import *
13import tkMessageBox
14
Guido van Rossum504b0bf1999-01-02 21:28:54 +000015from EditorWindow import EditorWindow, fixwordbreaks
16from FileList import FileList
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000017from ColorDelegator import ColorDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +000018from OutputWindow import OutputWindow
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000019
Guido van Rossumcc0ade81998-10-19 02:26:16 +000020# We need to patch linecache.checkcache, because we don't want it
21# to throw away our <pyshell#...> entries.
22# Rather than repeating its code here, we save those entries,
23# then call the original function, and then restore the saved entries.
24def linecache_checkcache(orig_checkcache=linecache.checkcache):
25 cache = linecache.cache
26 save = {}
27 for filename in cache.keys():
28 if filename[:1] + filename[-1:] == '<>':
29 save[filename] = cache[filename]
30 orig_checkcache()
31 cache.update(save)
32linecache.checkcache = linecache_checkcache
33
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000034
Guido van Rossum504b0bf1999-01-02 21:28:54 +000035# Note: <<newline-and-indent>> event is defined in AutoIndent.py
Guido van Rossumcc0ade81998-10-19 02:26:16 +000036
Guido van Rossum504b0bf1999-01-02 21:28:54 +000037#$ event <<plain-newline-and-indent>>
38#$ win <Control-j>
39#$ unix <Control-j>
40
41#$ event <<beginning-of-line>>
42#$ win <Control-a>
43#$ win <Home>
44#$ unix <Control-a>
45#$ unix <Home>
46
47#$ event <<history-next>>
48#$ win <Alt-n>
49#$ unix <Alt-n>
50
51#$ event <<history-previous>>
52#$ win <Alt-p>
53#$ unix <Alt-p>
54
55#$ event <<interrupt-execution>>
56#$ win <Control-c>
57#$ unix <Control-c>
58
59#$ event <<end-of-file>>
60#$ win <Control-d>
61#$ unix <Control-d>
62
63#$ event <<open-stack-viewer>>
64
65#$ event <<toggle-debugger>>
66
67
68class PyShellEditorWindow(EditorWindow):
69
70 # Regular text edit window when a shell is present
71 # XXX ought to merge with regular editor window
72
73 def __init__(self, *args):
74 apply(EditorWindow.__init__, (self,) + args)
75 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
76 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
77
78 rmenu_specs = [
79 ("Set breakpoint here", "<<set-breakpoint-here>>"),
80 ]
81
82 def set_breakpoint_here(self, event=None):
Guido van Rossumcc0ade81998-10-19 02:26:16 +000083 if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
84 self.text.bell()
85 return
86 self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
Guido van Rossum5af7a721998-10-12 23:59:27 +000087
88
89class PyShellFileList(FileList):
Guido van Rossum504b0bf1999-01-02 21:28:54 +000090
91 # File list when a shell is present
92
Guido van Rossum5af7a721998-10-12 23:59:27 +000093 EditorWindow = PyShellEditorWindow
Guido van Rossum504b0bf1999-01-02 21:28:54 +000094
Guido van Rossum5af7a721998-10-12 23:59:27 +000095 pyshell = None
96
Guido van Rossum504b0bf1999-01-02 21:28:54 +000097 def open_shell(self, event=None):
Guido van Rossum5af7a721998-10-12 23:59:27 +000098 if self.pyshell:
99 self.pyshell.wakeup()
100 else:
101 self.pyshell = PyShell(self)
102 self.pyshell.begin()
103 return self.pyshell
104
105
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000106class ModifiedColorDelegator(ColorDelegator):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000107
108 # Colorizer for the shell window itself
109
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000110 def recolorize_main(self):
111 self.tag_remove("TODO", "1.0", "iomark")
112 self.tag_add("SYNC", "1.0", "iomark")
113 ColorDelegator.recolorize_main(self)
114
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000115 tagdefs = ColorDelegator.tagdefs.copy()
Guido van Rossum7de69751999-04-20 15:45:30 +0000116 cprefs = ColorDelegator.cprefs
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000117
118 tagdefs.update({
Guido van Rossum7de69751999-04-20 15:45:30 +0000119 "stdin": {"foreground": cprefs.CStdIn[0],
120 "background": cprefs.CStdIn[1]},
121 "stdout": {"foreground": cprefs.CStdOut[0],
122 "background": cprefs.CStdOut[1]},
123 "stderr": {"foreground": cprefs.CStdErr[0],
124 "background": cprefs.CStdErr[1]},
125 "console": {"foreground": cprefs.CConsole[0],
126 "background": cprefs.CConsole[1]},
127 "ERROR": {"background": cprefs.CError[0],
128 "background": cprefs.CError[1]},
129 None: {"foreground": cprefs.CNormal[0],
130 "background": cprefs.CNormal[1]},
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000131 })
132
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000133
134class ModifiedInterpreter(InteractiveInterpreter):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000135
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000136 def __init__(self, tkconsole):
137 self.tkconsole = tkconsole
138 InteractiveInterpreter.__init__(self)
139
140 gid = 0
141
142 def runsource(self, source):
143 # Extend base class to stuff the source in the line cache
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000144 filename = "<pyshell#%d>" % self.gid
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000145 self.gid = self.gid + 1
146 lines = string.split(source, "\n")
147 linecache.cache[filename] = len(source)+1, 0, lines, filename
148 self.more = 0
149 return InteractiveInterpreter.runsource(self, source, filename)
150
151 def showsyntaxerror(self, filename=None):
152 # Extend base class to color the offending position
153 # (instead of printing it and pointing at it with a caret)
154 text = self.tkconsole.text
155 stuff = self.unpackerror()
156 if not stuff:
157 self.tkconsole.resetoutput()
158 InteractiveInterpreter.showsyntaxerror(self, filename)
159 return
160 msg, lineno, offset, line = stuff
161 if lineno == 1:
162 pos = "iomark + %d chars" % (offset-1)
163 else:
164 pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
165 offset-1)
166 text.tag_add("ERROR", pos)
167 text.see(pos)
168 char = text.get(pos)
169 if char in string.letters + string.digits + "_":
170 text.tag_add("ERROR", pos + " wordstart", pos)
171 self.tkconsole.resetoutput()
172 self.write("SyntaxError: %s\n" % str(msg))
173
174 def unpackerror(self):
175 type, value, tb = sys.exc_info()
176 ok = type == SyntaxError
177 if ok:
178 try:
179 msg, (dummy_filename, lineno, offset, line) = value
180 except:
181 ok = 0
182 if ok:
183 return msg, lineno, offset, line
184 else:
185 return None
186
187 def showtraceback(self):
188 # Extend base class method to reset output properly
189 text = self.tkconsole.text
190 self.tkconsole.resetoutput()
Guido van Rossum19563521998-10-13 16:32:05 +0000191 self.checklinecache()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000192 InteractiveInterpreter.showtraceback(self)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000193
Guido van Rossum19563521998-10-13 16:32:05 +0000194 def checklinecache(self):
195 c = linecache.cache
196 for key in c.keys():
197 if key[:1] + key[-1:] != "<>":
198 del c[key]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000199
Guido van Rossum35f75421998-10-13 23:51:13 +0000200 debugger = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000201
Guido van Rossum35f75421998-10-13 23:51:13 +0000202 def setdebugger(self, debugger):
203 self.debugger = debugger
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000204
Guido van Rossum35f75421998-10-13 23:51:13 +0000205 def getdebugger(self):
206 return self.debugger
207
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000208 def runcode(self, code):
209 # Override base class method
Guido van Rossum35f75421998-10-13 23:51:13 +0000210 debugger = self.debugger
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000211 try:
212 self.tkconsole.beginexecuting()
213 try:
Guido van Rossum35f75421998-10-13 23:51:13 +0000214 if debugger:
215 debugger.run(code, self.locals)
216 else:
217 exec code in self.locals
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000218 except SystemExit:
219 if tkMessageBox.askyesno(
220 "Exit?",
221 "Do you want to exit altogether?",
222 default="yes",
223 master=self.tkconsole.text):
224 raise
225 else:
226 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000227 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000228 self.tkconsole.open_stack_viewer()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000229 except:
230 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000231 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000232 self.tkconsole.open_stack_viewer()
233
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000234 finally:
235 self.tkconsole.endexecuting()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000236
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000237 def write(self, s):
238 # Override base class write
239 self.tkconsole.console.write(s)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000240
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000241
242class PyShell(OutputWindow):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000243
244 # Override classes
245 ColorDelegator = ModifiedColorDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000246
Guido van Rossum5af7a721998-10-12 23:59:27 +0000247 # Override menu bar specs
248 menu_specs = PyShellEditorWindow.menu_specs[:]
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000249 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
250
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000251 # New classes
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000252 from History import History
253
254 def __init__(self, flist=None):
255 self.interp = ModifiedInterpreter(self)
256 if flist is None:
257 root = Tk()
258 fixwordbreaks(root)
259 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000260 flist = PyShellFileList(root)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000261
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000262 OutputWindow.__init__(self, flist, None, None)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000263
264 import __builtin__
265 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
266
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000267 self.auto = self.extensions["AutoIndent"] # Required extension
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000268 self.auto.config(prefertabs=1)
269
270 text = self.text
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000271 text.configure(wrap="char")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000272 text.bind("<<newline-and-indent>>", self.enter_callback)
273 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
274 text.bind("<<interrupt-execution>>", self.cancel_callback)
275 text.bind("<<beginning-of-line>>", self.home_callback)
276 text.bind("<<end-of-file>>", self.eof_callback)
Guido van Rossum5af7a721998-10-12 23:59:27 +0000277 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Guido van Rossum35f75421998-10-13 23:51:13 +0000278 text.bind("<<toggle-debugger>>", self.toggle_debugger)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000279 text.bind("<<open-python-shell>>", self.flist.open_shell)
Guido van Rossum38df3c31999-01-08 15:31:07 +0000280 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000281
282 sys.stdout = PseudoFile(self, "stdout")
Guido van Rossum3f08d401998-10-13 15:21:41 +0000283 sys.stderr = PseudoFile(self, "stderr")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000284 sys.stdin = self
285 self.console = PseudoFile(self, "console")
286
287 self.history = self.History(self.text)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000288
289 reading = 0
290 executing = 0
291 canceled = 0
292 endoffile = 0
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000293
Guido van Rossum35f75421998-10-13 23:51:13 +0000294 def toggle_debugger(self, event=None):
295 if self.executing:
296 tkMessageBox.showerror("Don't debug now",
297 "You can only toggle the debugger when idle",
298 master=self.text)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000299 self.set_debugger_indicator()
Guido van Rossum35f75421998-10-13 23:51:13 +0000300 return "break"
Guido van Rossum35e55da1998-10-14 03:43:05 +0000301 else:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000302 db = self.interp.getdebugger()
303 if db:
304 self.close_debugger()
305 else:
306 self.open_debugger()
307
308 def set_debugger_indicator(self):
309 db = self.interp.getdebugger()
310 self.setvar("<<toggle-debugger>>", not not db)
Guido van Rossum38df3c31999-01-08 15:31:07 +0000311 def toggle_jit_stack_viewer( self, event=None):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000312 pass # All we need is the variable
Guido van Rossum38df3c31999-01-08 15:31:07 +0000313
Guido van Rossum35e55da1998-10-14 03:43:05 +0000314 def close_debugger(self):
315 db = self.interp.getdebugger()
316 if db:
317 self.interp.setdebugger(None)
Guido van Rossum35f75421998-10-13 23:51:13 +0000318 db.close()
319 self.resetoutput()
320 self.console.write("[DEBUG OFF]\n")
321 sys.ps1 = ">>> "
322 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000323 self.set_debugger_indicator()
Guido van Rossum35e55da1998-10-14 03:43:05 +0000324
325 def open_debugger(self):
326 import Debugger
327 self.interp.setdebugger(Debugger.Debugger(self))
Guido van Rossumadfe7731998-10-16 21:09:35 +0000328 sys.ps1 = "[DEBUG ON]\n>>> "
Guido van Rossum35e55da1998-10-14 03:43:05 +0000329 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000330 self.set_debugger_indicator()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000331
332 def beginexecuting(self):
333 # Helper for ModifiedInterpreter
334 self.resetoutput()
335 self.executing = 1
336 self._cancel_check = self.cancel_check
337 ##sys.settrace(self._cancel_check)
338
339 def endexecuting(self):
340 # Helper for ModifiedInterpreter
341 sys.settrace(None)
342 self.executing = 0
343 self.canceled = 0
344
345 def close(self):
346 # Extend base class method
347 if self.executing:
348 # XXX Need to ask a question here
349 if not tkMessageBox.askokcancel(
Guido van Rossum07ec8961999-01-28 22:02:47 +0000350 "Kill?",
351 "The program is still running; do you want to kill it?",
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000352 default="ok",
353 master=self.text):
354 return "cancel"
355 self.canceled = 1
356 if self.reading:
357 self.top.quit()
358 return "cancel"
Guido van Rossum5af7a721998-10-12 23:59:27 +0000359 reply = PyShellEditorWindow.close(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000360 if reply != "cancel":
Guido van Rossum5af7a721998-10-12 23:59:27 +0000361 self.flist.pyshell = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000362 # Restore std streams
363 sys.stdout = sys.__stdout__
364 sys.stderr = sys.__stderr__
365 sys.stdin = sys.__stdin__
366 # Break cycles
367 self.interp = None
368 self.console = None
369 return reply
370
371 def ispythonsource(self, filename):
372 # Override this so EditorWindow never removes the colorizer
373 return 1
374
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000375 def short_title(self):
376 return "Python Shell"
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000377
Guido van Rossum5af7a721998-10-12 23:59:27 +0000378 def begin(self):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000379 self.resetoutput()
380 self.write("Python %s on %s\n%s\n" %
381 (sys.version, sys.platform, sys.copyright))
382 try:
383 sys.ps1
384 except AttributeError:
385 sys.ps1 = ">>> "
386 self.showprompt()
387 import Tkinter
388 Tkinter._default_root = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000389
Guido van Rossum5af7a721998-10-12 23:59:27 +0000390 def interact(self):
391 self.begin()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000392 self.top.mainloop()
393
394 def readline(self):
395 save = self.reading
396 try:
397 self.reading = 1
398 self.top.mainloop()
399 finally:
400 self.reading = save
401 line = self.text.get("iomark", "end-1c")
402 self.resetoutput()
403 if self.canceled:
404 self.canceled = 0
405 raise KeyboardInterrupt
406 if self.endoffile:
407 self.endoffile = 0
408 return ""
409 return line
410
411 def cancel_callback(self, event):
412 try:
413 if self.text.compare("sel.first", "!=", "sel.last"):
414 return # Active selection -- always use default binding
415 except:
416 pass
417 if not (self.executing or self.reading):
418 self.resetoutput()
419 self.write("KeyboardInterrupt\n")
420 self.showprompt()
421 return "break"
422 self.endoffile = 0
423 self.canceled = 1
424 if self.reading:
425 self.top.quit()
426 return "break"
427
428 def eof_callback(self, event):
429 if self.executing and not self.reading:
430 return # Let the default binding (delete next char) take over
431 if not (self.text.compare("iomark", "==", "insert") and
432 self.text.compare("insert", "==", "end-1c")):
433 return # Let the default binding (delete next char) take over
434 if not self.executing:
435## if not tkMessageBox.askokcancel(
436## "Exit?",
437## "Are you sure you want to exit?",
438## default="ok", master=self.text):
439## return "break"
440 self.resetoutput()
441 self.close()
442 else:
443 self.canceled = 0
444 self.endoffile = 1
445 self.top.quit()
446 return "break"
447
448 def home_callback(self, event):
449 if event.state != 0 and event.keysym == "Home":
450 return # <Modifier-Home>; fall back to class binding
451 if self.text.compare("iomark", "<=", "insert") and \
452 self.text.compare("insert linestart", "<=", "iomark"):
453 self.text.mark_set("insert", "iomark")
454 self.text.tag_remove("sel", "1.0", "end")
455 self.text.see("insert")
456 return "break"
457
458 def linefeed_callback(self, event):
459 # Insert a linefeed without entering anything (still autoindented)
460 if self.reading:
461 self.text.insert("insert", "\n")
462 self.text.see("insert")
463 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000464 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000465 return "break"
466
467 def enter_callback(self, event):
468 if self.executing and not self.reading:
469 return # Let the default binding (insert '\n') take over
470 # If some text is selected, recall the selection
Guido van Rossum4650df91998-10-13 14:41:27 +0000471 # (but only if this before the I/O mark)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000472 try:
473 sel = self.text.get("sel.first", "sel.last")
474 if sel:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000475 if self.text.compare("sel.last", "<=", "iomark"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000476 self.recall(sel)
477 return "break"
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000478 except:
479 pass
480 # If we're strictly before the line containing iomark, recall
481 # the current line, less a leading prompt, less leading or
482 # trailing whitespace
483 if self.text.compare("insert", "<", "iomark linestart"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000484 # Check if there's a relevant stdin range -- if so, use it
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000485 prev = self.text.tag_prevrange("stdin", "insert")
486 if prev and self.text.compare("insert", "<", prev[1]):
487 self.recall(self.text.get(prev[0], prev[1]))
488 return "break"
489 next = self.text.tag_nextrange("stdin", "insert")
490 if next and self.text.compare("insert lineend", ">=", next[0]):
491 self.recall(self.text.get(next[0], next[1]))
492 return "break"
493 # No stdin mark -- just get the current line
494 self.recall(self.text.get("insert linestart", "insert lineend"))
495 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000496 # If we're in the current input before its last line,
497 # insert a newline right at the insert point
498 if self.text.compare("insert", "<", "end-1c linestart"):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000499 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000500 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000501 # We're in the last line; append a newline and submit it
502 self.text.mark_set("insert", "end-1c")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000503 if self.reading:
504 self.text.insert("insert", "\n")
505 self.text.see("insert")
506 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000507 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000508 self.text.tag_add("stdin", "iomark", "end-1c")
509 self.text.update_idletasks()
510 if self.reading:
511 self.top.quit() # Break out of recursive mainloop() in raw_input()
512 else:
513 self.runit()
514 return "break"
515
516 def recall(self, s):
517 if self.history:
518 self.history.recall(s)
519
520 def runit(self):
521 line = self.text.get("iomark", "end-1c")
522 # Strip off last newline and surrounding whitespace.
523 # (To allow you to hit return twice to end a statement.)
524 i = len(line)
525 while i > 0 and line[i-1] in " \t":
526 i = i-1
527 if i > 0 and line[i-1] == "\n":
528 i = i-1
529 while i > 0 and line[i-1] in " \t":
530 i = i-1
531 line = line[:i]
532 more = self.interp.runsource(line)
533 if not more:
534 self.showprompt()
535
536 def cancel_check(self, frame, what, args,
537 dooneevent=tkinter.dooneevent,
538 dontwait=tkinter.DONT_WAIT):
539 # Hack -- use the debugger hooks to be able to handle events
540 # and interrupt execution at any time.
541 # This slows execution down quite a bit, so you may want to
542 # disable this (by not calling settrace() in runcode() above)
543 # for full-bore (uninterruptable) speed.
544 # XXX This should become a user option.
545 if self.canceled:
546 return
547 dooneevent(dontwait)
548 if self.canceled:
549 self.canceled = 0
550 raise KeyboardInterrupt
551 return self._cancel_check
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000552
Guido van Rossum5af7a721998-10-12 23:59:27 +0000553 def open_stack_viewer(self, event=None):
554 try:
555 sys.last_traceback
556 except:
557 tkMessageBox.showerror("No stack trace",
558 "There is no stack trace yet.\n"
559 "(sys.last_traceback is not defined)",
560 master=self.text)
561 return
Guido van Rossum80d132d1998-10-16 16:12:11 +0000562 from StackViewer import StackBrowser
563 sv = StackBrowser(self.root, self.flist)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000564
565 def showprompt(self):
566 self.resetoutput()
567 try:
568 s = str(sys.ps1)
569 except:
570 s = ""
571 self.console.write(s)
572 self.text.mark_set("insert", "end-1c")
573
574 def resetoutput(self):
575 source = self.text.get("iomark", "end-1c")
576 if self.history:
577 self.history.history_store(source)
578 if self.text.get("end-2c") != "\n":
579 self.text.insert("end-1c", "\n")
580 self.text.mark_set("iomark", "end-1c")
581 sys.stdout.softspace = 0
582
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000583 def write(self, s, tags=()):
584 self.text.mark_gravity("iomark", "right")
585 OutputWindow.write(self, s, tags, "iomark")
586 self.text.mark_gravity("iomark", "left")
587 if self.canceled:
588 self.canceled = 0
589 raise KeyboardInterrupt
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000590
591class PseudoFile:
592
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000593 def __init__(self, shell, tags):
594 self.shell = shell
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000595 self.tags = tags
596
597 def write(self, s):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000598 self.shell.write(s, self.tags)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000599
600 def writelines(self, l):
601 map(self.write, l)
602
Guido van Rossum825df2a1999-03-29 14:52:28 +0000603 def flush(self):
604 pass
605
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000606
607def main():
Guido van Rossum80d132d1998-10-16 16:12:11 +0000608 debug = 0
609 try:
610 opts, args = getopt.getopt(sys.argv[1:], "d")
611 except getopt.error, msg:
612 sys.stderr.write("Error: %s\n" % str(msg))
613 sys.exit(2)
614 for o, a in opts:
615 if o == "-d":
616 debug = 1
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000617 global flist, root
618 root = Tk()
619 fixwordbreaks(root)
620 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000621 flist = PyShellFileList(root)
Guido van Rossum80d132d1998-10-16 16:12:11 +0000622 if args:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000623 for filename in sys.argv[1:]:
624 flist.open(filename)
Guido van Rossum8e473061999-02-01 23:06:17 +0000625 aPath = os.path.abspath(os.path.dirname(filename))
626 if not aPath in sys.path:
627 sys.path.insert(0, aPath)
628 else:
629 aPath = os.getcwd()
630 if not aPath in sys.path:
631 sys.path.insert(0, aPath)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000632 t = PyShell(flist)
Guido van Rossum5af7a721998-10-12 23:59:27 +0000633 flist.pyshell = t
634 t.begin()
Guido van Rossum80d132d1998-10-16 16:12:11 +0000635 if debug:
636 t.open_debugger()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000637 root.mainloop()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000638
639if __name__ == "__main__":
640 main()