blob: 73def14f914c35fae3d03b3ab19451f519e7fba9 [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
Guido van Rossumeeb88071999-04-22 20:49:35 +0000138 locals = sys.modules['__main__'].__dict__
139 InteractiveInterpreter.__init__(self, locals=locals)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000140
141 gid = 0
142
Guido van Rossumeeb88071999-04-22 20:49:35 +0000143 def execsource(self, source):
144 # Like runsource() but assumes complete exec source
145 filename = self.stuffsource(source)
146 self.execfile(filename, source)
147
148 def execfile(self, filename, source=None):
149 # Execute an existing file
150 if source is None:
151 source = open(filename, "r").read()
152 try:
153 code = compile(source, filename, "exec")
154 except (OverflowError, SyntaxError):
155 self.tkconsole.resetoutput()
156 InteractiveInterpreter.showsyntaxerror(self, filename)
157 else:
158 self.runcode(code)
159
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000160 def runsource(self, source):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000161 # Extend base class to stuff the source in the line cache first
162 filename = self.stuffsource(source)
163 self.more = 0
164 return InteractiveInterpreter.runsource(self, source, filename)
165
166 def stuffsource(self, source):
167 # Stuff source in the filename cache
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000168 filename = "<pyshell#%d>" % self.gid
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000169 self.gid = self.gid + 1
170 lines = string.split(source, "\n")
171 linecache.cache[filename] = len(source)+1, 0, lines, filename
Guido van Rossumeeb88071999-04-22 20:49:35 +0000172 return filename
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000173
174 def showsyntaxerror(self, filename=None):
175 # Extend base class to color the offending position
176 # (instead of printing it and pointing at it with a caret)
177 text = self.tkconsole.text
178 stuff = self.unpackerror()
179 if not stuff:
180 self.tkconsole.resetoutput()
181 InteractiveInterpreter.showsyntaxerror(self, filename)
182 return
183 msg, lineno, offset, line = stuff
184 if lineno == 1:
185 pos = "iomark + %d chars" % (offset-1)
186 else:
187 pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
188 offset-1)
189 text.tag_add("ERROR", pos)
190 text.see(pos)
191 char = text.get(pos)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000192 if char and char in string.letters + string.digits + "_":
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000193 text.tag_add("ERROR", pos + " wordstart", pos)
194 self.tkconsole.resetoutput()
195 self.write("SyntaxError: %s\n" % str(msg))
196
197 def unpackerror(self):
198 type, value, tb = sys.exc_info()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000199 ok = type is SyntaxError
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000200 if ok:
201 try:
202 msg, (dummy_filename, lineno, offset, line) = value
203 except:
204 ok = 0
205 if ok:
206 return msg, lineno, offset, line
207 else:
208 return None
209
210 def showtraceback(self):
211 # Extend base class method to reset output properly
212 text = self.tkconsole.text
213 self.tkconsole.resetoutput()
Guido van Rossum19563521998-10-13 16:32:05 +0000214 self.checklinecache()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000215 InteractiveInterpreter.showtraceback(self)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000216
Guido van Rossum19563521998-10-13 16:32:05 +0000217 def checklinecache(self):
218 c = linecache.cache
219 for key in c.keys():
220 if key[:1] + key[-1:] != "<>":
221 del c[key]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000222
Guido van Rossum35f75421998-10-13 23:51:13 +0000223 debugger = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000224
Guido van Rossum35f75421998-10-13 23:51:13 +0000225 def setdebugger(self, debugger):
226 self.debugger = debugger
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000227
Guido van Rossum35f75421998-10-13 23:51:13 +0000228 def getdebugger(self):
229 return self.debugger
230
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000231 def runcode(self, code):
232 # Override base class method
Guido van Rossum35f75421998-10-13 23:51:13 +0000233 debugger = self.debugger
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000234 try:
235 self.tkconsole.beginexecuting()
236 try:
Guido van Rossum35f75421998-10-13 23:51:13 +0000237 if debugger:
238 debugger.run(code, self.locals)
239 else:
240 exec code in self.locals
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000241 except SystemExit:
242 if tkMessageBox.askyesno(
243 "Exit?",
244 "Do you want to exit altogether?",
245 default="yes",
246 master=self.tkconsole.text):
247 raise
248 else:
249 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000250 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000251 self.tkconsole.open_stack_viewer()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000252 except:
253 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000254 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000255 self.tkconsole.open_stack_viewer()
256
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000257 finally:
258 self.tkconsole.endexecuting()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000259
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000260 def write(self, s):
261 # Override base class write
262 self.tkconsole.console.write(s)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000263
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000264
265class PyShell(OutputWindow):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000266
Guido van Rossumeeb88071999-04-22 20:49:35 +0000267 shell_title = "Python Shell"
268
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000269 # Override classes
270 ColorDelegator = ModifiedColorDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000271
Guido van Rossum5af7a721998-10-12 23:59:27 +0000272 # Override menu bar specs
273 menu_specs = PyShellEditorWindow.menu_specs[:]
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000274 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
275
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000276 # New classes
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000277 from History import History
278
279 def __init__(self, flist=None):
280 self.interp = ModifiedInterpreter(self)
281 if flist is None:
282 root = Tk()
283 fixwordbreaks(root)
284 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000285 flist = PyShellFileList(root)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000286
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000287 OutputWindow.__init__(self, flist, None, None)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000288
289 import __builtin__
290 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
291
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000292 self.auto = self.extensions["AutoIndent"] # Required extension
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000293 self.auto.config(prefertabs=1)
294
295 text = self.text
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000296 text.configure(wrap="char")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000297 text.bind("<<newline-and-indent>>", self.enter_callback)
298 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
299 text.bind("<<interrupt-execution>>", self.cancel_callback)
300 text.bind("<<beginning-of-line>>", self.home_callback)
301 text.bind("<<end-of-file>>", self.eof_callback)
Guido van Rossum5af7a721998-10-12 23:59:27 +0000302 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Guido van Rossum35f75421998-10-13 23:51:13 +0000303 text.bind("<<toggle-debugger>>", self.toggle_debugger)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000304 text.bind("<<open-python-shell>>", self.flist.open_shell)
Guido van Rossum38df3c31999-01-08 15:31:07 +0000305 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000306
Guido van Rossumeeb88071999-04-22 20:49:35 +0000307 self.save_stdout = sys.stdout
308 self.save_stderr = sys.stderr
309 self.save_stdin = sys.stdin
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000310 sys.stdout = PseudoFile(self, "stdout")
Guido van Rossum3f08d401998-10-13 15:21:41 +0000311 sys.stderr = PseudoFile(self, "stderr")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000312 sys.stdin = self
313 self.console = PseudoFile(self, "console")
314
315 self.history = self.History(self.text)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000316
317 reading = 0
318 executing = 0
319 canceled = 0
320 endoffile = 0
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000321
Guido van Rossum35f75421998-10-13 23:51:13 +0000322 def toggle_debugger(self, event=None):
323 if self.executing:
324 tkMessageBox.showerror("Don't debug now",
325 "You can only toggle the debugger when idle",
326 master=self.text)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000327 self.set_debugger_indicator()
Guido van Rossum35f75421998-10-13 23:51:13 +0000328 return "break"
Guido van Rossum35e55da1998-10-14 03:43:05 +0000329 else:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000330 db = self.interp.getdebugger()
331 if db:
332 self.close_debugger()
333 else:
334 self.open_debugger()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000335
Guido van Rossum07ec8961999-01-28 22:02:47 +0000336 def set_debugger_indicator(self):
337 db = self.interp.getdebugger()
338 self.setvar("<<toggle-debugger>>", not not db)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000339
Guido van Rossum38df3c31999-01-08 15:31:07 +0000340 def toggle_jit_stack_viewer( self, event=None):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000341 pass # All we need is the variable
Guido van Rossum38df3c31999-01-08 15:31:07 +0000342
Guido van Rossum35e55da1998-10-14 03:43:05 +0000343 def close_debugger(self):
344 db = self.interp.getdebugger()
345 if db:
346 self.interp.setdebugger(None)
Guido van Rossum35f75421998-10-13 23:51:13 +0000347 db.close()
348 self.resetoutput()
349 self.console.write("[DEBUG OFF]\n")
350 sys.ps1 = ">>> "
351 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000352 self.set_debugger_indicator()
Guido van Rossum35e55da1998-10-14 03:43:05 +0000353
354 def open_debugger(self):
355 import Debugger
356 self.interp.setdebugger(Debugger.Debugger(self))
Guido van Rossumadfe7731998-10-16 21:09:35 +0000357 sys.ps1 = "[DEBUG ON]\n>>> "
Guido van Rossum35e55da1998-10-14 03:43:05 +0000358 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000359 self.set_debugger_indicator()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000360
361 def beginexecuting(self):
362 # Helper for ModifiedInterpreter
363 self.resetoutput()
364 self.executing = 1
365 self._cancel_check = self.cancel_check
366 ##sys.settrace(self._cancel_check)
367
368 def endexecuting(self):
369 # Helper for ModifiedInterpreter
370 sys.settrace(None)
371 self.executing = 0
372 self.canceled = 0
373
374 def close(self):
375 # Extend base class method
376 if self.executing:
377 # XXX Need to ask a question here
378 if not tkMessageBox.askokcancel(
Guido van Rossum07ec8961999-01-28 22:02:47 +0000379 "Kill?",
380 "The program is still running; do you want to kill it?",
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000381 default="ok",
382 master=self.text):
383 return "cancel"
384 self.canceled = 1
385 if self.reading:
386 self.top.quit()
387 return "cancel"
Guido van Rossum5af7a721998-10-12 23:59:27 +0000388 reply = PyShellEditorWindow.close(self)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000389 if reply != "cancel":
Guido van Rossum5af7a721998-10-12 23:59:27 +0000390 self.flist.pyshell = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000391 # Restore std streams
Guido van Rossumeeb88071999-04-22 20:49:35 +0000392 sys.stdout = self.save_stdout
393 sys.stderr = self.save_stderr
394 sys.stdin = self.save_stdin
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000395 # Break cycles
396 self.interp = None
397 self.console = None
398 return reply
399
400 def ispythonsource(self, filename):
401 # Override this so EditorWindow never removes the colorizer
402 return 1
403
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000404 def short_title(self):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000405 return self.shell_title
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000406
Guido van Rossum5af7a721998-10-12 23:59:27 +0000407 def begin(self):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000408 self.resetoutput()
409 self.write("Python %s on %s\n%s\n" %
410 (sys.version, sys.platform, sys.copyright))
411 try:
412 sys.ps1
413 except AttributeError:
414 sys.ps1 = ">>> "
415 self.showprompt()
416 import Tkinter
417 Tkinter._default_root = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000418
Guido van Rossum5af7a721998-10-12 23:59:27 +0000419 def interact(self):
420 self.begin()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000421 self.top.mainloop()
422
423 def readline(self):
424 save = self.reading
425 try:
426 self.reading = 1
427 self.top.mainloop()
428 finally:
429 self.reading = save
430 line = self.text.get("iomark", "end-1c")
431 self.resetoutput()
432 if self.canceled:
433 self.canceled = 0
434 raise KeyboardInterrupt
435 if self.endoffile:
436 self.endoffile = 0
437 return ""
438 return line
439
440 def cancel_callback(self, event):
441 try:
442 if self.text.compare("sel.first", "!=", "sel.last"):
443 return # Active selection -- always use default binding
444 except:
445 pass
446 if not (self.executing or self.reading):
447 self.resetoutput()
448 self.write("KeyboardInterrupt\n")
449 self.showprompt()
450 return "break"
451 self.endoffile = 0
452 self.canceled = 1
453 if self.reading:
454 self.top.quit()
455 return "break"
456
457 def eof_callback(self, event):
458 if self.executing and not self.reading:
459 return # Let the default binding (delete next char) take over
460 if not (self.text.compare("iomark", "==", "insert") and
461 self.text.compare("insert", "==", "end-1c")):
462 return # Let the default binding (delete next char) take over
463 if not self.executing:
464## if not tkMessageBox.askokcancel(
465## "Exit?",
466## "Are you sure you want to exit?",
467## default="ok", master=self.text):
468## return "break"
469 self.resetoutput()
470 self.close()
471 else:
472 self.canceled = 0
473 self.endoffile = 1
474 self.top.quit()
475 return "break"
476
477 def home_callback(self, event):
478 if event.state != 0 and event.keysym == "Home":
479 return # <Modifier-Home>; fall back to class binding
480 if self.text.compare("iomark", "<=", "insert") and \
481 self.text.compare("insert linestart", "<=", "iomark"):
482 self.text.mark_set("insert", "iomark")
483 self.text.tag_remove("sel", "1.0", "end")
484 self.text.see("insert")
485 return "break"
486
487 def linefeed_callback(self, event):
488 # Insert a linefeed without entering anything (still autoindented)
489 if self.reading:
490 self.text.insert("insert", "\n")
491 self.text.see("insert")
492 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000493 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000494 return "break"
495
496 def enter_callback(self, event):
497 if self.executing and not self.reading:
498 return # Let the default binding (insert '\n') take over
499 # If some text is selected, recall the selection
Guido van Rossum4650df91998-10-13 14:41:27 +0000500 # (but only if this before the I/O mark)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000501 try:
502 sel = self.text.get("sel.first", "sel.last")
503 if sel:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000504 if self.text.compare("sel.last", "<=", "iomark"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000505 self.recall(sel)
506 return "break"
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000507 except:
508 pass
509 # If we're strictly before the line containing iomark, recall
510 # the current line, less a leading prompt, less leading or
511 # trailing whitespace
512 if self.text.compare("insert", "<", "iomark linestart"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000513 # Check if there's a relevant stdin range -- if so, use it
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000514 prev = self.text.tag_prevrange("stdin", "insert")
515 if prev and self.text.compare("insert", "<", prev[1]):
516 self.recall(self.text.get(prev[0], prev[1]))
517 return "break"
518 next = self.text.tag_nextrange("stdin", "insert")
519 if next and self.text.compare("insert lineend", ">=", next[0]):
520 self.recall(self.text.get(next[0], next[1]))
521 return "break"
522 # No stdin mark -- just get the current line
523 self.recall(self.text.get("insert linestart", "insert lineend"))
524 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000525 # If we're in the current input before its last line,
526 # insert a newline right at the insert point
527 if self.text.compare("insert", "<", "end-1c linestart"):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000528 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000529 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000530 # We're in the last line; append a newline and submit it
531 self.text.mark_set("insert", "end-1c")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000532 if self.reading:
533 self.text.insert("insert", "\n")
534 self.text.see("insert")
535 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000536 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000537 self.text.tag_add("stdin", "iomark", "end-1c")
538 self.text.update_idletasks()
539 if self.reading:
540 self.top.quit() # Break out of recursive mainloop() in raw_input()
541 else:
542 self.runit()
543 return "break"
544
545 def recall(self, s):
546 if self.history:
547 self.history.recall(s)
548
549 def runit(self):
550 line = self.text.get("iomark", "end-1c")
551 # Strip off last newline and surrounding whitespace.
552 # (To allow you to hit return twice to end a statement.)
553 i = len(line)
554 while i > 0 and line[i-1] in " \t":
555 i = i-1
556 if i > 0 and line[i-1] == "\n":
557 i = i-1
558 while i > 0 and line[i-1] in " \t":
559 i = i-1
560 line = line[:i]
561 more = self.interp.runsource(line)
562 if not more:
563 self.showprompt()
564
565 def cancel_check(self, frame, what, args,
566 dooneevent=tkinter.dooneevent,
567 dontwait=tkinter.DONT_WAIT):
568 # Hack -- use the debugger hooks to be able to handle events
569 # and interrupt execution at any time.
570 # This slows execution down quite a bit, so you may want to
571 # disable this (by not calling settrace() in runcode() above)
572 # for full-bore (uninterruptable) speed.
573 # XXX This should become a user option.
574 if self.canceled:
575 return
576 dooneevent(dontwait)
577 if self.canceled:
578 self.canceled = 0
579 raise KeyboardInterrupt
580 return self._cancel_check
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000581
Guido van Rossum5af7a721998-10-12 23:59:27 +0000582 def open_stack_viewer(self, event=None):
583 try:
584 sys.last_traceback
585 except:
586 tkMessageBox.showerror("No stack trace",
587 "There is no stack trace yet.\n"
588 "(sys.last_traceback is not defined)",
589 master=self.text)
590 return
Guido van Rossum80d132d1998-10-16 16:12:11 +0000591 from StackViewer import StackBrowser
592 sv = StackBrowser(self.root, self.flist)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000593
594 def showprompt(self):
595 self.resetoutput()
596 try:
597 s = str(sys.ps1)
598 except:
599 s = ""
600 self.console.write(s)
601 self.text.mark_set("insert", "end-1c")
602
603 def resetoutput(self):
604 source = self.text.get("iomark", "end-1c")
605 if self.history:
606 self.history.history_store(source)
607 if self.text.get("end-2c") != "\n":
608 self.text.insert("end-1c", "\n")
609 self.text.mark_set("iomark", "end-1c")
610 sys.stdout.softspace = 0
611
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000612 def write(self, s, tags=()):
613 self.text.mark_gravity("iomark", "right")
614 OutputWindow.write(self, s, tags, "iomark")
615 self.text.mark_gravity("iomark", "left")
616 if self.canceled:
617 self.canceled = 0
618 raise KeyboardInterrupt
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000619
620class PseudoFile:
621
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000622 def __init__(self, shell, tags):
623 self.shell = shell
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000624 self.tags = tags
625
626 def write(self, s):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000627 self.shell.write(s, self.tags)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000628
629 def writelines(self, l):
630 map(self.write, l)
631
Guido van Rossum825df2a1999-03-29 14:52:28 +0000632 def flush(self):
633 pass
634
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000635
Guido van Rossumeeb88071999-04-22 20:49:35 +0000636usage_msg = """\
637usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
638
639-c command run this command
640-d enable debugger
641-e edit mode; arguments are files to be edited
642-s run $PYTHONSTARTUP before anything else
643-t title set title of shell window
644
645When neither -c nor -e is used, and there are arguments, and the first
646argument is not '-', the first argument is run as a script. Remaining
647arguments are arguments to the script or to the command run by -c.
648"""
649
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000650def main():
Guido van Rossumeeb88071999-04-22 20:49:35 +0000651 cmd = None
652 edit = 0
Guido van Rossum80d132d1998-10-16 16:12:11 +0000653 debug = 0
Guido van Rossumeeb88071999-04-22 20:49:35 +0000654 startup = 0
655
Guido van Rossum80d132d1998-10-16 16:12:11 +0000656 try:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000657 opts, args = getopt.getopt(sys.argv[1:], "c:deist:")
Guido van Rossum80d132d1998-10-16 16:12:11 +0000658 except getopt.error, msg:
659 sys.stderr.write("Error: %s\n" % str(msg))
Guido van Rossumeeb88071999-04-22 20:49:35 +0000660 sys.stderr.write(usage_msg)
Guido van Rossum80d132d1998-10-16 16:12:11 +0000661 sys.exit(2)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000662
Guido van Rossum80d132d1998-10-16 16:12:11 +0000663 for o, a in opts:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000664 if o == '-c':
665 cmd = a
666 if o == '-d':
Guido van Rossum80d132d1998-10-16 16:12:11 +0000667 debug = 1
Guido van Rossumeeb88071999-04-22 20:49:35 +0000668 if o == '-e':
669 edit = 1
670 if o == '-s':
671 startup = 1
672 if o == '-t':
673 PyShell.shell_title = a
674
675 if not edit:
676 if cmd:
677 sys.argv = ["-c"] + args
678 else:
679 sys.argv = args or [""]
680
681 for i in range(len(sys.path)):
682 sys.path[i] = os.path.abspath(sys.path[i])
683
684 pathx = []
685 if edit:
686 for filename in args:
687 pathx.append(os.path.dirname(filename))
688 elif args and args[0] != "-":
689 pathx.append(os.path.dirname(args[0]))
690 else:
691 pathx.append(os.curdir)
692 for dir in pathx:
693 dir = os.path.abspath(dir)
694 if not dir in sys.path:
695 sys.path.insert(0, dir)
696
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000697 global flist, root
698 root = Tk()
699 fixwordbreaks(root)
700 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000701 flist = PyShellFileList(root)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000702
703 if edit:
704 for filename in args:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000705 flist.open(filename)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000706
707 shell = PyShell(flist)
708 interp = shell.interp
709 flist.pyshell = shell
710
711 if startup:
712 filename = os.environ.get("IDLESTARTUP") or \
713 os.environ.get("PYTHONSTARTUP")
714 if filename and os.path.isfile(filename):
715 interp.execfile(filename)
716
Guido van Rossum80d132d1998-10-16 16:12:11 +0000717 if debug:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000718 shell.open_debugger()
719 if cmd:
720 interp.execsource(cmd)
721 elif not edit and args and args[0] != "-":
722 interp.execfile(args[0])
723
724 shell.begin()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000725 root.mainloop()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000726
Guido van Rossumeeb88071999-04-22 20:49:35 +0000727
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000728if __name__ == "__main__":
729 main()