blob: 4a425765d7388ed31a7016872db1479d77cc9e99 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001"""Extension to execute code outside the Python shell window.
2
Kurt B. Kaiser969de452002-06-12 03:28:57 +00003This adds the following commands:
David Scherer7aced172000-08-15 01:13:23 +00004
Kurt B. Kaiser969de452002-06-12 03:28:57 +00005- Check module does a full syntax check of the current module.
David Scherer7aced172000-08-15 01:13:23 +00006It also runs the tabnanny to catch any inconsistent tabs.
7
Kurt B. Kaiser63857a42002-09-05 02:31:20 +00008- Run module executes the module's code in the __main__ namespace. The window
9must have been saved previously. The module is added to sys.modules, and is
10also added to the __main__ namespace.
David Scherer7aced172000-08-15 01:13:23 +000011
Chui Tey5d2af632002-05-26 13:36:41 +000012XXX Redesign this interface (yet again) as follows:
13
14- Present a dialog box for ``Run script''
15
16- Allow specify command line arguments in the dialog box
17
David Scherer7aced172000-08-15 01:13:23 +000018"""
19
David Scherer7aced172000-08-15 01:13:23 +000020import tkMessageBox
21
22indent_message = """Error: Inconsistent indentation detected!
23
24This means that either:
25
Chui Tey5d2af632002-05-26 13:36:41 +0000261) your indentation is outright incorrect (easy to fix), or
David Scherer7aced172000-08-15 01:13:23 +000027
Chui Tey5d2af632002-05-26 13:36:41 +0000282) your indentation mixes tabs and spaces in a way that depends on \
David Scherer7aced172000-08-15 01:13:23 +000029how many spaces a tab is worth.
30
31To fix case 2, change all tabs to spaces by using Select All followed \
32by Untabify Region (both in the Edit menu)."""
33
Kurt B. Kaiser969de452002-06-12 03:28:57 +000034
35# XXX TBD Implement stop-execution KBK 11Jun02
David Scherer7aced172000-08-15 01:13:23 +000036class ScriptBinding:
Steven M. Gava42f6c642001-07-12 06:46:53 +000037
David Scherer7aced172000-08-15 01:13:23 +000038 menudefs = [
Kurt B. Kaiser969de452002-06-12 03:28:57 +000039 ('run', [None,
40# ('Check module', '<<check-module>>'),
David Scherer7aced172000-08-15 01:13:23 +000041 ('Run script', '<<run-script>>'),
42 ]
43 ),
44 ]
45
46 def __init__(self, editwin):
47 self.editwin = editwin
48 # Provide instance variables referenced by Debugger
49 # XXX This should be done differently
50 self.flist = self.editwin.flist
51 self.root = self.flist.root
52
53 def check_module_event(self, event):
54 filename = self.getfilename()
55 if not filename:
56 return
57 if not self.tabnanny(filename):
58 return
59 if not self.checksyntax(filename):
60 return
61
62 def tabnanny(self, filename):
63 import tabnanny
64 import tokenize
David Scherer7aced172000-08-15 01:13:23 +000065 f = open(filename, 'r')
66 try:
Kurt B. Kaiser05bab1e2002-09-18 03:05:19 +000067 tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
David Scherer7aced172000-08-15 01:13:23 +000068 except tokenize.TokenError, msg:
Neal Norwitz6453c1f2002-11-30 19:18:46 +000069 self.errorbox("Token error", "Token error:\n%s" % msg)
70 return False
David Scherer7aced172000-08-15 01:13:23 +000071 except tabnanny.NannyNag, nag:
72 # The error messages from tabnanny are too confusing...
73 self.editwin.gotoline(nag.get_lineno())
74 self.errorbox("Tab/space error", indent_message)
Neal Norwitz6453c1f2002-11-30 19:18:46 +000075 return False
76 return True
David Scherer7aced172000-08-15 01:13:23 +000077
78 def checksyntax(self, filename):
79 f = open(filename, 'r')
80 source = f.read()
81 f.close()
82 if '\r' in source:
83 import re
84 source = re.sub(r"\r\n", "\n", source)
85 if source and source[-1] != '\n':
86 source = source + '\n'
87 try:
88 compile(source, filename, "exec")
89 except (SyntaxError, OverflowError), err:
90 try:
91 msg, (errorfilename, lineno, offset, line) = err
92 if not errorfilename:
93 err.args = msg, (filename, lineno, offset, line)
94 err.filename = filename
95 except:
96 lineno = None
97 msg = "*** " + str(err)
98 if lineno:
99 self.editwin.gotoline(lineno)
100 self.errorbox("Syntax error",
101 "There's an error in your program:\n" + msg)
Neal Norwitz6453c1f2002-11-30 19:18:46 +0000102 return True
David Scherer7aced172000-08-15 01:13:23 +0000103
David Scherer7aced172000-08-15 01:13:23 +0000104 def run_script_event(self, event):
105 filename = self.getfilename()
106 if not filename:
107 return
David Scherer7aced172000-08-15 01:13:23 +0000108 flist = self.editwin.flist
109 shell = flist.open_shell()
110 interp = shell.interp
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000111 if interp.tkconsole.executing:
112 interp.display_executing_dialog()
113 return
114 interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000115 # XXX Too often this discards arguments the user just set...
116 interp.runcommand("""if 1:
117 _filename = %s
118 import sys as _sys
119 from os.path import basename as _basename
120 if (not _sys.argv or
121 _basename(_sys.argv[0]) != _basename(_filename)):
Kurt B. Kaiserd694c1f2002-07-28 03:35:31 +0000122 # XXX 25 July 2002 KBK should this be sys.argv not _sys.argv?
Chui Tey5d2af632002-05-26 13:36:41 +0000123 _sys.argv = [_filename]
124 del _filename, _sys, _basename
125 \n""" % `filename`)
David Scherer7aced172000-08-15 01:13:23 +0000126 interp.execfile(filename)
127
128 def getfilename(self):
129 # Logic to make sure we have a saved filename
130 # XXX Better logic would offer to save!
131 if not self.editwin.get_saved():
Steven M. Gava42f6c642001-07-12 06:46:53 +0000132 name = (self.editwin.short_title() or
133 self.editwin.long_title() or
134 "Untitled")
David Scherer7aced172000-08-15 01:13:23 +0000135 self.errorbox("Not saved",
Steven M. Gava42f6c642001-07-12 06:46:53 +0000136 "The buffer for %s is not saved.\n" % name +
137 "Please save it first!")
David Scherer7aced172000-08-15 01:13:23 +0000138 self.editwin.text.focus_set()
139 return
140 filename = self.editwin.io.filename
141 if not filename:
142 self.errorbox("No file name",
143 "This window has no file name")
144 return
145 return filename
146
147 def errorbox(self, title, message):
148 # XXX This should really be a function of EditorWindow...
149 tkMessageBox.showerror(title, message, master=self.editwin.text)
150 self.editwin.text.focus_set()