Commit 8c95c27c authored by Guido van Rossum's avatar Guido van Rossum

Added a new command: Check module (Alt-F5) It does a full syntax check

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.
parent 772dd417
"""Extension to execute code outside the Python shell window. """Extension to execute code outside the Python shell window.
This adds two commands (to the Edit menu, until there's a separate This adds the following commands (to the Edit menu, until there's a
Python menu): 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 - Import module (F5) is equivalent to either import or reload of the
current module. The window must have been saved previously. The current module. The window must have been saved previously. The
...@@ -18,16 +21,29 @@ import os ...@@ -18,16 +21,29 @@ import os
import imp import imp
import tkMessageBox 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: class ScriptBinding:
keydefs = { keydefs = {
'<<check-module>>': ['<Alt-F5>', '<Meta-F5>'],
'<<import-module>>': ['<F5>'], '<<import-module>>': ['<F5>'],
'<<run-script>>': ['<Control-F5>'], '<<run-script>>': ['<Control-F5>'],
} }
menudefs = [ menudefs = [
('edit', [None, ('edit', [None,
('Check module', '<<check-module>>'),
('Import module', '<<import-module>>'), ('Import module', '<<import-module>>'),
('Run script', '<<run-script>>'), ('Run script', '<<run-script>>'),
] ]
...@@ -41,6 +57,59 @@ class ScriptBinding: ...@@ -41,6 +57,59 @@ class ScriptBinding:
self.flist = self.editwin.flist self.flist = self.editwin.flist
self.root = self.flist.root 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): def import_module_event(self, event):
filename = self.getfilename() filename = self.getfilename()
if not filename: if not filename:
...@@ -75,22 +144,26 @@ class ScriptBinding: ...@@ -75,22 +144,26 @@ class ScriptBinding:
interp = shell.interp interp = shell.interp
if (not sys.argv or if (not sys.argv or
os.path.basename(sys.argv[0]) != os.path.basename(filename)): os.path.basename(sys.argv[0]) != os.path.basename(filename)):
# XXX Too often this discards arguments the user just set...
sys.argv = [filename] sys.argv = [filename]
interp.execfile(filename) interp.execfile(filename)
def getfilename(self): def getfilename(self):
# Logic to make sure we have a saved filename # Logic to make sure we have a saved filename
# XXX Better logic would offer to save!
if not self.editwin.get_saved(): if not self.editwin.get_saved():
tkMessageBox.showerror("Not saved", self.errorbox("Not saved",
"Please save first!", "Please save first!")
master=self.editwin.text)
self.editwin.text.focus_set() self.editwin.text.focus_set()
return return
filename = self.editwin.io.filename filename = self.editwin.io.filename
if not filename: if not filename:
tkMessageBox.showerror("No file name", self.errorbox("No file name",
"This window has no file name", "This window has no file name")
master=self.editwin.text)
self.editwin.text.focus_set()
return return
return filename 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()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment