blob: c24bf81204e62cc2a9ca9072b9bd403b0ec82b8b [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
David Scherer7aced172000-08-15 01:13:23 +000068 f = open(filename, 'r')
69 try:
Kurt B. Kaiser05bab1e2002-09-18 03:05:19 +000070 tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
David Scherer7aced172000-08-15 01:13:23 +000071 except tokenize.TokenError, msg:
72 self.errorbox("Token error",
73 "Token error:\n%s" % str(msg))
74 return 0
75 except tabnanny.NannyNag, nag:
76 # The error messages from tabnanny are too confusing...
77 self.editwin.gotoline(nag.get_lineno())
78 self.errorbox("Tab/space error", indent_message)
79 return 0
80 return 1
81
82 def checksyntax(self, filename):
83 f = open(filename, 'r')
84 source = f.read()
85 f.close()
86 if '\r' in source:
87 import re
88 source = re.sub(r"\r\n", "\n", source)
89 if source and source[-1] != '\n':
90 source = source + '\n'
91 try:
92 compile(source, filename, "exec")
93 except (SyntaxError, OverflowError), err:
94 try:
95 msg, (errorfilename, lineno, offset, line) = err
96 if not errorfilename:
97 err.args = msg, (filename, lineno, offset, line)
98 err.filename = filename
99 except:
100 lineno = None
101 msg = "*** " + str(err)
102 if lineno:
103 self.editwin.gotoline(lineno)
104 self.errorbox("Syntax error",
105 "There's an error in your program:\n" + msg)
106 return 1
107
David Scherer7aced172000-08-15 01:13:23 +0000108 def run_script_event(self, event):
109 filename = self.getfilename()
110 if not filename:
111 return
David Scherer7aced172000-08-15 01:13:23 +0000112 flist = self.editwin.flist
113 shell = flist.open_shell()
114 interp = shell.interp
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000115 if interp.tkconsole.executing:
116 interp.display_executing_dialog()
117 return
118 interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000119 # XXX Too often this discards arguments the user just set...
120 interp.runcommand("""if 1:
121 _filename = %s
122 import sys as _sys
123 from os.path import basename as _basename
124 if (not _sys.argv or
125 _basename(_sys.argv[0]) != _basename(_filename)):
Kurt B. Kaiserd694c1f2002-07-28 03:35:31 +0000126 # XXX 25 July 2002 KBK should this be sys.argv not _sys.argv?
Chui Tey5d2af632002-05-26 13:36:41 +0000127 _sys.argv = [_filename]
128 del _filename, _sys, _basename
129 \n""" % `filename`)
David Scherer7aced172000-08-15 01:13:23 +0000130 interp.execfile(filename)
131
132 def getfilename(self):
133 # Logic to make sure we have a saved filename
134 # XXX Better logic would offer to save!
135 if not self.editwin.get_saved():
Steven M. Gava42f6c642001-07-12 06:46:53 +0000136 name = (self.editwin.short_title() or
137 self.editwin.long_title() or
138 "Untitled")
David Scherer7aced172000-08-15 01:13:23 +0000139 self.errorbox("Not saved",
Steven M. Gava42f6c642001-07-12 06:46:53 +0000140 "The buffer for %s is not saved.\n" % name +
141 "Please save it first!")
David Scherer7aced172000-08-15 01:13:23 +0000142 self.editwin.text.focus_set()
143 return
144 filename = self.editwin.io.filename
145 if not filename:
146 self.errorbox("No file name",
147 "This window has no file name")
148 return
149 return filename
150
151 def errorbox(self, title, message):
152 # XXX This should really be a function of EditorWindow...
153 tkMessageBox.showerror(title, message, master=self.editwin.text)
154 self.editwin.text.focus_set()