blob: 90f9b2c58587a19c1b8f66fe2a555b635ba1dd07 [file] [log] [blame]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00001#! /usr/bin/env python
2
3import os
4import sys
5import string
Guido van Rossum80d132d1998-10-16 16:12:11 +00006import getopt
Guido van Rossum5af7a721998-10-12 23:59:27 +00007import re
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +00008
9import linecache
10from code import InteractiveInterpreter
11
12from Tkinter import *
13import tkMessageBox
14
Guido van Rossum504b0bf1999-01-02 21:28:54 +000015from EditorWindow import EditorWindow, fixwordbreaks
16from FileList import FileList
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000017from ColorDelegator import ColorDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +000018from OutputWindow import OutputWindow
Guido van Rossum27f550c1999-04-22 20:56:23 +000019import idlever
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000020
Guido van Rossumcc0ade81998-10-19 02:26:16 +000021# We need to patch linecache.checkcache, because we don't want it
22# to throw away our <pyshell#...> entries.
23# Rather than repeating its code here, we save those entries,
24# then call the original function, and then restore the saved entries.
25def linecache_checkcache(orig_checkcache=linecache.checkcache):
26 cache = linecache.cache
27 save = {}
28 for filename in cache.keys():
29 if filename[:1] + filename[-1:] == '<>':
30 save[filename] = cache[filename]
31 orig_checkcache()
32 cache.update(save)
33linecache.checkcache = linecache_checkcache
34
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000035
Guido van Rossum504b0bf1999-01-02 21:28:54 +000036# Note: <<newline-and-indent>> event is defined in AutoIndent.py
Guido van Rossumcc0ade81998-10-19 02:26:16 +000037
Guido van Rossum504b0bf1999-01-02 21:28:54 +000038#$ event <<plain-newline-and-indent>>
39#$ win <Control-j>
40#$ unix <Control-j>
41
42#$ event <<beginning-of-line>>
43#$ win <Control-a>
44#$ win <Home>
45#$ unix <Control-a>
46#$ unix <Home>
47
48#$ event <<history-next>>
49#$ win <Alt-n>
50#$ unix <Alt-n>
51
52#$ event <<history-previous>>
53#$ win <Alt-p>
54#$ unix <Alt-p>
55
56#$ event <<interrupt-execution>>
57#$ win <Control-c>
58#$ unix <Control-c>
59
60#$ event <<end-of-file>>
61#$ win <Control-d>
62#$ unix <Control-d>
63
64#$ event <<open-stack-viewer>>
65
66#$ event <<toggle-debugger>>
67
68
69class PyShellEditorWindow(EditorWindow):
70
71 # Regular text edit window when a shell is present
72 # XXX ought to merge with regular editor window
73
74 def __init__(self, *args):
75 apply(EditorWindow.__init__, (self,) + args)
76 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
77 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
78
79 rmenu_specs = [
80 ("Set breakpoint here", "<<set-breakpoint-here>>"),
81 ]
82
83 def set_breakpoint_here(self, event=None):
Guido van Rossumcc0ade81998-10-19 02:26:16 +000084 if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
85 self.text.bell()
86 return
87 self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
Guido van Rossum5af7a721998-10-12 23:59:27 +000088
89
90class PyShellFileList(FileList):
Guido van Rossum504b0bf1999-01-02 21:28:54 +000091
92 # File list when a shell is present
93
Guido van Rossum5af7a721998-10-12 23:59:27 +000094 EditorWindow = PyShellEditorWindow
Guido van Rossum504b0bf1999-01-02 21:28:54 +000095
Guido van Rossum5af7a721998-10-12 23:59:27 +000096 pyshell = None
97
Guido van Rossum504b0bf1999-01-02 21:28:54 +000098 def open_shell(self, event=None):
Guido van Rossum5af7a721998-10-12 23:59:27 +000099 if self.pyshell:
100 self.pyshell.wakeup()
101 else:
102 self.pyshell = PyShell(self)
103 self.pyshell.begin()
104 return self.pyshell
105
106
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000107class ModifiedColorDelegator(ColorDelegator):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000108
109 # Colorizer for the shell window itself
110
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000111 def recolorize_main(self):
112 self.tag_remove("TODO", "1.0", "iomark")
113 self.tag_add("SYNC", "1.0", "iomark")
114 ColorDelegator.recolorize_main(self)
115
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000116 tagdefs = ColorDelegator.tagdefs.copy()
Guido van Rossum7de69751999-04-20 15:45:30 +0000117 cprefs = ColorDelegator.cprefs
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000118
119 tagdefs.update({
Guido van Rossum7de69751999-04-20 15:45:30 +0000120 "stdin": {"foreground": cprefs.CStdIn[0],
121 "background": cprefs.CStdIn[1]},
122 "stdout": {"foreground": cprefs.CStdOut[0],
123 "background": cprefs.CStdOut[1]},
124 "stderr": {"foreground": cprefs.CStdErr[0],
125 "background": cprefs.CStdErr[1]},
126 "console": {"foreground": cprefs.CConsole[0],
127 "background": cprefs.CConsole[1]},
128 "ERROR": {"background": cprefs.CError[0],
129 "background": cprefs.CError[1]},
130 None: {"foreground": cprefs.CNormal[0],
131 "background": cprefs.CNormal[1]},
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000132 })
133
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000134
135class ModifiedInterpreter(InteractiveInterpreter):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000136
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000137 def __init__(self, tkconsole):
138 self.tkconsole = tkconsole
Guido van Rossumeeb88071999-04-22 20:49:35 +0000139 locals = sys.modules['__main__'].__dict__
140 InteractiveInterpreter.__init__(self, locals=locals)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000141
142 gid = 0
143
Guido van Rossumeeb88071999-04-22 20:49:35 +0000144 def execsource(self, source):
145 # Like runsource() but assumes complete exec source
146 filename = self.stuffsource(source)
147 self.execfile(filename, source)
148
149 def execfile(self, filename, source=None):
150 # Execute an existing file
151 if source is None:
152 source = open(filename, "r").read()
153 try:
154 code = compile(source, filename, "exec")
155 except (OverflowError, SyntaxError):
156 self.tkconsole.resetoutput()
157 InteractiveInterpreter.showsyntaxerror(self, filename)
158 else:
159 self.runcode(code)
160
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000161 def runsource(self, source):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000162 # Extend base class to stuff the source in the line cache first
163 filename = self.stuffsource(source)
164 self.more = 0
165 return InteractiveInterpreter.runsource(self, source, filename)
166
167 def stuffsource(self, source):
168 # Stuff source in the filename cache
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000169 filename = "<pyshell#%d>" % self.gid
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000170 self.gid = self.gid + 1
171 lines = string.split(source, "\n")
172 linecache.cache[filename] = len(source)+1, 0, lines, filename
Guido van Rossumeeb88071999-04-22 20:49:35 +0000173 return filename
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000174
175 def showsyntaxerror(self, filename=None):
176 # Extend base class to color the offending position
177 # (instead of printing it and pointing at it with a caret)
178 text = self.tkconsole.text
179 stuff = self.unpackerror()
180 if not stuff:
181 self.tkconsole.resetoutput()
182 InteractiveInterpreter.showsyntaxerror(self, filename)
183 return
184 msg, lineno, offset, line = stuff
185 if lineno == 1:
186 pos = "iomark + %d chars" % (offset-1)
187 else:
188 pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
189 offset-1)
190 text.tag_add("ERROR", pos)
191 text.see(pos)
192 char = text.get(pos)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000193 if char and char in string.letters + string.digits + "_":
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000194 text.tag_add("ERROR", pos + " wordstart", pos)
195 self.tkconsole.resetoutput()
196 self.write("SyntaxError: %s\n" % str(msg))
197
198 def unpackerror(self):
199 type, value, tb = sys.exc_info()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000200 ok = type is SyntaxError
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000201 if ok:
202 try:
203 msg, (dummy_filename, lineno, offset, line) = value
204 except:
205 ok = 0
206 if ok:
207 return msg, lineno, offset, line
208 else:
209 return None
210
211 def showtraceback(self):
212 # Extend base class method to reset output properly
213 text = self.tkconsole.text
214 self.tkconsole.resetoutput()
Guido van Rossum19563521998-10-13 16:32:05 +0000215 self.checklinecache()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000216 InteractiveInterpreter.showtraceback(self)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000217
Guido van Rossum19563521998-10-13 16:32:05 +0000218 def checklinecache(self):
219 c = linecache.cache
220 for key in c.keys():
221 if key[:1] + key[-1:] != "<>":
222 del c[key]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000223
Guido van Rossum35f75421998-10-13 23:51:13 +0000224 debugger = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000225
Guido van Rossum35f75421998-10-13 23:51:13 +0000226 def setdebugger(self, debugger):
227 self.debugger = debugger
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000228
Guido van Rossum35f75421998-10-13 23:51:13 +0000229 def getdebugger(self):
230 return self.debugger
231
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000232 def runcode(self, code):
233 # Override base class method
Guido van Rossum35f75421998-10-13 23:51:13 +0000234 debugger = self.debugger
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000235 try:
236 self.tkconsole.beginexecuting()
237 try:
Guido van Rossum35f75421998-10-13 23:51:13 +0000238 if debugger:
239 debugger.run(code, self.locals)
240 else:
241 exec code in self.locals
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000242 except SystemExit:
243 if tkMessageBox.askyesno(
244 "Exit?",
245 "Do you want to exit altogether?",
246 default="yes",
247 master=self.tkconsole.text):
248 raise
249 else:
250 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000251 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000252 self.tkconsole.open_stack_viewer()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000253 except:
254 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000255 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000256 self.tkconsole.open_stack_viewer()
257
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000258 finally:
259 self.tkconsole.endexecuting()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000260
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000261 def write(self, s):
262 # Override base class write
263 self.tkconsole.console.write(s)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000264
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000265
266class PyShell(OutputWindow):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000267
Guido van Rossumeeb88071999-04-22 20:49:35 +0000268 shell_title = "Python Shell"
269
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000270 # Override classes
271 ColorDelegator = ModifiedColorDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000272
Guido van Rossum5af7a721998-10-12 23:59:27 +0000273 # Override menu bar specs
274 menu_specs = PyShellEditorWindow.menu_specs[:]
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000275 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
276
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000277 # New classes
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000278 from IdleHistory import History
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000279
280 def __init__(self, flist=None):
281 self.interp = ModifiedInterpreter(self)
282 if flist is None:
283 root = Tk()
284 fixwordbreaks(root)
285 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000286 flist = PyShellFileList(root)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000287
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000288 OutputWindow.__init__(self, flist, None, None)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000289
290 import __builtin__
291 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
292
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000293 self.auto = self.extensions["AutoIndent"] # Required extension
Guido van Rossumbbaba851999-06-01 19:55:34 +0000294 self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000295
296 text = self.text
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000297 text.configure(wrap="char")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000298 text.bind("<<newline-and-indent>>", self.enter_callback)
299 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
300 text.bind("<<interrupt-execution>>", self.cancel_callback)
301 text.bind("<<beginning-of-line>>", self.home_callback)
302 text.bind("<<end-of-file>>", self.eof_callback)
Guido van Rossum5af7a721998-10-12 23:59:27 +0000303 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Guido van Rossum35f75421998-10-13 23:51:13 +0000304 text.bind("<<toggle-debugger>>", self.toggle_debugger)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000305 text.bind("<<open-python-shell>>", self.flist.open_shell)
Guido van Rossum38df3c31999-01-08 15:31:07 +0000306 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000307
Guido van Rossumeeb88071999-04-22 20:49:35 +0000308 self.save_stdout = sys.stdout
309 self.save_stderr = sys.stderr
310 self.save_stdin = sys.stdin
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000311 sys.stdout = PseudoFile(self, "stdout")
Guido van Rossum3f08d401998-10-13 15:21:41 +0000312 sys.stderr = PseudoFile(self, "stderr")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000313 sys.stdin = self
314 self.console = PseudoFile(self, "console")
315
316 self.history = self.History(self.text)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000317
318 reading = 0
319 executing = 0
320 canceled = 0
321 endoffile = 0
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000322
Guido van Rossum35f75421998-10-13 23:51:13 +0000323 def toggle_debugger(self, event=None):
324 if self.executing:
325 tkMessageBox.showerror("Don't debug now",
326 "You can only toggle the debugger when idle",
327 master=self.text)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000328 self.set_debugger_indicator()
Guido van Rossum35f75421998-10-13 23:51:13 +0000329 return "break"
Guido van Rossum35e55da1998-10-14 03:43:05 +0000330 else:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000331 db = self.interp.getdebugger()
332 if db:
333 self.close_debugger()
334 else:
335 self.open_debugger()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000336
Guido van Rossum07ec8961999-01-28 22:02:47 +0000337 def set_debugger_indicator(self):
338 db = self.interp.getdebugger()
339 self.setvar("<<toggle-debugger>>", not not db)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000340
Guido van Rossum38df3c31999-01-08 15:31:07 +0000341 def toggle_jit_stack_viewer( self, event=None):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000342 pass # All we need is the variable
Guido van Rossum38df3c31999-01-08 15:31:07 +0000343
Guido van Rossum35e55da1998-10-14 03:43:05 +0000344 def close_debugger(self):
345 db = self.interp.getdebugger()
346 if db:
347 self.interp.setdebugger(None)
Guido van Rossum35f75421998-10-13 23:51:13 +0000348 db.close()
349 self.resetoutput()
350 self.console.write("[DEBUG OFF]\n")
351 sys.ps1 = ">>> "
352 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000353 self.set_debugger_indicator()
Guido van Rossum35e55da1998-10-14 03:43:05 +0000354
355 def open_debugger(self):
356 import Debugger
357 self.interp.setdebugger(Debugger.Debugger(self))
Guido van Rossumadfe7731998-10-16 21:09:35 +0000358 sys.ps1 = "[DEBUG ON]\n>>> "
Guido van Rossum35e55da1998-10-14 03:43:05 +0000359 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000360 self.set_debugger_indicator()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000361
362 def beginexecuting(self):
363 # Helper for ModifiedInterpreter
364 self.resetoutput()
365 self.executing = 1
Guido van Rossumfed9b911999-06-25 16:09:27 +0000366 ##self._cancel_check = self.cancel_check
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000367 ##sys.settrace(self._cancel_check)
368
369 def endexecuting(self):
370 # Helper for ModifiedInterpreter
Guido van Rossumfed9b911999-06-25 16:09:27 +0000371 ##sys.settrace(None)
372 ##self._cancel_check = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000373 self.executing = 0
374 self.canceled = 0
375
376 def close(self):
377 # Extend base class method
378 if self.executing:
379 # XXX Need to ask a question here
380 if not tkMessageBox.askokcancel(
Guido van Rossum07ec8961999-01-28 22:02:47 +0000381 "Kill?",
382 "The program is still running; do you want to kill it?",
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000383 default="ok",
384 master=self.text):
385 return "cancel"
386 self.canceled = 1
387 if self.reading:
388 self.top.quit()
389 return "cancel"
Guido van Rossumfed9b911999-06-25 16:09:27 +0000390 return PyShellEditorWindow.close(self)
391
392 def _close(self):
393 # Restore std streams
394 sys.stdout = self.save_stdout
395 sys.stderr = self.save_stderr
396 sys.stdin = self.save_stdin
397 # Break cycles
398 self.interp = None
399 self.console = None
400 self.auto = None
401 self.flist.pyshell = None
402 self.history = None
403 OutputWindow._close(self) # Really EditorWindow._close
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000404
405 def ispythonsource(self, filename):
406 # Override this so EditorWindow never removes the colorizer
407 return 1
408
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000409 def short_title(self):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000410 return self.shell_title
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000411
Guido van Rossum5af7a721998-10-12 23:59:27 +0000412 def begin(self):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000413 self.resetoutput()
Guido van Rossum26c2cb41999-04-26 22:20:38 +0000414 self.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" %
Guido van Rossum27f550c1999-04-22 20:56:23 +0000415 (sys.version, sys.platform, sys.copyright,
416 idlever.IDLE_VERSION))
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000417 try:
418 sys.ps1
419 except AttributeError:
420 sys.ps1 = ">>> "
421 self.showprompt()
422 import Tkinter
423 Tkinter._default_root = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000424
Guido van Rossum5af7a721998-10-12 23:59:27 +0000425 def interact(self):
426 self.begin()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000427 self.top.mainloop()
428
429 def readline(self):
430 save = self.reading
431 try:
432 self.reading = 1
433 self.top.mainloop()
434 finally:
435 self.reading = save
436 line = self.text.get("iomark", "end-1c")
437 self.resetoutput()
438 if self.canceled:
439 self.canceled = 0
440 raise KeyboardInterrupt
441 if self.endoffile:
442 self.endoffile = 0
443 return ""
444 return line
445
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000446 def isatty(self):
447 return 1
448
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000449 def cancel_callback(self, event):
450 try:
451 if self.text.compare("sel.first", "!=", "sel.last"):
452 return # Active selection -- always use default binding
453 except:
454 pass
455 if not (self.executing or self.reading):
456 self.resetoutput()
457 self.write("KeyboardInterrupt\n")
458 self.showprompt()
459 return "break"
460 self.endoffile = 0
461 self.canceled = 1
462 if self.reading:
463 self.top.quit()
464 return "break"
465
466 def eof_callback(self, event):
467 if self.executing and not self.reading:
468 return # Let the default binding (delete next char) take over
469 if not (self.text.compare("iomark", "==", "insert") and
470 self.text.compare("insert", "==", "end-1c")):
471 return # Let the default binding (delete next char) take over
472 if not self.executing:
473## if not tkMessageBox.askokcancel(
474## "Exit?",
475## "Are you sure you want to exit?",
476## default="ok", master=self.text):
477## return "break"
478 self.resetoutput()
479 self.close()
480 else:
481 self.canceled = 0
482 self.endoffile = 1
483 self.top.quit()
484 return "break"
485
486 def home_callback(self, event):
487 if event.state != 0 and event.keysym == "Home":
488 return # <Modifier-Home>; fall back to class binding
489 if self.text.compare("iomark", "<=", "insert") and \
490 self.text.compare("insert linestart", "<=", "iomark"):
491 self.text.mark_set("insert", "iomark")
492 self.text.tag_remove("sel", "1.0", "end")
493 self.text.see("insert")
494 return "break"
495
496 def linefeed_callback(self, event):
497 # Insert a linefeed without entering anything (still autoindented)
498 if self.reading:
499 self.text.insert("insert", "\n")
500 self.text.see("insert")
501 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000502 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000503 return "break"
504
505 def enter_callback(self, event):
506 if self.executing and not self.reading:
507 return # Let the default binding (insert '\n') take over
508 # If some text is selected, recall the selection
Guido van Rossum4650df91998-10-13 14:41:27 +0000509 # (but only if this before the I/O mark)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000510 try:
511 sel = self.text.get("sel.first", "sel.last")
512 if sel:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000513 if self.text.compare("sel.last", "<=", "iomark"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000514 self.recall(sel)
515 return "break"
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000516 except:
517 pass
518 # If we're strictly before the line containing iomark, recall
519 # the current line, less a leading prompt, less leading or
520 # trailing whitespace
521 if self.text.compare("insert", "<", "iomark linestart"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000522 # Check if there's a relevant stdin range -- if so, use it
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000523 prev = self.text.tag_prevrange("stdin", "insert")
524 if prev and self.text.compare("insert", "<", prev[1]):
525 self.recall(self.text.get(prev[0], prev[1]))
526 return "break"
527 next = self.text.tag_nextrange("stdin", "insert")
528 if next and self.text.compare("insert lineend", ">=", next[0]):
529 self.recall(self.text.get(next[0], next[1]))
530 return "break"
531 # No stdin mark -- just get the current line
532 self.recall(self.text.get("insert linestart", "insert lineend"))
533 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000534 # If we're in the current input before its last line,
535 # insert a newline right at the insert point
536 if self.text.compare("insert", "<", "end-1c linestart"):
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"
Guido van Rossum4650df91998-10-13 14:41:27 +0000539 # We're in the last line; append a newline and submit it
540 self.text.mark_set("insert", "end-1c")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000541 if self.reading:
542 self.text.insert("insert", "\n")
543 self.text.see("insert")
544 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000545 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000546 self.text.tag_add("stdin", "iomark", "end-1c")
547 self.text.update_idletasks()
548 if self.reading:
549 self.top.quit() # Break out of recursive mainloop() in raw_input()
550 else:
551 self.runit()
552 return "break"
553
554 def recall(self, s):
555 if self.history:
556 self.history.recall(s)
557
558 def runit(self):
559 line = self.text.get("iomark", "end-1c")
560 # Strip off last newline and surrounding whitespace.
561 # (To allow you to hit return twice to end a statement.)
562 i = len(line)
563 while i > 0 and line[i-1] in " \t":
564 i = i-1
565 if i > 0 and line[i-1] == "\n":
566 i = i-1
567 while i > 0 and line[i-1] in " \t":
568 i = i-1
569 line = line[:i]
570 more = self.interp.runsource(line)
571 if not more:
572 self.showprompt()
573
574 def cancel_check(self, frame, what, args,
575 dooneevent=tkinter.dooneevent,
576 dontwait=tkinter.DONT_WAIT):
577 # Hack -- use the debugger hooks to be able to handle events
578 # and interrupt execution at any time.
579 # This slows execution down quite a bit, so you may want to
580 # disable this (by not calling settrace() in runcode() above)
581 # for full-bore (uninterruptable) speed.
582 # XXX This should become a user option.
583 if self.canceled:
584 return
585 dooneevent(dontwait)
586 if self.canceled:
587 self.canceled = 0
588 raise KeyboardInterrupt
589 return self._cancel_check
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000590
Guido van Rossum5af7a721998-10-12 23:59:27 +0000591 def open_stack_viewer(self, event=None):
592 try:
593 sys.last_traceback
594 except:
595 tkMessageBox.showerror("No stack trace",
596 "There is no stack trace yet.\n"
597 "(sys.last_traceback is not defined)",
598 master=self.text)
599 return
Guido van Rossum80d132d1998-10-16 16:12:11 +0000600 from StackViewer import StackBrowser
601 sv = StackBrowser(self.root, self.flist)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000602
603 def showprompt(self):
604 self.resetoutput()
605 try:
606 s = str(sys.ps1)
607 except:
608 s = ""
609 self.console.write(s)
610 self.text.mark_set("insert", "end-1c")
611
612 def resetoutput(self):
613 source = self.text.get("iomark", "end-1c")
614 if self.history:
615 self.history.history_store(source)
616 if self.text.get("end-2c") != "\n":
617 self.text.insert("end-1c", "\n")
618 self.text.mark_set("iomark", "end-1c")
619 sys.stdout.softspace = 0
620
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000621 def write(self, s, tags=()):
622 self.text.mark_gravity("iomark", "right")
623 OutputWindow.write(self, s, tags, "iomark")
624 self.text.mark_gravity("iomark", "left")
625 if self.canceled:
626 self.canceled = 0
627 raise KeyboardInterrupt
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000628
629class PseudoFile:
630
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000631 def __init__(self, shell, tags):
632 self.shell = shell
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000633 self.tags = tags
634
635 def write(self, s):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000636 self.shell.write(s, self.tags)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000637
638 def writelines(self, l):
639 map(self.write, l)
640
Guido van Rossum825df2a1999-03-29 14:52:28 +0000641 def flush(self):
642 pass
643
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000644 def isatty(self):
645 return 1
646
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000647
Guido van Rossumeeb88071999-04-22 20:49:35 +0000648usage_msg = """\
649usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
650
651-c command run this command
652-d enable debugger
653-e edit mode; arguments are files to be edited
Guido van Rossum27f550c1999-04-22 20:56:23 +0000654-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
Guido van Rossumeeb88071999-04-22 20:49:35 +0000655-t title set title of shell window
656
657When neither -c nor -e is used, and there are arguments, and the first
658argument is not '-', the first argument is run as a script. Remaining
659arguments are arguments to the script or to the command run by -c.
660"""
661
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000662def main():
Guido van Rossumeeb88071999-04-22 20:49:35 +0000663 cmd = None
664 edit = 0
Guido van Rossum80d132d1998-10-16 16:12:11 +0000665 debug = 0
Guido van Rossumeeb88071999-04-22 20:49:35 +0000666 startup = 0
667
Guido van Rossum80d132d1998-10-16 16:12:11 +0000668 try:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000669 opts, args = getopt.getopt(sys.argv[1:], "c:deist:")
Guido van Rossum80d132d1998-10-16 16:12:11 +0000670 except getopt.error, msg:
671 sys.stderr.write("Error: %s\n" % str(msg))
Guido van Rossumeeb88071999-04-22 20:49:35 +0000672 sys.stderr.write(usage_msg)
Guido van Rossum80d132d1998-10-16 16:12:11 +0000673 sys.exit(2)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000674
Guido van Rossum80d132d1998-10-16 16:12:11 +0000675 for o, a in opts:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000676 if o == '-c':
677 cmd = a
678 if o == '-d':
Guido van Rossum80d132d1998-10-16 16:12:11 +0000679 debug = 1
Guido van Rossumeeb88071999-04-22 20:49:35 +0000680 if o == '-e':
681 edit = 1
682 if o == '-s':
683 startup = 1
684 if o == '-t':
685 PyShell.shell_title = a
686
687 if not edit:
688 if cmd:
689 sys.argv = ["-c"] + args
690 else:
691 sys.argv = args or [""]
692
693 for i in range(len(sys.path)):
694 sys.path[i] = os.path.abspath(sys.path[i])
695
696 pathx = []
697 if edit:
698 for filename in args:
699 pathx.append(os.path.dirname(filename))
700 elif args and args[0] != "-":
701 pathx.append(os.path.dirname(args[0]))
702 else:
703 pathx.append(os.curdir)
704 for dir in pathx:
705 dir = os.path.abspath(dir)
706 if not dir in sys.path:
707 sys.path.insert(0, dir)
708
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000709 global flist, root
710 root = Tk()
711 fixwordbreaks(root)
712 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000713 flist = PyShellFileList(root)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000714
715 if edit:
716 for filename in args:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000717 flist.open(filename)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000718
719 shell = PyShell(flist)
720 interp = shell.interp
721 flist.pyshell = shell
722
723 if startup:
724 filename = os.environ.get("IDLESTARTUP") or \
725 os.environ.get("PYTHONSTARTUP")
726 if filename and os.path.isfile(filename):
727 interp.execfile(filename)
728
Guido van Rossum80d132d1998-10-16 16:12:11 +0000729 if debug:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000730 shell.open_debugger()
731 if cmd:
732 interp.execsource(cmd)
733 elif not edit and args and args[0] != "-":
734 interp.execfile(args[0])
735
736 shell.begin()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000737 root.mainloop()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000738 root.destroy()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000739
Guido van Rossumeeb88071999-04-22 20:49:35 +0000740
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000741if __name__ == "__main__":
742 main()