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