Updated for hfsplus module, new gusi libs.
[python/dscho.git] / Tools / idle / ScriptBinding.py
blob4071681b7fd16864b7bcb1ae1523c81f53981233
1 """Extension to execute code outside the Python shell window.
3 This adds the following commands (to the Edit menu, until there's a
4 separate Python menu):
6 - Check module (Alt-F5) does a full syntax check of the current module.
7 It also runs the tabnanny to catch any inconsistent tabs.
9 - Import module (F5) is equivalent to either import or reload of the
10 current module. The window must have been saved previously. The
11 module is added to sys.modules, and is also added to the __main__
12 namespace. Output goes to the shell window.
14 - Run module (Control-F5) does the same but executes the module's
15 code in the __main__ namespace.
17 """
19 import sys
20 import os
21 import imp
22 import tkMessageBox
24 indent_message = """Error: Inconsistent indentation detected!
26 This means that either:
28 (1) your indentation is outright incorrect (easy to fix), or
30 (2) your indentation mixes tabs and spaces in a way that depends on \
31 how many spaces a tab is worth.
33 To fix case 2, change all tabs to spaces by using Select All followed \
34 by Untabify Region (both in the Edit menu)."""
36 class ScriptBinding:
38 keydefs = {
39 '<<check-module>>': ['<Alt-F5>', '<Meta-F5>'],
40 '<<import-module>>': ['<F5>'],
41 '<<run-script>>': ['<Control-F5>'],
44 menudefs = [
45 ('edit', [None,
46 ('Check module', '<<check-module>>'),
47 ('Import module', '<<import-module>>'),
48 ('Run script', '<<run-script>>'),
53 def __init__(self, editwin):
54 self.editwin = editwin
55 # Provide instance variables referenced by Debugger
56 # XXX This should be done differently
57 self.flist = self.editwin.flist
58 self.root = self.flist.root
60 def check_module_event(self, event):
61 filename = self.getfilename()
62 if not filename:
63 return
64 if not self.tabnanny(filename):
65 return
66 if not self.checksyntax(filename):
67 return
69 def tabnanny(self, filename):
70 import tabnanny
71 import tokenize
72 f = open(filename, 'r')
73 try:
74 tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
75 except tokenize.TokenError, msg:
76 self.errorbox("Token error",
77 "Token error:\n%s" % str(msg))
78 return 0
79 except tabnanny.NannyNag, nag:
80 # The error messages from tabnanny are too confusing...
81 self.editwin.gotoline(nag.get_lineno())
82 self.errorbox("Tab/space error", indent_message)
83 return 0
84 return 1
86 def checksyntax(self, filename):
87 f = open(filename, 'r')
88 source = f.read()
89 f.close()
90 if '\r' in source:
91 import re
92 source = re.sub(r"\r\n", "\n", source)
93 if source and source[-1] != '\n':
94 source = source + '\n'
95 try:
96 compile(source, filename, "exec")
97 except (SyntaxError, OverflowError), err:
98 try:
99 msg, (errorfilename, lineno, offset, line) = err
100 if not errorfilename:
101 err.args = msg, (filename, lineno, offset, line)
102 err.filename = filename
103 except:
104 lineno = None
105 msg = "*** " + str(err)
106 if lineno:
107 self.editwin.gotoline(lineno)
108 self.errorbox("Syntax error",
109 "There's an error in your program:\n" + msg)
110 return 1
112 def import_module_event(self, event):
113 filename = self.getfilename()
114 if not filename:
115 return
117 modname, ext = os.path.splitext(os.path.basename(filename))
118 if sys.modules.has_key(modname):
119 mod = sys.modules[modname]
120 else:
121 mod = imp.new_module(modname)
122 sys.modules[modname] = mod
123 mod.__file__ = filename
124 setattr(sys.modules['__main__'], modname, mod)
126 dir = os.path.dirname(filename)
127 dir = os.path.normpath(os.path.abspath(dir))
128 if dir not in sys.path:
129 sys.path.insert(0, dir)
131 flist = self.editwin.flist
132 shell = flist.open_shell()
133 interp = shell.interp
134 interp.runcode("reload(%s)" % modname)
136 def run_script_event(self, event):
137 filename = self.getfilename()
138 if not filename:
139 return
141 flist = self.editwin.flist
142 shell = flist.open_shell()
143 interp = shell.interp
144 if (not sys.argv or
145 os.path.basename(sys.argv[0]) != os.path.basename(filename)):
146 # XXX Too often this discards arguments the user just set...
147 sys.argv = [filename]
148 interp.execfile(filename)
150 def getfilename(self):
151 # Logic to make sure we have a saved filename
152 # XXX Better logic would offer to save!
153 if not self.editwin.get_saved():
154 name = (self.editwin.short_title() or
155 self.editwin.long_title() or
156 "Untitled")
157 self.errorbox("Not saved",
158 "The buffer for %s is not saved.\n" % name +
159 "Please save it first!")
160 self.editwin.text.focus_set()
161 return
162 filename = self.editwin.io.filename
163 if not filename:
164 self.errorbox("No file name",
165 "This window has no file name")
166 return
167 return filename
169 def errorbox(self, title, message):
170 # XXX This should really be a function of EditorWindow...
171 tkMessageBox.showerror(title, message, master=self.editwin.text)
172 self.editwin.text.focus_set()