symbian-qemu-0.9.1-12/python-2.6.1/Lib/idlelib/PyShell.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 #! /usr/bin/env python
       
     2 
       
     3 import os
       
     4 import os.path
       
     5 import sys
       
     6 import string
       
     7 import getopt
       
     8 import re
       
     9 import socket
       
    10 import time
       
    11 import threading
       
    12 import traceback
       
    13 import types
       
    14 import macosxSupport
       
    15 
       
    16 import linecache
       
    17 from code import InteractiveInterpreter
       
    18 
       
    19 try:
       
    20     from Tkinter import *
       
    21 except ImportError:
       
    22     print>>sys.__stderr__, "** IDLE can't import Tkinter.  " \
       
    23                            "Your Python may not be configured for Tk. **"
       
    24     sys.exit(1)
       
    25 import tkMessageBox
       
    26 
       
    27 from EditorWindow import EditorWindow, fixwordbreaks
       
    28 from FileList import FileList
       
    29 from ColorDelegator import ColorDelegator
       
    30 from UndoDelegator import UndoDelegator
       
    31 from OutputWindow import OutputWindow
       
    32 from configHandler import idleConf
       
    33 import idlever
       
    34 
       
    35 import rpc
       
    36 import Debugger
       
    37 import RemoteDebugger
       
    38 
       
    39 IDENTCHARS = string.ascii_letters + string.digits + "_"
       
    40 LOCALHOST = '127.0.0.1'
       
    41 
       
    42 try:
       
    43     from signal import SIGTERM
       
    44 except ImportError:
       
    45     SIGTERM = 15
       
    46 
       
    47 # Override warnings module to write to warning_stream.  Initialize to send IDLE
       
    48 # internal warnings to the console.  ScriptBinding.check_syntax() will
       
    49 # temporarily redirect the stream to the shell window to display warnings when
       
    50 # checking user's code.
       
    51 global warning_stream
       
    52 warning_stream = sys.__stderr__
       
    53 try:
       
    54     import warnings
       
    55 except ImportError:
       
    56     pass
       
    57 else:
       
    58     def idle_showwarning(message, category, filename, lineno,
       
    59                          file=None, line=None):
       
    60         file = warning_stream
       
    61         try:
       
    62             file.write(warnings.formatwarning(message, category, filename,\
       
    63                                               lineno, file=file, line=line))
       
    64         except IOError:
       
    65             pass  ## file (probably __stderr__) is invalid, warning dropped.
       
    66     warnings.showwarning = idle_showwarning
       
    67     def idle_formatwarning(message, category, filename, lineno,
       
    68                            file=None, line=None):
       
    69         """Format warnings the IDLE way"""
       
    70         s = "\nWarning (from warnings module):\n"
       
    71         s += '  File \"%s\", line %s\n' % (filename, lineno)
       
    72         line = linecache.getline(filename, lineno).strip() \
       
    73             if line is None else line
       
    74         if line:
       
    75             s += "    %s\n" % line
       
    76         s += "%s: %s\n>>> " % (category.__name__, message)
       
    77         return s
       
    78     warnings.formatwarning = idle_formatwarning
       
    79 
       
    80 def extended_linecache_checkcache(filename=None,
       
    81                                   orig_checkcache=linecache.checkcache):
       
    82     """Extend linecache.checkcache to preserve the <pyshell#...> entries
       
    83 
       
    84     Rather than repeating the linecache code, patch it to save the
       
    85     <pyshell#...> entries, call the original linecache.checkcache()
       
    86     (which destroys them), and then restore the saved entries.
       
    87 
       
    88     orig_checkcache is bound at definition time to the original
       
    89     method, allowing it to be patched.
       
    90 
       
    91     """
       
    92     cache = linecache.cache
       
    93     save = {}
       
    94     for filename in cache.keys():
       
    95         if filename[:1] + filename[-1:] == '<>':
       
    96             save[filename] = cache[filename]
       
    97     orig_checkcache()
       
    98     cache.update(save)
       
    99 
       
   100 # Patch linecache.checkcache():
       
   101 linecache.checkcache = extended_linecache_checkcache
       
   102 
       
   103 
       
   104 class PyShellEditorWindow(EditorWindow):
       
   105     "Regular text edit window in IDLE, supports breakpoints"
       
   106 
       
   107     def __init__(self, *args):
       
   108         self.breakpoints = []
       
   109         EditorWindow.__init__(self, *args)
       
   110         self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
       
   111         self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
       
   112         self.text.bind("<<open-python-shell>>", self.flist.open_shell)
       
   113 
       
   114         self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
       
   115                                            'breakpoints.lst')
       
   116         # whenever a file is changed, restore breakpoints
       
   117         if self.io.filename: self.restore_file_breaks()
       
   118         def filename_changed_hook(old_hook=self.io.filename_change_hook,
       
   119                                   self=self):
       
   120             self.restore_file_breaks()
       
   121             old_hook()
       
   122         self.io.set_filename_change_hook(filename_changed_hook)
       
   123 
       
   124     rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
       
   125                    ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
       
   126 
       
   127     def set_breakpoint(self, lineno):
       
   128         text = self.text
       
   129         filename = self.io.filename
       
   130         text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
       
   131         try:
       
   132             i = self.breakpoints.index(lineno)
       
   133         except ValueError:  # only add if missing, i.e. do once
       
   134             self.breakpoints.append(lineno)
       
   135         try:    # update the subprocess debugger
       
   136             debug = self.flist.pyshell.interp.debugger
       
   137             debug.set_breakpoint_here(filename, lineno)
       
   138         except: # but debugger may not be active right now....
       
   139             pass
       
   140 
       
   141     def set_breakpoint_here(self, event=None):
       
   142         text = self.text
       
   143         filename = self.io.filename
       
   144         if not filename:
       
   145             text.bell()
       
   146             return
       
   147         lineno = int(float(text.index("insert")))
       
   148         self.set_breakpoint(lineno)
       
   149 
       
   150     def clear_breakpoint_here(self, event=None):
       
   151         text = self.text
       
   152         filename = self.io.filename
       
   153         if not filename:
       
   154             text.bell()
       
   155             return
       
   156         lineno = int(float(text.index("insert")))
       
   157         try:
       
   158             self.breakpoints.remove(lineno)
       
   159         except:
       
   160             pass
       
   161         text.tag_remove("BREAK", "insert linestart",\
       
   162                         "insert lineend +1char")
       
   163         try:
       
   164             debug = self.flist.pyshell.interp.debugger
       
   165             debug.clear_breakpoint_here(filename, lineno)
       
   166         except:
       
   167             pass
       
   168 
       
   169     def clear_file_breaks(self):
       
   170         if self.breakpoints:
       
   171             text = self.text
       
   172             filename = self.io.filename
       
   173             if not filename:
       
   174                 text.bell()
       
   175                 return
       
   176             self.breakpoints = []
       
   177             text.tag_remove("BREAK", "1.0", END)
       
   178             try:
       
   179                 debug = self.flist.pyshell.interp.debugger
       
   180                 debug.clear_file_breaks(filename)
       
   181             except:
       
   182                 pass
       
   183 
       
   184     def store_file_breaks(self):
       
   185         "Save breakpoints when file is saved"
       
   186         # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
       
   187         #     be run.  The breaks are saved at that time.  If we introduce
       
   188         #     a temporary file save feature the save breaks functionality
       
   189         #     needs to be re-verified, since the breaks at the time the
       
   190         #     temp file is created may differ from the breaks at the last
       
   191         #     permanent save of the file.  Currently, a break introduced
       
   192         #     after a save will be effective, but not persistent.
       
   193         #     This is necessary to keep the saved breaks synched with the
       
   194         #     saved file.
       
   195         #
       
   196         #     Breakpoints are set as tagged ranges in the text.  Certain
       
   197         #     kinds of edits cause these ranges to be deleted: Inserting
       
   198         #     or deleting a line just before a breakpoint, and certain
       
   199         #     deletions prior to a breakpoint.  These issues need to be
       
   200         #     investigated and understood.  It's not clear if they are
       
   201         #     Tk issues or IDLE issues, or whether they can actually
       
   202         #     be fixed.  Since a modified file has to be saved before it is
       
   203         #     run, and since self.breakpoints (from which the subprocess
       
   204         #     debugger is loaded) is updated during the save, the visible
       
   205         #     breaks stay synched with the subprocess even if one of these
       
   206         #     unexpected breakpoint deletions occurs.
       
   207         breaks = self.breakpoints
       
   208         filename = self.io.filename
       
   209         try:
       
   210             lines = open(self.breakpointPath,"r").readlines()
       
   211         except IOError:
       
   212             lines = []
       
   213         new_file = open(self.breakpointPath,"w")
       
   214         for line in lines:
       
   215             if not line.startswith(filename + '='):
       
   216                 new_file.write(line)
       
   217         self.update_breakpoints()
       
   218         breaks = self.breakpoints
       
   219         if breaks:
       
   220             new_file.write(filename + '=' + str(breaks) + '\n')
       
   221         new_file.close()
       
   222 
       
   223     def restore_file_breaks(self):
       
   224         self.text.update()   # this enables setting "BREAK" tags to be visible
       
   225         filename = self.io.filename
       
   226         if filename is None:
       
   227             return
       
   228         if os.path.isfile(self.breakpointPath):
       
   229             lines = open(self.breakpointPath,"r").readlines()
       
   230             for line in lines:
       
   231                 if line.startswith(filename + '='):
       
   232                     breakpoint_linenumbers = eval(line[len(filename)+1:])
       
   233                     for breakpoint_linenumber in breakpoint_linenumbers:
       
   234                         self.set_breakpoint(breakpoint_linenumber)
       
   235 
       
   236     def update_breakpoints(self):
       
   237         "Retrieves all the breakpoints in the current window"
       
   238         text = self.text
       
   239         ranges = text.tag_ranges("BREAK")
       
   240         linenumber_list = self.ranges_to_linenumbers(ranges)
       
   241         self.breakpoints = linenumber_list
       
   242 
       
   243     def ranges_to_linenumbers(self, ranges):
       
   244         lines = []
       
   245         for index in range(0, len(ranges), 2):
       
   246             lineno = int(float(ranges[index]))
       
   247             end = int(float(ranges[index+1]))
       
   248             while lineno < end:
       
   249                 lines.append(lineno)
       
   250                 lineno += 1
       
   251         return lines
       
   252 
       
   253 # XXX 13 Dec 2002 KBK Not used currently
       
   254 #    def saved_change_hook(self):
       
   255 #        "Extend base method - clear breaks if module is modified"
       
   256 #        if not self.get_saved():
       
   257 #            self.clear_file_breaks()
       
   258 #        EditorWindow.saved_change_hook(self)
       
   259 
       
   260     def _close(self):
       
   261         "Extend base method - clear breaks when module is closed"
       
   262         self.clear_file_breaks()
       
   263         EditorWindow._close(self)
       
   264 
       
   265 
       
   266 class PyShellFileList(FileList):
       
   267     "Extend base class: IDLE supports a shell and breakpoints"
       
   268 
       
   269     # override FileList's class variable, instances return PyShellEditorWindow
       
   270     # instead of EditorWindow when new edit windows are created.
       
   271     EditorWindow = PyShellEditorWindow
       
   272 
       
   273     pyshell = None
       
   274 
       
   275     def open_shell(self, event=None):
       
   276         if self.pyshell:
       
   277             self.pyshell.top.wakeup()
       
   278         else:
       
   279             self.pyshell = PyShell(self)
       
   280             if self.pyshell:
       
   281                 if not self.pyshell.begin():
       
   282                     return None
       
   283         return self.pyshell
       
   284 
       
   285 
       
   286 class ModifiedColorDelegator(ColorDelegator):
       
   287     "Extend base class: colorizer for the shell window itself"
       
   288 
       
   289     def __init__(self):
       
   290         ColorDelegator.__init__(self)
       
   291         self.LoadTagDefs()
       
   292 
       
   293     def recolorize_main(self):
       
   294         self.tag_remove("TODO", "1.0", "iomark")
       
   295         self.tag_add("SYNC", "1.0", "iomark")
       
   296         ColorDelegator.recolorize_main(self)
       
   297 
       
   298     def LoadTagDefs(self):
       
   299         ColorDelegator.LoadTagDefs(self)
       
   300         theme = idleConf.GetOption('main','Theme','name')
       
   301         self.tagdefs.update({
       
   302             "stdin": {'background':None,'foreground':None},
       
   303             "stdout": idleConf.GetHighlight(theme, "stdout"),
       
   304             "stderr": idleConf.GetHighlight(theme, "stderr"),
       
   305             "console": idleConf.GetHighlight(theme, "console"),
       
   306         })
       
   307 
       
   308 class ModifiedUndoDelegator(UndoDelegator):
       
   309     "Extend base class: forbid insert/delete before the I/O mark"
       
   310 
       
   311     def insert(self, index, chars, tags=None):
       
   312         try:
       
   313             if self.delegate.compare(index, "<", "iomark"):
       
   314                 self.delegate.bell()
       
   315                 return
       
   316         except TclError:
       
   317             pass
       
   318         UndoDelegator.insert(self, index, chars, tags)
       
   319 
       
   320     def delete(self, index1, index2=None):
       
   321         try:
       
   322             if self.delegate.compare(index1, "<", "iomark"):
       
   323                 self.delegate.bell()
       
   324                 return
       
   325         except TclError:
       
   326             pass
       
   327         UndoDelegator.delete(self, index1, index2)
       
   328 
       
   329 
       
   330 class MyRPCClient(rpc.RPCClient):
       
   331 
       
   332     def handle_EOF(self):
       
   333         "Override the base class - just re-raise EOFError"
       
   334         raise EOFError
       
   335 
       
   336 
       
   337 class ModifiedInterpreter(InteractiveInterpreter):
       
   338 
       
   339     def __init__(self, tkconsole):
       
   340         self.tkconsole = tkconsole
       
   341         locals = sys.modules['__main__'].__dict__
       
   342         InteractiveInterpreter.__init__(self, locals=locals)
       
   343         self.save_warnings_filters = None
       
   344         self.restarting = False
       
   345         self.subprocess_arglist = self.build_subprocess_arglist()
       
   346 
       
   347     port = 8833
       
   348     rpcclt = None
       
   349     rpcpid = None
       
   350 
       
   351     def spawn_subprocess(self):
       
   352         args = self.subprocess_arglist
       
   353         self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
       
   354 
       
   355     def build_subprocess_arglist(self):
       
   356         w = ['-W' + s for s in sys.warnoptions]
       
   357         if 1/2 > 0: # account for new division
       
   358             w.append('-Qnew')
       
   359         # Maybe IDLE is installed and is being accessed via sys.path,
       
   360         # or maybe it's not installed and the idle.py script is being
       
   361         # run from the IDLE source directory.
       
   362         del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
       
   363                                        default=False, type='bool')
       
   364         if __name__ == 'idlelib.PyShell':
       
   365             command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
       
   366         else:
       
   367             command = "__import__('run').main(%r)" % (del_exitf,)
       
   368         if sys.platform[:3] == 'win' and ' ' in sys.executable:
       
   369             # handle embedded space in path by quoting the argument
       
   370             decorated_exec = '"%s"' % sys.executable
       
   371         else:
       
   372             decorated_exec = sys.executable
       
   373         return [decorated_exec] + w + ["-c", command, str(self.port)]
       
   374 
       
   375     def start_subprocess(self):
       
   376         # spawning first avoids passing a listening socket to the subprocess
       
   377         self.spawn_subprocess()
       
   378         #time.sleep(20) # test to simulate GUI not accepting connection
       
   379         addr = (LOCALHOST, self.port)
       
   380         # Idle starts listening for connection on localhost
       
   381         for i in range(3):
       
   382             time.sleep(i)
       
   383             try:
       
   384                 self.rpcclt = MyRPCClient(addr)
       
   385                 break
       
   386             except socket.error, err:
       
   387                 pass
       
   388         else:
       
   389             self.display_port_binding_error()
       
   390             return None
       
   391         # Accept the connection from the Python execution server
       
   392         self.rpcclt.listening_sock.settimeout(10)
       
   393         try:
       
   394             self.rpcclt.accept()
       
   395         except socket.timeout, err:
       
   396             self.display_no_subprocess_error()
       
   397             return None
       
   398         self.rpcclt.register("stdin", self.tkconsole)
       
   399         self.rpcclt.register("stdout", self.tkconsole.stdout)
       
   400         self.rpcclt.register("stderr", self.tkconsole.stderr)
       
   401         self.rpcclt.register("flist", self.tkconsole.flist)
       
   402         self.rpcclt.register("linecache", linecache)
       
   403         self.rpcclt.register("interp", self)
       
   404         self.transfer_path()
       
   405         self.poll_subprocess()
       
   406         return self.rpcclt
       
   407 
       
   408     def restart_subprocess(self):
       
   409         if self.restarting:
       
   410             return self.rpcclt
       
   411         self.restarting = True
       
   412         # close only the subprocess debugger
       
   413         debug = self.getdebugger()
       
   414         if debug:
       
   415             try:
       
   416                 # Only close subprocess debugger, don't unregister gui_adap!
       
   417                 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
       
   418             except:
       
   419                 pass
       
   420         # Kill subprocess, spawn a new one, accept connection.
       
   421         self.rpcclt.close()
       
   422         self.unix_terminate()
       
   423         console = self.tkconsole
       
   424         was_executing = console.executing
       
   425         console.executing = False
       
   426         self.spawn_subprocess()
       
   427         try:
       
   428             self.rpcclt.accept()
       
   429         except socket.timeout, err:
       
   430             self.display_no_subprocess_error()
       
   431             return None
       
   432         self.transfer_path()
       
   433         # annotate restart in shell window and mark it
       
   434         console.text.delete("iomark", "end-1c")
       
   435         if was_executing:
       
   436             console.write('\n')
       
   437             console.showprompt()
       
   438         halfbar = ((int(console.width) - 16) // 2) * '='
       
   439         console.write(halfbar + ' RESTART ' + halfbar)
       
   440         console.text.mark_set("restart", "end-1c")
       
   441         console.text.mark_gravity("restart", "left")
       
   442         console.showprompt()
       
   443         # restart subprocess debugger
       
   444         if debug:
       
   445             # Restarted debugger connects to current instance of debug GUI
       
   446             gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
       
   447             # reload remote debugger breakpoints for all PyShellEditWindows
       
   448             debug.load_breakpoints()
       
   449         self.restarting = False
       
   450         return self.rpcclt
       
   451 
       
   452     def __request_interrupt(self):
       
   453         self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
       
   454 
       
   455     def interrupt_subprocess(self):
       
   456         threading.Thread(target=self.__request_interrupt).start()
       
   457 
       
   458     def kill_subprocess(self):
       
   459         try:
       
   460             self.rpcclt.close()
       
   461         except AttributeError:  # no socket
       
   462             pass
       
   463         self.unix_terminate()
       
   464         self.tkconsole.executing = False
       
   465         self.rpcclt = None
       
   466 
       
   467     def unix_terminate(self):
       
   468         "UNIX: make sure subprocess is terminated and collect status"
       
   469         if hasattr(os, 'kill'):
       
   470             try:
       
   471                 os.kill(self.rpcpid, SIGTERM)
       
   472             except OSError:
       
   473                 # process already terminated:
       
   474                 return
       
   475             else:
       
   476                 try:
       
   477                     os.waitpid(self.rpcpid, 0)
       
   478                 except OSError:
       
   479                     return
       
   480 
       
   481     def transfer_path(self):
       
   482         self.runcommand("""if 1:
       
   483         import sys as _sys
       
   484         _sys.path = %r
       
   485         del _sys
       
   486         \n""" % (sys.path,))
       
   487 
       
   488     active_seq = None
       
   489 
       
   490     def poll_subprocess(self):
       
   491         clt = self.rpcclt
       
   492         if clt is None:
       
   493             return
       
   494         try:
       
   495             response = clt.pollresponse(self.active_seq, wait=0.05)
       
   496         except (EOFError, IOError, KeyboardInterrupt):
       
   497             # lost connection or subprocess terminated itself, restart
       
   498             # [the KBI is from rpc.SocketIO.handle_EOF()]
       
   499             if self.tkconsole.closing:
       
   500                 return
       
   501             response = None
       
   502             self.restart_subprocess()
       
   503         if response:
       
   504             self.tkconsole.resetoutput()
       
   505             self.active_seq = None
       
   506             how, what = response
       
   507             console = self.tkconsole.console
       
   508             if how == "OK":
       
   509                 if what is not None:
       
   510                     print >>console, repr(what)
       
   511             elif how == "EXCEPTION":
       
   512                 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
       
   513                     self.remote_stack_viewer()
       
   514             elif how == "ERROR":
       
   515                 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
       
   516                 print >>sys.__stderr__, errmsg, what
       
   517                 print >>console, errmsg, what
       
   518             # we received a response to the currently active seq number:
       
   519             try:
       
   520                 self.tkconsole.endexecuting()
       
   521             except AttributeError:  # shell may have closed
       
   522                 pass
       
   523         # Reschedule myself
       
   524         if not self.tkconsole.closing:
       
   525             self.tkconsole.text.after(self.tkconsole.pollinterval,
       
   526                                       self.poll_subprocess)
       
   527 
       
   528     debugger = None
       
   529 
       
   530     def setdebugger(self, debugger):
       
   531         self.debugger = debugger
       
   532 
       
   533     def getdebugger(self):
       
   534         return self.debugger
       
   535 
       
   536     def open_remote_stack_viewer(self):
       
   537         """Initiate the remote stack viewer from a separate thread.
       
   538 
       
   539         This method is called from the subprocess, and by returning from this
       
   540         method we allow the subprocess to unblock.  After a bit the shell
       
   541         requests the subprocess to open the remote stack viewer which returns a
       
   542         static object looking at the last exceptiopn.  It is queried through
       
   543         the RPC mechanism.
       
   544 
       
   545         """
       
   546         self.tkconsole.text.after(300, self.remote_stack_viewer)
       
   547         return
       
   548 
       
   549     def remote_stack_viewer(self):
       
   550         import RemoteObjectBrowser
       
   551         oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
       
   552         if oid is None:
       
   553             self.tkconsole.root.bell()
       
   554             return
       
   555         item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
       
   556         from TreeWidget import ScrolledCanvas, TreeNode
       
   557         top = Toplevel(self.tkconsole.root)
       
   558         theme = idleConf.GetOption('main','Theme','name')
       
   559         background = idleConf.GetHighlight(theme, 'normal')['background']
       
   560         sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
       
   561         sc.frame.pack(expand=1, fill="both")
       
   562         node = TreeNode(sc.canvas, None, item)
       
   563         node.expand()
       
   564         # XXX Should GC the remote tree when closing the window
       
   565 
       
   566     gid = 0
       
   567 
       
   568     def execsource(self, source):
       
   569         "Like runsource() but assumes complete exec source"
       
   570         filename = self.stuffsource(source)
       
   571         self.execfile(filename, source)
       
   572 
       
   573     def execfile(self, filename, source=None):
       
   574         "Execute an existing file"
       
   575         if source is None:
       
   576             source = open(filename, "r").read()
       
   577         try:
       
   578             code = compile(source, filename, "exec")
       
   579         except (OverflowError, SyntaxError):
       
   580             self.tkconsole.resetoutput()
       
   581             tkerr = self.tkconsole.stderr
       
   582             print>>tkerr, '*** Error in script or command!\n'
       
   583             print>>tkerr, 'Traceback (most recent call last):'
       
   584             InteractiveInterpreter.showsyntaxerror(self, filename)
       
   585             self.tkconsole.showprompt()
       
   586         else:
       
   587             self.runcode(code)
       
   588 
       
   589     def runsource(self, source):
       
   590         "Extend base class method: Stuff the source in the line cache first"
       
   591         filename = self.stuffsource(source)
       
   592         self.more = 0
       
   593         self.save_warnings_filters = warnings.filters[:]
       
   594         warnings.filterwarnings(action="error", category=SyntaxWarning)
       
   595         if isinstance(source, types.UnicodeType):
       
   596             import IOBinding
       
   597             try:
       
   598                 source = source.encode(IOBinding.encoding)
       
   599             except UnicodeError:
       
   600                 self.tkconsole.resetoutput()
       
   601                 self.write("Unsupported characters in input\n")
       
   602                 return
       
   603         try:
       
   604             # InteractiveInterpreter.runsource() calls its runcode() method,
       
   605             # which is overridden (see below)
       
   606             return InteractiveInterpreter.runsource(self, source, filename)
       
   607         finally:
       
   608             if self.save_warnings_filters is not None:
       
   609                 warnings.filters[:] = self.save_warnings_filters
       
   610                 self.save_warnings_filters = None
       
   611 
       
   612     def stuffsource(self, source):
       
   613         "Stuff source in the filename cache"
       
   614         filename = "<pyshell#%d>" % self.gid
       
   615         self.gid = self.gid + 1
       
   616         lines = source.split("\n")
       
   617         linecache.cache[filename] = len(source)+1, 0, lines, filename
       
   618         return filename
       
   619 
       
   620     def prepend_syspath(self, filename):
       
   621         "Prepend sys.path with file's directory if not already included"
       
   622         self.runcommand("""if 1:
       
   623             _filename = %r
       
   624             import sys as _sys
       
   625             from os.path import dirname as _dirname
       
   626             _dir = _dirname(_filename)
       
   627             if not _dir in _sys.path:
       
   628                 _sys.path.insert(0, _dir)
       
   629             del _filename, _sys, _dirname, _dir
       
   630             \n""" % (filename,))
       
   631 
       
   632     def showsyntaxerror(self, filename=None):
       
   633         """Extend base class method: Add Colorizing
       
   634 
       
   635         Color the offending position instead of printing it and pointing at it
       
   636         with a caret.
       
   637 
       
   638         """
       
   639         text = self.tkconsole.text
       
   640         stuff = self.unpackerror()
       
   641         if stuff:
       
   642             msg, lineno, offset, line = stuff
       
   643             if lineno == 1:
       
   644                 pos = "iomark + %d chars" % (offset-1)
       
   645             else:
       
   646                 pos = "iomark linestart + %d lines + %d chars" % \
       
   647                       (lineno-1, offset-1)
       
   648             text.tag_add("ERROR", pos)
       
   649             text.see(pos)
       
   650             char = text.get(pos)
       
   651             if char and char in IDENTCHARS:
       
   652                 text.tag_add("ERROR", pos + " wordstart", pos)
       
   653             self.tkconsole.resetoutput()
       
   654             self.write("SyntaxError: %s\n" % str(msg))
       
   655         else:
       
   656             self.tkconsole.resetoutput()
       
   657             InteractiveInterpreter.showsyntaxerror(self, filename)
       
   658         self.tkconsole.showprompt()
       
   659 
       
   660     def unpackerror(self):
       
   661         type, value, tb = sys.exc_info()
       
   662         ok = type is SyntaxError
       
   663         if ok:
       
   664             try:
       
   665                 msg, (dummy_filename, lineno, offset, line) = value
       
   666                 if not offset:
       
   667                     offset = 0
       
   668             except:
       
   669                 ok = 0
       
   670         if ok:
       
   671             return msg, lineno, offset, line
       
   672         else:
       
   673             return None
       
   674 
       
   675     def showtraceback(self):
       
   676         "Extend base class method to reset output properly"
       
   677         self.tkconsole.resetoutput()
       
   678         self.checklinecache()
       
   679         InteractiveInterpreter.showtraceback(self)
       
   680         if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
       
   681             self.tkconsole.open_stack_viewer()
       
   682 
       
   683     def checklinecache(self):
       
   684         c = linecache.cache
       
   685         for key in c.keys():
       
   686             if key[:1] + key[-1:] != "<>":
       
   687                 del c[key]
       
   688 
       
   689     def runcommand(self, code):
       
   690         "Run the code without invoking the debugger"
       
   691         # The code better not raise an exception!
       
   692         if self.tkconsole.executing:
       
   693             self.display_executing_dialog()
       
   694             return 0
       
   695         if self.rpcclt:
       
   696             self.rpcclt.remotequeue("exec", "runcode", (code,), {})
       
   697         else:
       
   698             exec code in self.locals
       
   699         return 1
       
   700 
       
   701     def runcode(self, code):
       
   702         "Override base class method"
       
   703         if self.tkconsole.executing:
       
   704             self.interp.restart_subprocess()
       
   705         self.checklinecache()
       
   706         if self.save_warnings_filters is not None:
       
   707             warnings.filters[:] = self.save_warnings_filters
       
   708             self.save_warnings_filters = None
       
   709         debugger = self.debugger
       
   710         try:
       
   711             self.tkconsole.beginexecuting()
       
   712             if not debugger and self.rpcclt is not None:
       
   713                 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
       
   714                                                         (code,), {})
       
   715             elif debugger:
       
   716                 debugger.run(code, self.locals)
       
   717             else:
       
   718                 exec code in self.locals
       
   719         except SystemExit:
       
   720             if not self.tkconsole.closing:
       
   721                 if tkMessageBox.askyesno(
       
   722                     "Exit?",
       
   723                     "Do you want to exit altogether?",
       
   724                     default="yes",
       
   725                     master=self.tkconsole.text):
       
   726                     raise
       
   727                 else:
       
   728                     self.showtraceback()
       
   729             else:
       
   730                 raise
       
   731         except:
       
   732             if use_subprocess:
       
   733                 print >>self.tkconsole.stderr, \
       
   734                          "IDLE internal error in runcode()"
       
   735                 self.showtraceback()
       
   736                 self.tkconsole.endexecuting()
       
   737             else:
       
   738                 if self.tkconsole.canceled:
       
   739                     self.tkconsole.canceled = False
       
   740                     print >>self.tkconsole.stderr, "KeyboardInterrupt"
       
   741                 else:
       
   742                     self.showtraceback()
       
   743         finally:
       
   744             if not use_subprocess:
       
   745                 try:
       
   746                     self.tkconsole.endexecuting()
       
   747                 except AttributeError:  # shell may have closed
       
   748                     pass
       
   749 
       
   750     def write(self, s):
       
   751         "Override base class method"
       
   752         self.tkconsole.stderr.write(s)
       
   753 
       
   754     def display_port_binding_error(self):
       
   755         tkMessageBox.showerror(
       
   756             "Port Binding Error",
       
   757             "IDLE can't bind TCP/IP port 8833, which is necessary to "
       
   758             "communicate with its Python execution server.  Either "
       
   759             "no networking is installed on this computer or another "
       
   760             "process (another IDLE?) is using the port.  Run IDLE with the -n "
       
   761             "command line switch to start without a subprocess and refer to "
       
   762             "Help/IDLE Help 'Running without a subprocess' for further "
       
   763             "details.",
       
   764             master=self.tkconsole.text)
       
   765 
       
   766     def display_no_subprocess_error(self):
       
   767         tkMessageBox.showerror(
       
   768             "Subprocess Startup Error",
       
   769             "IDLE's subprocess didn't make connection.  Either IDLE can't "
       
   770             "start a subprocess or personal firewall software is blocking "
       
   771             "the connection.",
       
   772             master=self.tkconsole.text)
       
   773 
       
   774     def display_executing_dialog(self):
       
   775         tkMessageBox.showerror(
       
   776             "Already executing",
       
   777             "The Python Shell window is already executing a command; "
       
   778             "please wait until it is finished.",
       
   779             master=self.tkconsole.text)
       
   780 
       
   781 
       
   782 class PyShell(OutputWindow):
       
   783 
       
   784     shell_title = "Python Shell"
       
   785 
       
   786     # Override classes
       
   787     ColorDelegator = ModifiedColorDelegator
       
   788     UndoDelegator = ModifiedUndoDelegator
       
   789 
       
   790     # Override menus
       
   791     menu_specs = [
       
   792         ("file", "_File"),
       
   793         ("edit", "_Edit"),
       
   794         ("debug", "_Debug"),
       
   795         ("options", "_Options"),
       
   796         ("windows", "_Windows"),
       
   797         ("help", "_Help"),
       
   798     ]
       
   799 
       
   800     if macosxSupport.runningAsOSXApp():
       
   801         del menu_specs[-3]
       
   802         menu_specs[-2] = ("windows", "_Window")
       
   803 
       
   804 
       
   805     # New classes
       
   806     from IdleHistory import History
       
   807 
       
   808     def __init__(self, flist=None):
       
   809         if use_subprocess:
       
   810             ms = self.menu_specs
       
   811             if ms[2][0] != "shell":
       
   812                 ms.insert(2, ("shell", "She_ll"))
       
   813         self.interp = ModifiedInterpreter(self)
       
   814         if flist is None:
       
   815             root = Tk()
       
   816             fixwordbreaks(root)
       
   817             root.withdraw()
       
   818             flist = PyShellFileList(root)
       
   819         #
       
   820         OutputWindow.__init__(self, flist, None, None)
       
   821         #
       
   822 ##        self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
       
   823         self.usetabs = True
       
   824         # indentwidth must be 8 when using tabs.  See note in EditorWindow:
       
   825         self.indentwidth = 8
       
   826         self.context_use_ps1 = True
       
   827         #
       
   828         text = self.text
       
   829         text.configure(wrap="char")
       
   830         text.bind("<<newline-and-indent>>", self.enter_callback)
       
   831         text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
       
   832         text.bind("<<interrupt-execution>>", self.cancel_callback)
       
   833         text.bind("<<end-of-file>>", self.eof_callback)
       
   834         text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
       
   835         text.bind("<<toggle-debugger>>", self.toggle_debugger)
       
   836         text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
       
   837         if use_subprocess:
       
   838             text.bind("<<view-restart>>", self.view_restart_mark)
       
   839             text.bind("<<restart-shell>>", self.restart_shell)
       
   840         #
       
   841         self.save_stdout = sys.stdout
       
   842         self.save_stderr = sys.stderr
       
   843         self.save_stdin = sys.stdin
       
   844         import IOBinding
       
   845         self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
       
   846         self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
       
   847         self.console = PseudoFile(self, "console", IOBinding.encoding)
       
   848         if not use_subprocess:
       
   849             sys.stdout = self.stdout
       
   850             sys.stderr = self.stderr
       
   851             sys.stdin = self
       
   852         #
       
   853         self.history = self.History(self.text)
       
   854         #
       
   855         self.pollinterval = 50  # millisec
       
   856 
       
   857     def get_standard_extension_names(self):
       
   858         return idleConf.GetExtensions(shell_only=True)
       
   859 
       
   860     reading = False
       
   861     executing = False
       
   862     canceled = False
       
   863     endoffile = False
       
   864     closing = False
       
   865 
       
   866     def set_warning_stream(self, stream):
       
   867         global warning_stream
       
   868         warning_stream = stream
       
   869 
       
   870     def get_warning_stream(self):
       
   871         return warning_stream
       
   872 
       
   873     def toggle_debugger(self, event=None):
       
   874         if self.executing:
       
   875             tkMessageBox.showerror("Don't debug now",
       
   876                 "You can only toggle the debugger when idle",
       
   877                 master=self.text)
       
   878             self.set_debugger_indicator()
       
   879             return "break"
       
   880         else:
       
   881             db = self.interp.getdebugger()
       
   882             if db:
       
   883                 self.close_debugger()
       
   884             else:
       
   885                 self.open_debugger()
       
   886 
       
   887     def set_debugger_indicator(self):
       
   888         db = self.interp.getdebugger()
       
   889         self.setvar("<<toggle-debugger>>", not not db)
       
   890 
       
   891     def toggle_jit_stack_viewer(self, event=None):
       
   892         pass # All we need is the variable
       
   893 
       
   894     def close_debugger(self):
       
   895         db = self.interp.getdebugger()
       
   896         if db:
       
   897             self.interp.setdebugger(None)
       
   898             db.close()
       
   899             if self.interp.rpcclt:
       
   900                 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
       
   901             self.resetoutput()
       
   902             self.console.write("[DEBUG OFF]\n")
       
   903             sys.ps1 = ">>> "
       
   904             self.showprompt()
       
   905         self.set_debugger_indicator()
       
   906 
       
   907     def open_debugger(self):
       
   908         if self.interp.rpcclt:
       
   909             dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
       
   910                                                            self)
       
   911         else:
       
   912             dbg_gui = Debugger.Debugger(self)
       
   913         self.interp.setdebugger(dbg_gui)
       
   914         dbg_gui.load_breakpoints()
       
   915         sys.ps1 = "[DEBUG ON]\n>>> "
       
   916         self.showprompt()
       
   917         self.set_debugger_indicator()
       
   918 
       
   919     def beginexecuting(self):
       
   920         "Helper for ModifiedInterpreter"
       
   921         self.resetoutput()
       
   922         self.executing = 1
       
   923 
       
   924     def endexecuting(self):
       
   925         "Helper for ModifiedInterpreter"
       
   926         self.executing = 0
       
   927         self.canceled = 0
       
   928         self.showprompt()
       
   929 
       
   930     def close(self):
       
   931         "Extend EditorWindow.close()"
       
   932         if self.executing:
       
   933             response = tkMessageBox.askokcancel(
       
   934                 "Kill?",
       
   935                 "The program is still running!\n Do you want to kill it?",
       
   936                 default="ok",
       
   937                 parent=self.text)
       
   938             if response is False:
       
   939                 return "cancel"
       
   940         if self.reading:
       
   941             self.top.quit()
       
   942         self.canceled = True
       
   943         self.closing = True
       
   944         # Wait for poll_subprocess() rescheduling to stop
       
   945         self.text.after(2 * self.pollinterval, self.close2)
       
   946 
       
   947     def close2(self):
       
   948         return EditorWindow.close(self)
       
   949 
       
   950     def _close(self):
       
   951         "Extend EditorWindow._close(), shut down debugger and execution server"
       
   952         self.close_debugger()
       
   953         if use_subprocess:
       
   954             self.interp.kill_subprocess()
       
   955         # Restore std streams
       
   956         sys.stdout = self.save_stdout
       
   957         sys.stderr = self.save_stderr
       
   958         sys.stdin = self.save_stdin
       
   959         # Break cycles
       
   960         self.interp = None
       
   961         self.console = None
       
   962         self.flist.pyshell = None
       
   963         self.history = None
       
   964         EditorWindow._close(self)
       
   965 
       
   966     def ispythonsource(self, filename):
       
   967         "Override EditorWindow method: never remove the colorizer"
       
   968         return True
       
   969 
       
   970     def short_title(self):
       
   971         return self.shell_title
       
   972 
       
   973     COPYRIGHT = \
       
   974           'Type "copyright", "credits" or "license()" for more information.'
       
   975 
       
   976     firewallmessage = """
       
   977     ****************************************************************
       
   978     Personal firewall software may warn about the connection IDLE
       
   979     makes to its subprocess using this computer's internal loopback
       
   980     interface.  This connection is not visible on any external
       
   981     interface and no data is sent to or received from the Internet.
       
   982     ****************************************************************
       
   983     """
       
   984 
       
   985     def begin(self):
       
   986         self.resetoutput()
       
   987         if use_subprocess:
       
   988             nosub = ''
       
   989             client = self.interp.start_subprocess()
       
   990             if not client:
       
   991                 self.close()
       
   992                 return False
       
   993         else:
       
   994             nosub = "==== No Subprocess ===="
       
   995         self.write("Python %s on %s\n%s\n%s\nIDLE %s      %s\n" %
       
   996                    (sys.version, sys.platform, self.COPYRIGHT,
       
   997                     self.firewallmessage, idlever.IDLE_VERSION, nosub))
       
   998         self.showprompt()
       
   999         import Tkinter
       
  1000         Tkinter._default_root = None # 03Jan04 KBK What's this?
       
  1001         return True
       
  1002 
       
  1003     def readline(self):
       
  1004         save = self.reading
       
  1005         try:
       
  1006             self.reading = 1
       
  1007             self.top.mainloop()  # nested mainloop()
       
  1008         finally:
       
  1009             self.reading = save
       
  1010         line = self.text.get("iomark", "end-1c")
       
  1011         if len(line) == 0:  # may be EOF if we quit our mainloop with Ctrl-C
       
  1012             line = "\n"
       
  1013         if isinstance(line, unicode):
       
  1014             import IOBinding
       
  1015             try:
       
  1016                 line = line.encode(IOBinding.encoding)
       
  1017             except UnicodeError:
       
  1018                 pass
       
  1019         self.resetoutput()
       
  1020         if self.canceled:
       
  1021             self.canceled = 0
       
  1022             if not use_subprocess:
       
  1023                 raise KeyboardInterrupt
       
  1024         if self.endoffile:
       
  1025             self.endoffile = 0
       
  1026             line = ""
       
  1027         return line
       
  1028 
       
  1029     def isatty(self):
       
  1030         return True
       
  1031 
       
  1032     def cancel_callback(self, event=None):
       
  1033         try:
       
  1034             if self.text.compare("sel.first", "!=", "sel.last"):
       
  1035                 return # Active selection -- always use default binding
       
  1036         except:
       
  1037             pass
       
  1038         if not (self.executing or self.reading):
       
  1039             self.resetoutput()
       
  1040             self.interp.write("KeyboardInterrupt\n")
       
  1041             self.showprompt()
       
  1042             return "break"
       
  1043         self.endoffile = 0
       
  1044         self.canceled = 1
       
  1045         if (self.executing and self.interp.rpcclt):
       
  1046             if self.interp.getdebugger():
       
  1047                 self.interp.restart_subprocess()
       
  1048             else:
       
  1049                 self.interp.interrupt_subprocess()
       
  1050         if self.reading:
       
  1051             self.top.quit()  # exit the nested mainloop() in readline()
       
  1052         return "break"
       
  1053 
       
  1054     def eof_callback(self, event):
       
  1055         if self.executing and not self.reading:
       
  1056             return # Let the default binding (delete next char) take over
       
  1057         if not (self.text.compare("iomark", "==", "insert") and
       
  1058                 self.text.compare("insert", "==", "end-1c")):
       
  1059             return # Let the default binding (delete next char) take over
       
  1060         if not self.executing:
       
  1061             self.resetoutput()
       
  1062             self.close()
       
  1063         else:
       
  1064             self.canceled = 0
       
  1065             self.endoffile = 1
       
  1066             self.top.quit()
       
  1067         return "break"
       
  1068 
       
  1069     def linefeed_callback(self, event):
       
  1070         # Insert a linefeed without entering anything (still autoindented)
       
  1071         if self.reading:
       
  1072             self.text.insert("insert", "\n")
       
  1073             self.text.see("insert")
       
  1074         else:
       
  1075             self.newline_and_indent_event(event)
       
  1076         return "break"
       
  1077 
       
  1078     def enter_callback(self, event):
       
  1079         if self.executing and not self.reading:
       
  1080             return # Let the default binding (insert '\n') take over
       
  1081         # If some text is selected, recall the selection
       
  1082         # (but only if this before the I/O mark)
       
  1083         try:
       
  1084             sel = self.text.get("sel.first", "sel.last")
       
  1085             if sel:
       
  1086                 if self.text.compare("sel.last", "<=", "iomark"):
       
  1087                     self.recall(sel, event)
       
  1088                     return "break"
       
  1089         except:
       
  1090             pass
       
  1091         # If we're strictly before the line containing iomark, recall
       
  1092         # the current line, less a leading prompt, less leading or
       
  1093         # trailing whitespace
       
  1094         if self.text.compare("insert", "<", "iomark linestart"):
       
  1095             # Check if there's a relevant stdin range -- if so, use it
       
  1096             prev = self.text.tag_prevrange("stdin", "insert")
       
  1097             if prev and self.text.compare("insert", "<", prev[1]):
       
  1098                 self.recall(self.text.get(prev[0], prev[1]), event)
       
  1099                 return "break"
       
  1100             next = self.text.tag_nextrange("stdin", "insert")
       
  1101             if next and self.text.compare("insert lineend", ">=", next[0]):
       
  1102                 self.recall(self.text.get(next[0], next[1]), event)
       
  1103                 return "break"
       
  1104             # No stdin mark -- just get the current line, less any prompt
       
  1105             indices = self.text.tag_nextrange("console", "insert linestart")
       
  1106             if indices and \
       
  1107                self.text.compare(indices[0], "<=", "insert linestart"):
       
  1108                 self.recall(self.text.get(indices[1], "insert lineend"), event)
       
  1109             else:
       
  1110                 self.recall(self.text.get("insert linestart", "insert lineend"), event)
       
  1111             return "break"
       
  1112         # If we're between the beginning of the line and the iomark, i.e.
       
  1113         # in the prompt area, move to the end of the prompt
       
  1114         if self.text.compare("insert", "<", "iomark"):
       
  1115             self.text.mark_set("insert", "iomark")
       
  1116         # If we're in the current input and there's only whitespace
       
  1117         # beyond the cursor, erase that whitespace first
       
  1118         s = self.text.get("insert", "end-1c")
       
  1119         if s and not s.strip():
       
  1120             self.text.delete("insert", "end-1c")
       
  1121         # If we're in the current input before its last line,
       
  1122         # insert a newline right at the insert point
       
  1123         if self.text.compare("insert", "<", "end-1c linestart"):
       
  1124             self.newline_and_indent_event(event)
       
  1125             return "break"
       
  1126         # We're in the last line; append a newline and submit it
       
  1127         self.text.mark_set("insert", "end-1c")
       
  1128         if self.reading:
       
  1129             self.text.insert("insert", "\n")
       
  1130             self.text.see("insert")
       
  1131         else:
       
  1132             self.newline_and_indent_event(event)
       
  1133         self.text.tag_add("stdin", "iomark", "end-1c")
       
  1134         self.text.update_idletasks()
       
  1135         if self.reading:
       
  1136             self.top.quit() # Break out of recursive mainloop() in raw_input()
       
  1137         else:
       
  1138             self.runit()
       
  1139         return "break"
       
  1140 
       
  1141     def recall(self, s, event):
       
  1142         # remove leading and trailing empty or whitespace lines
       
  1143         s = re.sub(r'^\s*\n', '' , s)
       
  1144         s = re.sub(r'\n\s*$', '', s)
       
  1145         lines = s.split('\n')
       
  1146         self.text.undo_block_start()
       
  1147         try:
       
  1148             self.text.tag_remove("sel", "1.0", "end")
       
  1149             self.text.mark_set("insert", "end-1c")
       
  1150             prefix = self.text.get("insert linestart", "insert")
       
  1151             if prefix.rstrip().endswith(':'):
       
  1152                 self.newline_and_indent_event(event)
       
  1153                 prefix = self.text.get("insert linestart", "insert")
       
  1154             self.text.insert("insert", lines[0].strip())
       
  1155             if len(lines) > 1:
       
  1156                 orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0)
       
  1157                 new_base_indent  = re.search(r'^([ \t]*)', prefix).group(0)
       
  1158                 for line in lines[1:]:
       
  1159                     if line.startswith(orig_base_indent):
       
  1160                         # replace orig base indentation with new indentation
       
  1161                         line = new_base_indent + line[len(orig_base_indent):]
       
  1162                     self.text.insert('insert', '\n'+line.rstrip())
       
  1163         finally:
       
  1164             self.text.see("insert")
       
  1165             self.text.undo_block_stop()
       
  1166 
       
  1167     def runit(self):
       
  1168         line = self.text.get("iomark", "end-1c")
       
  1169         # Strip off last newline and surrounding whitespace.
       
  1170         # (To allow you to hit return twice to end a statement.)
       
  1171         i = len(line)
       
  1172         while i > 0 and line[i-1] in " \t":
       
  1173             i = i-1
       
  1174         if i > 0 and line[i-1] == "\n":
       
  1175             i = i-1
       
  1176         while i > 0 and line[i-1] in " \t":
       
  1177             i = i-1
       
  1178         line = line[:i]
       
  1179         more = self.interp.runsource(line)
       
  1180 
       
  1181     def open_stack_viewer(self, event=None):
       
  1182         if self.interp.rpcclt:
       
  1183             return self.interp.remote_stack_viewer()
       
  1184         try:
       
  1185             sys.last_traceback
       
  1186         except:
       
  1187             tkMessageBox.showerror("No stack trace",
       
  1188                 "There is no stack trace yet.\n"
       
  1189                 "(sys.last_traceback is not defined)",
       
  1190                 master=self.text)
       
  1191             return
       
  1192         from StackViewer import StackBrowser
       
  1193         sv = StackBrowser(self.root, self.flist)
       
  1194 
       
  1195     def view_restart_mark(self, event=None):
       
  1196         self.text.see("iomark")
       
  1197         self.text.see("restart")
       
  1198 
       
  1199     def restart_shell(self, event=None):
       
  1200         self.interp.restart_subprocess()
       
  1201 
       
  1202     def showprompt(self):
       
  1203         self.resetoutput()
       
  1204         try:
       
  1205             s = str(sys.ps1)
       
  1206         except:
       
  1207             s = ""
       
  1208         self.console.write(s)
       
  1209         self.text.mark_set("insert", "end-1c")
       
  1210         self.set_line_and_column()
       
  1211         self.io.reset_undo()
       
  1212 
       
  1213     def resetoutput(self):
       
  1214         source = self.text.get("iomark", "end-1c")
       
  1215         if self.history:
       
  1216             self.history.history_store(source)
       
  1217         if self.text.get("end-2c") != "\n":
       
  1218             self.text.insert("end-1c", "\n")
       
  1219         self.text.mark_set("iomark", "end-1c")
       
  1220         self.set_line_and_column()
       
  1221         sys.stdout.softspace = 0
       
  1222 
       
  1223     def write(self, s, tags=()):
       
  1224         try:
       
  1225             self.text.mark_gravity("iomark", "right")
       
  1226             OutputWindow.write(self, s, tags, "iomark")
       
  1227             self.text.mark_gravity("iomark", "left")
       
  1228         except:
       
  1229             pass
       
  1230         if self.canceled:
       
  1231             self.canceled = 0
       
  1232             if not use_subprocess:
       
  1233                 raise KeyboardInterrupt
       
  1234 
       
  1235 class PseudoFile(object):
       
  1236 
       
  1237     def __init__(self, shell, tags, encoding=None):
       
  1238         self.shell = shell
       
  1239         self.tags = tags
       
  1240         self.softspace = 0
       
  1241         self.encoding = encoding
       
  1242 
       
  1243     def write(self, s):
       
  1244         self.shell.write(s, self.tags)
       
  1245 
       
  1246     def writelines(self, l):
       
  1247         map(self.write, l)
       
  1248 
       
  1249     def flush(self):
       
  1250         pass
       
  1251 
       
  1252     def isatty(self):
       
  1253         return True
       
  1254 
       
  1255 
       
  1256 usage_msg = """\
       
  1257 
       
  1258 USAGE: idle  [-deins] [-t title] [file]*
       
  1259        idle  [-dns] [-t title] (-c cmd | -r file) [arg]*
       
  1260        idle  [-dns] [-t title] - [arg]*
       
  1261 
       
  1262   -h         print this help message and exit
       
  1263   -n         run IDLE without a subprocess (see Help/IDLE Help for details)
       
  1264 
       
  1265 The following options will override the IDLE 'settings' configuration:
       
  1266 
       
  1267   -e         open an edit window
       
  1268   -i         open a shell window
       
  1269 
       
  1270 The following options imply -i and will open a shell:
       
  1271 
       
  1272   -c cmd     run the command in a shell, or
       
  1273   -r file    run script from file
       
  1274 
       
  1275   -d         enable the debugger
       
  1276   -s         run $IDLESTARTUP or $PYTHONSTARTUP before anything else
       
  1277   -t title   set title of shell window
       
  1278 
       
  1279 A default edit window will be bypassed when -c, -r, or - are used.
       
  1280 
       
  1281 [arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
       
  1282 
       
  1283 Examples:
       
  1284 
       
  1285 idle
       
  1286         Open an edit window or shell depending on IDLE's configuration.
       
  1287 
       
  1288 idle foo.py foobar.py
       
  1289         Edit the files, also open a shell if configured to start with shell.
       
  1290 
       
  1291 idle -est "Baz" foo.py
       
  1292         Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
       
  1293         window with the title "Baz".
       
  1294 
       
  1295 idle -c "import sys; print sys.argv" "foo"
       
  1296         Open a shell window and run the command, passing "-c" in sys.argv[0]
       
  1297         and "foo" in sys.argv[1].
       
  1298 
       
  1299 idle -d -s -r foo.py "Hello World"
       
  1300         Open a shell window, run a startup script, enable the debugger, and
       
  1301         run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
       
  1302         sys.argv[1].
       
  1303 
       
  1304 echo "import sys; print sys.argv" | idle - "foobar"
       
  1305         Open a shell window, run the script piped in, passing '' in sys.argv[0]
       
  1306         and "foobar" in sys.argv[1].
       
  1307 """
       
  1308 
       
  1309 def main():
       
  1310     global flist, root, use_subprocess
       
  1311 
       
  1312     use_subprocess = True
       
  1313     enable_shell = False
       
  1314     enable_edit = False
       
  1315     debug = False
       
  1316     cmd = None
       
  1317     script = None
       
  1318     startup = False
       
  1319     try:
       
  1320         opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
       
  1321     except getopt.error, msg:
       
  1322         sys.stderr.write("Error: %s\n" % str(msg))
       
  1323         sys.stderr.write(usage_msg)
       
  1324         sys.exit(2)
       
  1325     for o, a in opts:
       
  1326         if o == '-c':
       
  1327             cmd = a
       
  1328             enable_shell = True
       
  1329         if o == '-d':
       
  1330             debug = True
       
  1331             enable_shell = True
       
  1332         if o == '-e':
       
  1333             enable_edit = True
       
  1334         if o == '-h':
       
  1335             sys.stdout.write(usage_msg)
       
  1336             sys.exit()
       
  1337         if o == '-i':
       
  1338             enable_shell = True
       
  1339         if o == '-n':
       
  1340             use_subprocess = False
       
  1341         if o == '-r':
       
  1342             script = a
       
  1343             if os.path.isfile(script):
       
  1344                 pass
       
  1345             else:
       
  1346                 print "No script file: ", script
       
  1347                 sys.exit()
       
  1348             enable_shell = True
       
  1349         if o == '-s':
       
  1350             startup = True
       
  1351             enable_shell = True
       
  1352         if o == '-t':
       
  1353             PyShell.shell_title = a
       
  1354             enable_shell = True
       
  1355     if args and args[0] == '-':
       
  1356         cmd = sys.stdin.read()
       
  1357         enable_shell = True
       
  1358     # process sys.argv and sys.path:
       
  1359     for i in range(len(sys.path)):
       
  1360         sys.path[i] = os.path.abspath(sys.path[i])
       
  1361     if args and args[0] == '-':
       
  1362         sys.argv = [''] + args[1:]
       
  1363     elif cmd:
       
  1364         sys.argv = ['-c'] + args
       
  1365     elif script:
       
  1366         sys.argv = [script] + args
       
  1367     elif args:
       
  1368         enable_edit = True
       
  1369         pathx = []
       
  1370         for filename in args:
       
  1371             pathx.append(os.path.dirname(filename))
       
  1372         for dir in pathx:
       
  1373             dir = os.path.abspath(dir)
       
  1374             if not dir in sys.path:
       
  1375                 sys.path.insert(0, dir)
       
  1376     else:
       
  1377         dir = os.getcwd()
       
  1378         if not dir in sys.path:
       
  1379             sys.path.insert(0, dir)
       
  1380     # check the IDLE settings configuration (but command line overrides)
       
  1381     edit_start = idleConf.GetOption('main', 'General',
       
  1382                                     'editor-on-startup', type='bool')
       
  1383     enable_edit = enable_edit or edit_start
       
  1384     enable_shell = enable_shell or not edit_start
       
  1385     # start editor and/or shell windows:
       
  1386     root = Tk(className="Idle")
       
  1387 
       
  1388     fixwordbreaks(root)
       
  1389     root.withdraw()
       
  1390     flist = PyShellFileList(root)
       
  1391     macosxSupport.setupApp(root, flist)
       
  1392 
       
  1393     if enable_edit:
       
  1394         if not (cmd or script):
       
  1395             for filename in args:
       
  1396                 flist.open(filename)
       
  1397             if not args:
       
  1398                 flist.new()
       
  1399     if enable_shell:
       
  1400         shell = flist.open_shell()
       
  1401         if not shell:
       
  1402             return # couldn't open shell
       
  1403 
       
  1404         if macosxSupport.runningAsOSXApp() and flist.dict:
       
  1405             # On OSX: when the user has double-clicked on a file that causes
       
  1406             # IDLE to be launched the shell window will open just in front of
       
  1407             # the file she wants to see. Lower the interpreter window when
       
  1408             # there are open files.
       
  1409             shell.top.lower()
       
  1410 
       
  1411     shell = flist.pyshell
       
  1412     # handle remaining options:
       
  1413     if debug:
       
  1414         shell.open_debugger()
       
  1415     if startup:
       
  1416         filename = os.environ.get("IDLESTARTUP") or \
       
  1417                    os.environ.get("PYTHONSTARTUP")
       
  1418         if filename and os.path.isfile(filename):
       
  1419             shell.interp.execfile(filename)
       
  1420     if shell and cmd or script:
       
  1421         shell.interp.runcommand("""if 1:
       
  1422             import sys as _sys
       
  1423             _sys.argv = %r
       
  1424             del _sys
       
  1425             \n""" % (sys.argv,))
       
  1426         if cmd:
       
  1427             shell.interp.execsource(cmd)
       
  1428         elif script:
       
  1429             shell.interp.prepend_syspath(script)
       
  1430             shell.interp.execfile(script)
       
  1431 
       
  1432     root.mainloop()
       
  1433     root.destroy()
       
  1434 
       
  1435 if __name__ == "__main__":
       
  1436     sys.modules['PyShell'] = sys.modules['__main__']
       
  1437     main()