home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / PYSHELL.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  24.0 KB  |  771 lines

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