]> granicus.if.org Git - python/commitdiff
Added a new command: Check module (Alt-F5) It does a full syntax check
authorGuido van Rossum <guido@python.org>
Tue, 22 Feb 2000 00:19:58 +0000 (00:19 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 22 Feb 2000 00:19:58 +0000 (00:19 +0000)
of the current module.  It also runs the tabnanny to catch any
inconsistent tabs.

Also did a little bit of refactoring: added an errorbox() method to
simplify the display of error dialogs.

Tools/idle/ScriptBinding.py

index 9af8236ffd04984e2ea9455a6f3cef9932c9dd35..aa46c680b8a7ca309f300bf875342741cfecfaca 100644 (file)
@@ -1,7 +1,10 @@
 """Extension to execute code outside the Python shell window.
 
-This adds two commands (to the Edit menu, until there's a separate
-Python menu):
+This adds the following commands (to the Edit menu, until there's a
+separate Python menu):
+
+- Check module (Alt-F5) does a full syntax check of the current module.
+It also runs the tabnanny to catch any inconsistent tabs.
 
 - Import module (F5) is equivalent to either import or reload of the
 current module.  The window must have been saved previously. The
@@ -18,16 +21,29 @@ import os
 import imp
 import tkMessageBox
 
+indent_message = """Error: Inconsistent indentation detected!
+
+This means that either:
+
+(1) your indentation is outright incorrect (easy to fix), or
+
+(2) your indentation mixes tabs and spaces in a way that depends on \
+how many spaces a tab is worth.
+
+To fix case 2, change all tabs to spaces by using Select All followed \
+by Untabify Region (both in the Edit menu)."""
 
 class ScriptBinding:
     
     keydefs = {
+        '<<check-module>>': ['<Alt-F5>', '<Meta-F5>'],
         '<<import-module>>': ['<F5>'],
         '<<run-script>>': ['<Control-F5>'],
     }
     
     menudefs = [
         ('edit', [None,
+                  ('Check module', '<<check-module>>'),
                   ('Import module', '<<import-module>>'),
                   ('Run script', '<<run-script>>'),
                  ]
@@ -41,6 +57,59 @@ class ScriptBinding:
         self.flist = self.editwin.flist
         self.root = self.flist.root
 
+    def check_module_event(self, event):
+        filename = self.getfilename()
+        if not filename:
+            return
+        if not self.tabnanny(filename):
+            return
+        if not self.checksyntax(filename):
+            return
+
+    def tabnanny(self, filename):
+        import tabnanny
+        import tokenize
+        tabnanny.reset_globals()
+        f = open(filename, 'r')
+        try:
+            tokenize.tokenize(f.readline, tabnanny.tokeneater)
+        except tokenize.TokenError, msg:
+            self.errorbox("Token error",
+                          "Token error:\n%s" % str(msg))
+            return 0
+        except tabnanny.NannyNag, nag:
+            # The error messages from tabnanny are too confusing...
+            self.editwin.gotoline(nag.get_lineno())
+            self.errorbox("Tab/space error", indent_message)
+            return 0
+        return 1
+
+    def checksyntax(self, filename):
+        f = open(filename, 'r')
+        source = f.read()
+        f.close()
+        if '\r' in source:
+            import re
+            source = re.sub(r"\r\n", "\n", source)
+        if source and source[-1] != '\n':
+            source = source + '\n'
+        try:
+            compile(source, filename, "exec")
+        except (SyntaxError, OverflowError), err:
+            try:
+                msg, (errorfilename, lineno, offset, line) = err
+                if not errorfilename:
+                    err.args = msg, (filename, lineno, offset, line)
+                    err.filename = filename
+            except:
+                lineno = None
+                msg = "*** " + str(err)
+            if lineno:
+                self.editwin.gotoline(lineno)
+            self.errorbox("Syntax error",
+                          "There's an error in your program:\n" + msg)
+        return 1
+
     def import_module_event(self, event):
         filename = self.getfilename()
         if not filename:
@@ -75,22 +144,26 @@ class ScriptBinding:
         interp = shell.interp
         if (not sys.argv or
             os.path.basename(sys.argv[0]) != os.path.basename(filename)):
+            # XXX Too often this discards arguments the user just set...
             sys.argv = [filename]
         interp.execfile(filename)
 
     def getfilename(self):
         # Logic to make sure we have a saved filename
+        # XXX Better logic would offer to save!
         if not self.editwin.get_saved():
-            tkMessageBox.showerror("Not saved",
-                                   "Please save first!",
-                                   master=self.editwin.text)
+            self.errorbox("Not saved",
+                          "Please save first!")
             self.editwin.text.focus_set()
             return
         filename = self.editwin.io.filename
         if not filename:
-            tkMessageBox.showerror("No file name",
-                                   "This window has no file name",
-                                   master=self.editwin.text)
-            self.editwin.text.focus_set()
+            self.errorbox("No file name",
+                          "This window has no file name")
             return
         return filename
+
+    def errorbox(self, title, message):
+        # XXX This should really be a function of EditorWindow...
+        tkMessageBox.showerror(title, message, master=self.editwin.text)
+        self.editwin.text.focus_set()