diff options
Diffstat (limited to 'Tools/idle')
-rw-r--r-- | Tools/idle/ScriptBinding.py | 91 |
1 files changed, 82 insertions, 9 deletions
diff --git a/Tools/idle/ScriptBinding.py b/Tools/idle/ScriptBinding.py index 9af8236..aa46c68 100644 --- a/Tools/idle/ScriptBinding.py +++ b/Tools/idle/ScriptBinding.py @@ -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() |