Mercurial > cpython-lru_cache-weakref
annotate Lib/idlelib/PyShell.py @ 18586:fe44428f9774 legacy-trunk
py-cvs-2001_07_13 (Rev 1.34) merge
"Amazing. A very subtle change in policy in descr-branch actually
found a bug here. Here's the deal: Class PyShell derives from class
OutputWindow. Method PyShell.close()
wants to invoke its parent method, but because PyShell long ago was
inherited from class PyShellEditorWindow, it invokes
PyShelEditorWindow.close(self). Now, class PyShellEditorWindow itself
derives from class OutputWindow, and inherits the close() method from
there without overriding it. Under the old rules,
PyShellEditorWindow.close would return an unbound method restricted to
the class that defined the implementation of close(), which was
OutputWindow.close. Under the new rules, the unbound method is
restricted to the class whose method was requested, that is
PyShellEditorWindow, and this was correctly trapped as an error." --GvR
| author | Kurt B. Kaiser <kbk@shore.net> |
|---|---|
| date | Sat, 14 Jul 2001 05:10:34 +0000 |
| parents | 12e7ad108229 |
| children | 6238a222b7cd |
| rev | line source |
|---|---|
| 13975 | 1 #! /usr/bin/env python |
| 2 | |
| 3 # changes by dscherer@cmu.edu | |
| 4 | |
| 5 # the main() function has been replaced by a whole class, in order to | |
| 6 # address the constraint that only one process can sit on the port | |
| 7 # hard-coded into the loader. | |
| 8 | |
| 9 # It attempts to load the RPC protocol server and publish itself. If | |
| 10 # that fails, it assumes that some other copy of IDLE is already running | |
| 11 # on the port and attempts to contact it. It then uses the RPC mechanism | |
| 12 # to ask that copy to do whatever it was instructed (via the command | |
| 13 # line) to do. (Think netscape -remote). The handling of command line | |
| 14 # arguments for remotes is still very incomplete. | |
| 15 | |
| 16 # default behavior (no command line options) is to NOT start the Python | |
| 17 # Shell. If files are specified, they are opened, otherwise a single | |
| 18 # blank editor window opens. | |
| 19 | |
| 20 # If any command line -options are specified, a shell does appear. This | |
| 21 # is necessary to make the current semantics of the options make sense. | |
| 22 | |
| 23 import os | |
| 24 import spawn | |
| 25 import sys | |
| 26 import string | |
| 27 import getopt | |
| 28 import re | |
| 29 import protocol | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
30 import warnings |
| 13975 | 31 |
| 32 import linecache | |
| 33 from code import InteractiveInterpreter | |
| 34 | |
| 35 from Tkinter import * | |
| 36 import tkMessageBox | |
| 37 | |
| 38 from EditorWindow import EditorWindow, fixwordbreaks | |
| 39 from FileList import FileList | |
| 40 from ColorDelegator import ColorDelegator | |
| 41 from UndoDelegator import UndoDelegator | |
| 42 from OutputWindow import OutputWindow, OnDemandOutputWindow | |
| 43 from IdleConf import idleconf | |
| 44 import idlever | |
| 45 | |
| 46 # We need to patch linecache.checkcache, because we don't want it | |
| 47 # to throw away our <pyshell#...> entries. | |
| 48 # Rather than repeating its code here, we save those entries, | |
| 49 # then call the original function, and then restore the saved entries. | |
| 50 def linecache_checkcache(orig_checkcache=linecache.checkcache): | |
| 51 cache = linecache.cache | |
| 52 save = {} | |
| 53 for filename in cache.keys(): | |
| 54 if filename[:1] + filename[-1:] == '<>': | |
| 55 save[filename] = cache[filename] | |
| 56 orig_checkcache() | |
| 57 cache.update(save) | |
| 58 linecache.checkcache = linecache_checkcache | |
| 59 | |
| 60 | |
| 61 # Note: <<newline-and-indent>> event is defined in AutoIndent.py | |
| 62 | |
| 63 #$ event <<plain-newline-and-indent>> | |
| 64 #$ win <Control-j> | |
| 65 #$ unix <Control-j> | |
| 66 | |
| 67 #$ event <<beginning-of-line>> | |
| 68 #$ win <Control-a> | |
| 69 #$ win <Home> | |
| 70 #$ unix <Control-a> | |
| 71 #$ unix <Home> | |
| 72 | |
| 73 #$ event <<history-next>> | |
| 74 #$ win <Alt-n> | |
| 75 #$ unix <Alt-n> | |
| 76 | |
| 77 #$ event <<history-previous>> | |
| 78 #$ win <Alt-p> | |
| 79 #$ unix <Alt-p> | |
| 80 | |
| 81 #$ event <<interrupt-execution>> | |
| 82 #$ win <Control-c> | |
| 83 #$ unix <Control-c> | |
| 84 | |
| 85 #$ event <<end-of-file>> | |
| 86 #$ win <Control-d> | |
| 87 #$ unix <Control-d> | |
| 88 | |
| 89 #$ event <<open-stack-viewer>> | |
| 90 | |
| 91 #$ event <<toggle-debugger>> | |
| 92 | |
| 93 | |
| 94 class PyShellEditorWindow(EditorWindow): | |
| 95 | |
| 96 # Regular text edit window when a shell is present | |
| 97 # XXX ought to merge with regular editor window | |
| 98 | |
| 99 def __init__(self, *args): | |
| 100 apply(EditorWindow.__init__, (self,) + args) | |
| 101 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here) | |
| 102 self.text.bind("<<open-python-shell>>", self.flist.open_shell) | |
| 103 | |
| 104 rmenu_specs = [ | |
| 105 ("Set breakpoint here", "<<set-breakpoint-here>>"), | |
| 106 ] | |
| 107 | |
| 108 def set_breakpoint_here(self, event=None): | |
| 109 if not self.flist.pyshell or not self.flist.pyshell.interp.debugger: | |
| 110 self.text.bell() | |
| 111 return | |
| 112 self.flist.pyshell.interp.debugger.set_breakpoint_here(self) | |
| 113 | |
| 114 | |
| 115 class PyShellFileList(FileList): | |
| 116 | |
| 117 # File list when a shell is present | |
| 118 | |
| 119 EditorWindow = PyShellEditorWindow | |
| 120 | |
| 121 pyshell = None | |
| 122 | |
| 123 def open_shell(self, event=None): | |
| 124 if self.pyshell: | |
| 125 self.pyshell.wakeup() | |
| 126 else: | |
| 127 self.pyshell = PyShell(self) | |
| 128 self.pyshell.begin() | |
| 129 return self.pyshell | |
| 130 | |
| 131 | |
| 132 class ModifiedColorDelegator(ColorDelegator): | |
| 133 | |
| 134 # Colorizer for the shell window itself | |
| 135 | |
| 136 def recolorize_main(self): | |
| 137 self.tag_remove("TODO", "1.0", "iomark") | |
| 138 self.tag_add("SYNC", "1.0", "iomark") | |
| 139 ColorDelegator.recolorize_main(self) | |
| 140 | |
| 141 tagdefs = ColorDelegator.tagdefs.copy() | |
| 142 cconf = idleconf.getsection('Colors') | |
| 143 | |
| 144 tagdefs.update({ | |
| 145 "stdin": cconf.getcolor("stdin"), | |
| 146 "stdout": cconf.getcolor("stdout"), | |
| 147 "stderr": cconf.getcolor("stderr"), | |
| 148 "console": cconf.getcolor("console"), | |
| 149 "ERROR": cconf.getcolor("ERROR"), | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
150 None: cconf.getcolor("normal"), |
| 13975 | 151 }) |
| 152 | |
| 153 | |
| 154 class ModifiedUndoDelegator(UndoDelegator): | |
| 155 | |
| 156 # Forbid insert/delete before the I/O mark | |
| 157 | |
| 158 def insert(self, index, chars, tags=None): | |
| 159 try: | |
| 160 if self.delegate.compare(index, "<", "iomark"): | |
| 161 self.delegate.bell() | |
| 162 return | |
| 163 except TclError: | |
| 164 pass | |
| 165 UndoDelegator.insert(self, index, chars, tags) | |
| 166 | |
| 167 def delete(self, index1, index2=None): | |
| 168 try: | |
| 169 if self.delegate.compare(index1, "<", "iomark"): | |
| 170 self.delegate.bell() | |
| 171 return | |
| 172 except TclError: | |
| 173 pass | |
| 174 UndoDelegator.delete(self, index1, index2) | |
| 175 | |
| 176 class ModifiedInterpreter(InteractiveInterpreter): | |
| 177 | |
| 178 def __init__(self, tkconsole): | |
| 179 self.tkconsole = tkconsole | |
| 180 locals = sys.modules['__main__'].__dict__ | |
| 181 InteractiveInterpreter.__init__(self, locals=locals) | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
182 self.save_warnings_filters = None |
| 13975 | 183 |
| 184 gid = 0 | |
| 185 | |
| 186 def execsource(self, source): | |
| 187 # Like runsource() but assumes complete exec source | |
| 188 filename = self.stuffsource(source) | |
| 189 self.execfile(filename, source) | |
| 190 | |
| 191 def execfile(self, filename, source=None): | |
| 192 # Execute an existing file | |
| 193 if source is None: | |
| 194 source = open(filename, "r").read() | |
| 195 try: | |
| 196 code = compile(source, filename, "exec") | |
| 197 except (OverflowError, SyntaxError): | |
| 198 self.tkconsole.resetoutput() | |
| 199 InteractiveInterpreter.showsyntaxerror(self, filename) | |
| 200 else: | |
| 201 self.runcode(code) | |
| 202 | |
| 203 def runsource(self, source): | |
| 204 # Extend base class to stuff the source in the line cache first | |
| 205 filename = self.stuffsource(source) | |
| 206 self.more = 0 | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
207 self.save_warnings_filters = warnings.filters[:] |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
208 warnings.filterwarnings(action="error", category=SyntaxWarning) |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
209 try: |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
210 return InteractiveInterpreter.runsource(self, source, filename) |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
211 finally: |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
212 if self.save_warnings_filters is not None: |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
213 warnings.filters[:] = self.save_warnings_filters |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
214 self.save_warnings_filters = None |
| 13975 | 215 |
| 216 def stuffsource(self, source): | |
| 217 # Stuff source in the filename cache | |
| 218 filename = "<pyshell#%d>" % self.gid | |
| 219 self.gid = self.gid + 1 | |
| 220 lines = string.split(source, "\n") | |
| 221 linecache.cache[filename] = len(source)+1, 0, lines, filename | |
| 222 return filename | |
| 223 | |
| 224 def showsyntaxerror(self, filename=None): | |
| 225 # Extend base class to color the offending position | |
| 226 # (instead of printing it and pointing at it with a caret) | |
| 227 text = self.tkconsole.text | |
| 228 stuff = self.unpackerror() | |
| 229 if not stuff: | |
| 230 self.tkconsole.resetoutput() | |
| 231 InteractiveInterpreter.showsyntaxerror(self, filename) | |
| 232 return | |
| 233 msg, lineno, offset, line = stuff | |
| 234 if lineno == 1: | |
| 235 pos = "iomark + %d chars" % (offset-1) | |
| 236 else: | |
| 237 pos = "iomark linestart + %d lines + %d chars" % (lineno-1, | |
| 238 offset-1) | |
| 239 text.tag_add("ERROR", pos) | |
| 240 text.see(pos) | |
| 241 char = text.get(pos) | |
| 242 if char and char in string.letters + string.digits + "_": | |
| 243 text.tag_add("ERROR", pos + " wordstart", pos) | |
| 244 self.tkconsole.resetoutput() | |
| 245 self.write("SyntaxError: %s\n" % str(msg)) | |
| 246 | |
| 247 def unpackerror(self): | |
| 248 type, value, tb = sys.exc_info() | |
| 249 ok = type is SyntaxError | |
| 250 if ok: | |
| 251 try: | |
| 252 msg, (dummy_filename, lineno, offset, line) = value | |
| 253 except: | |
| 254 ok = 0 | |
| 255 if ok: | |
| 256 return msg, lineno, offset, line | |
| 257 else: | |
| 258 return None | |
| 259 | |
| 260 def showtraceback(self): | |
| 261 # Extend base class method to reset output properly | |
| 262 text = self.tkconsole.text | |
| 263 self.tkconsole.resetoutput() | |
| 264 self.checklinecache() | |
| 265 InteractiveInterpreter.showtraceback(self) | |
| 266 | |
| 267 def checklinecache(self): | |
| 268 c = linecache.cache | |
| 269 for key in c.keys(): | |
| 270 if key[:1] + key[-1:] != "<>": | |
| 271 del c[key] | |
| 272 | |
| 273 debugger = None | |
| 274 | |
| 275 def setdebugger(self, debugger): | |
| 276 self.debugger = debugger | |
| 277 | |
| 278 def getdebugger(self): | |
| 279 return self.debugger | |
| 280 | |
| 281 def runcode(self, code): | |
| 282 # Override base class method | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
283 if self.save_warnings_filters is not None: |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
284 warnings.filters[:] = self.save_warnings_filters |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
285 self.save_warnings_filters = None |
| 13975 | 286 debugger = self.debugger |
| 287 try: | |
| 288 self.tkconsole.beginexecuting() | |
| 289 try: | |
| 290 if debugger: | |
| 291 debugger.run(code, self.locals) | |
| 292 else: | |
| 293 exec code in self.locals | |
| 294 except SystemExit: | |
| 295 if tkMessageBox.askyesno( | |
| 296 "Exit?", | |
| 297 "Do you want to exit altogether?", | |
| 298 default="yes", | |
| 299 master=self.tkconsole.text): | |
| 300 raise | |
| 301 else: | |
| 302 self.showtraceback() | |
| 303 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"): | |
| 304 self.tkconsole.open_stack_viewer() | |
| 305 except: | |
| 306 self.showtraceback() | |
| 307 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"): | |
| 308 self.tkconsole.open_stack_viewer() | |
| 309 | |
| 310 finally: | |
| 311 self.tkconsole.endexecuting() | |
| 312 | |
| 313 def write(self, s): | |
| 314 # Override base class write | |
| 315 self.tkconsole.console.write(s) | |
| 316 | |
| 317 | |
| 318 class PyShell(OutputWindow): | |
| 319 | |
| 320 shell_title = "Python Shell" | |
| 321 | |
| 322 # Override classes | |
| 323 ColorDelegator = ModifiedColorDelegator | |
| 324 UndoDelegator = ModifiedUndoDelegator | |
| 325 | |
| 326 # Override menu bar specs | |
| 327 menu_specs = PyShellEditorWindow.menu_specs[:] | |
| 328 menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug")) | |
| 329 | |
| 330 # New classes | |
| 331 from IdleHistory import History | |
| 332 | |
| 333 def __init__(self, flist=None): | |
| 334 self.interp = ModifiedInterpreter(self) | |
| 335 if flist is None: | |
| 336 root = Tk() | |
| 337 fixwordbreaks(root) | |
| 338 root.withdraw() | |
| 339 flist = PyShellFileList(root) | |
| 340 | |
| 341 OutputWindow.__init__(self, flist, None, None) | |
| 342 | |
| 343 import __builtin__ | |
| 344 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D." | |
| 345 | |
| 346 self.auto = self.extensions["AutoIndent"] # Required extension | |
| 347 self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1) | |
| 348 | |
| 349 text = self.text | |
| 350 text.configure(wrap="char") | |
| 351 text.bind("<<newline-and-indent>>", self.enter_callback) | |
| 352 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback) | |
| 353 text.bind("<<interrupt-execution>>", self.cancel_callback) | |
| 354 text.bind("<<beginning-of-line>>", self.home_callback) | |
| 355 text.bind("<<end-of-file>>", self.eof_callback) | |
| 356 text.bind("<<open-stack-viewer>>", self.open_stack_viewer) | |
| 357 text.bind("<<toggle-debugger>>", self.toggle_debugger) | |
| 358 text.bind("<<open-python-shell>>", self.flist.open_shell) | |
| 359 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer) | |
| 360 | |
| 361 self.save_stdout = sys.stdout | |
| 362 self.save_stderr = sys.stderr | |
| 363 self.save_stdin = sys.stdin | |
| 364 sys.stdout = PseudoFile(self, "stdout") | |
| 365 sys.stderr = PseudoFile(self, "stderr") | |
| 366 sys.stdin = self | |
| 367 self.console = PseudoFile(self, "console") | |
| 368 | |
| 369 self.history = self.History(self.text) | |
| 370 | |
| 371 reading = 0 | |
| 372 executing = 0 | |
| 373 canceled = 0 | |
| 374 endoffile = 0 | |
| 375 | |
| 376 def toggle_debugger(self, event=None): | |
| 377 if self.executing: | |
| 378 tkMessageBox.showerror("Don't debug now", | |
| 379 "You can only toggle the debugger when idle", | |
| 380 master=self.text) | |
| 381 self.set_debugger_indicator() | |
| 382 return "break" | |
| 383 else: | |
| 384 db = self.interp.getdebugger() | |
| 385 if db: | |
| 386 self.close_debugger() | |
| 387 else: | |
| 388 self.open_debugger() | |
| 389 | |
| 390 def set_debugger_indicator(self): | |
| 391 db = self.interp.getdebugger() | |
| 392 self.setvar("<<toggle-debugger>>", not not db) | |
| 393 | |
| 394 def toggle_jit_stack_viewer( self, event=None): | |
| 395 pass # All we need is the variable | |
| 396 | |
| 397 def close_debugger(self): | |
| 398 db = self.interp.getdebugger() | |
| 399 if db: | |
| 400 self.interp.setdebugger(None) | |
| 401 db.close() | |
| 402 self.resetoutput() | |
| 403 self.console.write("[DEBUG OFF]\n") | |
| 404 sys.ps1 = ">>> " | |
| 405 self.showprompt() | |
| 406 self.set_debugger_indicator() | |
| 407 | |
| 408 def open_debugger(self): | |
| 409 import Debugger | |
| 410 self.interp.setdebugger(Debugger.Debugger(self)) | |
| 411 sys.ps1 = "[DEBUG ON]\n>>> " | |
| 412 self.showprompt() | |
| 413 self.set_debugger_indicator() | |
| 414 | |
| 415 def beginexecuting(self): | |
| 416 # Helper for ModifiedInterpreter | |
| 417 self.resetoutput() | |
| 418 self.executing = 1 | |
| 419 ##self._cancel_check = self.cancel_check | |
| 420 ##sys.settrace(self._cancel_check) | |
| 421 | |
| 422 def endexecuting(self): | |
| 423 # Helper for ModifiedInterpreter | |
| 424 ##sys.settrace(None) | |
| 425 ##self._cancel_check = None | |
| 426 self.executing = 0 | |
| 427 self.canceled = 0 | |
| 428 | |
| 429 def close(self): | |
| 430 # Extend base class method | |
| 431 if self.executing: | |
| 432 # XXX Need to ask a question here | |
| 433 if not tkMessageBox.askokcancel( | |
| 434 "Kill?", | |
| 435 "The program is still running; do you want to kill it?", | |
| 436 default="ok", | |
| 437 master=self.text): | |
| 438 return "cancel" | |
| 439 self.canceled = 1 | |
| 440 if self.reading: | |
| 441 self.top.quit() | |
| 442 return "cancel" | |
|
18586
fe44428f9774
py-cvs-2001_07_13 (Rev 1.34) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
18560
diff
changeset
|
443 return OutputWindow.close(self) |
| 13975 | 444 |
| 445 def _close(self): | |
| 446 self.close_debugger() | |
| 447 # Restore std streams | |
| 448 sys.stdout = self.save_stdout | |
| 449 sys.stderr = self.save_stderr | |
| 450 sys.stdin = self.save_stdin | |
| 451 # Break cycles | |
| 452 self.interp = None | |
| 453 self.console = None | |
| 454 self.auto = None | |
| 455 self.flist.pyshell = None | |
| 456 self.history = None | |
| 457 OutputWindow._close(self) # Really EditorWindow._close | |
| 458 | |
| 459 def ispythonsource(self, filename): | |
| 460 # Override this so EditorWindow never removes the colorizer | |
| 461 return 1 | |
| 462 | |
| 463 def short_title(self): | |
| 464 return self.shell_title | |
| 465 | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
466 COPYRIGHT = \ |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
467 'Type "copyright", "credits" or "license" for more information.' |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
468 |
| 13975 | 469 def begin(self): |
| 470 self.resetoutput() | |
| 471 self.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" % | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
472 (sys.version, sys.platform, self.COPYRIGHT, |
| 13975 | 473 idlever.IDLE_VERSION)) |
| 474 try: | |
| 475 sys.ps1 | |
| 476 except AttributeError: | |
| 477 sys.ps1 = ">>> " | |
| 478 self.showprompt() | |
| 479 import Tkinter | |
| 480 Tkinter._default_root = None | |
| 481 | |
| 482 def interact(self): | |
| 483 self.begin() | |
| 484 self.top.mainloop() | |
| 485 | |
| 486 def readline(self): | |
| 487 save = self.reading | |
| 488 try: | |
| 489 self.reading = 1 | |
| 490 self.top.mainloop() | |
| 491 finally: | |
| 492 self.reading = save | |
| 493 line = self.text.get("iomark", "end-1c") | |
| 494 self.resetoutput() | |
| 495 if self.canceled: | |
| 496 self.canceled = 0 | |
| 497 raise KeyboardInterrupt | |
| 498 if self.endoffile: | |
| 499 self.endoffile = 0 | |
| 500 return "" | |
| 501 return line | |
| 502 | |
| 503 def isatty(self): | |
| 504 return 1 | |
| 505 | |
| 506 def cancel_callback(self, event): | |
| 507 try: | |
| 508 if self.text.compare("sel.first", "!=", "sel.last"): | |
| 509 return # Active selection -- always use default binding | |
| 510 except: | |
| 511 pass | |
| 512 if not (self.executing or self.reading): | |
| 513 self.resetoutput() | |
| 514 self.write("KeyboardInterrupt\n") | |
| 515 self.showprompt() | |
| 516 return "break" | |
| 517 self.endoffile = 0 | |
| 518 self.canceled = 1 | |
| 519 if self.reading: | |
| 520 self.top.quit() | |
| 521 return "break" | |
| 522 | |
| 523 def eof_callback(self, event): | |
| 524 if self.executing and not self.reading: | |
| 525 return # Let the default binding (delete next char) take over | |
| 526 if not (self.text.compare("iomark", "==", "insert") and | |
| 527 self.text.compare("insert", "==", "end-1c")): | |
| 528 return # Let the default binding (delete next char) take over | |
| 529 if not self.executing: | |
| 530 ## if not tkMessageBox.askokcancel( | |
| 531 ## "Exit?", | |
| 532 ## "Are you sure you want to exit?", | |
| 533 ## default="ok", master=self.text): | |
| 534 ## return "break" | |
| 535 self.resetoutput() | |
| 536 self.close() | |
| 537 else: | |
| 538 self.canceled = 0 | |
| 539 self.endoffile = 1 | |
| 540 self.top.quit() | |
| 541 return "break" | |
| 542 | |
| 543 def home_callback(self, event): | |
| 544 if event.state != 0 and event.keysym == "Home": | |
| 545 return # <Modifier-Home>; fall back to class binding | |
| 546 if self.text.compare("iomark", "<=", "insert") and \ | |
| 547 self.text.compare("insert linestart", "<=", "iomark"): | |
| 548 self.text.mark_set("insert", "iomark") | |
| 549 self.text.tag_remove("sel", "1.0", "end") | |
| 550 self.text.see("insert") | |
| 551 return "break" | |
| 552 | |
| 553 def linefeed_callback(self, event): | |
| 554 # Insert a linefeed without entering anything (still autoindented) | |
| 555 if self.reading: | |
| 556 self.text.insert("insert", "\n") | |
| 557 self.text.see("insert") | |
| 558 else: | |
| 559 self.auto.auto_indent(event) | |
| 560 return "break" | |
| 561 | |
| 562 def enter_callback(self, event): | |
| 563 if self.executing and not self.reading: | |
| 564 return # Let the default binding (insert '\n') take over | |
| 565 # If some text is selected, recall the selection | |
| 566 # (but only if this before the I/O mark) | |
| 567 try: | |
| 568 sel = self.text.get("sel.first", "sel.last") | |
| 569 if sel: | |
| 570 if self.text.compare("sel.last", "<=", "iomark"): | |
| 571 self.recall(sel) | |
| 572 return "break" | |
| 573 except: | |
| 574 pass | |
| 575 # If we're strictly before the line containing iomark, recall | |
| 576 # the current line, less a leading prompt, less leading or | |
| 577 # trailing whitespace | |
| 578 if self.text.compare("insert", "<", "iomark linestart"): | |
| 579 # Check if there's a relevant stdin range -- if so, use it | |
| 580 prev = self.text.tag_prevrange("stdin", "insert") | |
| 581 if prev and self.text.compare("insert", "<", prev[1]): | |
| 582 self.recall(self.text.get(prev[0], prev[1])) | |
| 583 return "break" | |
| 584 next = self.text.tag_nextrange("stdin", "insert") | |
| 585 if next and self.text.compare("insert lineend", ">=", next[0]): | |
| 586 self.recall(self.text.get(next[0], next[1])) | |
| 587 return "break" | |
| 588 # No stdin mark -- just get the current line | |
| 589 self.recall(self.text.get("insert linestart", "insert lineend")) | |
| 590 return "break" | |
| 591 # If we're in the current input and there's only whitespace | |
| 592 # beyond the cursor, erase that whitespace first | |
| 593 s = self.text.get("insert", "end-1c") | |
| 594 if s and not string.strip(s): | |
| 595 self.text.delete("insert", "end-1c") | |
| 596 # If we're in the current input before its last line, | |
| 597 # insert a newline right at the insert point | |
| 598 if self.text.compare("insert", "<", "end-1c linestart"): | |
| 599 self.auto.auto_indent(event) | |
| 600 return "break" | |
| 601 # We're in the last line; append a newline and submit it | |
| 602 self.text.mark_set("insert", "end-1c") | |
| 603 if self.reading: | |
| 604 self.text.insert("insert", "\n") | |
| 605 self.text.see("insert") | |
| 606 else: | |
| 607 self.auto.auto_indent(event) | |
| 608 self.text.tag_add("stdin", "iomark", "end-1c") | |
| 609 self.text.update_idletasks() | |
| 610 if self.reading: | |
| 611 self.top.quit() # Break out of recursive mainloop() in raw_input() | |
| 612 else: | |
| 613 self.runit() | |
| 614 return "break" | |
| 615 | |
| 616 def recall(self, s): | |
| 617 if self.history: | |
| 618 self.history.recall(s) | |
| 619 | |
| 620 def runit(self): | |
| 621 line = self.text.get("iomark", "end-1c") | |
| 622 # Strip off last newline and surrounding whitespace. | |
| 623 # (To allow you to hit return twice to end a statement.) | |
| 624 i = len(line) | |
| 625 while i > 0 and line[i-1] in " \t": | |
| 626 i = i-1 | |
| 627 if i > 0 and line[i-1] == "\n": | |
| 628 i = i-1 | |
| 629 while i > 0 and line[i-1] in " \t": | |
| 630 i = i-1 | |
| 631 line = line[:i] | |
| 632 more = self.interp.runsource(line) | |
| 633 if not more: | |
| 634 self.showprompt() | |
| 635 | |
| 636 def cancel_check(self, frame, what, args, | |
| 637 dooneevent=tkinter.dooneevent, | |
| 638 dontwait=tkinter.DONT_WAIT): | |
| 639 # Hack -- use the debugger hooks to be able to handle events | |
| 640 # and interrupt execution at any time. | |
| 641 # This slows execution down quite a bit, so you may want to | |
| 642 # disable this (by not calling settrace() in runcode() above) | |
| 643 # for full-bore (uninterruptable) speed. | |
| 644 # XXX This should become a user option. | |
| 645 if self.canceled: | |
| 646 return | |
| 647 dooneevent(dontwait) | |
| 648 if self.canceled: | |
| 649 self.canceled = 0 | |
| 650 raise KeyboardInterrupt | |
| 651 return self._cancel_check | |
| 652 | |
| 653 def open_stack_viewer(self, event=None): | |
| 654 try: | |
| 655 sys.last_traceback | |
| 656 except: | |
| 657 tkMessageBox.showerror("No stack trace", | |
| 658 "There is no stack trace yet.\n" | |
| 659 "(sys.last_traceback is not defined)", | |
| 660 master=self.text) | |
| 661 return | |
| 662 from StackViewer import StackBrowser | |
| 663 sv = StackBrowser(self.root, self.flist) | |
| 664 | |
| 665 def showprompt(self): | |
| 666 self.resetoutput() | |
| 667 try: | |
| 668 s = str(sys.ps1) | |
| 669 except: | |
| 670 s = "" | |
| 671 self.console.write(s) | |
| 672 self.text.mark_set("insert", "end-1c") | |
| 673 | |
| 674 def resetoutput(self): | |
| 675 source = self.text.get("iomark", "end-1c") | |
| 676 if self.history: | |
| 677 self.history.history_store(source) | |
| 678 if self.text.get("end-2c") != "\n": | |
| 679 self.text.insert("end-1c", "\n") | |
| 680 self.text.mark_set("iomark", "end-1c") | |
| 681 sys.stdout.softspace = 0 | |
| 682 | |
| 683 def write(self, s, tags=()): | |
| 684 self.text.mark_gravity("iomark", "right") | |
| 685 OutputWindow.write(self, s, tags, "iomark") | |
| 686 self.text.mark_gravity("iomark", "left") | |
| 687 if self.canceled: | |
| 688 self.canceled = 0 | |
| 689 raise KeyboardInterrupt | |
| 690 | |
| 691 class PseudoFile: | |
| 692 | |
| 693 def __init__(self, shell, tags): | |
| 694 self.shell = shell | |
| 695 self.tags = tags | |
| 696 | |
| 697 def write(self, s): | |
| 698 self.shell.write(s, self.tags) | |
| 699 | |
| 700 def writelines(self, l): | |
| 701 map(self.write, l) | |
| 702 | |
| 703 def flush(self): | |
| 704 pass | |
| 705 | |
| 706 def isatty(self): | |
| 707 return 1 | |
| 708 | |
| 709 usage_msg = """\ | |
| 710 usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ... | |
| 711 | |
| 712 -c command run this command | |
| 713 -d enable debugger | |
| 714 -e edit mode; arguments are files to be edited | |
| 715 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else | |
| 716 -t title set title of shell window | |
| 717 | |
| 718 When neither -c nor -e is used, and there are arguments, and the first | |
| 719 argument is not '-', the first argument is run as a script. Remaining | |
| 720 arguments are arguments to the script or to the command run by -c. | |
| 721 """ | |
| 722 | |
| 723 class usageError: | |
| 724 def __init__(self, string): self.string = string | |
| 725 def __repr__(self): return self.string | |
| 726 | |
| 727 class main: | |
| 728 def __init__(self): | |
| 729 try: | |
| 730 self.server = protocol.Server(connection_hook = self.address_ok) | |
| 731 protocol.publish( 'IDLE', self.connect ) | |
| 732 self.main( sys.argv[1:] ) | |
| 733 return | |
| 734 except protocol.connectionLost: | |
| 735 try: | |
| 736 client = protocol.Client() | |
| 737 IDLE = client.getobject('IDLE') | |
| 738 if IDLE: | |
| 739 try: | |
| 740 IDLE.remote( sys.argv[1:] ) | |
| 741 except usageError, msg: | |
| 742 sys.stderr.write("Error: %s\n" % str(msg)) | |
| 743 sys.stderr.write(usage_msg) | |
| 744 return | |
| 745 except protocol.connectionLost: | |
| 746 pass | |
| 747 | |
| 748 # xxx Should scream via Tk() | |
| 749 print "Something already has our socket, but it won't open a window for me!" | |
| 750 print "Unable to proceed." | |
| 751 | |
| 752 def idle(self): | |
| 753 spawn.kill_zombies() | |
| 754 self.server.rpc_loop() | |
| 755 root.after(25, self.idle) | |
| 756 | |
| 757 # We permit connections from localhost only | |
| 758 def address_ok(self, addr): | |
| 759 return addr[0] == '127.0.0.1' | |
| 760 | |
| 761 def connect(self, client, addr): | |
| 762 return self | |
| 763 | |
| 764 def remote( self, argv ): | |
| 765 # xxx Should make this behavior match the behavior in main, or redo | |
| 766 # command line options entirely. | |
| 767 | |
| 768 try: | |
| 769 opts, args = getopt.getopt(argv, "c:deist:") | |
| 770 except getopt.error, msg: | |
| 771 raise usageError(msg) | |
| 772 | |
| 773 for filename in args: | |
| 774 flist.open(filename) | |
| 775 if not args: | |
| 776 flist.new() | |
| 777 | |
| 778 def main( self, argv ): | |
| 779 cmd = None | |
| 780 edit = 0 | |
| 781 noshell = 1 | |
| 782 | |
| 783 debug = 0 | |
| 784 startup = 0 | |
| 785 | |
| 786 try: | |
| 787 opts, args = getopt.getopt(argv, "c:deist:") | |
| 788 except getopt.error, msg: | |
| 789 sys.stderr.write("Error: %s\n" % str(msg)) | |
| 790 sys.stderr.write(usage_msg) | |
| 791 sys.exit(2) | |
| 792 | |
| 793 for o, a in opts: | |
| 794 noshell = 0 | |
| 795 if o == '-c': | |
| 796 cmd = a | |
| 797 if o == '-d': | |
| 798 debug = 1 | |
| 799 if o == '-e': | |
| 800 edit = 1 | |
| 801 if o == '-s': | |
| 802 startup = 1 | |
| 803 if o == '-t': | |
| 804 PyShell.shell_title = a | |
| 805 | |
| 806 if noshell: edit=1 | |
| 807 | |
| 808 for i in range(len(sys.path)): | |
| 809 sys.path[i] = os.path.abspath(sys.path[i]) | |
| 810 | |
| 811 pathx = [] | |
| 812 if edit: | |
| 813 for filename in args: | |
| 814 pathx.append(os.path.dirname(filename)) | |
| 815 elif args and args[0] != "-": | |
| 816 pathx.append(os.path.dirname(args[0])) | |
| 817 else: | |
| 818 pathx.append(os.curdir) | |
| 819 for dir in pathx: | |
| 820 dir = os.path.abspath(dir) | |
| 821 if not dir in sys.path: | |
| 822 sys.path.insert(0, dir) | |
| 823 | |
| 824 global flist, root | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
825 root = Tk(className="Idle") |
| 13975 | 826 fixwordbreaks(root) |
| 827 root.withdraw() | |
| 828 flist = PyShellFileList(root) | |
| 829 | |
| 830 if edit: | |
| 831 for filename in args: | |
| 832 flist.open(filename) | |
| 833 if not args: | |
| 834 flist.new() | |
|
18560
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
835 else: |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
836 if cmd: |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
837 sys.argv = ["-c"] + args |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
838 else: |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
839 sys.argv = args or [""] |
|
12e7ad108229
cvs-py-rel2_1 (Rev 1.29 - 1.33) merge
Kurt B. Kaiser <kbk@shore.net>
parents:
13975
diff
changeset
|
840 |
| 13975 | 841 #dbg=OnDemandOutputWindow(flist) |
| 842 #dbg.set_title('Internal IDLE Problem') | |
| 843 #sys.stdout = PseudoFile(dbg,['stdout']) | |
| 844 #sys.stderr = PseudoFile(dbg,['stderr']) | |
| 845 | |
| 846 if noshell: | |
| 847 flist.pyshell = None | |
| 848 else: | |
| 849 shell = PyShell(flist) | |
| 850 interp = shell.interp | |
| 851 flist.pyshell = shell | |
| 852 | |
| 853 if startup: | |
| 854 filename = os.environ.get("IDLESTARTUP") or \ | |
| 855 os.environ.get("PYTHONSTARTUP") | |
| 856 if filename and os.path.isfile(filename): | |
| 857 interp.execfile(filename) | |
| 858 | |
| 859 if debug: | |
| 860 shell.open_debugger() | |
| 861 if cmd: | |
| 862 interp.execsource(cmd) | |
| 863 elif not edit and args and args[0] != "-": | |
| 864 interp.execfile(args[0]) | |
| 865 | |
| 866 shell.begin() | |
| 867 | |
| 868 self.idle() | |
| 869 root.mainloop() | |
| 870 root.destroy() | |
| 871 | |
| 872 | |
| 873 if __name__ == "__main__": | |
| 874 main() |
