blob: cc265101a5a7de348d3ea10c61a30df4ff5f2f7e [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
20import sys
21import os
22import imp
23import tkMessageBox
24
25indent_message = """Error: Inconsistent indentation detected!
26
27This means that either:
28
Chui Tey5d2af632002-05-26 13:36:41 +0000291) your indentation is outright incorrect (easy to fix), or
David Scherer7aced172000-08-15 01:13:23 +000030
Chui Tey5d2af632002-05-26 13:36:41 +0000312) your indentation mixes tabs and spaces in a way that depends on \
David Scherer7aced172000-08-15 01:13:23 +000032how many spaces a tab is worth.
33
34To fix case 2, change all tabs to spaces by using Select All followed \
35by Untabify Region (both in the Edit menu)."""
36
Kurt B. Kaiser969de452002-06-12 03:28:57 +000037
38# XXX TBD Implement stop-execution KBK 11Jun02
David Scherer7aced172000-08-15 01:13:23 +000039class ScriptBinding:
Steven M. Gava42f6c642001-07-12 06:46:53 +000040
David Scherer7aced172000-08-15 01:13:23 +000041 menudefs = [
Kurt B. Kaiser969de452002-06-12 03:28:57 +000042 ('run', [None,
43# ('Check module', '<<check-module>>'),
David Scherer7aced172000-08-15 01:13:23 +000044 ('Run script', '<<run-script>>'),
45 ]
46 ),
47 ]
48
49 def __init__(self, editwin):
50 self.editwin = editwin
51 # Provide instance variables referenced by Debugger
52 # XXX This should be done differently
53 self.flist = self.editwin.flist
54 self.root = self.flist.root
55
56 def check_module_event(self, event):
57 filename = self.getfilename()
58 if not filename:
59 return
60 if not self.tabnanny(filename):
61 return
62 if not self.checksyntax(filename):
63 return
64
65 def tabnanny(self, filename):
66 import tabnanny
67 import tokenize
68 tabnanny.reset_globals()
69 f = open(filename, 'r')
70 try:
71 tokenize.tokenize(f.readline, tabnanny.tokeneater)
72 except tokenize.TokenError, msg:
73 self.errorbox("Token error",
74 "Token error:\n%s" % str(msg))
75 return 0
76 except tabnanny.NannyNag, nag:
77 # The error messages from tabnanny are too confusing...
78 self.editwin.gotoline(nag.get_lineno())
79 self.errorbox("Tab/space error", indent_message)
80 return 0
81 return 1
82
83 def checksyntax(self, filename):
84 f = open(filename, 'r')
85 source = f.read()
86 f.close()
87 if '\r' in source:
88 import re
89 source = re.sub(r"\r\n", "\n", source)
90 if source and source[-1] != '\n':
91 source = source + '\n'
92 try:
93 compile(source, filename, "exec")
94 except (SyntaxError, OverflowError), err:
95 try:
96 msg, (errorfilename, lineno, offset, line) = err
97 if not errorfilename:
98 err.args = msg, (filename, lineno, offset, line)
99 err.filename = filename
100 except:
101 lineno = None
102 msg = "*** " + str(err)
103 if lineno:
104 self.editwin.gotoline(lineno)
105 self.errorbox("Syntax error",
106 "There's an error in your program:\n" + msg)
107 return 1
108
David Scherer7aced172000-08-15 01:13:23 +0000109 def run_script_event(self, event):
110 filename = self.getfilename()
111 if not filename:
112 return
David Scherer7aced172000-08-15 01:13:23 +0000113 flist = self.editwin.flist
114 shell = flist.open_shell()
115 interp = shell.interp
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000116 if interp.tkconsole.executing:
117 interp.display_executing_dialog()
118 return
119 interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000120 # XXX Too often this discards arguments the user just set...
121 interp.runcommand("""if 1:
122 _filename = %s
123 import sys as _sys
124 from os.path import basename as _basename
125 if (not _sys.argv or
126 _basename(_sys.argv[0]) != _basename(_filename)):
Kurt B. Kaiserd694c1f2002-07-28 03:35:31 +0000127 # XXX 25 July 2002 KBK should this be sys.argv not _sys.argv?
Chui Tey5d2af632002-05-26 13:36:41 +0000128 _sys.argv = [_filename]
129 del _filename, _sys, _basename
130 \n""" % `filename`)
David Scherer7aced172000-08-15 01:13:23 +0000131 interp.execfile(filename)
132
133 def getfilename(self):
134 # Logic to make sure we have a saved filename
135 # XXX Better logic would offer to save!
136 if not self.editwin.get_saved():
Steven M. Gava42f6c642001-07-12 06:46:53 +0000137 name = (self.editwin.short_title() or
138 self.editwin.long_title() or
139 "Untitled")
David Scherer7aced172000-08-15 01:13:23 +0000140 self.errorbox("Not saved",
Steven M. Gava42f6c642001-07-12 06:46:53 +0000141 "The buffer for %s is not saved.\n" % name +
142 "Please save it first!")
David Scherer7aced172000-08-15 01:13:23 +0000143 self.editwin.text.focus_set()
144 return
145 filename = self.editwin.io.filename
146 if not filename:
147 self.errorbox("No file name",
148 "This window has no file name")
149 return
150 return filename
151
152 def errorbox(self, title, message):
153 # XXX This should really be a function of EditorWindow...
154 tkMessageBox.showerror(title, message, master=self.editwin.text)
155 self.editwin.text.focus_set()