blob: 86c0f6b0ae4bc1f1bee004ee4770542bc06bd731 [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 Rossum9de98832000-03-07 18:51:49 +000018from UndoDelegator import UndoDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +000019from OutputWindow import OutputWindow
Jeremy Hylton6b3edf02000-03-07 17:55:32 +000020from IdleConf import idleconf
Guido van Rossum27f550c1999-04-22 20:56:23 +000021import idlever
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000022
Guido van Rossumcc0ade81998-10-19 02:26:16 +000023# We need to patch linecache.checkcache, because we don't want it
24# to throw away our <pyshell#...> entries.
25# Rather than repeating its code here, we save those entries,
26# then call the original function, and then restore the saved entries.
27def linecache_checkcache(orig_checkcache=linecache.checkcache):
28 cache = linecache.cache
29 save = {}
30 for filename in cache.keys():
31 if filename[:1] + filename[-1:] == '<>':
32 save[filename] = cache[filename]
33 orig_checkcache()
34 cache.update(save)
35linecache.checkcache = linecache_checkcache
36
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +000037
Guido van Rossum504b0bf1999-01-02 21:28:54 +000038# Note: <<newline-and-indent>> event is defined in AutoIndent.py
Guido van Rossumcc0ade81998-10-19 02:26:16 +000039
Guido van Rossum504b0bf1999-01-02 21:28:54 +000040#$ event <<plain-newline-and-indent>>
41#$ win <Control-j>
42#$ unix <Control-j>
43
44#$ event <<beginning-of-line>>
45#$ win <Control-a>
46#$ win <Home>
47#$ unix <Control-a>
48#$ unix <Home>
49
50#$ event <<history-next>>
51#$ win <Alt-n>
52#$ unix <Alt-n>
53
54#$ event <<history-previous>>
55#$ win <Alt-p>
56#$ unix <Alt-p>
57
58#$ event <<interrupt-execution>>
59#$ win <Control-c>
60#$ unix <Control-c>
61
62#$ event <<end-of-file>>
63#$ win <Control-d>
64#$ unix <Control-d>
65
66#$ event <<open-stack-viewer>>
67
68#$ event <<toggle-debugger>>
69
70
71class PyShellEditorWindow(EditorWindow):
72
73 # Regular text edit window when a shell is present
74 # XXX ought to merge with regular editor window
75
76 def __init__(self, *args):
77 apply(EditorWindow.__init__, (self,) + args)
78 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
79 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
80
81 rmenu_specs = [
82 ("Set breakpoint here", "<<set-breakpoint-here>>"),
83 ]
84
85 def set_breakpoint_here(self, event=None):
Guido van Rossumcc0ade81998-10-19 02:26:16 +000086 if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
87 self.text.bell()
88 return
89 self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
Guido van Rossum5af7a721998-10-12 23:59:27 +000090
91
92class PyShellFileList(FileList):
Guido van Rossum504b0bf1999-01-02 21:28:54 +000093
94 # File list when a shell is present
95
Guido van Rossum5af7a721998-10-12 23:59:27 +000096 EditorWindow = PyShellEditorWindow
Guido van Rossum504b0bf1999-01-02 21:28:54 +000097
Guido van Rossum5af7a721998-10-12 23:59:27 +000098 pyshell = None
99
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000100 def open_shell(self, event=None):
Guido van Rossum5af7a721998-10-12 23:59:27 +0000101 if self.pyshell:
102 self.pyshell.wakeup()
103 else:
104 self.pyshell = PyShell(self)
105 self.pyshell.begin()
106 return self.pyshell
107
108
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000109class ModifiedColorDelegator(ColorDelegator):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000110
111 # Colorizer for the shell window itself
112
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000113 def recolorize_main(self):
114 self.tag_remove("TODO", "1.0", "iomark")
115 self.tag_add("SYNC", "1.0", "iomark")
116 ColorDelegator.recolorize_main(self)
117
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000118 tagdefs = ColorDelegator.tagdefs.copy()
Jeremy Hylton6b3edf02000-03-07 17:55:32 +0000119 cconf = idleconf.getsection('Colors')
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000120
121 tagdefs.update({
Jeremy Hyltone81f28b2000-03-03 23:06:45 +0000122 "stdin": cconf.getcolor("stdin"),
123 "stdout": cconf.getcolor("stdout"),
124 "stderr": cconf.getcolor("stderr"),
125 "console": cconf.getcolor("console"),
126 "ERROR": cconf.getcolor("ERROR"),
Tim Peters70c43782001-01-17 08:48:39 +0000127 None: cconf.getcolor("normal"),
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000128 })
129
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000130
Guido van Rossum9de98832000-03-07 18:51:49 +0000131class ModifiedUndoDelegator(UndoDelegator):
132
133 # Forbid insert/delete before the I/O mark
134
135 def insert(self, index, chars, tags=None):
136 try:
137 if self.delegate.compare(index, "<", "iomark"):
138 self.delegate.bell()
139 return
140 except TclError:
141 pass
142 UndoDelegator.insert(self, index, chars, tags)
143
144 def delete(self, index1, index2=None):
145 try:
146 if self.delegate.compare(index1, "<", "iomark"):
147 self.delegate.bell()
148 return
149 except TclError:
150 pass
151 UndoDelegator.delete(self, index1, index2)
152
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000153class ModifiedInterpreter(InteractiveInterpreter):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000154
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000155 def __init__(self, tkconsole):
156 self.tkconsole = tkconsole
Guido van Rossumeeb88071999-04-22 20:49:35 +0000157 locals = sys.modules['__main__'].__dict__
158 InteractiveInterpreter.__init__(self, locals=locals)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000159
160 gid = 0
161
Guido van Rossumeeb88071999-04-22 20:49:35 +0000162 def execsource(self, source):
163 # Like runsource() but assumes complete exec source
164 filename = self.stuffsource(source)
165 self.execfile(filename, source)
166
167 def execfile(self, filename, source=None):
168 # Execute an existing file
169 if source is None:
170 source = open(filename, "r").read()
171 try:
172 code = compile(source, filename, "exec")
173 except (OverflowError, SyntaxError):
174 self.tkconsole.resetoutput()
175 InteractiveInterpreter.showsyntaxerror(self, filename)
176 else:
177 self.runcode(code)
178
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000179 def runsource(self, source):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000180 # Extend base class to stuff the source in the line cache first
181 filename = self.stuffsource(source)
182 self.more = 0
183 return InteractiveInterpreter.runsource(self, source, filename)
184
185 def stuffsource(self, source):
186 # Stuff source in the filename cache
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000187 filename = "<pyshell#%d>" % self.gid
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000188 self.gid = self.gid + 1
189 lines = string.split(source, "\n")
190 linecache.cache[filename] = len(source)+1, 0, lines, filename
Guido van Rossumeeb88071999-04-22 20:49:35 +0000191 return filename
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000192
193 def showsyntaxerror(self, filename=None):
194 # Extend base class to color the offending position
195 # (instead of printing it and pointing at it with a caret)
196 text = self.tkconsole.text
197 stuff = self.unpackerror()
198 if not stuff:
199 self.tkconsole.resetoutput()
200 InteractiveInterpreter.showsyntaxerror(self, filename)
201 return
202 msg, lineno, offset, line = stuff
203 if lineno == 1:
204 pos = "iomark + %d chars" % (offset-1)
205 else:
206 pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
207 offset-1)
208 text.tag_add("ERROR", pos)
209 text.see(pos)
210 char = text.get(pos)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000211 if char and char in string.letters + string.digits + "_":
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000212 text.tag_add("ERROR", pos + " wordstart", pos)
213 self.tkconsole.resetoutput()
214 self.write("SyntaxError: %s\n" % str(msg))
215
216 def unpackerror(self):
217 type, value, tb = sys.exc_info()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000218 ok = type is SyntaxError
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000219 if ok:
220 try:
221 msg, (dummy_filename, lineno, offset, line) = value
222 except:
223 ok = 0
224 if ok:
225 return msg, lineno, offset, line
226 else:
227 return None
228
229 def showtraceback(self):
230 # Extend base class method to reset output properly
231 text = self.tkconsole.text
232 self.tkconsole.resetoutput()
Guido van Rossum19563521998-10-13 16:32:05 +0000233 self.checklinecache()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000234 InteractiveInterpreter.showtraceback(self)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000235
Guido van Rossum19563521998-10-13 16:32:05 +0000236 def checklinecache(self):
237 c = linecache.cache
238 for key in c.keys():
239 if key[:1] + key[-1:] != "<>":
240 del c[key]
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000241
Guido van Rossum35f75421998-10-13 23:51:13 +0000242 debugger = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000243
Guido van Rossum35f75421998-10-13 23:51:13 +0000244 def setdebugger(self, debugger):
245 self.debugger = debugger
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000246
Guido van Rossum35f75421998-10-13 23:51:13 +0000247 def getdebugger(self):
248 return self.debugger
249
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000250 def runcode(self, code):
251 # Override base class method
Guido van Rossum35f75421998-10-13 23:51:13 +0000252 debugger = self.debugger
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000253 try:
254 self.tkconsole.beginexecuting()
255 try:
Guido van Rossum35f75421998-10-13 23:51:13 +0000256 if debugger:
257 debugger.run(code, self.locals)
258 else:
259 exec code in self.locals
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000260 except SystemExit:
261 if tkMessageBox.askyesno(
262 "Exit?",
263 "Do you want to exit altogether?",
264 default="yes",
265 master=self.tkconsole.text):
266 raise
267 else:
268 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000269 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000270 self.tkconsole.open_stack_viewer()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000271 except:
272 self.showtraceback()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000273 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
Guido van Rossum38df3c31999-01-08 15:31:07 +0000274 self.tkconsole.open_stack_viewer()
275
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000276 finally:
277 self.tkconsole.endexecuting()
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000278
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000279 def write(self, s):
280 # Override base class write
281 self.tkconsole.console.write(s)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000282
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000283
284class PyShell(OutputWindow):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000285
Guido van Rossumeeb88071999-04-22 20:49:35 +0000286 shell_title = "Python Shell"
287
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000288 # Override classes
289 ColorDelegator = ModifiedColorDelegator
Guido van Rossum9de98832000-03-07 18:51:49 +0000290 UndoDelegator = ModifiedUndoDelegator
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000291
Guido van Rossum5af7a721998-10-12 23:59:27 +0000292 # Override menu bar specs
293 menu_specs = PyShellEditorWindow.menu_specs[:]
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000294 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
295
Guido van Rossumcc0ade81998-10-19 02:26:16 +0000296 # New classes
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000297 from IdleHistory import History
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000298
299 def __init__(self, flist=None):
300 self.interp = ModifiedInterpreter(self)
301 if flist is None:
302 root = Tk()
303 fixwordbreaks(root)
304 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000305 flist = PyShellFileList(root)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000306
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000307 OutputWindow.__init__(self, flist, None, None)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000308
309 import __builtin__
310 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
311
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000312 self.auto = self.extensions["AutoIndent"] # Required extension
Guido van Rossumbbaba851999-06-01 19:55:34 +0000313 self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000314
315 text = self.text
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000316 text.configure(wrap="char")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000317 text.bind("<<newline-and-indent>>", self.enter_callback)
318 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
319 text.bind("<<interrupt-execution>>", self.cancel_callback)
320 text.bind("<<beginning-of-line>>", self.home_callback)
321 text.bind("<<end-of-file>>", self.eof_callback)
Guido van Rossum5af7a721998-10-12 23:59:27 +0000322 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Guido van Rossum35f75421998-10-13 23:51:13 +0000323 text.bind("<<toggle-debugger>>", self.toggle_debugger)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000324 text.bind("<<open-python-shell>>", self.flist.open_shell)
Guido van Rossum38df3c31999-01-08 15:31:07 +0000325 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000326
Guido van Rossumeeb88071999-04-22 20:49:35 +0000327 self.save_stdout = sys.stdout
328 self.save_stderr = sys.stderr
329 self.save_stdin = sys.stdin
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000330 sys.stdout = PseudoFile(self, "stdout")
Guido van Rossum3f08d401998-10-13 15:21:41 +0000331 sys.stderr = PseudoFile(self, "stderr")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000332 sys.stdin = self
333 self.console = PseudoFile(self, "console")
334
335 self.history = self.History(self.text)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000336
337 reading = 0
338 executing = 0
339 canceled = 0
340 endoffile = 0
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000341
Guido van Rossum35f75421998-10-13 23:51:13 +0000342 def toggle_debugger(self, event=None):
343 if self.executing:
344 tkMessageBox.showerror("Don't debug now",
345 "You can only toggle the debugger when idle",
346 master=self.text)
Guido van Rossum07ec8961999-01-28 22:02:47 +0000347 self.set_debugger_indicator()
Guido van Rossum35f75421998-10-13 23:51:13 +0000348 return "break"
Guido van Rossum35e55da1998-10-14 03:43:05 +0000349 else:
Guido van Rossum07ec8961999-01-28 22:02:47 +0000350 db = self.interp.getdebugger()
351 if db:
352 self.close_debugger()
353 else:
354 self.open_debugger()
Guido van Rossumeeb88071999-04-22 20:49:35 +0000355
Guido van Rossum07ec8961999-01-28 22:02:47 +0000356 def set_debugger_indicator(self):
357 db = self.interp.getdebugger()
358 self.setvar("<<toggle-debugger>>", not not db)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000359
Guido van Rossum38df3c31999-01-08 15:31:07 +0000360 def toggle_jit_stack_viewer( self, event=None):
Guido van Rossum07ec8961999-01-28 22:02:47 +0000361 pass # All we need is the variable
Guido van Rossum38df3c31999-01-08 15:31:07 +0000362
Guido van Rossum35e55da1998-10-14 03:43:05 +0000363 def close_debugger(self):
364 db = self.interp.getdebugger()
365 if db:
366 self.interp.setdebugger(None)
Guido van Rossum35f75421998-10-13 23:51:13 +0000367 db.close()
368 self.resetoutput()
369 self.console.write("[DEBUG OFF]\n")
370 sys.ps1 = ">>> "
371 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000372 self.set_debugger_indicator()
Guido van Rossum35e55da1998-10-14 03:43:05 +0000373
374 def open_debugger(self):
375 import Debugger
376 self.interp.setdebugger(Debugger.Debugger(self))
Guido van Rossumadfe7731998-10-16 21:09:35 +0000377 sys.ps1 = "[DEBUG ON]\n>>> "
Guido van Rossum35e55da1998-10-14 03:43:05 +0000378 self.showprompt()
Guido van Rossum07ec8961999-01-28 22:02:47 +0000379 self.set_debugger_indicator()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000380
381 def beginexecuting(self):
382 # Helper for ModifiedInterpreter
383 self.resetoutput()
384 self.executing = 1
Guido van Rossumfed9b911999-06-25 16:09:27 +0000385 ##self._cancel_check = self.cancel_check
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000386 ##sys.settrace(self._cancel_check)
387
388 def endexecuting(self):
389 # Helper for ModifiedInterpreter
Guido van Rossumfed9b911999-06-25 16:09:27 +0000390 ##sys.settrace(None)
391 ##self._cancel_check = None
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000392 self.executing = 0
393 self.canceled = 0
394
395 def close(self):
396 # Extend base class method
397 if self.executing:
398 # XXX Need to ask a question here
399 if not tkMessageBox.askokcancel(
Guido van Rossum07ec8961999-01-28 22:02:47 +0000400 "Kill?",
401 "The program is still running; do you want to kill it?",
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000402 default="ok",
403 master=self.text):
404 return "cancel"
405 self.canceled = 1
406 if self.reading:
407 self.top.quit()
408 return "cancel"
Guido van Rossumfed9b911999-06-25 16:09:27 +0000409 return PyShellEditorWindow.close(self)
410
411 def _close(self):
Guido van Rossum16e0bab1999-06-25 17:26:34 +0000412 self.close_debugger()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000413 # Restore std streams
414 sys.stdout = self.save_stdout
415 sys.stderr = self.save_stderr
416 sys.stdin = self.save_stdin
417 # Break cycles
418 self.interp = None
419 self.console = None
420 self.auto = None
421 self.flist.pyshell = None
422 self.history = None
423 OutputWindow._close(self) # Really EditorWindow._close
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000424
425 def ispythonsource(self, filename):
426 # Override this so EditorWindow never removes the colorizer
427 return 1
428
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000429 def short_title(self):
Guido van Rossumeeb88071999-04-22 20:49:35 +0000430 return self.shell_title
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000431
Guido van Rossumfa6013c2000-09-05 13:51:14 +0000432 COPYRIGHT = \
433 'Type "copyright", "credits" or "license" for more information.'
434
Guido van Rossum5af7a721998-10-12 23:59:27 +0000435 def begin(self):
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000436 self.resetoutput()
Guido van Rossum26c2cb41999-04-26 22:20:38 +0000437 self.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" %
Guido van Rossumfa6013c2000-09-05 13:51:14 +0000438 (sys.version, sys.platform, self.COPYRIGHT,
Guido van Rossum27f550c1999-04-22 20:56:23 +0000439 idlever.IDLE_VERSION))
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000440 try:
441 sys.ps1
442 except AttributeError:
443 sys.ps1 = ">>> "
444 self.showprompt()
445 import Tkinter
446 Tkinter._default_root = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000447
Guido van Rossum5af7a721998-10-12 23:59:27 +0000448 def interact(self):
449 self.begin()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000450 self.top.mainloop()
451
452 def readline(self):
453 save = self.reading
454 try:
455 self.reading = 1
456 self.top.mainloop()
457 finally:
458 self.reading = save
459 line = self.text.get("iomark", "end-1c")
460 self.resetoutput()
461 if self.canceled:
462 self.canceled = 0
463 raise KeyboardInterrupt
464 if self.endoffile:
465 self.endoffile = 0
466 return ""
467 return line
468
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000469 def isatty(self):
470 return 1
471
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000472 def cancel_callback(self, event):
473 try:
474 if self.text.compare("sel.first", "!=", "sel.last"):
475 return # Active selection -- always use default binding
476 except:
477 pass
478 if not (self.executing or self.reading):
479 self.resetoutput()
480 self.write("KeyboardInterrupt\n")
481 self.showprompt()
482 return "break"
483 self.endoffile = 0
484 self.canceled = 1
485 if self.reading:
486 self.top.quit()
487 return "break"
488
489 def eof_callback(self, event):
490 if self.executing and not self.reading:
491 return # Let the default binding (delete next char) take over
492 if not (self.text.compare("iomark", "==", "insert") and
493 self.text.compare("insert", "==", "end-1c")):
494 return # Let the default binding (delete next char) take over
495 if not self.executing:
496## if not tkMessageBox.askokcancel(
497## "Exit?",
498## "Are you sure you want to exit?",
499## default="ok", master=self.text):
500## return "break"
501 self.resetoutput()
502 self.close()
503 else:
504 self.canceled = 0
505 self.endoffile = 1
506 self.top.quit()
507 return "break"
508
509 def home_callback(self, event):
510 if event.state != 0 and event.keysym == "Home":
511 return # <Modifier-Home>; fall back to class binding
512 if self.text.compare("iomark", "<=", "insert") and \
513 self.text.compare("insert linestart", "<=", "iomark"):
514 self.text.mark_set("insert", "iomark")
515 self.text.tag_remove("sel", "1.0", "end")
516 self.text.see("insert")
517 return "break"
518
519 def linefeed_callback(self, event):
520 # Insert a linefeed without entering anything (still autoindented)
521 if self.reading:
522 self.text.insert("insert", "\n")
523 self.text.see("insert")
524 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000525 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000526 return "break"
527
528 def enter_callback(self, event):
529 if self.executing and not self.reading:
530 return # Let the default binding (insert '\n') take over
531 # If some text is selected, recall the selection
Guido van Rossum4650df91998-10-13 14:41:27 +0000532 # (but only if this before the I/O mark)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000533 try:
534 sel = self.text.get("sel.first", "sel.last")
535 if sel:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000536 if self.text.compare("sel.last", "<=", "iomark"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000537 self.recall(sel)
538 return "break"
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000539 except:
540 pass
541 # If we're strictly before the line containing iomark, recall
542 # the current line, less a leading prompt, less leading or
543 # trailing whitespace
544 if self.text.compare("insert", "<", "iomark linestart"):
Guido van Rossum4650df91998-10-13 14:41:27 +0000545 # Check if there's a relevant stdin range -- if so, use it
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000546 prev = self.text.tag_prevrange("stdin", "insert")
547 if prev and self.text.compare("insert", "<", prev[1]):
548 self.recall(self.text.get(prev[0], prev[1]))
549 return "break"
550 next = self.text.tag_nextrange("stdin", "insert")
551 if next and self.text.compare("insert lineend", ">=", next[0]):
552 self.recall(self.text.get(next[0], next[1]))
553 return "break"
554 # No stdin mark -- just get the current line
555 self.recall(self.text.get("insert linestart", "insert lineend"))
556 return "break"
Guido van Rossumfd6315e2000-03-07 15:05:50 +0000557 # If we're in the current input and there's only whitespace
558 # beyond the cursor, erase that whitespace first
559 s = self.text.get("insert", "end-1c")
560 if s and not string.strip(s):
561 self.text.delete("insert", "end-1c")
Guido van Rossum4650df91998-10-13 14:41:27 +0000562 # If we're in the current input before its last line,
563 # insert a newline right at the insert point
564 if self.text.compare("insert", "<", "end-1c linestart"):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000565 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000566 return "break"
Guido van Rossum4650df91998-10-13 14:41:27 +0000567 # We're in the last line; append a newline and submit it
568 self.text.mark_set("insert", "end-1c")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000569 if self.reading:
570 self.text.insert("insert", "\n")
571 self.text.see("insert")
572 else:
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000573 self.auto.auto_indent(event)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000574 self.text.tag_add("stdin", "iomark", "end-1c")
575 self.text.update_idletasks()
576 if self.reading:
577 self.top.quit() # Break out of recursive mainloop() in raw_input()
578 else:
579 self.runit()
580 return "break"
581
582 def recall(self, s):
583 if self.history:
584 self.history.recall(s)
585
586 def runit(self):
587 line = self.text.get("iomark", "end-1c")
588 # Strip off last newline and surrounding whitespace.
589 # (To allow you to hit return twice to end a statement.)
590 i = len(line)
591 while i > 0 and line[i-1] in " \t":
592 i = i-1
593 if i > 0 and line[i-1] == "\n":
594 i = i-1
595 while i > 0 and line[i-1] in " \t":
596 i = i-1
597 line = line[:i]
598 more = self.interp.runsource(line)
599 if not more:
600 self.showprompt()
601
602 def cancel_check(self, frame, what, args,
603 dooneevent=tkinter.dooneevent,
604 dontwait=tkinter.DONT_WAIT):
605 # Hack -- use the debugger hooks to be able to handle events
606 # and interrupt execution at any time.
607 # This slows execution down quite a bit, so you may want to
608 # disable this (by not calling settrace() in runcode() above)
609 # for full-bore (uninterruptable) speed.
610 # XXX This should become a user option.
611 if self.canceled:
612 return
613 dooneevent(dontwait)
614 if self.canceled:
615 self.canceled = 0
616 raise KeyboardInterrupt
617 return self._cancel_check
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000618
Guido van Rossum5af7a721998-10-12 23:59:27 +0000619 def open_stack_viewer(self, event=None):
620 try:
621 sys.last_traceback
622 except:
623 tkMessageBox.showerror("No stack trace",
624 "There is no stack trace yet.\n"
625 "(sys.last_traceback is not defined)",
626 master=self.text)
627 return
Guido van Rossum80d132d1998-10-16 16:12:11 +0000628 from StackViewer import StackBrowser
629 sv = StackBrowser(self.root, self.flist)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000630
631 def showprompt(self):
632 self.resetoutput()
633 try:
634 s = str(sys.ps1)
635 except:
636 s = ""
637 self.console.write(s)
638 self.text.mark_set("insert", "end-1c")
639
640 def resetoutput(self):
641 source = self.text.get("iomark", "end-1c")
642 if self.history:
643 self.history.history_store(source)
644 if self.text.get("end-2c") != "\n":
645 self.text.insert("end-1c", "\n")
646 self.text.mark_set("iomark", "end-1c")
647 sys.stdout.softspace = 0
648
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000649 def write(self, s, tags=()):
650 self.text.mark_gravity("iomark", "right")
651 OutputWindow.write(self, s, tags, "iomark")
652 self.text.mark_gravity("iomark", "left")
653 if self.canceled:
654 self.canceled = 0
655 raise KeyboardInterrupt
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000656
657class PseudoFile:
658
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000659 def __init__(self, shell, tags):
660 self.shell = shell
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000661 self.tags = tags
662
663 def write(self, s):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000664 self.shell.write(s, self.tags)
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000665
666 def writelines(self, l):
667 map(self.write, l)
668
Guido van Rossum825df2a1999-03-29 14:52:28 +0000669 def flush(self):
670 pass
671
Guido van Rossumb6f8cf11999-05-21 04:46:17 +0000672 def isatty(self):
673 return 1
674
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000675
Guido van Rossumeeb88071999-04-22 20:49:35 +0000676usage_msg = """\
677usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
678
679-c command run this command
680-d enable debugger
681-e edit mode; arguments are files to be edited
Guido van Rossum27f550c1999-04-22 20:56:23 +0000682-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
Guido van Rossumeeb88071999-04-22 20:49:35 +0000683-t title set title of shell window
684
685When neither -c nor -e is used, and there are arguments, and the first
686argument is not '-', the first argument is run as a script. Remaining
687arguments are arguments to the script or to the command run by -c.
688"""
689
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000690def main():
Guido van Rossumeeb88071999-04-22 20:49:35 +0000691 cmd = None
692 edit = 0
Guido van Rossum80d132d1998-10-16 16:12:11 +0000693 debug = 0
Guido van Rossumeeb88071999-04-22 20:49:35 +0000694 startup = 0
695
Guido van Rossum80d132d1998-10-16 16:12:11 +0000696 try:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000697 opts, args = getopt.getopt(sys.argv[1:], "c:deist:")
Guido van Rossum80d132d1998-10-16 16:12:11 +0000698 except getopt.error, msg:
699 sys.stderr.write("Error: %s\n" % str(msg))
Guido van Rossumeeb88071999-04-22 20:49:35 +0000700 sys.stderr.write(usage_msg)
Guido van Rossum80d132d1998-10-16 16:12:11 +0000701 sys.exit(2)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000702
Guido van Rossum80d132d1998-10-16 16:12:11 +0000703 for o, a in opts:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000704 if o == '-c':
705 cmd = a
706 if o == '-d':
Guido van Rossum80d132d1998-10-16 16:12:11 +0000707 debug = 1
Guido van Rossumeeb88071999-04-22 20:49:35 +0000708 if o == '-e':
709 edit = 1
710 if o == '-s':
711 startup = 1
712 if o == '-t':
713 PyShell.shell_title = a
714
Guido van Rossumeeb88071999-04-22 20:49:35 +0000715 for i in range(len(sys.path)):
716 sys.path[i] = os.path.abspath(sys.path[i])
717
718 pathx = []
719 if edit:
720 for filename in args:
721 pathx.append(os.path.dirname(filename))
722 elif args and args[0] != "-":
723 pathx.append(os.path.dirname(args[0]))
724 else:
725 pathx.append(os.curdir)
726 for dir in pathx:
727 dir = os.path.abspath(dir)
728 if not dir in sys.path:
729 sys.path.insert(0, dir)
730
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000731 global flist, root
Fred Drake10515b62000-09-15 04:32:56 +0000732 root = Tk(className="Idle")
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000733 fixwordbreaks(root)
734 root.withdraw()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000735 flist = PyShellFileList(root)
Guido van Rossumeeb88071999-04-22 20:49:35 +0000736
737 if edit:
738 for filename in args:
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000739 flist.open(filename)
Fred Drake10515b62000-09-15 04:32:56 +0000740 else:
741 if cmd:
742 sys.argv = ["-c"] + args
743 else:
744 sys.argv = args or [""]
745
Guido van Rossumeeb88071999-04-22 20:49:35 +0000746
747 shell = PyShell(flist)
748 interp = shell.interp
749 flist.pyshell = shell
750
751 if startup:
752 filename = os.environ.get("IDLESTARTUP") or \
753 os.environ.get("PYTHONSTARTUP")
754 if filename and os.path.isfile(filename):
755 interp.execfile(filename)
756
Guido van Rossum80d132d1998-10-16 16:12:11 +0000757 if debug:
Guido van Rossumeeb88071999-04-22 20:49:35 +0000758 shell.open_debugger()
759 if cmd:
760 interp.execsource(cmd)
761 elif not edit and args and args[0] != "-":
762 interp.execfile(args[0])
763
764 shell.begin()
Guido van Rossum5af7a721998-10-12 23:59:27 +0000765 root.mainloop()
Guido van Rossumfed9b911999-06-25 16:09:27 +0000766 root.destroy()
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000767
Guido van Rossumeeb88071999-04-22 20:49:35 +0000768
Guido van Rossum3b4ca0d1998-10-10 18:48:31 +0000769if __name__ == "__main__":
770 main()