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