blob: fe8947feab435d11d53a5de731b174c1078f2582 [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,
Kurt B. Kaiser6eadc6c2002-12-03 23:09:23 +000040 ('Check module', '<<check-module>>'),
41 ('Run script', '<<run-script>>'), ]), ]
David Scherer7aced172000-08-15 01:13:23 +000042
43 def __init__(self, editwin):
44 self.editwin = editwin
45 # Provide instance variables referenced by Debugger
46 # XXX This should be done differently
47 self.flist = self.editwin.flist
48 self.root = self.flist.root
49
50 def check_module_event(self, event):
51 filename = self.getfilename()
52 if not filename:
53 return
54 if not self.tabnanny(filename):
55 return
56 if not self.checksyntax(filename):
57 return
58
59 def tabnanny(self, filename):
60 import tabnanny
61 import tokenize
David Scherer7aced172000-08-15 01:13:23 +000062 f = open(filename, 'r')
63 try:
Kurt B. Kaiser05bab1e2002-09-18 03:05:19 +000064 tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
David Scherer7aced172000-08-15 01:13:23 +000065 except tokenize.TokenError, msg:
Neal Norwitz6453c1f2002-11-30 19:18:46 +000066 self.errorbox("Token error", "Token error:\n%s" % msg)
67 return False
David Scherer7aced172000-08-15 01:13:23 +000068 except tabnanny.NannyNag, nag:
69 # The error messages from tabnanny are too confusing...
70 self.editwin.gotoline(nag.get_lineno())
71 self.errorbox("Tab/space error", indent_message)
Neal Norwitz6453c1f2002-11-30 19:18:46 +000072 return False
73 return True
David Scherer7aced172000-08-15 01:13:23 +000074
75 def checksyntax(self, filename):
76 f = open(filename, 'r')
77 source = f.read()
78 f.close()
79 if '\r' in source:
80 import re
81 source = re.sub(r"\r\n", "\n", source)
82 if source and source[-1] != '\n':
83 source = source + '\n'
84 try:
85 compile(source, filename, "exec")
86 except (SyntaxError, OverflowError), err:
87 try:
88 msg, (errorfilename, lineno, offset, line) = err
89 if not errorfilename:
90 err.args = msg, (filename, lineno, offset, line)
91 err.filename = filename
92 except:
93 lineno = None
94 msg = "*** " + str(err)
95 if lineno:
96 self.editwin.gotoline(lineno)
97 self.errorbox("Syntax error",
98 "There's an error in your program:\n" + msg)
Neal Norwitz6453c1f2002-11-30 19:18:46 +000099 return True
David Scherer7aced172000-08-15 01:13:23 +0000100
David Scherer7aced172000-08-15 01:13:23 +0000101 def run_script_event(self, event):
102 filename = self.getfilename()
103 if not filename:
104 return
David Scherer7aced172000-08-15 01:13:23 +0000105 flist = self.editwin.flist
106 shell = flist.open_shell()
107 interp = shell.interp
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000108 if interp.tkconsole.executing:
109 interp.display_executing_dialog()
110 return
111 interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000112 # XXX Too often this discards arguments the user just set...
113 interp.runcommand("""if 1:
114 _filename = %s
115 import sys as _sys
116 from os.path import basename as _basename
117 if (not _sys.argv or
118 _basename(_sys.argv[0]) != _basename(_filename)):
Kurt B. Kaiserd694c1f2002-07-28 03:35:31 +0000119 # XXX 25 July 2002 KBK should this be sys.argv not _sys.argv?
Chui Tey5d2af632002-05-26 13:36:41 +0000120 _sys.argv = [_filename]
121 del _filename, _sys, _basename
122 \n""" % `filename`)
David Scherer7aced172000-08-15 01:13:23 +0000123 interp.execfile(filename)
124
125 def getfilename(self):
126 # Logic to make sure we have a saved filename
127 # XXX Better logic would offer to save!
128 if not self.editwin.get_saved():
Steven M. Gava42f6c642001-07-12 06:46:53 +0000129 name = (self.editwin.short_title() or
130 self.editwin.long_title() or
131 "Untitled")
David Scherer7aced172000-08-15 01:13:23 +0000132 self.errorbox("Not saved",
Steven M. Gava42f6c642001-07-12 06:46:53 +0000133 "The buffer for %s is not saved.\n" % name +
134 "Please save it first!")
David Scherer7aced172000-08-15 01:13:23 +0000135 self.editwin.text.focus_set()
136 return
137 filename = self.editwin.io.filename
138 if not filename:
139 self.errorbox("No file name",
140 "This window has no file name")
141 return
142 return filename
143
144 def errorbox(self, title, message):
145 # XXX This should really be a function of EditorWindow...
146 tkMessageBox.showerror(title, message, master=self.editwin.text)
147 self.editwin.text.focus_set()