| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  | """Extension to execute code outside the Python shell window.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  | 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. | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-04-22 22:27:40 +00:00
										 |  |  | - Import module (F5) is equivalent to either import or reload of the | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  | current module.  The window must have been saved previously. The | 
					
						
							| 
									
										
										
										
											1999-04-22 22:27:40 +00:00
										 |  |  | module is added to sys.modules, and is also added to the __main__ | 
					
						
							|  |  |  | namespace.  Output goes to the shell window. | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-04-22 22:27:40 +00:00
										 |  |  | - Run module (Control-F5) does the same but executes the module's | 
					
						
							|  |  |  | code in the __main__ namespace. | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | import os | 
					
						
							|  |  |  | import imp | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  | import tkMessageBox | 
					
						
							| 
									
										
										
										
											1999-03-29 14:52:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  | 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)."""
 | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ScriptBinding: | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  |      | 
					
						
							|  |  |  |     keydefs = { | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  |         '<<check-module>>': ['<Alt-F5>', '<Meta-F5>'], | 
					
						
							| 
									
										
										
										
											1999-04-22 22:27:40 +00:00
										 |  |  |         '<<import-module>>': ['<F5>'], | 
					
						
							|  |  |  |         '<<run-script>>': ['<Control-F5>'], | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     menudefs = [ | 
					
						
							|  |  |  |         ('edit', [None, | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  |                   ('Check module', '<<check-module>>'), | 
					
						
							| 
									
										
										
										
											1999-04-22 22:27:40 +00:00
										 |  |  |                   ('Import module', '<<import-module>>'), | 
					
						
							|  |  |  |                   ('Run script', '<<run-script>>'), | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  |                  ] | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |     ] | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, editwin): | 
					
						
							|  |  |  |         self.editwin = editwin | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  |         # Provide instance variables referenced by Debugger | 
					
						
							|  |  |  |         # XXX This should be done differently | 
					
						
							|  |  |  |         self.flist = self.editwin.flist | 
					
						
							|  |  |  |         self.root = self.flist.root | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  |     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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-04-22 22:27:40 +00:00
										 |  |  |     def import_module_event(self, event): | 
					
						
							|  |  |  |         filename = self.getfilename() | 
					
						
							|  |  |  |         if not filename: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         modname, ext = os.path.splitext(os.path.basename(filename)) | 
					
						
							|  |  |  |         if sys.modules.has_key(modname): | 
					
						
							|  |  |  |             mod = sys.modules[modname] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             mod = imp.new_module(modname) | 
					
						
							|  |  |  |             sys.modules[modname] = mod | 
					
						
							|  |  |  |         mod.__file__ = filename | 
					
						
							|  |  |  |         setattr(sys.modules['__main__'], modname, mod) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dir = os.path.dirname(filename) | 
					
						
							|  |  |  |         dir = os.path.normpath(os.path.abspath(dir)) | 
					
						
							|  |  |  |         if dir not in sys.path: | 
					
						
							|  |  |  |             sys.path.insert(0, dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         flist = self.editwin.flist | 
					
						
							|  |  |  |         shell = flist.open_shell() | 
					
						
							|  |  |  |         interp = shell.interp | 
					
						
							|  |  |  |         interp.runcode("reload(%s)" % modname) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def run_script_event(self, event): | 
					
						
							|  |  |  |         filename = self.getfilename() | 
					
						
							|  |  |  |         if not filename: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         flist = self.editwin.flist | 
					
						
							|  |  |  |         shell = flist.open_shell() | 
					
						
							|  |  |  |         interp = shell.interp | 
					
						
							| 
									
										
										
										
											1999-06-01 18:18:27 +00:00
										 |  |  |         if (not sys.argv or | 
					
						
							|  |  |  |             os.path.basename(sys.argv[0]) != os.path.basename(filename)): | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  |             # XXX Too often this discards arguments the user just set... | 
					
						
							| 
									
										
										
										
											1999-06-01 18:18:27 +00:00
										 |  |  |             sys.argv = [filename] | 
					
						
							| 
									
										
										
										
											1999-04-22 22:27:40 +00:00
										 |  |  |         interp.execfile(filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getfilename(self): | 
					
						
							|  |  |  |         # Logic to make sure we have a saved filename | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  |         # XXX Better logic would offer to save! | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  |         if not self.editwin.get_saved(): | 
					
						
							| 
									
										
										
										
											2000-09-15 15:45:57 +00:00
										 |  |  |             name = (self.editwin.short_title() or | 
					
						
							|  |  |  |                     self.editwin.long_title() or | 
					
						
							|  |  |  |                     "Untitled") | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  |             self.errorbox("Not saved", | 
					
						
							| 
									
										
										
										
											2000-09-15 15:45:57 +00:00
										 |  |  |                           "The buffer for %s is not saved.\n" % name + | 
					
						
							|  |  |  |                           "Please save it first!") | 
					
						
							| 
									
										
										
										
											1999-01-09 05:00:17 +00:00
										 |  |  |             self.editwin.text.focus_set() | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  |         filename = self.editwin.io.filename | 
					
						
							|  |  |  |         if not filename: | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  |             self.errorbox("No file name", | 
					
						
							|  |  |  |                           "This window has no file name") | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											1999-04-22 22:27:40 +00:00
										 |  |  |         return filename | 
					
						
							| 
									
										
										
										
											2000-02-22 00:19:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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() |