blob: cf854d3c3b389f4362e525cae133e29b14e68a01 [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
Fred Drakecd694c42001-07-20 18:58:42 +000039IDENTCHARS = string.ascii_letters + string.digits + "_"
40
41
Guido van Rossum504b0bf1999-01-02 21:28:54 +000042# Note: <<newline-and-indent>> event is defined in AutoIndent.py
Guido van Rossumcc0ade81998-10-19 02:26:16 +000043
Guido van Rossum504b0bf1999-01-02 21:28:54 +000044#$ event <<plain-newline-and-indent>>
45#$ win <Control-j>
46#$ unix <Control-j>
47
48#$ event <<beginning-of-line>>
49#$ win <Control-a>
50#$ win <Home>
51#$ unix <Control-a>
52#$ unix <Home>
53
54#$ event <<history-next>>
55#$ win <Alt-n>
56#$ unix <Alt-n>
57
58#$ event <<history-previous>>
59#$ win <Alt-p>
60#$ unix <Alt-p>
61
62#$ event <<interrupt-execution>>
63#$ win <Control-c>
64#$ unix <Control-c>
65
66#$ event <<end-of-file>>
67#$ win <Control-d>
68#$ unix <Control-d>
69
70#$ event <<open-stack-viewer>>
71
72#$ event <<toggle-debugger>>
73
74
75class PyShellEditorWindow(EditorWindow):
76
77 # Regular text edit window when a shell is present
78 # XXX ought to merge with regular editor window
Raymond Hettinger7f7d5bf2002-05-21 17:00:20 +000079 runnable = True # Shell not present, enable Import Module and Run Script
Guido van Rossum504b0bf1999-01-02 21:28:54 +000080
81 def __init__(self, *args):
82 apply(EditorWindow.__init__, (self,) + args)
83 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
84 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
85
86 rmenu_specs = [
87 ("Set breakpoint here", "<<set-breakpoint-here>>"),
88 ]
89
90 def set_breakpoint_here(self, event=None):
Guido van Rossumcc0ade81998-10-19 02:26:16 +000091 if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
92 self.text.bell()
93 return
94 self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
Guido van Rossum5af7a721998-10-12 23:59:27 +000095
96
97class PyShellFileList(FileList):
Guido van Rossum504b0bf1999-01-02 21:28:54 +000098
99 # File list when a shell is present
100
Guido van Rossum5af7a721998-10-12 23:59:27 +0000101 EditorWindow = PyShellEditorWindow
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000102
Guido van Rossum5af7a721998-10-12 23:59:27 +0000103 pyshell = None
104
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000105 def open_shell(self, event=None):
Guido van Rossum5af7a721998-10-12 23:59:27 +0000106 if self.pyshell:
107 self.pyshell.wakeup()
108 else:
109 self.pyshell = PyShell(self)
110 self.pyshell.begin()
111 return self.pyshell
112
113
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000114class ModifiedColorDelegator(ColorDelegator):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000115
116 # Colorizer for the shell window itself
117
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000118 def recolorize_main(self):
119 self.tag_remove("TODO", "1.0", "iomark")
120 self.tag_add("SYNC", "1.0", "iomark")
121 ColorDelegator.recolorize_main(self)
122
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000123 tagdefs = ColorDelegator.tagdefs.copy()
Jeremy Hylton6b3edf02000-03-07 17:55:32 +0000124 cconf = idleconf.getsection('Colors')
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000125
126 tagdefs.update({
Jeremy Hyltone81f28b2000-03-03 23:06:45 +0000127 "stdin": cconf.getcolor("stdin"),
128 "stdout": cconf.getcolor("stdout"),
129 "stderr": cconf.getcolor("stderr"),
130 "console": cconf.getcolor("console"),
131 "ERROR": cconf.getcolor("ERROR"),
Tim Peters70c43782001-01-17 08:48:39 +0000132 None: cconf.getcolor("normal"),
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000133 })
134
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000135
Guido van Rossum9de98832000-03-07 18:51:49 +0000136class ModifiedUndoDelegator(UndoDelegator):
137
138 # Forbid insert/delete before the I/O mark
139
140 def insert(self, index, chars, tags=None):
141 try:
142 if self.delegate.compare(index, "<", "iomark"):
143 self.delegate.bell()
144 return
145 except TclError:
146 pass
147 UndoDelegator.insert(self, index, chars, tags)
148
149 def delete(self, index1, index2=None):
150 try:
151 if self.delegate.compare(index1, "<", "iomark"):
152 self.delegate.bell()
153 return
154 except TclError:
155 pass
156 UndoDelegator.delete(self, index1, index2)
157
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000158class ModifiedInterpreter(InteractiveInterpreter):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000159
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000160 def __init__(self, tkconsole):
161 self.tkconsole = tkconsole
Guido van Rossumeeb88071999-04-22 20:49:35 +0000162 locals = sys.modules['__main__'].__dict__
163 InteractiveInterpreter.__init__(self, locals=locals)
Tim Peters301ab7f2001-03-29 03:34:43 +0000164 self.save_warnings_filters = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000165
166 gid = 0
167
Guido van Rossumeeb88071999-04-22 20:49:35 +0000168 def execsource(self, source):
169 # Like runsource() but assumes complete exec source
170 filename = self.stuffsource(source)
171 self.execfile(filename, source)
172
173 def execfile(self, filename, source=None):
174 # Execute an existing file
175 if source is None:
176 source = open(filename, "r").read()
177 try:
178 code = compile(source, filename, "exec")
179 except (OverflowError, SyntaxError):
180 self.tkconsole.resetoutput()
181 InteractiveInterpreter.showsyntaxerror(self, filename)
182 else:
183 self.runcode(code)
184
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000185 def runsource(self, source):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000186 # Extend base class to stuff the source in the line cache first
187 filename = self.stuffsource(source)
188 self.more = 0
Guido van Rossumb4ce4302001-03-26 17:41:35 +0000189 self.save_warnings_filters = warnings.filters[:]
190 warnings.filterwarnings(action="error", category=SyntaxWarning)
191 try:
192 return InteractiveInterpreter.runsource(self, source, filename)
193 finally:
194 if self.save_warnings_filters is not None:
195 warnings.filters[:] = self.save_warnings_filters
196 self.save_warnings_filters = None
Guido van Rossumeeb88071999-04-22 20:49:35 +0000197
198 def stuffsource(self, source):
199 # Stuff source in the filename cache
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000200 filename = "<pyshell#%d>" % self.gid
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000201 self.gid = self.gid + 1
202 lines = string.split(source, "\n")
203 linecache.cache[filename] = len(source)+1, 0, lines, filename
Guido van Rossumeeb88071999-04-22 20:49:35 +0000204 return filename
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000205
206 def showsyntaxerror(self, filename=None):
207 # Extend base class to color the offending position
208 # (instead of printing it and pointing at it with a caret)
209 text = self.tkconsole.text
210 stuff = self.unpackerror()
211 if not stuff:
212 self.tkconsole.resetoutput()
213 InteractiveInterpreter.showsyntaxerror(self, filename)
214 return
215 msg, lineno, offset, line = stuff
216 if lineno == 1:
217 pos = "iomark + %d chars" % (offset-1)
218 else:
219 pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
220 offset-1)
221 text.tag_add("ERROR", pos)
222 text.see(pos)
223 char = text.get(pos)
Fred Drakecd694c42001-07-20 18:58:42 +0000224 if char and char in IDENTCHARS:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000225 text.tag_add("ERROR", pos + " wordstart", pos)
226 self.tkconsole.resetoutput()
227 self.write("SyntaxError: %s\n" % str(msg))
228
229 def unpackerror(self):
230 type, value, tb = sys.exc_info()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000231 ok = type is SyntaxError
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000232 if ok:
233 try:
234 msg, (dummy_filename, lineno, offset, line) = value
235 except:
236 ok = 0
237 if ok:
238 return msg, lineno, offset, line
239 else:
240 return None
241
242 def showtraceback(self):
243 # Extend base class method to reset output properly
244 text = self.tkconsole.text
245 self.tkconsole.resetoutput()
Guido van Rossum19563521998-10-13 16:32:05 +0000246 self.checklinecache()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000247 InteractiveInterpreter.showtraceback(self)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000248
Guido van Rossum19563521998-10-13 16:32:05 +0000249 def checklinecache(self):
250 c = linecache.cache
251 for key in c.keys():
252 if key[:1] + key[-1:] != "<>":
253 del c[key]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000254
Guido van Rossum35f75421998-10-13 23:51:13 +0000255 debugger = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000256
Guido van Rossum35f75421998-10-13 23:51:13 +0000257 def setdebugger(self, debugger):
258 self.debugger = debugger
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000259
Guido van Rossum35f75421998-10-13 23:51:13 +0000260 def getdebugger(self):
261 return self.debugger
262
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000263 def runcode(self, code):
264 # Override base class method
Guido van Rossumb4ce4302001-03-26 17:41:35 +0000265 if self.save_warnings_filters is not None:
266 warnings.filters[:] = self.save_warnings_filters
267 self.save_warnings_filters = None
Guido van Rossum35f75421998-10-13 23:51:13 +0000268 debugger = self.debugger
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000269 try:
270 self.tkconsole.beginexecuting()
271 try:
Guido van Rossum35f75421998-10-13 23:51:13 +0000272 if debugger:
273 debugger.run(code, self.locals)
274 else:
275 exec code in self.locals
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000276 except SystemExit:
277 if tkMessageBox.askyesno(
278 "Exit?",
279 "Do you want to exit altogether?",
280 default="yes",
281 master=self.tkconsole.text):
282 raise
283 else:
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()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000287 except:
288 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000289 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000290 self.tkconsole.open_stack_viewer()
291
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000292 finally:
293 self.tkconsole.endexecuting()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000294
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000295 def write(self, s):
296 # Override base class write
297 self.tkconsole.console.write(s)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000298
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000299
300class PyShell(OutputWindow):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000301
Guido van Rossumeeb88071999-04-22 20:49:35 +0000302 shell_title = "Python Shell"
303
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000304 # Override classes
305 ColorDelegator = ModifiedColorDelegator
Guido van Rossum9de98832000-03-07 18:51:49 +0000306 UndoDelegator = ModifiedUndoDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000307
Guido van Rossum5af7a721998-10-12 23:59:27 +0000308 # Override menu bar specs
309 menu_specs = PyShellEditorWindow.menu_specs[:]
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000310 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
311
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000312 # New classes
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000313 from IdleHistory import History
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000314
315 def __init__(self, flist=None):
316 self.interp = ModifiedInterpreter(self)
317 if flist is None:
318 root = Tk()
319 fixwordbreaks(root)
320 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000321 flist = PyShellFileList(root)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000322
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000323 OutputWindow.__init__(self, flist, None, None)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000324
325 import __builtin__
326 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
327
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000328 self.auto = self.extensions["AutoIndent"] # Required extension
Guido van Rossumbbaba851999-06-01 19:55:34 +0000329 self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000330
331 text = self.text
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000332 text.configure(wrap="char")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000333 text.bind("<<newline-and-indent>>", self.enter_callback)
334 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
335 text.bind("<<interrupt-execution>>", self.cancel_callback)
336 text.bind("<<beginning-of-line>>", self.home_callback)
337 text.bind("<<end-of-file>>", self.eof_callback)
Guido van Rossum5af7a721998-10-12 23:59:27 +0000338 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Guido van Rossum35f75421998-10-13 23:51:13 +0000339 text.bind("<<toggle-debugger>>", self.toggle_debugger)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000340 text.bind("<<open-python-shell>>", self.flist.open_shell)
Guido van Rossum38df3c31999-01-08 15:31:07 +0000341 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000342
Guido van Rossumeeb88071999-04-22 20:49:35 +0000343 self.save_stdout = sys.stdout
344 self.save_stderr = sys.stderr
345 self.save_stdin = sys.stdin
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000346 sys.stdout = PseudoFile(self, "stdout")
Guido van Rossum3f08d401998-10-13 15:21:41 +0000347 sys.stderr = PseudoFile(self, "stderr")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000348 sys.stdin = self
349 self.console = PseudoFile(self, "console")
350
351 self.history = self.History(self.text)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000352
353 reading = 0
354 executing = 0
355 canceled = 0
356 endoffile = 0
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000357
Guido van Rossum35f75421998-10-13 23:51:13 +0000358 def toggle_debugger(self, event=None):
359 if self.executing:
360 tkMessageBox.showerror("Don't debug now",
361 "You can only toggle the debugger when idle",
362 master=self.text)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000363 self.set_debugger_indicator()
Guido van Rossum35f75421998-10-13 23:51:13 +0000364 return "break"
Guido van Rossum35e55da1998-10-14 03:43:05 +0000365 else:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000366 db = self.interp.getdebugger()
367 if db:
368 self.close_debugger()
369 else:
370 self.open_debugger()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000371
Guido van Rossum07ec8961999-01-28 22:02:47 +0000372 def set_debugger_indicator(self):
373 db = self.interp.getdebugger()
374 self.setvar("<<toggle-debugger>>", not not db)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000375
Guido van Rossum38df3c31999-01-08 15:31:07 +0000376 def toggle_jit_stack_viewer( self, event=None):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000377 pass # All we need is the variable
Guido van Rossum38df3c31999-01-08 15:31:07 +0000378
Guido van Rossum35e55da1998-10-14 03:43:05 +0000379 def close_debugger(self):
380 db = self.interp.getdebugger()
381 if db:
382 self.interp.setdebugger(None)
Guido van Rossum35f75421998-10-13 23:51:13 +0000383 db.close()
384 self.resetoutput()
385 self.console.write("[DEBUG OFF]\n")
386 sys.ps1 = ">>> "
387 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000388 self.set_debugger_indicator()
Guido van Rossum35e55da1998-10-14 03:43:05 +0000389
390 def open_debugger(self):
391 import Debugger
392 self.interp.setdebugger(Debugger.Debugger(self))
Guido van Rossumadfe7731998-10-16 21:09:35 +0000393 sys.ps1 = "[DEBUG ON]\n>>> "
Guido van Rossum35e55da1998-10-14 03:43:05 +0000394 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000395 self.set_debugger_indicator()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000396
397 def beginexecuting(self):
398 # Helper for ModifiedInterpreter
399 self.resetoutput()
400 self.executing = 1
Guido van Rossumfed9b911999-06-25 16:09:27 +0000401 ##self._cancel_check = self.cancel_check
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000402 ##sys.settrace(self._cancel_check)
403
404 def endexecuting(self):
405 # Helper for ModifiedInterpreter
Guido van Rossumfed9b911999-06-25 16:09:27 +0000406 ##sys.settrace(None)
407 ##self._cancel_check = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000408 self.executing = 0
409 self.canceled = 0
410
411 def close(self):
412 # Extend base class method
413 if self.executing:
414 # XXX Need to ask a question here
415 if not tkMessageBox.askokcancel(
Guido van Rossum07ec8961999-01-28 22:02:47 +0000416 "Kill?",
417 "The program is still running; do you want to kill it?",
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000418 default="ok",
419 master=self.text):
420 return "cancel"
421 self.canceled = 1
422 if self.reading:
423 self.top.quit()
424 return "cancel"
Guido van Rossum42696012001-07-06 20:26:31 +0000425 return OutputWindow.close(self)
Guido van Rossumfed9b911999-06-25 16:09:27 +0000426
427 def _close(self):
Guido van Rossum16e0bab1999-06-25 17:26:34 +0000428 self.close_debugger()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000429 # Restore std streams
430 sys.stdout = self.save_stdout
431 sys.stderr = self.save_stderr
432 sys.stdin = self.save_stdin
433 # Break cycles
434 self.interp = None
435 self.console = None
436 self.auto = None
437 self.flist.pyshell = None
438 self.history = None
439 OutputWindow._close(self) # Really EditorWindow._close
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000440
441 def ispythonsource(self, filename):
442 # Override this so EditorWindow never removes the colorizer
Tim Petersbc0e9102002-04-04 22:55:58 +0000443 return True
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000444
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000445 def short_title(self):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000446 return self.shell_title
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000447
Guido van Rossumfa6013c2000-09-05 13:51:14 +0000448 COPYRIGHT = \
449 'Type "copyright", "credits" or "license" for more information.'
450
Guido van Rossum5af7a721998-10-12 23:59:27 +0000451 def begin(self):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000452 self.resetoutput()
Guido van Rossum26c2cb41999-04-26 22:20:38 +0000453 self.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" %
Guido van Rossumfa6013c2000-09-05 13:51:14 +0000454 (sys.version, sys.platform, self.COPYRIGHT,
Guido van Rossum27f550c1999-04-22 20:56:23 +0000455 idlever.IDLE_VERSION))
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000456 try:
457 sys.ps1
458 except AttributeError:
459 sys.ps1 = ">>> "
460 self.showprompt()
461 import Tkinter
462 Tkinter._default_root = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000463
Guido van Rossum5af7a721998-10-12 23:59:27 +0000464 def interact(self):
465 self.begin()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000466 self.top.mainloop()
467
468 def readline(self):
469 save = self.reading
470 try:
471 self.reading = 1
472 self.top.mainloop()
473 finally:
474 self.reading = save
475 line = self.text.get("iomark", "end-1c")
476 self.resetoutput()
477 if self.canceled:
478 self.canceled = 0
479 raise KeyboardInterrupt
480 if self.endoffile:
481 self.endoffile = 0
482 return ""
483 return line
484
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000485 def isatty(self):
Tim Petersbc0e9102002-04-04 22:55:58 +0000486 return True
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000487
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000488 def cancel_callback(self, event):
489 try:
490 if self.text.compare("sel.first", "!=", "sel.last"):
491 return # Active selection -- always use default binding
492 except:
493 pass
494 if not (self.executing or self.reading):
495 self.resetoutput()
496 self.write("KeyboardInterrupt\n")
497 self.showprompt()
498 return "break"
499 self.endoffile = 0
500 self.canceled = 1
501 if self.reading:
502 self.top.quit()
503 return "break"
504
505 def eof_callback(self, event):
506 if self.executing and not self.reading:
507 return # Let the default binding (delete next char) take over
508 if not (self.text.compare("iomark", "==", "insert") and
509 self.text.compare("insert", "==", "end-1c")):
510 return # Let the default binding (delete next char) take over
511 if not self.executing:
512## if not tkMessageBox.askokcancel(
513## "Exit?",
514## "Are you sure you want to exit?",
515## default="ok", master=self.text):
516## return "break"
517 self.resetoutput()
518 self.close()
519 else:
520 self.canceled = 0
521 self.endoffile = 1
522 self.top.quit()
523 return "break"
524
525 def home_callback(self, event):
526 if event.state != 0 and event.keysym == "Home":
527 return # <Modifier-Home>; fall back to class binding
528 if self.text.compare("iomark", "<=", "insert") and \
529 self.text.compare("insert linestart", "<=", "iomark"):
530 self.text.mark_set("insert", "iomark")
531 self.text.tag_remove("sel", "1.0", "end")
532 self.text.see("insert")
533 return "break"
534
535 def linefeed_callback(self, event):
536 # Insert a linefeed without entering anything (still autoindented)
537 if self.reading:
538 self.text.insert("insert", "\n")
539 self.text.see("insert")
540 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000541 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000542 return "break"
543
544 def enter_callback(self, event):
545 if self.executing and not self.reading:
546 return # Let the default binding (insert '\n') take over
547 # If some text is selected, recall the selection
Guido van Rossum4650df91998-10-13 14:41:27 +0000548 # (but only if this before the I/O mark)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000549 try:
550 sel = self.text.get("sel.first", "sel.last")
551 if sel:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000552 if self.text.compare("sel.last", "<=", "iomark"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000553 self.recall(sel)
554 return "break"
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000555 except:
556 pass
557 # If we're strictly before the line containing iomark, recall
558 # the current line, less a leading prompt, less leading or
559 # trailing whitespace
560 if self.text.compare("insert", "<", "iomark linestart"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000561 # Check if there's a relevant stdin range -- if so, use it
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000562 prev = self.text.tag_prevrange("stdin", "insert")
563 if prev and self.text.compare("insert", "<", prev[1]):
564 self.recall(self.text.get(prev[0], prev[1]))
565 return "break"
566 next = self.text.tag_nextrange("stdin", "insert")
567 if next and self.text.compare("insert lineend", ">=", next[0]):
568 self.recall(self.text.get(next[0], next[1]))
569 return "break"
570 # No stdin mark -- just get the current line
571 self.recall(self.text.get("insert linestart", "insert lineend"))
572 return "break"
Guido van Rossumfd6315e2000-03-07 15:05:50 +0000573 # If we're in the current input and there's only whitespace
574 # beyond the cursor, erase that whitespace first
575 s = self.text.get("insert", "end-1c")
576 if s and not string.strip(s):
577 self.text.delete("insert", "end-1c")
Guido van Rossum4650df91998-10-13 14:41:27 +0000578 # If we're in the current input before its last line,
579 # insert a newline right at the insert point
580 if self.text.compare("insert", "<", "end-1c linestart"):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000581 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000582 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000583 # We're in the last line; append a newline and submit it
584 self.text.mark_set("insert", "end-1c")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000585 if self.reading:
586 self.text.insert("insert", "\n")
587 self.text.see("insert")
588 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000589 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000590 self.text.tag_add("stdin", "iomark", "end-1c")
591 self.text.update_idletasks()
592 if self.reading:
593 self.top.quit() # Break out of recursive mainloop() in raw_input()
594 else:
595 self.runit()
596 return "break"
597
598 def recall(self, s):
599 if self.history:
600 self.history.recall(s)
601
602 def runit(self):
603 line = self.text.get("iomark", "end-1c")
604 # Strip off last newline and surrounding whitespace.
605 # (To allow you to hit return twice to end a statement.)
606 i = len(line)
607 while i > 0 and line[i-1] in " \t":
608 i = i-1
609 if i > 0 and line[i-1] == "\n":
610 i = i-1
611 while i > 0 and line[i-1] in " \t":
612 i = i-1
613 line = line[:i]
614 more = self.interp.runsource(line)
615 if not more:
616 self.showprompt()
617
618 def cancel_check(self, frame, what, args,
619 dooneevent=tkinter.dooneevent,
620 dontwait=tkinter.DONT_WAIT):
621 # Hack -- use the debugger hooks to be able to handle events
622 # and interrupt execution at any time.
623 # This slows execution down quite a bit, so you may want to
624 # disable this (by not calling settrace() in runcode() above)
625 # for full-bore (uninterruptable) speed.
626 # XXX This should become a user option.
627 if self.canceled:
628 return
629 dooneevent(dontwait)
630 if self.canceled:
631 self.canceled = 0
632 raise KeyboardInterrupt
633 return self._cancel_check
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000634
Guido van Rossum5af7a721998-10-12 23:59:27 +0000635 def open_stack_viewer(self, event=None):
636 try:
637 sys.last_traceback
638 except:
639 tkMessageBox.showerror("No stack trace",
640 "There is no stack trace yet.\n"
641 "(sys.last_traceback is not defined)",
642 master=self.text)
643 return
Guido van Rossum80d132d1998-10-16 16:12:11 +0000644 from StackViewer import StackBrowser
645 sv = StackBrowser(self.root, self.flist)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000646
647 def showprompt(self):
648 self.resetoutput()
649 try:
650 s = str(sys.ps1)
651 except:
652 s = ""
653 self.console.write(s)
654 self.text.mark_set("insert", "end-1c")
655
656 def resetoutput(self):
657 source = self.text.get("iomark", "end-1c")
658 if self.history:
659 self.history.history_store(source)
660 if self.text.get("end-2c") != "\n":
661 self.text.insert("end-1c", "\n")
662 self.text.mark_set("iomark", "end-1c")
663 sys.stdout.softspace = 0
664
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000665 def write(self, s, tags=()):
666 self.text.mark_gravity("iomark", "right")
667 OutputWindow.write(self, s, tags, "iomark")
668 self.text.mark_gravity("iomark", "left")
669 if self.canceled:
670 self.canceled = 0
671 raise KeyboardInterrupt
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000672
673class PseudoFile:
674
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000675 def __init__(self, shell, tags):
676 self.shell = shell
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000677 self.tags = tags
678
679 def write(self, s):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000680 self.shell.write(s, self.tags)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000681
682 def writelines(self, l):
683 map(self.write, l)
684
Guido van Rossum825df2a1999-03-29 14:52:28 +0000685 def flush(self):
686 pass
687
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000688 def isatty(self):
Tim Petersbc0e9102002-04-04 22:55:58 +0000689 return True
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000690
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000691
Guido van Rossumeeb88071999-04-22 20:49:35 +0000692usage_msg = """\
693usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
694
695-c command run this command
696-d enable debugger
697-e edit mode; arguments are files to be edited
Guido van Rossum27f550c1999-04-22 20:56:23 +0000698-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
Guido van Rossumeeb88071999-04-22 20:49:35 +0000699-t title set title of shell window
700
701When neither -c nor -e is used, and there are arguments, and the first
702argument is not '-', the first argument is run as a script. Remaining
703arguments are arguments to the script or to the command run by -c.
704"""
705
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000706def main():
Guido van Rossumeeb88071999-04-22 20:49:35 +0000707 cmd = None
708 edit = 0
Guido van Rossum80d132d1998-10-16 16:12:11 +0000709 debug = 0
Guido van Rossumeeb88071999-04-22 20:49:35 +0000710 startup = 0
711
Guido van Rossum80d132d1998-10-16 16:12:11 +0000712 try:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000713 opts, args = getopt.getopt(sys.argv[1:], "c:deist:")
Guido van Rossum80d132d1998-10-16 16:12:11 +0000714 except getopt.error, msg:
715 sys.stderr.write("Error: %s\n" % str(msg))
Guido van Rossumeeb88071999-04-22 20:49:35 +0000716 sys.stderr.write(usage_msg)
Guido van Rossum80d132d1998-10-16 16:12:11 +0000717 sys.exit(2)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000718
Guido van Rossum80d132d1998-10-16 16:12:11 +0000719 for o, a in opts:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000720 if o == '-c':
721 cmd = a
722 if o == '-d':
Guido van Rossum80d132d1998-10-16 16:12:11 +0000723 debug = 1
Guido van Rossumeeb88071999-04-22 20:49:35 +0000724 if o == '-e':
725 edit = 1
726 if o == '-s':
727 startup = 1
728 if o == '-t':
729 PyShell.shell_title = a
730
Guido van Rossumeeb88071999-04-22 20:49:35 +0000731 for i in range(len(sys.path)):
732 sys.path[i] = os.path.abspath(sys.path[i])
733
734 pathx = []
735 if edit:
736 for filename in args:
737 pathx.append(os.path.dirname(filename))
738 elif args and args[0] != "-":
739 pathx.append(os.path.dirname(args[0]))
740 else:
741 pathx.append(os.curdir)
742 for dir in pathx:
743 dir = os.path.abspath(dir)
744 if not dir in sys.path:
745 sys.path.insert(0, dir)
746
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000747 global flist, root
Fred Drake10515b62000-09-15 04:32:56 +0000748 root = Tk(className="Idle")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000749 fixwordbreaks(root)
750 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000751 flist = PyShellFileList(root)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000752
753 if edit:
754 for filename in args:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000755 flist.open(filename)
Fred Drake10515b62000-09-15 04:32:56 +0000756 else:
757 if cmd:
758 sys.argv = ["-c"] + args
759 else:
760 sys.argv = args or [""]
761
Guido van Rossumeeb88071999-04-22 20:49:35 +0000762
763 shell = PyShell(flist)
764 interp = shell.interp
765 flist.pyshell = shell
766
767 if startup:
768 filename = os.environ.get("IDLESTARTUP") or \
769 os.environ.get("PYTHONSTARTUP")
770 if filename and os.path.isfile(filename):
771 interp.execfile(filename)
772
Guido van Rossum80d132d1998-10-16 16:12:11 +0000773 if debug:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000774 shell.open_debugger()
775 if cmd:
776 interp.execsource(cmd)
777 elif not edit and args and args[0] != "-":
778 interp.execfile(args[0])
779
780 shell.begin()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000781 root.mainloop()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000782 root.destroy()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000783
Guido van Rossumeeb88071999-04-22 20:49:35 +0000784
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000785if __name__ == "__main__":
786 main()