home *** CD-ROM | disk | FTP | other *** search
/ Freelog 33 / Freelog033.iso / Progr / Python-2.2.1.exe / PYSHELL.PY < prev    next >
Encoding:
Python Source  |  2001-07-20  |  24.6 KB  |  786 lines

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