[Python-checkins] CVS: python/dist/src/Tools/idle ScriptBinding.py,1.7,1.8

Guido van Rossum guido@cnri.reston.va.us
Mon, 21 Feb 2000 19:20:01 -0500 (EST)


Update of /projects/cvsroot/python/dist/src/Tools/idle
In directory eric:/projects/python/develop/guido/src/Tools/idle

Modified Files:
	ScriptBinding.py 
Log Message:
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.


Index: ScriptBinding.py
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Tools/idle/ScriptBinding.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -r1.7 -r1.8
*** ScriptBinding.py	1999/06/01 18:18:27	1.7
--- ScriptBinding.py	2000/02/22 00:19:58	1.8
***************
*** 1,7 ****
  """Extension to execute code outside the Python shell window.
  
! This adds two commands (to the Edit menu, until there's a separate
! Python menu):
  
  - Import module (F5) is equivalent to either import or reload of the
  current module.  The window must have been saved previously. The
--- 1,10 ----
  """Extension to execute code outside the Python shell window.
  
! 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
***************
*** 19,26 ****
--- 22,41 ----
  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>'],
***************
*** 29,32 ****
--- 44,48 ----
      menudefs = [
          ('edit', [None,
+                   ('Check module', '<<check-module>>'),
                    ('Import module', '<<import-module>>'),
                    ('Run script', '<<run-script>>'),
***************
*** 42,45 ****
--- 58,114 ----
          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()
***************
*** 76,79 ****
--- 145,149 ----
          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)
***************
*** 81,96 ****
      def getfilename(self):
          # Logic to make sure we have a saved filename
          if not self.editwin.get_saved():
!             tkMessageBox.showerror("Not saved",
!                                    "Please save first!",
!                                    master=self.editwin.text)
              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()
              return
          return filename
--- 151,169 ----
      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():
!             self.errorbox("Not saved",
!                           "Please save first!")
              self.editwin.text.focus_set()
              return
          filename = self.editwin.io.filename
          if not filename:
!             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()