python-2.5.2/win32/Lib/idlelib/ScriptBinding.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """Extension to execute code outside the Python shell window.
       
     2 
       
     3 This adds the following commands:
       
     4 
       
     5 - Check module does a full syntax check of the current module.
       
     6   It also runs the tabnanny to catch any inconsistent tabs.
       
     7 
       
     8 - Run module executes the module's code in the __main__ namespace.  The window
       
     9   must have been saved previously. The module is added to sys.modules, and is
       
    10   also added to the __main__ namespace.
       
    11 
       
    12 XXX GvR Redesign this interface (yet again) as follows:
       
    13 
       
    14 - Present a dialog box for ``Run Module''
       
    15 
       
    16 - Allow specify command line arguments in the dialog box
       
    17 
       
    18 """
       
    19 
       
    20 import os
       
    21 import re
       
    22 import string
       
    23 import tabnanny
       
    24 import tokenize
       
    25 import tkMessageBox
       
    26 import PyShell
       
    27 
       
    28 from configHandler import idleConf
       
    29 
       
    30 IDENTCHARS = string.ascii_letters + string.digits + "_"
       
    31 
       
    32 indent_message = """Error: Inconsistent indentation detected!
       
    33 
       
    34 1) Your indentation is outright incorrect (easy to fix), OR
       
    35 
       
    36 2) Your indentation mixes tabs and spaces.
       
    37 
       
    38 To fix case 2, change all tabs to spaces by using Edit->Select All followed \
       
    39 by Format->Untabify Region and specify the number of columns used by each tab.
       
    40 """
       
    41 
       
    42 class ScriptBinding:
       
    43 
       
    44     menudefs = [
       
    45         ('run', [None,
       
    46                  ('Check Module', '<<check-module>>'),
       
    47                  ('Run Module', '<<run-module>>'), ]), ]
       
    48 
       
    49     def __init__(self, editwin):
       
    50         self.editwin = editwin
       
    51         # Provide instance variables referenced by Debugger
       
    52         # XXX This should be done differently
       
    53         self.flist = self.editwin.flist
       
    54         self.root = self.editwin.root
       
    55 
       
    56     def check_module_event(self, event):
       
    57         filename = self.getfilename()
       
    58         if not filename:
       
    59             return
       
    60         if not self.checksyntax(filename):
       
    61             return
       
    62         if not self.tabnanny(filename):
       
    63             return
       
    64 
       
    65     def tabnanny(self, filename):
       
    66         f = open(filename, 'r')
       
    67         try:
       
    68             tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
       
    69         except tokenize.TokenError, msg:
       
    70             msgtxt, (lineno, start) = msg
       
    71             self.editwin.gotoline(lineno)
       
    72             self.errorbox("Tabnanny Tokenizing Error",
       
    73                           "Token Error: %s" % msgtxt)
       
    74             return False
       
    75         except tabnanny.NannyNag, nag:
       
    76             # The error messages from tabnanny are too confusing...
       
    77             self.editwin.gotoline(nag.get_lineno())
       
    78             self.errorbox("Tab/space error", indent_message)
       
    79             return False
       
    80         return True
       
    81 
       
    82     def checksyntax(self, filename):
       
    83         self.shell = shell = self.flist.open_shell()
       
    84         saved_stream = shell.get_warning_stream()
       
    85         shell.set_warning_stream(shell.stderr)
       
    86         f = open(filename, 'r')
       
    87         source = f.read()
       
    88         f.close()
       
    89         if '\r' in source:
       
    90             source = re.sub(r"\r\n", "\n", source)
       
    91             source = re.sub(r"\r", "\n", source)
       
    92         if source and source[-1] != '\n':
       
    93             source = source + '\n'
       
    94         text = self.editwin.text
       
    95         text.tag_remove("ERROR", "1.0", "end")
       
    96         try:
       
    97             try:
       
    98                 # If successful, return the compiled code
       
    99                 return compile(source, filename, "exec")
       
   100             except (SyntaxError, OverflowError), err:
       
   101                 try:
       
   102                     msg, (errorfilename, lineno, offset, line) = err
       
   103                     if not errorfilename:
       
   104                         err.args = msg, (filename, lineno, offset, line)
       
   105                         err.filename = filename
       
   106                     self.colorize_syntax_error(msg, lineno, offset)
       
   107                 except:
       
   108                     msg = "*** " + str(err)
       
   109                 self.errorbox("Syntax error",
       
   110                               "There's an error in your program:\n" + msg)
       
   111                 return False
       
   112         finally:
       
   113             shell.set_warning_stream(saved_stream)
       
   114 
       
   115     def colorize_syntax_error(self, msg, lineno, offset):
       
   116         text = self.editwin.text
       
   117         pos = "0.0 + %d lines + %d chars" % (lineno-1, offset-1)
       
   118         text.tag_add("ERROR", pos)
       
   119         char = text.get(pos)
       
   120         if char and char in IDENTCHARS:
       
   121             text.tag_add("ERROR", pos + " wordstart", pos)
       
   122         if '\n' == text.get(pos):   # error at line end
       
   123             text.mark_set("insert", pos)
       
   124         else:
       
   125             text.mark_set("insert", pos + "+1c")
       
   126         text.see(pos)
       
   127 
       
   128     def run_module_event(self, event):
       
   129         """Run the module after setting up the environment.
       
   130 
       
   131         First check the syntax.  If OK, make sure the shell is active and
       
   132         then transfer the arguments, set the run environment's working
       
   133         directory to the directory of the module being executed and also
       
   134         add that directory to its sys.path if not already included.
       
   135 
       
   136         """
       
   137         filename = self.getfilename()
       
   138         if not filename:
       
   139             return
       
   140         code = self.checksyntax(filename)
       
   141         if not code:
       
   142             return
       
   143         if not self.tabnanny(filename):
       
   144             return
       
   145         shell = self.shell
       
   146         interp = shell.interp
       
   147         if PyShell.use_subprocess:
       
   148             shell.restart_shell()
       
   149         dirname = os.path.dirname(filename)
       
   150         # XXX Too often this discards arguments the user just set...
       
   151         interp.runcommand("""if 1:
       
   152             _filename = %r
       
   153             import sys as _sys
       
   154             from os.path import basename as _basename
       
   155             if (not _sys.argv or
       
   156                 _basename(_sys.argv[0]) != _basename(_filename)):
       
   157                 _sys.argv = [_filename]
       
   158             import os as _os
       
   159             _os.chdir(%r)
       
   160             del _filename, _sys, _basename, _os
       
   161             \n""" % (filename, dirname))
       
   162         interp.prepend_syspath(filename)
       
   163         # XXX KBK 03Jul04 When run w/o subprocess, runtime warnings still
       
   164         #         go to __stderr__.  With subprocess, they go to the shell.
       
   165         #         Need to change streams in PyShell.ModifiedInterpreter.
       
   166         interp.runcode(code)
       
   167 
       
   168     def getfilename(self):
       
   169         """Get source filename.  If not saved, offer to save (or create) file
       
   170 
       
   171         The debugger requires a source file.  Make sure there is one, and that
       
   172         the current version of the source buffer has been saved.  If the user
       
   173         declines to save or cancels the Save As dialog, return None.
       
   174 
       
   175         If the user has configured IDLE for Autosave, the file will be
       
   176         silently saved if it already exists and is dirty.
       
   177 
       
   178         """
       
   179         filename = self.editwin.io.filename
       
   180         if not self.editwin.get_saved():
       
   181             autosave = idleConf.GetOption('main', 'General',
       
   182                                           'autosave', type='bool')
       
   183             if autosave and filename:
       
   184                 self.editwin.io.save(None)
       
   185             else:
       
   186                 reply = self.ask_save_dialog()
       
   187                 self.editwin.text.focus_set()
       
   188                 if reply == "ok":
       
   189                     self.editwin.io.save(None)
       
   190                     filename = self.editwin.io.filename
       
   191                 else:
       
   192                     filename = None
       
   193         return filename
       
   194 
       
   195     def ask_save_dialog(self):
       
   196         msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?"
       
   197         mb = tkMessageBox.Message(title="Save Before Run or Check",
       
   198                                   message=msg,
       
   199                                   icon=tkMessageBox.QUESTION,
       
   200                                   type=tkMessageBox.OKCANCEL,
       
   201                                   default=tkMessageBox.OK,
       
   202                                   master=self.editwin.text)
       
   203         return mb.show()
       
   204 
       
   205     def errorbox(self, title, message):
       
   206         # XXX This should really be a function of EditorWindow...
       
   207         tkMessageBox.showerror(title, message, master=self.editwin.text)
       
   208         self.editwin.text.focus_set()