blob: 2eaf93623be4736654684a66e956f93d23f378a8 [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
Martin v. Löwiseade4a12002-08-05 14:55:21 +00009import types
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000010
11import linecache
12from code import InteractiveInterpreter
13
14from Tkinter import *
15import tkMessageBox
16
Guido van Rossum504b0bf1999-01-02 21:28:54 +000017from EditorWindow import EditorWindow, fixwordbreaks
18from FileList import FileList
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000019from ColorDelegator import ColorDelegator
Guido van Rossum9de98832000-03-07 18:51:49 +000020from UndoDelegator import UndoDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +000021from OutputWindow import OutputWindow
Jeremy Hylton6b3edf02000-03-07 17:55:32 +000022from IdleConf import idleconf
Guido van Rossum27f550c1999-04-22 20:56:23 +000023import idlever
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000024
Guido van Rossumcc0ade81998-10-19 02:26:16 +000025# We need to patch linecache.checkcache, because we don't want it
26# to throw away our <pyshell#...> entries.
27# Rather than repeating its code here, we save those entries,
28# then call the original function, and then restore the saved entries.
29def linecache_checkcache(orig_checkcache=linecache.checkcache):
30 cache = linecache.cache
31 save = {}
32 for filename in cache.keys():
33 if filename[:1] + filename[-1:] == '<>':
34 save[filename] = cache[filename]
35 orig_checkcache()
36 cache.update(save)
37linecache.checkcache = linecache_checkcache
38
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000039
Fred Drakecd694c42001-07-20 18:58:42 +000040IDENTCHARS = string.ascii_letters + string.digits + "_"
41
42
Guido van Rossum504b0bf1999-01-02 21:28:54 +000043# Note: <<newline-and-indent>> event is defined in AutoIndent.py
Guido van Rossumcc0ade81998-10-19 02:26:16 +000044
Guido van Rossum504b0bf1999-01-02 21:28:54 +000045#$ event <<plain-newline-and-indent>>
46#$ win <Control-j>
47#$ unix <Control-j>
48
49#$ event <<beginning-of-line>>
50#$ win <Control-a>
51#$ win <Home>
52#$ unix <Control-a>
53#$ unix <Home>
54
55#$ event <<history-next>>
56#$ win <Alt-n>
57#$ unix <Alt-n>
58
59#$ event <<history-previous>>
60#$ win <Alt-p>
61#$ unix <Alt-p>
62
63#$ event <<interrupt-execution>>
64#$ win <Control-c>
65#$ unix <Control-c>
66
67#$ event <<end-of-file>>
68#$ win <Control-d>
69#$ unix <Control-d>
70
71#$ event <<open-stack-viewer>>
72
73#$ event <<toggle-debugger>>
74
75
76class PyShellEditorWindow(EditorWindow):
77
78 # Regular text edit window when a shell is present
79 # XXX ought to merge with regular editor window
Raymond Hettinger7f7d5bf2002-05-21 17:00:20 +000080 runnable = True # Shell not present, enable Import Module and Run Script
Guido van Rossum504b0bf1999-01-02 21:28:54 +000081
82 def __init__(self, *args):
83 apply(EditorWindow.__init__, (self,) + args)
84 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
85 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
86
87 rmenu_specs = [
88 ("Set breakpoint here", "<<set-breakpoint-here>>"),
89 ]
90
91 def set_breakpoint_here(self, event=None):
Guido van Rossumcc0ade81998-10-19 02:26:16 +000092 if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
93 self.text.bell()
94 return
95 self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
Guido van Rossum5af7a721998-10-12 23:59:27 +000096
97
98class PyShellFileList(FileList):
Guido van Rossum504b0bf1999-01-02 21:28:54 +000099
100 # File list when a shell is present
101
Guido van Rossum5af7a721998-10-12 23:59:27 +0000102 EditorWindow = PyShellEditorWindow
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000103
Guido van Rossum5af7a721998-10-12 23:59:27 +0000104 pyshell = None
105
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000106 def open_shell(self, event=None):
Guido van Rossum5af7a721998-10-12 23:59:27 +0000107 if self.pyshell:
108 self.pyshell.wakeup()
109 else:
110 self.pyshell = PyShell(self)
111 self.pyshell.begin()
112 return self.pyshell
113
114
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000115class ModifiedColorDelegator(ColorDelegator):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000116
117 # Colorizer for the shell window itself
118
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000119 def recolorize_main(self):
120 self.tag_remove("TODO", "1.0", "iomark")
121 self.tag_add("SYNC", "1.0", "iomark")
122 ColorDelegator.recolorize_main(self)
123
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000124 tagdefs = ColorDelegator.tagdefs.copy()
Jeremy Hylton6b3edf02000-03-07 17:55:32 +0000125 cconf = idleconf.getsection('Colors')
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000126
127 tagdefs.update({
Jeremy Hyltone81f28b2000-03-03 23:06:45 +0000128 "stdin": cconf.getcolor("stdin"),
129 "stdout": cconf.getcolor("stdout"),
130 "stderr": cconf.getcolor("stderr"),
131 "console": cconf.getcolor("console"),
132 "ERROR": cconf.getcolor("ERROR"),
Tim Peters70c43782001-01-17 08:48:39 +0000133 None: cconf.getcolor("normal"),
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000134 })
135
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000136
Guido van Rossum9de98832000-03-07 18:51:49 +0000137class ModifiedUndoDelegator(UndoDelegator):
138
139 # Forbid insert/delete before the I/O mark
140
141 def insert(self, index, chars, tags=None):
142 try:
143 if self.delegate.compare(index, "<", "iomark"):
144 self.delegate.bell()
145 return
146 except TclError:
147 pass
148 UndoDelegator.insert(self, index, chars, tags)
149
150 def delete(self, index1, index2=None):
151 try:
152 if self.delegate.compare(index1, "<", "iomark"):
153 self.delegate.bell()
154 return
155 except TclError:
156 pass
157 UndoDelegator.delete(self, index1, index2)
158
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000159class ModifiedInterpreter(InteractiveInterpreter):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000160
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000161 def __init__(self, tkconsole):
162 self.tkconsole = tkconsole
Guido van Rossumeeb88071999-04-22 20:49:35 +0000163 locals = sys.modules['__main__'].__dict__
164 InteractiveInterpreter.__init__(self, locals=locals)
Tim Peters301ab7f2001-03-29 03:34:43 +0000165 self.save_warnings_filters = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000166
167 gid = 0
168
Guido van Rossumeeb88071999-04-22 20:49:35 +0000169 def execsource(self, source):
170 # Like runsource() but assumes complete exec source
171 filename = self.stuffsource(source)
172 self.execfile(filename, source)
173
174 def execfile(self, filename, source=None):
175 # Execute an existing file
176 if source is None:
177 source = open(filename, "r").read()
178 try:
179 code = compile(source, filename, "exec")
180 except (OverflowError, SyntaxError):
181 self.tkconsole.resetoutput()
182 InteractiveInterpreter.showsyntaxerror(self, filename)
183 else:
184 self.runcode(code)
185
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000186 def runsource(self, source):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000187 # Extend base class to stuff the source in the line cache first
188 filename = self.stuffsource(source)
189 self.more = 0
Guido van Rossumb4ce4302001-03-26 17:41:35 +0000190 self.save_warnings_filters = warnings.filters[:]
191 warnings.filterwarnings(action="error", category=SyntaxWarning)
Martin v. Löwiseade4a12002-08-05 14:55:21 +0000192 if isinstance(source, types.UnicodeType):
193 import IOBinding
Martin v. Löwis75ea1e12002-08-10 12:22:12 +0000194 try:
195 source = source.encode(IOBinding.encoding)
196 except UnicodeError:
197 self.tkconsole.resetoutput()
198 self.write("Unsupported characters in input")
199 return
Guido van Rossumb4ce4302001-03-26 17:41:35 +0000200 try:
201 return InteractiveInterpreter.runsource(self, source, filename)
202 finally:
203 if self.save_warnings_filters is not None:
204 warnings.filters[:] = self.save_warnings_filters
205 self.save_warnings_filters = None
Guido van Rossumeeb88071999-04-22 20:49:35 +0000206
207 def stuffsource(self, source):
208 # Stuff source in the filename cache
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000209 filename = "<pyshell#%d>" % self.gid
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000210 self.gid = self.gid + 1
Walter Dörwaldaaab30e2002-09-11 20:36:02 +0000211 lines = source.split("\n")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000212 linecache.cache[filename] = len(source)+1, 0, lines, filename
Guido van Rossumeeb88071999-04-22 20:49:35 +0000213 return filename
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000214
215 def showsyntaxerror(self, filename=None):
216 # Extend base class to color the offending position
217 # (instead of printing it and pointing at it with a caret)
218 text = self.tkconsole.text
219 stuff = self.unpackerror()
220 if not stuff:
221 self.tkconsole.resetoutput()
222 InteractiveInterpreter.showsyntaxerror(self, filename)
223 return
224 msg, lineno, offset, line = stuff
225 if lineno == 1:
226 pos = "iomark + %d chars" % (offset-1)
227 else:
228 pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
229 offset-1)
230 text.tag_add("ERROR", pos)
231 text.see(pos)
232 char = text.get(pos)
Fred Drakecd694c42001-07-20 18:58:42 +0000233 if char and char in IDENTCHARS:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000234 text.tag_add("ERROR", pos + " wordstart", pos)
235 self.tkconsole.resetoutput()
236 self.write("SyntaxError: %s\n" % str(msg))
237
238 def unpackerror(self):
239 type, value, tb = sys.exc_info()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000240 ok = type is SyntaxError
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000241 if ok:
242 try:
243 msg, (dummy_filename, lineno, offset, line) = value
244 except:
245 ok = 0
246 if ok:
247 return msg, lineno, offset, line
248 else:
249 return None
250
251 def showtraceback(self):
252 # Extend base class method to reset output properly
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000253 self.tkconsole.resetoutput()
Guido van Rossum19563521998-10-13 16:32:05 +0000254 self.checklinecache()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000255 InteractiveInterpreter.showtraceback(self)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000256
Guido van Rossum19563521998-10-13 16:32:05 +0000257 def checklinecache(self):
258 c = linecache.cache
259 for key in c.keys():
260 if key[:1] + key[-1:] != "<>":
261 del c[key]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000262
Guido van Rossum35f75421998-10-13 23:51:13 +0000263 debugger = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000264
Guido van Rossum35f75421998-10-13 23:51:13 +0000265 def setdebugger(self, debugger):
266 self.debugger = debugger
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000267
Guido van Rossum35f75421998-10-13 23:51:13 +0000268 def getdebugger(self):
269 return self.debugger
270
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000271 def runcode(self, code):
272 # Override base class method
Guido van Rossumb4ce4302001-03-26 17:41:35 +0000273 if self.save_warnings_filters is not None:
274 warnings.filters[:] = self.save_warnings_filters
275 self.save_warnings_filters = None
Guido van Rossum35f75421998-10-13 23:51:13 +0000276 debugger = self.debugger
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000277 try:
278 self.tkconsole.beginexecuting()
279 try:
Guido van Rossum35f75421998-10-13 23:51:13 +0000280 if debugger:
281 debugger.run(code, self.locals)
282 else:
283 exec code in self.locals
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000284 except SystemExit:
285 if tkMessageBox.askyesno(
286 "Exit?",
287 "Do you want to exit altogether?",
288 default="yes",
289 master=self.tkconsole.text):
290 raise
291 else:
292 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000293 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000294 self.tkconsole.open_stack_viewer()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000295 except:
296 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000297 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000298 self.tkconsole.open_stack_viewer()
299
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000300 finally:
301 self.tkconsole.endexecuting()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000302
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000303 def write(self, s):
304 # Override base class write
305 self.tkconsole.console.write(s)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000306
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000307
308class PyShell(OutputWindow):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000309
Guido van Rossumeeb88071999-04-22 20:49:35 +0000310 shell_title = "Python Shell"
311
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000312 # Override classes
313 ColorDelegator = ModifiedColorDelegator
Guido van Rossum9de98832000-03-07 18:51:49 +0000314 UndoDelegator = ModifiedUndoDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000315
Guido van Rossum5af7a721998-10-12 23:59:27 +0000316 # Override menu bar specs
317 menu_specs = PyShellEditorWindow.menu_specs[:]
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000318 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
319
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000320 # New classes
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000321 from IdleHistory import History
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000322
323 def __init__(self, flist=None):
324 self.interp = ModifiedInterpreter(self)
325 if flist is None:
326 root = Tk()
327 fixwordbreaks(root)
328 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000329 flist = PyShellFileList(root)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000330
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000331 OutputWindow.__init__(self, flist, None, None)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000332
333 import __builtin__
334 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
335
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000336 self.auto = self.extensions["AutoIndent"] # Required extension
Guido van Rossumbbaba851999-06-01 19:55:34 +0000337 self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000338
339 text = self.text
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000340 text.configure(wrap="char")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000341 text.bind("<<newline-and-indent>>", self.enter_callback)
342 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
343 text.bind("<<interrupt-execution>>", self.cancel_callback)
344 text.bind("<<beginning-of-line>>", self.home_callback)
345 text.bind("<<end-of-file>>", self.eof_callback)
Guido van Rossum5af7a721998-10-12 23:59:27 +0000346 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Guido van Rossum35f75421998-10-13 23:51:13 +0000347 text.bind("<<toggle-debugger>>", self.toggle_debugger)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000348 text.bind("<<open-python-shell>>", self.flist.open_shell)
Guido van Rossum38df3c31999-01-08 15:31:07 +0000349 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000350
Guido van Rossumeeb88071999-04-22 20:49:35 +0000351 self.save_stdout = sys.stdout
352 self.save_stderr = sys.stderr
353 self.save_stdin = sys.stdin
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000354 sys.stdout = PseudoFile(self, "stdout")
Guido van Rossum3f08d401998-10-13 15:21:41 +0000355 sys.stderr = PseudoFile(self, "stderr")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000356 sys.stdin = self
357 self.console = PseudoFile(self, "console")
358
359 self.history = self.History(self.text)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000360
361 reading = 0
362 executing = 0
363 canceled = 0
364 endoffile = 0
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000365
Guido van Rossum35f75421998-10-13 23:51:13 +0000366 def toggle_debugger(self, event=None):
367 if self.executing:
368 tkMessageBox.showerror("Don't debug now",
369 "You can only toggle the debugger when idle",
370 master=self.text)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000371 self.set_debugger_indicator()
Guido van Rossum35f75421998-10-13 23:51:13 +0000372 return "break"
Guido van Rossum35e55da1998-10-14 03:43:05 +0000373 else:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000374 db = self.interp.getdebugger()
375 if db:
376 self.close_debugger()
377 else:
378 self.open_debugger()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000379
Guido van Rossum07ec8961999-01-28 22:02:47 +0000380 def set_debugger_indicator(self):
381 db = self.interp.getdebugger()
382 self.setvar("<<toggle-debugger>>", not not db)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000383
Guido van Rossum38df3c31999-01-08 15:31:07 +0000384 def toggle_jit_stack_viewer( self, event=None):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000385 pass # All we need is the variable
Guido van Rossum38df3c31999-01-08 15:31:07 +0000386
Guido van Rossum35e55da1998-10-14 03:43:05 +0000387 def close_debugger(self):
388 db = self.interp.getdebugger()
389 if db:
390 self.interp.setdebugger(None)
Guido van Rossum35f75421998-10-13 23:51:13 +0000391 db.close()
392 self.resetoutput()
393 self.console.write("[DEBUG OFF]\n")
394 sys.ps1 = ">>> "
395 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000396 self.set_debugger_indicator()
Guido van Rossum35e55da1998-10-14 03:43:05 +0000397
398 def open_debugger(self):
399 import Debugger
400 self.interp.setdebugger(Debugger.Debugger(self))
Guido van Rossumadfe7731998-10-16 21:09:35 +0000401 sys.ps1 = "[DEBUG ON]\n>>> "
Guido van Rossum35e55da1998-10-14 03:43:05 +0000402 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000403 self.set_debugger_indicator()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000404
405 def beginexecuting(self):
406 # Helper for ModifiedInterpreter
407 self.resetoutput()
408 self.executing = 1
Guido van Rossumfed9b911999-06-25 16:09:27 +0000409 ##self._cancel_check = self.cancel_check
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000410 ##sys.settrace(self._cancel_check)
411
412 def endexecuting(self):
413 # Helper for ModifiedInterpreter
Guido van Rossumfed9b911999-06-25 16:09:27 +0000414 ##sys.settrace(None)
415 ##self._cancel_check = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000416 self.executing = 0
417 self.canceled = 0
418
419 def close(self):
420 # Extend base class method
421 if self.executing:
422 # XXX Need to ask a question here
423 if not tkMessageBox.askokcancel(
Guido van Rossum07ec8961999-01-28 22:02:47 +0000424 "Kill?",
425 "The program is still running; do you want to kill it?",
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000426 default="ok",
427 master=self.text):
428 return "cancel"
429 self.canceled = 1
430 if self.reading:
431 self.top.quit()
432 return "cancel"
Guido van Rossum42696012001-07-06 20:26:31 +0000433 return OutputWindow.close(self)
Guido van Rossumfed9b911999-06-25 16:09:27 +0000434
435 def _close(self):
Guido van Rossum16e0bab1999-06-25 17:26:34 +0000436 self.close_debugger()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000437 # Restore std streams
438 sys.stdout = self.save_stdout
439 sys.stderr = self.save_stderr
440 sys.stdin = self.save_stdin
441 # Break cycles
442 self.interp = None
443 self.console = None
444 self.auto = None
445 self.flist.pyshell = None
446 self.history = None
447 OutputWindow._close(self) # Really EditorWindow._close
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000448
449 def ispythonsource(self, filename):
450 # Override this so EditorWindow never removes the colorizer
Tim Petersbc0e9102002-04-04 22:55:58 +0000451 return True
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000452
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000453 def short_title(self):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000454 return self.shell_title
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000455
Guido van Rossumfa6013c2000-09-05 13:51:14 +0000456 COPYRIGHT = \
457 'Type "copyright", "credits" or "license" for more information.'
458
Guido van Rossum5af7a721998-10-12 23:59:27 +0000459 def begin(self):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000460 self.resetoutput()
Guido van Rossum26c2cb41999-04-26 22:20:38 +0000461 self.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" %
Guido van Rossumfa6013c2000-09-05 13:51:14 +0000462 (sys.version, sys.platform, self.COPYRIGHT,
Guido van Rossum27f550c1999-04-22 20:56:23 +0000463 idlever.IDLE_VERSION))
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000464 try:
465 sys.ps1
466 except AttributeError:
467 sys.ps1 = ">>> "
468 self.showprompt()
469 import Tkinter
470 Tkinter._default_root = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000471
Guido van Rossum5af7a721998-10-12 23:59:27 +0000472 def interact(self):
473 self.begin()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000474 self.top.mainloop()
475
476 def readline(self):
477 save = self.reading
478 try:
479 self.reading = 1
480 self.top.mainloop()
481 finally:
482 self.reading = save
483 line = self.text.get("iomark", "end-1c")
484 self.resetoutput()
485 if self.canceled:
486 self.canceled = 0
487 raise KeyboardInterrupt
488 if self.endoffile:
489 self.endoffile = 0
490 return ""
491 return line
492
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000493 def isatty(self):
Tim Petersbc0e9102002-04-04 22:55:58 +0000494 return True
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000495
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000496 def cancel_callback(self, event):
497 try:
498 if self.text.compare("sel.first", "!=", "sel.last"):
499 return # Active selection -- always use default binding
500 except:
501 pass
502 if not (self.executing or self.reading):
503 self.resetoutput()
504 self.write("KeyboardInterrupt\n")
505 self.showprompt()
506 return "break"
507 self.endoffile = 0
508 self.canceled = 1
509 if self.reading:
510 self.top.quit()
511 return "break"
512
513 def eof_callback(self, event):
514 if self.executing and not self.reading:
515 return # Let the default binding (delete next char) take over
516 if not (self.text.compare("iomark", "==", "insert") and
517 self.text.compare("insert", "==", "end-1c")):
518 return # Let the default binding (delete next char) take over
519 if not self.executing:
520## if not tkMessageBox.askokcancel(
521## "Exit?",
522## "Are you sure you want to exit?",
523## default="ok", master=self.text):
524## return "break"
525 self.resetoutput()
526 self.close()
527 else:
528 self.canceled = 0
529 self.endoffile = 1
530 self.top.quit()
531 return "break"
532
533 def home_callback(self, event):
534 if event.state != 0 and event.keysym == "Home":
535 return # <Modifier-Home>; fall back to class binding
536 if self.text.compare("iomark", "<=", "insert") and \
537 self.text.compare("insert linestart", "<=", "iomark"):
538 self.text.mark_set("insert", "iomark")
539 self.text.tag_remove("sel", "1.0", "end")
540 self.text.see("insert")
541 return "break"
542
543 def linefeed_callback(self, event):
544 # Insert a linefeed without entering anything (still autoindented)
545 if self.reading:
546 self.text.insert("insert", "\n")
547 self.text.see("insert")
548 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000549 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000550 return "break"
551
552 def enter_callback(self, event):
553 if self.executing and not self.reading:
554 return # Let the default binding (insert '\n') take over
555 # If some text is selected, recall the selection
Guido van Rossum4650df91998-10-13 14:41:27 +0000556 # (but only if this before the I/O mark)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000557 try:
558 sel = self.text.get("sel.first", "sel.last")
559 if sel:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000560 if self.text.compare("sel.last", "<=", "iomark"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000561 self.recall(sel)
562 return "break"
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000563 except:
564 pass
565 # If we're strictly before the line containing iomark, recall
566 # the current line, less a leading prompt, less leading or
567 # trailing whitespace
568 if self.text.compare("insert", "<", "iomark linestart"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000569 # Check if there's a relevant stdin range -- if so, use it
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000570 prev = self.text.tag_prevrange("stdin", "insert")
571 if prev and self.text.compare("insert", "<", prev[1]):
572 self.recall(self.text.get(prev[0], prev[1]))
573 return "break"
574 next = self.text.tag_nextrange("stdin", "insert")
575 if next and self.text.compare("insert lineend", ">=", next[0]):
576 self.recall(self.text.get(next[0], next[1]))
577 return "break"
578 # No stdin mark -- just get the current line
579 self.recall(self.text.get("insert linestart", "insert lineend"))
580 return "break"
Guido van Rossumfd6315e2000-03-07 15:05:50 +0000581 # If we're in the current input and there's only whitespace
582 # beyond the cursor, erase that whitespace first
583 s = self.text.get("insert", "end-1c")
Walter Dörwaldaaab30e2002-09-11 20:36:02 +0000584 if s and not s.strip():
Guido van Rossumfd6315e2000-03-07 15:05:50 +0000585 self.text.delete("insert", "end-1c")
Guido van Rossum4650df91998-10-13 14:41:27 +0000586 # If we're in the current input before its last line,
587 # insert a newline right at the insert point
588 if self.text.compare("insert", "<", "end-1c linestart"):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000589 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000590 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000591 # We're in the last line; append a newline and submit it
592 self.text.mark_set("insert", "end-1c")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000593 if self.reading:
594 self.text.insert("insert", "\n")
595 self.text.see("insert")
596 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000597 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000598 self.text.tag_add("stdin", "iomark", "end-1c")
599 self.text.update_idletasks()
600 if self.reading:
601 self.top.quit() # Break out of recursive mainloop() in raw_input()
602 else:
603 self.runit()
604 return "break"
605
606 def recall(self, s):
607 if self.history:
608 self.history.recall(s)
609
610 def runit(self):
611 line = self.text.get("iomark", "end-1c")
612 # Strip off last newline and surrounding whitespace.
613 # (To allow you to hit return twice to end a statement.)
614 i = len(line)
615 while i > 0 and line[i-1] in " \t":
616 i = i-1
617 if i > 0 and line[i-1] == "\n":
618 i = i-1
619 while i > 0 and line[i-1] in " \t":
620 i = i-1
621 line = line[:i]
622 more = self.interp.runsource(line)
623 if not more:
624 self.showprompt()
625
626 def cancel_check(self, frame, what, args,
627 dooneevent=tkinter.dooneevent,
628 dontwait=tkinter.DONT_WAIT):
629 # Hack -- use the debugger hooks to be able to handle events
630 # and interrupt execution at any time.
631 # This slows execution down quite a bit, so you may want to
632 # disable this (by not calling settrace() in runcode() above)
633 # for full-bore (uninterruptable) speed.
634 # XXX This should become a user option.
635 if self.canceled:
636 return
637 dooneevent(dontwait)
638 if self.canceled:
639 self.canceled = 0
640 raise KeyboardInterrupt
641 return self._cancel_check
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000642
Guido van Rossum5af7a721998-10-12 23:59:27 +0000643 def open_stack_viewer(self, event=None):
644 try:
645 sys.last_traceback
646 except:
647 tkMessageBox.showerror("No stack trace",
648 "There is no stack trace yet.\n"
649 "(sys.last_traceback is not defined)",
650 master=self.text)
651 return
Guido van Rossum80d132d1998-10-16 16:12:11 +0000652 from StackViewer import StackBrowser
653 sv = StackBrowser(self.root, self.flist)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000654
655 def showprompt(self):
656 self.resetoutput()
657 try:
658 s = str(sys.ps1)
659 except:
660 s = ""
661 self.console.write(s)
662 self.text.mark_set("insert", "end-1c")
663
664 def resetoutput(self):
665 source = self.text.get("iomark", "end-1c")
666 if self.history:
667 self.history.history_store(source)
668 if self.text.get("end-2c") != "\n":
669 self.text.insert("end-1c", "\n")
670 self.text.mark_set("iomark", "end-1c")
671 sys.stdout.softspace = 0
672
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000673 def write(self, s, tags=()):
674 self.text.mark_gravity("iomark", "right")
675 OutputWindow.write(self, s, tags, "iomark")
676 self.text.mark_gravity("iomark", "left")
677 if self.canceled:
678 self.canceled = 0
679 raise KeyboardInterrupt
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000680
681class PseudoFile:
682
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000683 def __init__(self, shell, tags):
684 self.shell = shell
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000685 self.tags = tags
686
687 def write(self, s):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000688 self.shell.write(s, self.tags)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000689
690 def writelines(self, l):
691 map(self.write, l)
692
Guido van Rossum825df2a1999-03-29 14:52:28 +0000693 def flush(self):
694 pass
695
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000696 def isatty(self):
Tim Petersbc0e9102002-04-04 22:55:58 +0000697 return True
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000698
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000699
Guido van Rossumeeb88071999-04-22 20:49:35 +0000700usage_msg = """\
701usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
702
703-c command run this command
704-d enable debugger
705-e edit mode; arguments are files to be edited
Guido van Rossum27f550c1999-04-22 20:56:23 +0000706-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
Guido van Rossumeeb88071999-04-22 20:49:35 +0000707-t title set title of shell window
708
709When neither -c nor -e is used, and there are arguments, and the first
710argument is not '-', the first argument is run as a script. Remaining
711arguments are arguments to the script or to the command run by -c.
712"""
713
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000714def main():
Guido van Rossumeeb88071999-04-22 20:49:35 +0000715 cmd = None
716 edit = 0
Guido van Rossum80d132d1998-10-16 16:12:11 +0000717 debug = 0
Guido van Rossumeeb88071999-04-22 20:49:35 +0000718 startup = 0
719
Guido van Rossum80d132d1998-10-16 16:12:11 +0000720 try:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000721 opts, args = getopt.getopt(sys.argv[1:], "c:deist:")
Guido van Rossum80d132d1998-10-16 16:12:11 +0000722 except getopt.error, msg:
723 sys.stderr.write("Error: %s\n" % str(msg))
Guido van Rossumeeb88071999-04-22 20:49:35 +0000724 sys.stderr.write(usage_msg)
Guido van Rossum80d132d1998-10-16 16:12:11 +0000725 sys.exit(2)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000726
Guido van Rossum80d132d1998-10-16 16:12:11 +0000727 for o, a in opts:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000728 if o == '-c':
729 cmd = a
730 if o == '-d':
Guido van Rossum80d132d1998-10-16 16:12:11 +0000731 debug = 1
Guido van Rossumeeb88071999-04-22 20:49:35 +0000732 if o == '-e':
733 edit = 1
734 if o == '-s':
735 startup = 1
736 if o == '-t':
737 PyShell.shell_title = a
738
Guido van Rossumeeb88071999-04-22 20:49:35 +0000739 for i in range(len(sys.path)):
740 sys.path[i] = os.path.abspath(sys.path[i])
741
742 pathx = []
743 if edit:
744 for filename in args:
745 pathx.append(os.path.dirname(filename))
746 elif args and args[0] != "-":
747 pathx.append(os.path.dirname(args[0]))
748 else:
749 pathx.append(os.curdir)
750 for dir in pathx:
751 dir = os.path.abspath(dir)
752 if not dir in sys.path:
753 sys.path.insert(0, dir)
754
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000755 global flist, root
Fred Drake10515b62000-09-15 04:32:56 +0000756 root = Tk(className="Idle")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000757 fixwordbreaks(root)
758 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000759 flist = PyShellFileList(root)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000760
761 if edit:
762 for filename in args:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000763 flist.open(filename)
Fred Drake10515b62000-09-15 04:32:56 +0000764 else:
765 if cmd:
766 sys.argv = ["-c"] + args
767 else:
768 sys.argv = args or [""]
769
Guido van Rossumeeb88071999-04-22 20:49:35 +0000770
771 shell = PyShell(flist)
772 interp = shell.interp
773 flist.pyshell = shell
774
775 if startup:
776 filename = os.environ.get("IDLESTARTUP") or \
777 os.environ.get("PYTHONSTARTUP")
778 if filename and os.path.isfile(filename):
779 interp.execfile(filename)
780
Guido van Rossum80d132d1998-10-16 16:12:11 +0000781 if debug:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000782 shell.open_debugger()
783 if cmd:
784 interp.execsource(cmd)
785 elif not edit and args and args[0] != "-":
786 interp.execfile(args[0])
787
788 shell.begin()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000789 root.mainloop()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000790 root.destroy()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000791
Guido van Rossumeeb88071999-04-22 20:49:35 +0000792
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000793if __name__ == "__main__":
794 main()