blob: bd34d181632a602a9fe02de1b1801d3614421bee [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 Rossumb4ce4302001-03-26 17:41:35 +00008import warnings
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00009
10import linecache
11from code import InteractiveInterpreter
12
13from Tkinter import *
14import tkMessageBox
15
Guido van Rossum504b0bf1999-01-02 21:28:54 +000016from EditorWindow import EditorWindow, fixwordbreaks
17from FileList import FileList
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000018from ColorDelegator import ColorDelegator
Guido van Rossum9de98832000-03-07 18:51:49 +000019from UndoDelegator import UndoDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +000020from OutputWindow import OutputWindow
Jeremy Hylton6b3edf02000-03-07 17:55:32 +000021from IdleConf import idleconf
Guido van Rossum27f550c1999-04-22 20:56:23 +000022import idlever
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000023
Guido van Rossumcc0ade81998-10-19 02:26:16 +000024# We need to patch linecache.checkcache, because we don't want it
25# to throw away our <pyshell#...> entries.
26# Rather than repeating its code here, we save those entries,
27# then call the original function, and then restore the saved entries.
28def linecache_checkcache(orig_checkcache=linecache.checkcache):
29 cache = linecache.cache
30 save = {}
31 for filename in cache.keys():
32 if filename[:1] + filename[-1:] == '<>':
33 save[filename] = cache[filename]
34 orig_checkcache()
35 cache.update(save)
36linecache.checkcache = linecache_checkcache
37
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000038
Guido van Rossum504b0bf1999-01-02 21:28:54 +000039# Note: <<newline-and-indent>> event is defined in AutoIndent.py
Guido van Rossumcc0ade81998-10-19 02:26:16 +000040
Guido van Rossum504b0bf1999-01-02 21:28:54 +000041#$ event <<plain-newline-and-indent>>
42#$ win <Control-j>
43#$ unix <Control-j>
44
45#$ event <<beginning-of-line>>
46#$ win <Control-a>
47#$ win <Home>
48#$ unix <Control-a>
49#$ unix <Home>
50
51#$ event <<history-next>>
52#$ win <Alt-n>
53#$ unix <Alt-n>
54
55#$ event <<history-previous>>
56#$ win <Alt-p>
57#$ unix <Alt-p>
58
59#$ event <<interrupt-execution>>
60#$ win <Control-c>
61#$ unix <Control-c>
62
63#$ event <<end-of-file>>
64#$ win <Control-d>
65#$ unix <Control-d>
66
67#$ event <<open-stack-viewer>>
68
69#$ event <<toggle-debugger>>
70
71
72class PyShellEditorWindow(EditorWindow):
73
74 # Regular text edit window when a shell is present
75 # XXX ought to merge with regular editor window
76
77 def __init__(self, *args):
78 apply(EditorWindow.__init__, (self,) + args)
79 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
80 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
81
82 rmenu_specs = [
83 ("Set breakpoint here", "<<set-breakpoint-here>>"),
84 ]
85
86 def set_breakpoint_here(self, event=None):
Guido van Rossumcc0ade81998-10-19 02:26:16 +000087 if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
88 self.text.bell()
89 return
90 self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
Guido van Rossum5af7a721998-10-12 23:59:27 +000091
92
93class PyShellFileList(FileList):
Guido van Rossum504b0bf1999-01-02 21:28:54 +000094
95 # File list when a shell is present
96
Guido van Rossum5af7a721998-10-12 23:59:27 +000097 EditorWindow = PyShellEditorWindow
Guido van Rossum504b0bf1999-01-02 21:28:54 +000098
Guido van Rossum5af7a721998-10-12 23:59:27 +000099 pyshell = None
100
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000101 def open_shell(self, event=None):
Guido van Rossum5af7a721998-10-12 23:59:27 +0000102 if self.pyshell:
103 self.pyshell.wakeup()
104 else:
105 self.pyshell = PyShell(self)
106 self.pyshell.begin()
107 return self.pyshell
108
109
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000110class ModifiedColorDelegator(ColorDelegator):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000111
112 # Colorizer for the shell window itself
113
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000114 def recolorize_main(self):
115 self.tag_remove("TODO", "1.0", "iomark")
116 self.tag_add("SYNC", "1.0", "iomark")
117 ColorDelegator.recolorize_main(self)
118
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000119 tagdefs = ColorDelegator.tagdefs.copy()
Jeremy Hylton6b3edf02000-03-07 17:55:32 +0000120 cconf = idleconf.getsection('Colors')
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000121
122 tagdefs.update({
Jeremy Hyltone81f28b2000-03-03 23:06:45 +0000123 "stdin": cconf.getcolor("stdin"),
124 "stdout": cconf.getcolor("stdout"),
125 "stderr": cconf.getcolor("stderr"),
126 "console": cconf.getcolor("console"),
127 "ERROR": cconf.getcolor("ERROR"),
Tim Peters70c43782001-01-17 08:48:39 +0000128 None: cconf.getcolor("normal"),
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000129 })
130
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000131
Guido van Rossum9de98832000-03-07 18:51:49 +0000132class ModifiedUndoDelegator(UndoDelegator):
133
134 # Forbid insert/delete before the I/O mark
135
136 def insert(self, index, chars, tags=None):
137 try:
138 if self.delegate.compare(index, "<", "iomark"):
139 self.delegate.bell()
140 return
141 except TclError:
142 pass
143 UndoDelegator.insert(self, index, chars, tags)
144
145 def delete(self, index1, index2=None):
146 try:
147 if self.delegate.compare(index1, "<", "iomark"):
148 self.delegate.bell()
149 return
150 except TclError:
151 pass
152 UndoDelegator.delete(self, index1, index2)
153
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000154class ModifiedInterpreter(InteractiveInterpreter):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000155
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000156 def __init__(self, tkconsole):
157 self.tkconsole = tkconsole
Guido van Rossumeeb88071999-04-22 20:49:35 +0000158 locals = sys.modules['__main__'].__dict__
159 InteractiveInterpreter.__init__(self, locals=locals)
Tim Peters301ab7f2001-03-29 03:34:43 +0000160 self.save_warnings_filters = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000161
162 gid = 0
163
Guido van Rossumeeb88071999-04-22 20:49:35 +0000164 def execsource(self, source):
165 # Like runsource() but assumes complete exec source
166 filename = self.stuffsource(source)
167 self.execfile(filename, source)
168
169 def execfile(self, filename, source=None):
170 # Execute an existing file
171 if source is None:
172 source = open(filename, "r").read()
173 try:
174 code = compile(source, filename, "exec")
175 except (OverflowError, SyntaxError):
176 self.tkconsole.resetoutput()
177 InteractiveInterpreter.showsyntaxerror(self, filename)
178 else:
179 self.runcode(code)
180
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000181 def runsource(self, source):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000182 # Extend base class to stuff the source in the line cache first
183 filename = self.stuffsource(source)
184 self.more = 0
Guido van Rossumb4ce4302001-03-26 17:41:35 +0000185 self.save_warnings_filters = warnings.filters[:]
186 warnings.filterwarnings(action="error", category=SyntaxWarning)
187 try:
188 return InteractiveInterpreter.runsource(self, source, filename)
189 finally:
190 if self.save_warnings_filters is not None:
191 warnings.filters[:] = self.save_warnings_filters
192 self.save_warnings_filters = None
Guido van Rossumeeb88071999-04-22 20:49:35 +0000193
194 def stuffsource(self, source):
195 # Stuff source in the filename cache
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000196 filename = "<pyshell#%d>" % self.gid
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000197 self.gid = self.gid + 1
198 lines = string.split(source, "\n")
199 linecache.cache[filename] = len(source)+1, 0, lines, filename
Guido van Rossumeeb88071999-04-22 20:49:35 +0000200 return filename
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000201
202 def showsyntaxerror(self, filename=None):
203 # Extend base class to color the offending position
204 # (instead of printing it and pointing at it with a caret)
205 text = self.tkconsole.text
206 stuff = self.unpackerror()
207 if not stuff:
208 self.tkconsole.resetoutput()
209 InteractiveInterpreter.showsyntaxerror(self, filename)
210 return
211 msg, lineno, offset, line = stuff
212 if lineno == 1:
213 pos = "iomark + %d chars" % (offset-1)
214 else:
215 pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
216 offset-1)
217 text.tag_add("ERROR", pos)
218 text.see(pos)
219 char = text.get(pos)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000220 if char and char in string.letters + string.digits + "_":
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000221 text.tag_add("ERROR", pos + " wordstart", pos)
222 self.tkconsole.resetoutput()
223 self.write("SyntaxError: %s\n" % str(msg))
224
225 def unpackerror(self):
226 type, value, tb = sys.exc_info()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000227 ok = type is SyntaxError
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000228 if ok:
229 try:
230 msg, (dummy_filename, lineno, offset, line) = value
231 except:
232 ok = 0
233 if ok:
234 return msg, lineno, offset, line
235 else:
236 return None
237
238 def showtraceback(self):
239 # Extend base class method to reset output properly
240 text = self.tkconsole.text
241 self.tkconsole.resetoutput()
Guido van Rossum19563521998-10-13 16:32:05 +0000242 self.checklinecache()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000243 InteractiveInterpreter.showtraceback(self)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000244
Guido van Rossum19563521998-10-13 16:32:05 +0000245 def checklinecache(self):
246 c = linecache.cache
247 for key in c.keys():
248 if key[:1] + key[-1:] != "<>":
249 del c[key]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000250
Guido van Rossum35f75421998-10-13 23:51:13 +0000251 debugger = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000252
Guido van Rossum35f75421998-10-13 23:51:13 +0000253 def setdebugger(self, debugger):
254 self.debugger = debugger
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000255
Guido van Rossum35f75421998-10-13 23:51:13 +0000256 def getdebugger(self):
257 return self.debugger
258
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000259 def runcode(self, code):
260 # Override base class method
Guido van Rossumb4ce4302001-03-26 17:41:35 +0000261 if self.save_warnings_filters is not None:
262 warnings.filters[:] = self.save_warnings_filters
263 self.save_warnings_filters = None
Guido van Rossum35f75421998-10-13 23:51:13 +0000264 debugger = self.debugger
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000265 try:
266 self.tkconsole.beginexecuting()
267 try:
Guido van Rossum35f75421998-10-13 23:51:13 +0000268 if debugger:
269 debugger.run(code, self.locals)
270 else:
271 exec code in self.locals
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000272 except SystemExit:
273 if tkMessageBox.askyesno(
274 "Exit?",
275 "Do you want to exit altogether?",
276 default="yes",
277 master=self.tkconsole.text):
278 raise
279 else:
280 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000281 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000282 self.tkconsole.open_stack_viewer()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000283 except:
284 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000285 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000286 self.tkconsole.open_stack_viewer()
287
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000288 finally:
289 self.tkconsole.endexecuting()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000290
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000291 def write(self, s):
292 # Override base class write
293 self.tkconsole.console.write(s)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000294
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000295
296class PyShell(OutputWindow):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000297
Guido van Rossumeeb88071999-04-22 20:49:35 +0000298 shell_title = "Python Shell"
299
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000300 # Override classes
301 ColorDelegator = ModifiedColorDelegator
Guido van Rossum9de98832000-03-07 18:51:49 +0000302 UndoDelegator = ModifiedUndoDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000303
Guido van Rossum5af7a721998-10-12 23:59:27 +0000304 # Override menu bar specs
305 menu_specs = PyShellEditorWindow.menu_specs[:]
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000306 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
307
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000308 # New classes
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000309 from IdleHistory import History
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000310
311 def __init__(self, flist=None):
312 self.interp = ModifiedInterpreter(self)
313 if flist is None:
314 root = Tk()
315 fixwordbreaks(root)
316 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000317 flist = PyShellFileList(root)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000318
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000319 OutputWindow.__init__(self, flist, None, None)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000320
321 import __builtin__
322 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
323
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000324 self.auto = self.extensions["AutoIndent"] # Required extension
Guido van Rossumbbaba851999-06-01 19:55:34 +0000325 self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000326
327 text = self.text
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000328 text.configure(wrap="char")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000329 text.bind("<<newline-and-indent>>", self.enter_callback)
330 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
331 text.bind("<<interrupt-execution>>", self.cancel_callback)
332 text.bind("<<beginning-of-line>>", self.home_callback)
333 text.bind("<<end-of-file>>", self.eof_callback)
Guido van Rossum5af7a721998-10-12 23:59:27 +0000334 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Guido van Rossum35f75421998-10-13 23:51:13 +0000335 text.bind("<<toggle-debugger>>", self.toggle_debugger)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000336 text.bind("<<open-python-shell>>", self.flist.open_shell)
Guido van Rossum38df3c31999-01-08 15:31:07 +0000337 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000338
Guido van Rossumeeb88071999-04-22 20:49:35 +0000339 self.save_stdout = sys.stdout
340 self.save_stderr = sys.stderr
341 self.save_stdin = sys.stdin
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000342 sys.stdout = PseudoFile(self, "stdout")
Guido van Rossum3f08d401998-10-13 15:21:41 +0000343 sys.stderr = PseudoFile(self, "stderr")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000344 sys.stdin = self
345 self.console = PseudoFile(self, "console")
346
347 self.history = self.History(self.text)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000348
349 reading = 0
350 executing = 0
351 canceled = 0
352 endoffile = 0
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000353
Guido van Rossum35f75421998-10-13 23:51:13 +0000354 def toggle_debugger(self, event=None):
355 if self.executing:
356 tkMessageBox.showerror("Don't debug now",
357 "You can only toggle the debugger when idle",
358 master=self.text)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000359 self.set_debugger_indicator()
Guido van Rossum35f75421998-10-13 23:51:13 +0000360 return "break"
Guido van Rossum35e55da1998-10-14 03:43:05 +0000361 else:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000362 db = self.interp.getdebugger()
363 if db:
364 self.close_debugger()
365 else:
366 self.open_debugger()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000367
Guido van Rossum07ec8961999-01-28 22:02:47 +0000368 def set_debugger_indicator(self):
369 db = self.interp.getdebugger()
370 self.setvar("<<toggle-debugger>>", not not db)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000371
Guido van Rossum38df3c31999-01-08 15:31:07 +0000372 def toggle_jit_stack_viewer( self, event=None):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000373 pass # All we need is the variable
Guido van Rossum38df3c31999-01-08 15:31:07 +0000374
Guido van Rossum35e55da1998-10-14 03:43:05 +0000375 def close_debugger(self):
376 db = self.interp.getdebugger()
377 if db:
378 self.interp.setdebugger(None)
Guido van Rossum35f75421998-10-13 23:51:13 +0000379 db.close()
380 self.resetoutput()
381 self.console.write("[DEBUG OFF]\n")
382 sys.ps1 = ">>> "
383 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000384 self.set_debugger_indicator()
Guido van Rossum35e55da1998-10-14 03:43:05 +0000385
386 def open_debugger(self):
387 import Debugger
388 self.interp.setdebugger(Debugger.Debugger(self))
Guido van Rossumadfe7731998-10-16 21:09:35 +0000389 sys.ps1 = "[DEBUG ON]\n>>> "
Guido van Rossum35e55da1998-10-14 03:43:05 +0000390 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000391 self.set_debugger_indicator()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000392
393 def beginexecuting(self):
394 # Helper for ModifiedInterpreter
395 self.resetoutput()
396 self.executing = 1
Guido van Rossumfed9b911999-06-25 16:09:27 +0000397 ##self._cancel_check = self.cancel_check
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000398 ##sys.settrace(self._cancel_check)
399
400 def endexecuting(self):
401 # Helper for ModifiedInterpreter
Guido van Rossumfed9b911999-06-25 16:09:27 +0000402 ##sys.settrace(None)
403 ##self._cancel_check = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000404 self.executing = 0
405 self.canceled = 0
406
407 def close(self):
408 # Extend base class method
409 if self.executing:
410 # XXX Need to ask a question here
411 if not tkMessageBox.askokcancel(
Guido van Rossum07ec8961999-01-28 22:02:47 +0000412 "Kill?",
413 "The program is still running; do you want to kill it?",
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000414 default="ok",
415 master=self.text):
416 return "cancel"
417 self.canceled = 1
418 if self.reading:
419 self.top.quit()
420 return "cancel"
Guido van Rossum42696012001-07-06 20:26:31 +0000421 return OutputWindow.close(self)
Guido van Rossumfed9b911999-06-25 16:09:27 +0000422
423 def _close(self):
Guido van Rossum16e0bab1999-06-25 17:26:34 +0000424 self.close_debugger()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000425 # Restore std streams
426 sys.stdout = self.save_stdout
427 sys.stderr = self.save_stderr
428 sys.stdin = self.save_stdin
429 # Break cycles
430 self.interp = None
431 self.console = None
432 self.auto = None
433 self.flist.pyshell = None
434 self.history = None
435 OutputWindow._close(self) # Really EditorWindow._close
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000436
437 def ispythonsource(self, filename):
438 # Override this so EditorWindow never removes the colorizer
439 return 1
440
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000441 def short_title(self):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000442 return self.shell_title
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000443
Guido van Rossumfa6013c2000-09-05 13:51:14 +0000444 COPYRIGHT = \
445 'Type "copyright", "credits" or "license" for more information.'
446
Guido van Rossum5af7a721998-10-12 23:59:27 +0000447 def begin(self):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000448 self.resetoutput()
Guido van Rossum26c2cb41999-04-26 22:20:38 +0000449 self.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" %
Guido van Rossumfa6013c2000-09-05 13:51:14 +0000450 (sys.version, sys.platform, self.COPYRIGHT,
Guido van Rossum27f550c1999-04-22 20:56:23 +0000451 idlever.IDLE_VERSION))
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000452 try:
453 sys.ps1
454 except AttributeError:
455 sys.ps1 = ">>> "
456 self.showprompt()
457 import Tkinter
458 Tkinter._default_root = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000459
Guido van Rossum5af7a721998-10-12 23:59:27 +0000460 def interact(self):
461 self.begin()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000462 self.top.mainloop()
463
464 def readline(self):
465 save = self.reading
466 try:
467 self.reading = 1
468 self.top.mainloop()
469 finally:
470 self.reading = save
471 line = self.text.get("iomark", "end-1c")
472 self.resetoutput()
473 if self.canceled:
474 self.canceled = 0
475 raise KeyboardInterrupt
476 if self.endoffile:
477 self.endoffile = 0
478 return ""
479 return line
480
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000481 def isatty(self):
482 return 1
483
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000484 def cancel_callback(self, event):
485 try:
486 if self.text.compare("sel.first", "!=", "sel.last"):
487 return # Active selection -- always use default binding
488 except:
489 pass
490 if not (self.executing or self.reading):
491 self.resetoutput()
492 self.write("KeyboardInterrupt\n")
493 self.showprompt()
494 return "break"
495 self.endoffile = 0
496 self.canceled = 1
497 if self.reading:
498 self.top.quit()
499 return "break"
500
501 def eof_callback(self, event):
502 if self.executing and not self.reading:
503 return # Let the default binding (delete next char) take over
504 if not (self.text.compare("iomark", "==", "insert") and
505 self.text.compare("insert", "==", "end-1c")):
506 return # Let the default binding (delete next char) take over
507 if not self.executing:
508## if not tkMessageBox.askokcancel(
509## "Exit?",
510## "Are you sure you want to exit?",
511## default="ok", master=self.text):
512## return "break"
513 self.resetoutput()
514 self.close()
515 else:
516 self.canceled = 0
517 self.endoffile = 1
518 self.top.quit()
519 return "break"
520
521 def home_callback(self, event):
522 if event.state != 0 and event.keysym == "Home":
523 return # <Modifier-Home>; fall back to class binding
524 if self.text.compare("iomark", "<=", "insert") and \
525 self.text.compare("insert linestart", "<=", "iomark"):
526 self.text.mark_set("insert", "iomark")
527 self.text.tag_remove("sel", "1.0", "end")
528 self.text.see("insert")
529 return "break"
530
531 def linefeed_callback(self, event):
532 # Insert a linefeed without entering anything (still autoindented)
533 if self.reading:
534 self.text.insert("insert", "\n")
535 self.text.see("insert")
536 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000537 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000538 return "break"
539
540 def enter_callback(self, event):
541 if self.executing and not self.reading:
542 return # Let the default binding (insert '\n') take over
543 # If some text is selected, recall the selection
Guido van Rossum4650df91998-10-13 14:41:27 +0000544 # (but only if this before the I/O mark)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000545 try:
546 sel = self.text.get("sel.first", "sel.last")
547 if sel:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000548 if self.text.compare("sel.last", "<=", "iomark"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000549 self.recall(sel)
550 return "break"
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000551 except:
552 pass
553 # If we're strictly before the line containing iomark, recall
554 # the current line, less a leading prompt, less leading or
555 # trailing whitespace
556 if self.text.compare("insert", "<", "iomark linestart"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000557 # Check if there's a relevant stdin range -- if so, use it
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000558 prev = self.text.tag_prevrange("stdin", "insert")
559 if prev and self.text.compare("insert", "<", prev[1]):
560 self.recall(self.text.get(prev[0], prev[1]))
561 return "break"
562 next = self.text.tag_nextrange("stdin", "insert")
563 if next and self.text.compare("insert lineend", ">=", next[0]):
564 self.recall(self.text.get(next[0], next[1]))
565 return "break"
566 # No stdin mark -- just get the current line
567 self.recall(self.text.get("insert linestart", "insert lineend"))
568 return "break"
Guido van Rossumfd6315e2000-03-07 15:05:50 +0000569 # If we're in the current input and there's only whitespace
570 # beyond the cursor, erase that whitespace first
571 s = self.text.get("insert", "end-1c")
572 if s and not string.strip(s):
573 self.text.delete("insert", "end-1c")
Guido van Rossum4650df91998-10-13 14:41:27 +0000574 # If we're in the current input before its last line,
575 # insert a newline right at the insert point
576 if self.text.compare("insert", "<", "end-1c linestart"):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000577 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000578 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000579 # We're in the last line; append a newline and submit it
580 self.text.mark_set("insert", "end-1c")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000581 if self.reading:
582 self.text.insert("insert", "\n")
583 self.text.see("insert")
584 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000585 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000586 self.text.tag_add("stdin", "iomark", "end-1c")
587 self.text.update_idletasks()
588 if self.reading:
589 self.top.quit() # Break out of recursive mainloop() in raw_input()
590 else:
591 self.runit()
592 return "break"
593
594 def recall(self, s):
595 if self.history:
596 self.history.recall(s)
597
598 def runit(self):
599 line = self.text.get("iomark", "end-1c")
600 # Strip off last newline and surrounding whitespace.
601 # (To allow you to hit return twice to end a statement.)
602 i = len(line)
603 while i > 0 and line[i-1] in " \t":
604 i = i-1
605 if i > 0 and line[i-1] == "\n":
606 i = i-1
607 while i > 0 and line[i-1] in " \t":
608 i = i-1
609 line = line[:i]
610 more = self.interp.runsource(line)
611 if not more:
612 self.showprompt()
613
614 def cancel_check(self, frame, what, args,
615 dooneevent=tkinter.dooneevent,
616 dontwait=tkinter.DONT_WAIT):
617 # Hack -- use the debugger hooks to be able to handle events
618 # and interrupt execution at any time.
619 # This slows execution down quite a bit, so you may want to
620 # disable this (by not calling settrace() in runcode() above)
621 # for full-bore (uninterruptable) speed.
622 # XXX This should become a user option.
623 if self.canceled:
624 return
625 dooneevent(dontwait)
626 if self.canceled:
627 self.canceled = 0
628 raise KeyboardInterrupt
629 return self._cancel_check
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000630
Guido van Rossum5af7a721998-10-12 23:59:27 +0000631 def open_stack_viewer(self, event=None):
632 try:
633 sys.last_traceback
634 except:
635 tkMessageBox.showerror("No stack trace",
636 "There is no stack trace yet.\n"
637 "(sys.last_traceback is not defined)",
638 master=self.text)
639 return
Guido van Rossum80d132d1998-10-16 16:12:11 +0000640 from StackViewer import StackBrowser
641 sv = StackBrowser(self.root, self.flist)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000642
643 def showprompt(self):
644 self.resetoutput()
645 try:
646 s = str(sys.ps1)
647 except:
648 s = ""
649 self.console.write(s)
650 self.text.mark_set("insert", "end-1c")
651
652 def resetoutput(self):
653 source = self.text.get("iomark", "end-1c")
654 if self.history:
655 self.history.history_store(source)
656 if self.text.get("end-2c") != "\n":
657 self.text.insert("end-1c", "\n")
658 self.text.mark_set("iomark", "end-1c")
659 sys.stdout.softspace = 0
660
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000661 def write(self, s, tags=()):
662 self.text.mark_gravity("iomark", "right")
663 OutputWindow.write(self, s, tags, "iomark")
664 self.text.mark_gravity("iomark", "left")
665 if self.canceled:
666 self.canceled = 0
667 raise KeyboardInterrupt
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000668
669class PseudoFile:
670
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000671 def __init__(self, shell, tags):
672 self.shell = shell
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000673 self.tags = tags
674
675 def write(self, s):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000676 self.shell.write(s, self.tags)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000677
678 def writelines(self, l):
679 map(self.write, l)
680
Guido van Rossum825df2a1999-03-29 14:52:28 +0000681 def flush(self):
682 pass
683
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000684 def isatty(self):
685 return 1
686
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000687
Guido van Rossumeeb88071999-04-22 20:49:35 +0000688usage_msg = """\
689usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
690
691-c command run this command
692-d enable debugger
693-e edit mode; arguments are files to be edited
Guido van Rossum27f550c1999-04-22 20:56:23 +0000694-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
Guido van Rossumeeb88071999-04-22 20:49:35 +0000695-t title set title of shell window
696
697When neither -c nor -e is used, and there are arguments, and the first
698argument is not '-', the first argument is run as a script. Remaining
699arguments are arguments to the script or to the command run by -c.
700"""
701
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000702def main():
Guido van Rossumeeb88071999-04-22 20:49:35 +0000703 cmd = None
704 edit = 0
Guido van Rossum80d132d1998-10-16 16:12:11 +0000705 debug = 0
Guido van Rossumeeb88071999-04-22 20:49:35 +0000706 startup = 0
707
Guido van Rossum80d132d1998-10-16 16:12:11 +0000708 try:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000709 opts, args = getopt.getopt(sys.argv[1:], "c:deist:")
Guido van Rossum80d132d1998-10-16 16:12:11 +0000710 except getopt.error, msg:
711 sys.stderr.write("Error: %s\n" % str(msg))
Guido van Rossumeeb88071999-04-22 20:49:35 +0000712 sys.stderr.write(usage_msg)
Guido van Rossum80d132d1998-10-16 16:12:11 +0000713 sys.exit(2)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000714
Guido van Rossum80d132d1998-10-16 16:12:11 +0000715 for o, a in opts:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000716 if o == '-c':
717 cmd = a
718 if o == '-d':
Guido van Rossum80d132d1998-10-16 16:12:11 +0000719 debug = 1
Guido van Rossumeeb88071999-04-22 20:49:35 +0000720 if o == '-e':
721 edit = 1
722 if o == '-s':
723 startup = 1
724 if o == '-t':
725 PyShell.shell_title = a
726
Guido van Rossumeeb88071999-04-22 20:49:35 +0000727 for i in range(len(sys.path)):
728 sys.path[i] = os.path.abspath(sys.path[i])
729
730 pathx = []
731 if edit:
732 for filename in args:
733 pathx.append(os.path.dirname(filename))
734 elif args and args[0] != "-":
735 pathx.append(os.path.dirname(args[0]))
736 else:
737 pathx.append(os.curdir)
738 for dir in pathx:
739 dir = os.path.abspath(dir)
740 if not dir in sys.path:
741 sys.path.insert(0, dir)
742
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000743 global flist, root
Fred Drake10515b62000-09-15 04:32:56 +0000744 root = Tk(className="Idle")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000745 fixwordbreaks(root)
746 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000747 flist = PyShellFileList(root)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000748
749 if edit:
750 for filename in args:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000751 flist.open(filename)
Fred Drake10515b62000-09-15 04:32:56 +0000752 else:
753 if cmd:
754 sys.argv = ["-c"] + args
755 else:
756 sys.argv = args or [""]
757
Guido van Rossumeeb88071999-04-22 20:49:35 +0000758
759 shell = PyShell(flist)
760 interp = shell.interp
761 flist.pyshell = shell
762
763 if startup:
764 filename = os.environ.get("IDLESTARTUP") or \
765 os.environ.get("PYTHONSTARTUP")
766 if filename and os.path.isfile(filename):
767 interp.execfile(filename)
768
Guido van Rossum80d132d1998-10-16 16:12:11 +0000769 if debug:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000770 shell.open_debugger()
771 if cmd:
772 interp.execsource(cmd)
773 elif not edit and args and args[0] != "-":
774 interp.execfile(args[0])
775
776 shell.begin()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000777 root.mainloop()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000778 root.destroy()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000779
Guido van Rossumeeb88071999-04-22 20:49:35 +0000780
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000781if __name__ == "__main__":
782 main()