blob: 0ee70d9f86b2bf7e3c2d1ff629af0a06efa7c791 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001#! /usr/bin/env python
2
David Scherer7aced172000-08-15 01:13:23 +00003import os
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +00004import os.path
David Scherer7aced172000-08-15 01:13:23 +00005import sys
6import string
7import getopt
8import re
Chui Tey5d2af632002-05-26 13:36:41 +00009import socket
10import time
Kurt B. Kaiser003091c2003-02-17 18:57:16 +000011import threading
Chui Tey5d2af632002-05-26 13:36:41 +000012import traceback
Kurt B. Kaiser62833982002-09-18 17:07:05 +000013import types
Kurt B. Kaiser0930c432002-12-06 21:45:24 +000014import exceptions
David Scherer7aced172000-08-15 01:13:23 +000015
16import linecache
17from code import InteractiveInterpreter
18
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +000019try:
20 from Tkinter import *
21except ImportError:
22 print>>sys.__stderr__, "** IDLE can't import Tkinter. " \
23 "Your Python may not be configured for Tk. **"
24 sys.exit(1)
David Scherer7aced172000-08-15 01:13:23 +000025import tkMessageBox
26
27from EditorWindow import EditorWindow, fixwordbreaks
28from FileList import FileList
29from ColorDelegator import ColorDelegator
30from UndoDelegator import UndoDelegator
Kurt B. Kaiser969de452002-06-12 03:28:57 +000031from OutputWindow import OutputWindow
Steven M. Gava99300612001-11-04 07:03:08 +000032from configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000033import idlever
34
Chui Tey5d2af632002-05-26 13:36:41 +000035import rpc
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +000036import Debugger
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000037import RemoteDebugger
Chui Tey5d2af632002-05-26 13:36:41 +000038
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000039IDENTCHARS = string.ascii_letters + string.digits + "_"
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000040LOCALHOST = '127.0.0.1'
Kurt B. Kaiserb9764192002-09-23 04:10:37 +000041
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000042try:
43 from signal import SIGTERM
44except ImportError:
45 SIGTERM = 15
46
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000047# Override warnings module to write to warning_stream. Initialize to send IDLE
48# internal warnings to the console. ScriptBinding.check_syntax() will
49# temporarily redirect the stream to the shell window to display warnings when
50# checking user's code.
51global warning_stream
52warning_stream = sys.__stderr__
Chui Tey5d2af632002-05-26 13:36:41 +000053try:
54 import warnings
55except ImportError:
56 pass
57else:
58 def idle_showwarning(message, category, filename, lineno):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000059 file = warning_stream
60 try:
61 file.write(warnings.formatwarning(message, category, filename, lineno))
62 except IOError:
63 pass ## file (probably __stderr__) is invalid, warning dropped.
Chui Tey5d2af632002-05-26 13:36:41 +000064 warnings.showwarning = idle_showwarning
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000065 def idle_formatwarning(message, category, filename, lineno):
66 """Format warnings the IDLE way"""
67 s = "\nWarning (from warnings module):\n"
68 s += ' File \"%s\", line %s\n' % (filename, lineno)
69 line = linecache.getline(filename, lineno).strip()
70 if line:
71 s += " %s\n" % line
72 s += "%s: %s\n>>> " % (category.__name__, message)
73 return s
74 warnings.formatwarning = idle_formatwarning
Chui Tey5d2af632002-05-26 13:36:41 +000075
Kurt B. Kaiser81885592002-11-29 22:10:53 +000076def extended_linecache_checkcache(orig_checkcache=linecache.checkcache):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000077 """Extend linecache.checkcache to preserve the <pyshell#...> entries
78
Kurt B. Kaiser81885592002-11-29 22:10:53 +000079 Rather than repeating the linecache code, patch it to save the pyshell#
80 entries, call the original linecache.checkcache(), and then restore the
81 saved entries. Assigning the orig_checkcache keyword arg freezes its value
82 at definition time to the (original) method linecache.checkcache(), i.e.
83 makes orig_checkcache lexical.
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000084
85 """
David Scherer7aced172000-08-15 01:13:23 +000086 cache = linecache.cache
87 save = {}
88 for filename in cache.keys():
89 if filename[:1] + filename[-1:] == '<>':
90 save[filename] = cache[filename]
91 orig_checkcache()
92 cache.update(save)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000093
Kurt B. Kaiser81885592002-11-29 22:10:53 +000094# Patch linecache.checkcache():
95linecache.checkcache = extended_linecache_checkcache
David Scherer7aced172000-08-15 01:13:23 +000096
Kurt B. Kaiser45186c42002-10-23 04:48:08 +000097
David Scherer7aced172000-08-15 01:13:23 +000098class PyShellEditorWindow(EditorWindow):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +000099 "Regular text edit window when a shell is present"
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000100
David Scherer7aced172000-08-15 01:13:23 +0000101 def __init__(self, *args):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000102 self.breakpoints = []
Raymond Hettinger931237e2003-07-09 18:48:24 +0000103 EditorWindow.__init__(self, *args)
David Scherer7aced172000-08-15 01:13:23 +0000104 self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000105 self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here)
David Scherer7aced172000-08-15 01:13:23 +0000106 self.text.bind("<<open-python-shell>>", self.flist.open_shell)
107
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000108 self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(),
109 'breakpoints.lst')
Chui Teya2adb0f2002-11-04 22:14:54 +0000110 # whenever a file is changed, restore breakpoints
111 if self.io.filename: self.restore_file_breaks()
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000112 def filename_changed_hook(old_hook=self.io.filename_change_hook,
113 self=self):
Chui Teya2adb0f2002-11-04 22:14:54 +0000114 self.restore_file_breaks()
115 old_hook()
116 self.io.set_filename_change_hook(filename_changed_hook)
117
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000118 rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
119 ("Clear Breakpoint", "<<clear-breakpoint-here>>")]
David Scherer7aced172000-08-15 01:13:23 +0000120
Chui Teya2adb0f2002-11-04 22:14:54 +0000121 def set_breakpoint(self, lineno):
122 text = self.text
123 filename = self.io.filename
124 text.tag_add("BREAK", "%d.0" % lineno, "%d.0" % (lineno+1))
125 try:
126 i = self.breakpoints.index(lineno)
127 except ValueError: # only add if missing, i.e. do once
128 self.breakpoints.append(lineno)
129 try: # update the subprocess debugger
130 debug = self.flist.pyshell.interp.debugger
131 debug.set_breakpoint_here(filename, lineno)
132 except: # but debugger may not be active right now....
133 pass
134
David Scherer7aced172000-08-15 01:13:23 +0000135 def set_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000136 text = self.text
137 filename = self.io.filename
138 if not filename:
139 text.bell()
David Scherer7aced172000-08-15 01:13:23 +0000140 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000141 lineno = int(float(text.index("insert")))
Chui Teya2adb0f2002-11-04 22:14:54 +0000142 self.set_breakpoint(lineno)
David Scherer7aced172000-08-15 01:13:23 +0000143
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000144 def clear_breakpoint_here(self, event=None):
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000145 text = self.text
146 filename = self.io.filename
147 if not filename:
148 text.bell()
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000149 return
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000150 lineno = int(float(text.index("insert")))
151 try:
152 self.breakpoints.remove(lineno)
153 except:
154 pass
155 text.tag_remove("BREAK", "insert linestart",\
156 "insert lineend +1char")
157 try:
158 debug = self.flist.pyshell.interp.debugger
159 debug.clear_breakpoint_here(filename, lineno)
160 except:
161 pass
162
163 def clear_file_breaks(self):
164 if self.breakpoints:
165 text = self.text
166 filename = self.io.filename
167 if not filename:
168 text.bell()
169 return
170 self.breakpoints = []
171 text.tag_remove("BREAK", "1.0", END)
172 try:
173 debug = self.flist.pyshell.interp.debugger
174 debug.clear_file_breaks(filename)
175 except:
176 pass
177
Chui Teya2adb0f2002-11-04 22:14:54 +0000178 def store_file_breaks(self):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000179 "Save breakpoints when file is saved"
180 # XXX 13 Dec 2002 KBK Currently the file must be saved before it can
181 # be run. The breaks are saved at that time. If we introduce
182 # a temporary file save feature the save breaks functionality
183 # needs to be re-verified, since the breaks at the time the
184 # temp file is created may differ from the breaks at the last
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000185 # permanent save of the file. Currently, a break introduced
186 # after a save will be effective, but not persistent.
187 # This is necessary to keep the saved breaks synched with the
188 # saved file.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000189 #
190 # Breakpoints are set as tagged ranges in the text. Certain
191 # kinds of edits cause these ranges to be deleted: Inserting
192 # or deleting a line just before a breakpoint, and certain
193 # deletions prior to a breakpoint. These issues need to be
194 # investigated and understood. It's not clear if they are
195 # Tk issues or IDLE issues, or whether they can actually
196 # be fixed. Since a modified file has to be saved before it is
197 # run, and since self.breakpoints (from which the subprocess
198 # debugger is loaded) is updated during the save, the visible
199 # breaks stay synched with the subprocess even if one of these
200 # unexpected breakpoint deletions occurs.
201 breaks = self.breakpoints
202 filename = self.io.filename
Chui Teya2adb0f2002-11-04 22:14:54 +0000203 try:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000204 lines = open(self.breakpointPath,"r").readlines()
Chui Teya2adb0f2002-11-04 22:14:54 +0000205 except IOError:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000206 lines = []
207 new_file = open(self.breakpointPath,"w")
Chui Teya2adb0f2002-11-04 22:14:54 +0000208 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000209 if not line.startswith(filename + '='):
Chui Teya2adb0f2002-11-04 22:14:54 +0000210 new_file.write(line)
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000211 self.update_breakpoints()
212 breaks = self.breakpoints
213 if breaks:
214 new_file.write(filename + '=' + str(breaks) + '\n')
Chui Teya2adb0f2002-11-04 22:14:54 +0000215 new_file.close()
216
217 def restore_file_breaks(self):
218 self.text.update() # this enables setting "BREAK" tags to be visible
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000219 filename = self.io.filename
220 if filename is None:
221 return
Chui Tey69371d62002-11-04 23:39:45 +0000222 if os.path.isfile(self.breakpointPath):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000223 lines = open(self.breakpointPath,"r").readlines()
Chui Tey69371d62002-11-04 23:39:45 +0000224 for line in lines:
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000225 if line.startswith(filename + '='):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000226 breakpoint_linenumbers = eval(line[len(filename)+1:])
Chui Tey69371d62002-11-04 23:39:45 +0000227 for breakpoint_linenumber in breakpoint_linenumbers:
228 self.set_breakpoint(breakpoint_linenumber)
Chui Teya2adb0f2002-11-04 22:14:54 +0000229
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000230 def update_breakpoints(self):
231 "Retrieves all the breakpoints in the current window"
Chui Teya2adb0f2002-11-04 22:14:54 +0000232 text = self.text
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000233 ranges = text.tag_ranges("BREAK")
234 linenumber_list = self.ranges_to_linenumbers(ranges)
235 self.breakpoints = linenumber_list
236
237 def ranges_to_linenumbers(self, ranges):
238 lines = []
239 for index in range(0, len(ranges), 2):
240 lineno = int(float(ranges[index]))
241 end = int(float(ranges[index+1]))
242 while lineno < end:
243 lines.append(lineno)
244 lineno += 1
245 return lines
246
Kurt B. Kaiser11220fa2002-12-24 00:57:22 +0000247# XXX 13 Dec 2002 KBK Not used currently
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000248# def saved_change_hook(self):
249# "Extend base method - clear breaks if module is modified"
250# if not self.get_saved():
251# self.clear_file_breaks()
252# EditorWindow.saved_change_hook(self)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000253
254 def _close(self):
255 "Extend base method - clear breaks when module is closed"
256 self.clear_file_breaks()
257 EditorWindow._close(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000258
David Scherer7aced172000-08-15 01:13:23 +0000259
260class PyShellFileList(FileList):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000261 "Extend base class: file list when a shell is present"
David Scherer7aced172000-08-15 01:13:23 +0000262
263 EditorWindow = PyShellEditorWindow
264
265 pyshell = None
266
267 def open_shell(self, event=None):
268 if self.pyshell:
269 self.pyshell.wakeup()
270 else:
271 self.pyshell = PyShell(self)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000272 if self.pyshell:
273 if not self.pyshell.begin():
274 return None
David Scherer7aced172000-08-15 01:13:23 +0000275 return self.pyshell
276
277
278class ModifiedColorDelegator(ColorDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000279 "Extend base class: colorizer for the shell window itself"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000280
Steven M. Gavab77d3432002-03-02 07:16:21 +0000281 def __init__(self):
282 ColorDelegator.__init__(self)
283 self.LoadTagDefs()
David Scherer7aced172000-08-15 01:13:23 +0000284
285 def recolorize_main(self):
286 self.tag_remove("TODO", "1.0", "iomark")
287 self.tag_add("SYNC", "1.0", "iomark")
288 ColorDelegator.recolorize_main(self)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000289
Steven M. Gavab77d3432002-03-02 07:16:21 +0000290 def LoadTagDefs(self):
291 ColorDelegator.LoadTagDefs(self)
292 theme = idleConf.GetOption('main','Theme','name')
293 self.tagdefs.update({
294 "stdin": {'background':None,'foreground':None},
295 "stdout": idleConf.GetHighlight(theme, "stdout"),
296 "stderr": idleConf.GetHighlight(theme, "stderr"),
297 "console": idleConf.GetHighlight(theme, "console"),
Steven M. Gavab77d3432002-03-02 07:16:21 +0000298 None: idleConf.GetHighlight(theme, "normal"),
299 })
David Scherer7aced172000-08-15 01:13:23 +0000300
David Scherer7aced172000-08-15 01:13:23 +0000301class ModifiedUndoDelegator(UndoDelegator):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000302 "Extend base class: forbid insert/delete before the I/O mark"
David Scherer7aced172000-08-15 01:13:23 +0000303
304 def insert(self, index, chars, tags=None):
305 try:
306 if self.delegate.compare(index, "<", "iomark"):
307 self.delegate.bell()
308 return
309 except TclError:
310 pass
311 UndoDelegator.insert(self, index, chars, tags)
312
313 def delete(self, index1, index2=None):
314 try:
315 if self.delegate.compare(index1, "<", "iomark"):
316 self.delegate.bell()
317 return
318 except TclError:
319 pass
320 UndoDelegator.delete(self, index1, index2)
321
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000322
323class MyRPCClient(rpc.RPCClient):
324
325 def handle_EOF(self):
326 "Override the base class - just re-raise EOFError"
327 raise EOFError
328
Kurt B. Kaiser8d1f11b2003-05-26 22:20:34 +0000329
David Scherer7aced172000-08-15 01:13:23 +0000330class ModifiedInterpreter(InteractiveInterpreter):
331
332 def __init__(self, tkconsole):
333 self.tkconsole = tkconsole
334 locals = sys.modules['__main__'].__dict__
335 InteractiveInterpreter.__init__(self, locals=locals)
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000336 self.save_warnings_filters = None
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000337 self.restarting = False
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000338 self.subprocess_arglist = self.build_subprocess_arglist()
David Scherer7aced172000-08-15 01:13:23 +0000339
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000340 port = 8833
Chui Tey5d2af632002-05-26 13:36:41 +0000341 rpcclt = None
342 rpcpid = None
343
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000344 def spawn_subprocess(self):
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000345 args = self.subprocess_arglist
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000346 self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000347
Tony Lowndsf53dec22002-12-20 04:24:43 +0000348 def build_subprocess_arglist(self):
Tony Lownds2398d572003-05-13 15:28:21 +0000349 w = ['-W' + s for s in sys.warnoptions]
350 # Maybe IDLE is installed and is being accessed via sys.path,
351 # or maybe it's not installed and the idle.py script is being
352 # run from the IDLE source directory.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000353 del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
354 default=False, type='bool')
Tony Lownds2398d572003-05-13 15:28:21 +0000355 if __name__ == 'idlelib.PyShell':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000356 command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
Tony Lowndsf2324b92002-09-29 00:34:10 +0000357 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000358 command = "__import__('run').main(%r)" % (del_exitf,)
Kurt B. Kaiserb7855182003-08-14 14:54:28 +0000359 if sys.platform[:3] == 'win' and ' ' in sys.executable:
360 # handle embedded space in path by quoting the argument
361 decorated_exec = '"%s"' % sys.executable
362 else:
363 decorated_exec = sys.executable
364 return [decorated_exec] + w + ["-c", command, str(self.port)]
Tony Lowndsf2324b92002-09-29 00:34:10 +0000365
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000366 def start_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000367 # spawning first avoids passing a listening socket to the subprocess
368 self.spawn_subprocess()
369 #time.sleep(20) # test to simulate GUI not accepting connection
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000370 addr = (LOCALHOST, self.port)
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +0000371 # Idle starts listening for connection on localhost
Kurt B. Kaiser5db48432003-05-15 03:40:51 +0000372 for i in range(3):
Chui Tey5d2af632002-05-26 13:36:41 +0000373 time.sleep(i)
374 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000375 self.rpcclt = MyRPCClient(addr)
Chui Tey5d2af632002-05-26 13:36:41 +0000376 break
377 except socket.error, err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000378 pass
Chui Tey5d2af632002-05-26 13:36:41 +0000379 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000380 self.display_port_binding_error()
381 return None
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000382 # Accept the connection from the Python execution server
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000383 self.rpcclt.listening_sock.settimeout(10)
384 try:
385 self.rpcclt.accept()
386 except socket.timeout, err:
387 self.display_no_subprocess_error()
388 return None
Kurt B. Kaiser969de452002-06-12 03:28:57 +0000389 self.rpcclt.register("stdin", self.tkconsole)
390 self.rpcclt.register("stdout", self.tkconsole.stdout)
391 self.rpcclt.register("stderr", self.tkconsole.stderr)
Chui Tey5d2af632002-05-26 13:36:41 +0000392 self.rpcclt.register("flist", self.tkconsole.flist)
Kurt B. Kaiser8cd0def2003-01-31 05:06:43 +0000393 self.rpcclt.register("linecache", linecache)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000394 self.rpcclt.register("interp", self)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000395 self.transfer_path()
Chui Tey5d2af632002-05-26 13:36:41 +0000396 self.poll_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000397 return self.rpcclt
Chui Tey5d2af632002-05-26 13:36:41 +0000398
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000399 def restart_subprocess(self):
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000400 if self.restarting:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000401 return self.rpcclt
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000402 self.restarting = True
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000403 # close only the subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000404 debug = self.getdebugger()
405 if debug:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000406 try:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000407 # Only close subprocess debugger, don't unregister gui_adap!
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000408 RemoteDebugger.close_subprocess_debugger(self.rpcclt)
409 except:
410 pass
411 # Kill subprocess, spawn a new one, accept connection.
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000412 self.rpcclt.close()
413 self.unix_terminate()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000414 console = self.tkconsole
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000415 was_executing = console.executing
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000416 console.executing = False
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000417 self.spawn_subprocess()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000418 try:
419 self.rpcclt.accept()
420 except socket.timeout, err:
421 self.display_no_subprocess_error()
422 return None
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000423 self.transfer_path()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000424 # annotate restart in shell window and mark it
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000425 console.text.delete("iomark", "end-1c")
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000426 if was_executing:
427 console.write('\n')
428 console.showprompt()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000429 halfbar = ((int(console.width) - 16) // 2) * '='
430 console.write(halfbar + ' RESTART ' + halfbar)
431 console.text.mark_set("restart", "end-1c")
432 console.text.mark_gravity("restart", "left")
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000433 console.showprompt()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000434 # restart subprocess debugger
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000435 if debug:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000436 # Restarted debugger connects to current instance of debug GUI
Kurt B. Kaiser63857a42002-09-05 02:31:20 +0000437 gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000438 # reload remote debugger breakpoints for all PyShellEditWindows
439 debug.load_breakpoints()
Kurt B. Kaiser6f805942003-05-24 21:12:46 +0000440 self.restarting = False
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000441 return self.rpcclt
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000442
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000443 def __request_interrupt(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000444 self.rpcclt.remotecall("exec", "interrupt_the_server", (), {})
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000445
446 def interrupt_subprocess(self):
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000447 threading.Thread(target=self.__request_interrupt).start()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000448
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000449 def kill_subprocess(self):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000450 try:
451 self.rpcclt.close()
452 except AttributeError: # no socket
453 pass
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000454 self.unix_terminate()
455 self.tkconsole.executing = False
456 self.rpcclt = None
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000457
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000458 def unix_terminate(self):
459 "UNIX: make sure subprocess is terminated and collect status"
460 if hasattr(os, 'kill'):
461 try:
462 os.kill(self.rpcpid, SIGTERM)
463 except OSError:
464 # process already terminated:
465 return
466 else:
467 try:
468 os.waitpid(self.rpcpid, 0)
469 except OSError:
470 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000471
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000472 def transfer_path(self):
473 self.runcommand("""if 1:
474 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +0000475 _sys.path = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000476 del _sys
Kurt B. Kaiserb2487332003-03-04 04:03:45 +0000477 _msg = 'Use File/Exit or your end-of-file key to quit IDLE'
478 __builtins__.quit = __builtins__.exit = _msg
479 del _msg
Walter Dörwald70a6b492004-02-12 17:35:32 +0000480 \n""" % (sys.path,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000481
Chui Tey5d2af632002-05-26 13:36:41 +0000482 active_seq = None
483
484 def poll_subprocess(self):
485 clt = self.rpcclt
486 if clt is None:
487 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000488 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000489 response = clt.pollresponse(self.active_seq, wait=0.05)
490 except (EOFError, IOError, KeyboardInterrupt):
491 # lost connection or subprocess terminated itself, restart
492 # [the KBI is from rpc.SocketIO.handle_EOF()]
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000493 if self.tkconsole.closing:
494 return
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000495 response = None
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000496 self.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000497 if response:
498 self.tkconsole.resetoutput()
499 self.active_seq = None
500 how, what = response
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000501 console = self.tkconsole.console
Chui Tey5d2af632002-05-26 13:36:41 +0000502 if how == "OK":
503 if what is not None:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000504 print >>console, repr(what)
Chui Tey5d2af632002-05-26 13:36:41 +0000505 elif how == "EXCEPTION":
Chui Tey5d2af632002-05-26 13:36:41 +0000506 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
507 self.remote_stack_viewer()
508 elif how == "ERROR":
Kurt B. Kaiser0930c432002-12-06 21:45:24 +0000509 errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
510 print >>sys.__stderr__, errmsg, what
Kurt B. Kaiserbc286132003-01-25 21:33:40 +0000511 print >>console, errmsg, what
512 # we received a response to the currently active seq number:
Chui Tey5d2af632002-05-26 13:36:41 +0000513 self.tkconsole.endexecuting()
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000514 # Reschedule myself
515 if not self.tkconsole.closing:
516 self.tkconsole.text.after(self.tkconsole.pollinterval,
517 self.poll_subprocess)
Chui Tey5d2af632002-05-26 13:36:41 +0000518
Kurt B. Kaiser45186c42002-10-23 04:48:08 +0000519 debugger = None
520
521 def setdebugger(self, debugger):
522 self.debugger = debugger
523
524 def getdebugger(self):
525 return self.debugger
526
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000527 def open_remote_stack_viewer(self):
528 """Initiate the remote stack viewer from a separate thread.
529
530 This method is called from the subprocess, and by returning from this
531 method we allow the subprocess to unblock. After a bit the shell
532 requests the subprocess to open the remote stack viewer which returns a
533 static object looking at the last exceptiopn. It is queried through
534 the RPC mechanism.
535
536 """
537 self.tkconsole.text.after(300, self.remote_stack_viewer)
538 return
539
Chui Tey5d2af632002-05-26 13:36:41 +0000540 def remote_stack_viewer(self):
541 import RemoteObjectBrowser
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000542 oid = self.rpcclt.remotequeue("exec", "stackviewer", ("flist",), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000543 if oid is None:
544 self.tkconsole.root.bell()
545 return
546 item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
547 from TreeWidget import ScrolledCanvas, TreeNode
548 top = Toplevel(self.tkconsole.root)
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000549 theme = idleConf.GetOption('main','Theme','name')
550 background = idleConf.GetHighlight(theme, 'normal')['background']
551 sc = ScrolledCanvas(top, bg=background, highlightthickness=0)
Chui Tey5d2af632002-05-26 13:36:41 +0000552 sc.frame.pack(expand=1, fill="both")
553 node = TreeNode(sc.canvas, None, item)
554 node.expand()
555 # XXX Should GC the remote tree when closing the window
556
David Scherer7aced172000-08-15 01:13:23 +0000557 gid = 0
558
559 def execsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000560 "Like runsource() but assumes complete exec source"
David Scherer7aced172000-08-15 01:13:23 +0000561 filename = self.stuffsource(source)
562 self.execfile(filename, source)
563
564 def execfile(self, filename, source=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000565 "Execute an existing file"
David Scherer7aced172000-08-15 01:13:23 +0000566 if source is None:
567 source = open(filename, "r").read()
568 try:
569 code = compile(source, filename, "exec")
570 except (OverflowError, SyntaxError):
571 self.tkconsole.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000572 tkerr = self.tkconsole.stderr
573 print>>tkerr, '*** Error in script or command!\n'
574 print>>tkerr, 'Traceback (most recent call last):'
David Scherer7aced172000-08-15 01:13:23 +0000575 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000576 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000577 else:
578 self.runcode(code)
579
580 def runsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000581 "Extend base class method: Stuff the source in the line cache first"
David Scherer7aced172000-08-15 01:13:23 +0000582 filename = self.stuffsource(source)
583 self.more = 0
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000584 self.save_warnings_filters = warnings.filters[:]
585 warnings.filterwarnings(action="error", category=SyntaxWarning)
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000586 if isinstance(source, types.UnicodeType):
587 import IOBinding
588 try:
589 source = source.encode(IOBinding.encoding)
590 except UnicodeError:
591 self.tkconsole.resetoutput()
592 self.write("Unsupported characters in input")
593 return
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000594 try:
595 return InteractiveInterpreter.runsource(self, source, filename)
596 finally:
597 if self.save_warnings_filters is not None:
598 warnings.filters[:] = self.save_warnings_filters
599 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000600
601 def stuffsource(self, source):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000602 "Stuff source in the filename cache"
David Scherer7aced172000-08-15 01:13:23 +0000603 filename = "<pyshell#%d>" % self.gid
604 self.gid = self.gid + 1
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000605 lines = source.split("\n")
David Scherer7aced172000-08-15 01:13:23 +0000606 linecache.cache[filename] = len(source)+1, 0, lines, filename
607 return filename
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000608
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000609 def prepend_syspath(self, filename):
610 "Prepend sys.path with file's directory if not already included"
611 self.runcommand("""if 1:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000612 _filename = %r
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000613 import sys as _sys
614 from os.path import dirname as _dirname
615 _dir = _dirname(_filename)
616 if not _dir in _sys.path:
617 _sys.path.insert(0, _dir)
618 del _filename, _sys, _dirname, _dir
Walter Dörwald70a6b492004-02-12 17:35:32 +0000619 \n""" % (filename,))
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +0000620
David Scherer7aced172000-08-15 01:13:23 +0000621 def showsyntaxerror(self, filename=None):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000622 """Extend base class method: Add Colorizing
623
624 Color the offending position instead of printing it and pointing at it
625 with a caret.
626
627 """
David Scherer7aced172000-08-15 01:13:23 +0000628 text = self.tkconsole.text
629 stuff = self.unpackerror()
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000630 if stuff:
631 msg, lineno, offset, line = stuff
632 if lineno == 1:
633 pos = "iomark + %d chars" % (offset-1)
634 else:
635 pos = "iomark linestart + %d lines + %d chars" % \
636 (lineno-1, offset-1)
637 text.tag_add("ERROR", pos)
638 text.see(pos)
639 char = text.get(pos)
640 if char and char in IDENTCHARS:
641 text.tag_add("ERROR", pos + " wordstart", pos)
642 self.tkconsole.resetoutput()
643 self.write("SyntaxError: %s\n" % str(msg))
644 else:
David Scherer7aced172000-08-15 01:13:23 +0000645 self.tkconsole.resetoutput()
646 InteractiveInterpreter.showsyntaxerror(self, filename)
Kurt B. Kaiser6e44cc22002-11-30 06:18:00 +0000647 self.tkconsole.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000648
649 def unpackerror(self):
650 type, value, tb = sys.exc_info()
651 ok = type is SyntaxError
652 if ok:
653 try:
654 msg, (dummy_filename, lineno, offset, line) = value
Kurt B. Kaiserbea57c62003-07-09 04:27:24 +0000655 if not offset:
656 offset = 0
David Scherer7aced172000-08-15 01:13:23 +0000657 except:
658 ok = 0
659 if ok:
660 return msg, lineno, offset, line
661 else:
662 return None
663
664 def showtraceback(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000665 "Extend base class method to reset output properly"
David Scherer7aced172000-08-15 01:13:23 +0000666 self.tkconsole.resetoutput()
667 self.checklinecache()
668 InteractiveInterpreter.showtraceback(self)
Chui Tey5d2af632002-05-26 13:36:41 +0000669 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
670 self.tkconsole.open_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +0000671
672 def checklinecache(self):
673 c = linecache.cache
674 for key in c.keys():
675 if key[:1] + key[-1:] != "<>":
676 del c[key]
677
Chui Tey5d2af632002-05-26 13:36:41 +0000678 def runcommand(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000679 "Run the code without invoking the debugger"
Chui Tey5d2af632002-05-26 13:36:41 +0000680 # The code better not raise an exception!
681 if self.tkconsole.executing:
Neal Norwitzf4c4f112002-11-30 18:49:10 +0000682 self.display_executing_dialog()
Chui Tey5d2af632002-05-26 13:36:41 +0000683 return 0
684 if self.rpcclt:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000685 self.rpcclt.remotequeue("exec", "runcode", (code,), {})
Chui Tey5d2af632002-05-26 13:36:41 +0000686 else:
687 exec code in self.locals
688 return 1
689
David Scherer7aced172000-08-15 01:13:23 +0000690 def runcode(self, code):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000691 "Override base class method"
Chui Tey5d2af632002-05-26 13:36:41 +0000692 if self.tkconsole.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000693 self.interp.restart_subprocess()
Chui Tey5d2af632002-05-26 13:36:41 +0000694 self.checklinecache()
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000695 if self.save_warnings_filters is not None:
696 warnings.filters[:] = self.save_warnings_filters
697 self.save_warnings_filters = None
David Scherer7aced172000-08-15 01:13:23 +0000698 debugger = self.debugger
699 try:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000700 self.tkconsole.beginexecuting()
701 try:
702 if not debugger and self.rpcclt is not None:
703 self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
704 (code,), {})
705 elif debugger:
706 debugger.run(code, self.locals)
707 else:
708 exec code in self.locals
709 except SystemExit:
710 if tkMessageBox.askyesno(
711 "Exit?",
712 "Do you want to exit altogether?",
713 default="yes",
714 master=self.tkconsole.text):
715 raise
716 else:
717 self.showtraceback()
718 except:
David Scherer7aced172000-08-15 01:13:23 +0000719 self.showtraceback()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000720 finally:
721 if not use_subprocess:
722 self.tkconsole.endexecuting()
David Scherer7aced172000-08-15 01:13:23 +0000723
724 def write(self, s):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000725 "Override base class method"
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000726 self.tkconsole.stderr.write(s)
David Scherer7aced172000-08-15 01:13:23 +0000727
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000728 def display_port_binding_error(self):
729 tkMessageBox.showerror(
730 "Port Binding Error",
731 "IDLE can't bind TCP/IP port 8833, which is necessary to "
732 "communicate with its Python execution server. Either "
733 "no networking is installed on this computer or another "
734 "process (another IDLE?) is using the port. Run IDLE with the -n "
735 "command line switch to start without a subprocess and refer to "
736 "Help/IDLE Help 'Running without a subprocess' for further "
737 "details.",
738 master=self.tkconsole.text)
739
740 def display_no_subprocess_error(self):
741 tkMessageBox.showerror(
742 "Subprocess Startup Error",
743 "IDLE's subprocess didn't make connection. Either IDLE can't "
744 "start a subprocess or personal firewall software is blocking "
745 "the connection.",
746 master=self.tkconsole.text)
747
748 def display_executing_dialog(self):
749 tkMessageBox.showerror(
750 "Already executing",
751 "The Python Shell window is already executing a command; "
752 "please wait until it is finished.",
753 master=self.tkconsole.text)
754
755
David Scherer7aced172000-08-15 01:13:23 +0000756class PyShell(OutputWindow):
757
758 shell_title = "Python Shell"
759
760 # Override classes
761 ColorDelegator = ModifiedColorDelegator
762 UndoDelegator = ModifiedUndoDelegator
763
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +0000764 # Override menus
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000765 menu_specs = [
766 ("file", "_File"),
767 ("edit", "_Edit"),
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000768 ("debug", "_Debug"),
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000769 ("options", "_Options"),
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +0000770 ("windows", "_Windows"),
771 ("help", "_Help"),
772 ]
David Scherer7aced172000-08-15 01:13:23 +0000773
774 # New classes
775 from IdleHistory import History
776
777 def __init__(self, flist=None):
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000778 if use_subprocess:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000779 ms = self.menu_specs
780 if ms[2][0] != "shell":
781 ms.insert(2, ("shell", "_Shell"))
David Scherer7aced172000-08-15 01:13:23 +0000782 self.interp = ModifiedInterpreter(self)
783 if flist is None:
784 root = Tk()
785 fixwordbreaks(root)
786 root.withdraw()
787 flist = PyShellFileList(root)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000788 #
David Scherer7aced172000-08-15 01:13:23 +0000789 OutputWindow.__init__(self, flist, None, None)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000790 #
David Scherer7aced172000-08-15 01:13:23 +0000791 import __builtin__
792 __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000793 #
Kurt B. Kaiseree7afca2002-09-14 02:50:56 +0000794 self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000795 #
David Scherer7aced172000-08-15 01:13:23 +0000796 text = self.text
797 text.configure(wrap="char")
798 text.bind("<<newline-and-indent>>", self.enter_callback)
799 text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
800 text.bind("<<interrupt-execution>>", self.cancel_callback)
801 text.bind("<<beginning-of-line>>", self.home_callback)
802 text.bind("<<end-of-file>>", self.eof_callback)
803 text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
Kurt B. Kaiser57bfe5d2003-05-10 00:09:52 +0000804 text.bind("<<toggle-debugger>>", self.toggle_debugger)
David Scherer7aced172000-08-15 01:13:23 +0000805 text.bind("<<open-python-shell>>", self.flist.open_shell)
806 text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000807 if use_subprocess:
808 text.bind("<<view-restart>>", self.view_restart_mark)
809 text.bind("<<restart-shell>>", self.restart_shell)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000810 #
David Scherer7aced172000-08-15 01:13:23 +0000811 self.save_stdout = sys.stdout
812 self.save_stderr = sys.stderr
813 self.save_stdin = sys.stdin
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000814 import IOBinding
815 self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
816 self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
817 self.console = PseudoFile(self, "console", IOBinding.encoding)
Chui Tey5d2af632002-05-26 13:36:41 +0000818 if not use_subprocess:
819 sys.stdout = self.stdout
820 sys.stderr = self.stderr
821 sys.stdin = self
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000822 #
David Scherer7aced172000-08-15 01:13:23 +0000823 self.history = self.History(self.text)
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000824 #
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000825 self.pollinterval = 50 # millisec
Chui Tey5d2af632002-05-26 13:36:41 +0000826
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000827 def get_standard_extension_names(self):
828 return idleConf.GetExtensions(shell_only=True)
829
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000830 reading = False
831 executing = False
832 canceled = False
833 endoffile = False
834 closing = False
David Scherer7aced172000-08-15 01:13:23 +0000835
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +0000836 def set_warning_stream(self, stream):
837 global warning_stream
838 warning_stream = stream
839
840 def get_warning_stream(self):
841 return warning_stream
842
David Scherer7aced172000-08-15 01:13:23 +0000843 def toggle_debugger(self, event=None):
844 if self.executing:
845 tkMessageBox.showerror("Don't debug now",
846 "You can only toggle the debugger when idle",
847 master=self.text)
848 self.set_debugger_indicator()
849 return "break"
850 else:
851 db = self.interp.getdebugger()
852 if db:
853 self.close_debugger()
854 else:
855 self.open_debugger()
856
857 def set_debugger_indicator(self):
858 db = self.interp.getdebugger()
859 self.setvar("<<toggle-debugger>>", not not db)
860
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000861 def toggle_jit_stack_viewer(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000862 pass # All we need is the variable
863
864 def close_debugger(self):
865 db = self.interp.getdebugger()
866 if db:
867 self.interp.setdebugger(None)
868 db.close()
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000869 if self.interp.rpcclt:
870 RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000871 self.resetoutput()
872 self.console.write("[DEBUG OFF]\n")
873 sys.ps1 = ">>> "
874 self.showprompt()
875 self.set_debugger_indicator()
876
877 def open_debugger(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000878 if self.interp.rpcclt:
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000879 dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
880 self)
881 else:
882 dbg_gui = Debugger.Debugger(self)
883 self.interp.setdebugger(dbg_gui)
884 dbg_gui.load_breakpoints()
Chui Tey5d2af632002-05-26 13:36:41 +0000885 sys.ps1 = "[DEBUG ON]\n>>> "
886 self.showprompt()
887 self.set_debugger_indicator()
888
David Scherer7aced172000-08-15 01:13:23 +0000889 def beginexecuting(self):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000890 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000891 self.resetoutput()
892 self.executing = 1
David Scherer7aced172000-08-15 01:13:23 +0000893
894 def endexecuting(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000895 "Helper for ModifiedInterpreter"
David Scherer7aced172000-08-15 01:13:23 +0000896 self.executing = 0
897 self.canceled = 0
Chui Tey5d2af632002-05-26 13:36:41 +0000898 self.showprompt()
David Scherer7aced172000-08-15 01:13:23 +0000899
900 def close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000901 "Extend EditorWindow.close()"
David Scherer7aced172000-08-15 01:13:23 +0000902 if self.executing:
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000903 response = tkMessageBox.askokcancel(
David Scherer7aced172000-08-15 01:13:23 +0000904 "Kill?",
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000905 "The program is still running!\n Do you want to kill it?",
David Scherer7aced172000-08-15 01:13:23 +0000906 default="ok",
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000907 parent=self.text)
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000908 if response == False:
David Scherer7aced172000-08-15 01:13:23 +0000909 return "cancel"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000910 self.closing = True
911 # Wait for poll_subprocess() rescheduling to stop
912 self.text.after(2 * self.pollinterval, self.close2)
Kurt B. Kaiser88957d82003-05-19 23:11:51 +0000913
914 def close2(self):
915 return EditorWindow.close(self)
David Scherer7aced172000-08-15 01:13:23 +0000916
917 def _close(self):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000918 "Extend EditorWindow._close(), shut down debugger and execution server"
David Scherer7aced172000-08-15 01:13:23 +0000919 self.close_debugger()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000920 if use_subprocess:
921 self.interp.kill_subprocess()
David Scherer7aced172000-08-15 01:13:23 +0000922 # Restore std streams
923 sys.stdout = self.save_stdout
924 sys.stderr = self.save_stderr
925 sys.stdin = self.save_stdin
926 # Break cycles
927 self.interp = None
928 self.console = None
David Scherer7aced172000-08-15 01:13:23 +0000929 self.flist.pyshell = None
930 self.history = None
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000931 EditorWindow._close(self)
David Scherer7aced172000-08-15 01:13:23 +0000932
933 def ispythonsource(self, filename):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000934 "Override EditorWindow method: never remove the colorizer"
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000935 return True
David Scherer7aced172000-08-15 01:13:23 +0000936
937 def short_title(self):
938 return self.shell_title
939
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000940 COPYRIGHT = \
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +0000941 'Type "copyright", "credits" or "license()" for more information.'
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000942
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000943 firewallmessage = """
944 ****************************************************************
945 Personal firewall software may warn about the connection IDLE
946 makes to its subprocess using this computer's internal loopback
947 interface. This connection is not visible on any external
948 interface and no data is sent to or received from the Internet.
949 ****************************************************************
950 """
951
David Scherer7aced172000-08-15 01:13:23 +0000952 def begin(self):
953 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000954 if use_subprocess:
955 nosub = ''
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000956 client = self.interp.start_subprocess()
957 if not client:
958 self.close()
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000959 return False
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +0000960 else:
961 nosub = "==== No Subprocess ===="
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000962 self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
Kurt B. Kaiser94bd7742001-07-14 00:13:28 +0000963 (sys.version, sys.platform, self.COPYRIGHT,
Kurt B. Kaiser220fecf2003-07-27 03:24:19 +0000964 self.firewallmessage, idlever.IDLE_VERSION, nosub))
David Scherer7aced172000-08-15 01:13:23 +0000965 self.showprompt()
966 import Tkinter
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000967 Tkinter._default_root = None # 03Jan04 KBK What's this?
Kurt B. Kaiser76637292004-01-21 22:10:01 +0000968 return True
David Scherer7aced172000-08-15 01:13:23 +0000969
970 def readline(self):
971 save = self.reading
972 try:
973 self.reading = 1
974 self.top.mainloop()
975 finally:
976 self.reading = save
977 line = self.text.get("iomark", "end-1c")
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000978 if isinstance(line, unicode):
979 import IOBinding
980 try:
981 line = line.encode(IOBinding.encoding)
982 except UnicodeError:
983 pass
David Scherer7aced172000-08-15 01:13:23 +0000984 self.resetoutput()
985 if self.canceled:
986 self.canceled = 0
987 raise KeyboardInterrupt
988 if self.endoffile:
989 self.endoffile = 0
990 return ""
991 return line
992
993 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +0000994 return True
David Scherer7aced172000-08-15 01:13:23 +0000995
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000996 def cancel_callback(self, event=None):
David Scherer7aced172000-08-15 01:13:23 +0000997 try:
998 if self.text.compare("sel.first", "!=", "sel.last"):
999 return # Active selection -- always use default binding
1000 except:
1001 pass
1002 if not (self.executing or self.reading):
1003 self.resetoutput()
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001004 self.interp.write("KeyboardInterrupt\n")
David Scherer7aced172000-08-15 01:13:23 +00001005 self.showprompt()
1006 return "break"
1007 self.endoffile = 0
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001008 self.canceled = 1
David Scherer7aced172000-08-15 01:13:23 +00001009 if self.reading:
1010 self.top.quit()
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001011 elif (self.executing and self.interp.rpcclt):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001012 if self.interp.getdebugger():
1013 self.interp.restart_subprocess()
1014 else:
1015 self.interp.interrupt_subprocess()
David Scherer7aced172000-08-15 01:13:23 +00001016 return "break"
1017
1018 def eof_callback(self, event):
1019 if self.executing and not self.reading:
1020 return # Let the default binding (delete next char) take over
1021 if not (self.text.compare("iomark", "==", "insert") and
1022 self.text.compare("insert", "==", "end-1c")):
1023 return # Let the default binding (delete next char) take over
1024 if not self.executing:
David Scherer7aced172000-08-15 01:13:23 +00001025 self.resetoutput()
1026 self.close()
1027 else:
1028 self.canceled = 0
1029 self.endoffile = 1
1030 self.top.quit()
1031 return "break"
1032
1033 def home_callback(self, event):
1034 if event.state != 0 and event.keysym == "Home":
1035 return # <Modifier-Home>; fall back to class binding
1036 if self.text.compare("iomark", "<=", "insert") and \
1037 self.text.compare("insert linestart", "<=", "iomark"):
1038 self.text.mark_set("insert", "iomark")
1039 self.text.tag_remove("sel", "1.0", "end")
1040 self.text.see("insert")
1041 return "break"
1042
1043 def linefeed_callback(self, event):
1044 # Insert a linefeed without entering anything (still autoindented)
1045 if self.reading:
1046 self.text.insert("insert", "\n")
1047 self.text.see("insert")
1048 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001049 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001050 return "break"
1051
1052 def enter_callback(self, event):
1053 if self.executing and not self.reading:
1054 return # Let the default binding (insert '\n') take over
1055 # If some text is selected, recall the selection
1056 # (but only if this before the I/O mark)
1057 try:
1058 sel = self.text.get("sel.first", "sel.last")
1059 if sel:
1060 if self.text.compare("sel.last", "<=", "iomark"):
1061 self.recall(sel)
1062 return "break"
1063 except:
1064 pass
1065 # If we're strictly before the line containing iomark, recall
1066 # the current line, less a leading prompt, less leading or
1067 # trailing whitespace
1068 if self.text.compare("insert", "<", "iomark linestart"):
1069 # Check if there's a relevant stdin range -- if so, use it
1070 prev = self.text.tag_prevrange("stdin", "insert")
1071 if prev and self.text.compare("insert", "<", prev[1]):
1072 self.recall(self.text.get(prev[0], prev[1]))
1073 return "break"
1074 next = self.text.tag_nextrange("stdin", "insert")
1075 if next and self.text.compare("insert lineend", ">=", next[0]):
1076 self.recall(self.text.get(next[0], next[1]))
1077 return "break"
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001078 # No stdin mark -- just get the current line, less any prompt
1079 line = self.text.get("insert linestart", "insert lineend")
1080 last_line_of_prompt = sys.ps1.split('\n')[-1]
1081 if line.startswith(last_line_of_prompt):
1082 line = line[len(last_line_of_prompt):]
1083 self.recall(line)
David Scherer7aced172000-08-15 01:13:23 +00001084 return "break"
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001085 # If we're between the beginning of the line and the iomark, i.e.
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001086 # in the prompt area, move to the end of the prompt
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001087 if self.text.compare("insert", "<", "iomark"):
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001088 self.text.mark_set("insert", "iomark")
David Scherer7aced172000-08-15 01:13:23 +00001089 # If we're in the current input and there's only whitespace
1090 # beyond the cursor, erase that whitespace first
1091 s = self.text.get("insert", "end-1c")
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001092 if s and not s.strip():
David Scherer7aced172000-08-15 01:13:23 +00001093 self.text.delete("insert", "end-1c")
1094 # If we're in the current input before its last line,
1095 # insert a newline right at the insert point
1096 if self.text.compare("insert", "<", "end-1c linestart"):
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001097 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001098 return "break"
1099 # We're in the last line; append a newline and submit it
1100 self.text.mark_set("insert", "end-1c")
1101 if self.reading:
1102 self.text.insert("insert", "\n")
1103 self.text.see("insert")
1104 else:
Kurt B. Kaiser822a77f2002-12-16 02:07:11 +00001105 self.newline_and_indent_event(event)
David Scherer7aced172000-08-15 01:13:23 +00001106 self.text.tag_add("stdin", "iomark", "end-1c")
1107 self.text.update_idletasks()
1108 if self.reading:
1109 self.top.quit() # Break out of recursive mainloop() in raw_input()
1110 else:
1111 self.runit()
1112 return "break"
1113
1114 def recall(self, s):
1115 if self.history:
1116 self.history.recall(s)
1117
1118 def runit(self):
1119 line = self.text.get("iomark", "end-1c")
1120 # Strip off last newline and surrounding whitespace.
1121 # (To allow you to hit return twice to end a statement.)
1122 i = len(line)
1123 while i > 0 and line[i-1] in " \t":
1124 i = i-1
1125 if i > 0 and line[i-1] == "\n":
1126 i = i-1
1127 while i > 0 and line[i-1] in " \t":
1128 i = i-1
1129 line = line[:i]
1130 more = self.interp.runsource(line)
David Scherer7aced172000-08-15 01:13:23 +00001131
David Scherer7aced172000-08-15 01:13:23 +00001132 def open_stack_viewer(self, event=None):
Chui Tey5d2af632002-05-26 13:36:41 +00001133 if self.interp.rpcclt:
1134 return self.interp.remote_stack_viewer()
David Scherer7aced172000-08-15 01:13:23 +00001135 try:
1136 sys.last_traceback
1137 except:
1138 tkMessageBox.showerror("No stack trace",
1139 "There is no stack trace yet.\n"
1140 "(sys.last_traceback is not defined)",
1141 master=self.text)
1142 return
1143 from StackViewer import StackBrowser
1144 sv = StackBrowser(self.root, self.flist)
1145
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001146 def view_restart_mark(self, event=None):
1147 self.text.see("iomark")
1148 self.text.see("restart")
1149
1150 def restart_shell(self, event=None):
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +00001151 self.interp.restart_subprocess()
Kurt B. Kaiser1061e722003-01-04 01:43:53 +00001152
David Scherer7aced172000-08-15 01:13:23 +00001153 def showprompt(self):
1154 self.resetoutput()
1155 try:
1156 s = str(sys.ps1)
1157 except:
1158 s = ""
1159 self.console.write(s)
1160 self.text.mark_set("insert", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001161 self.set_line_and_column()
Kurt B. Kaiserdc1e7092002-07-11 04:33:41 +00001162 self.io.reset_undo()
David Scherer7aced172000-08-15 01:13:23 +00001163
1164 def resetoutput(self):
1165 source = self.text.get("iomark", "end-1c")
1166 if self.history:
1167 self.history.history_store(source)
1168 if self.text.get("end-2c") != "\n":
1169 self.text.insert("end-1c", "\n")
1170 self.text.mark_set("iomark", "end-1c")
Chui Tey5d2af632002-05-26 13:36:41 +00001171 self.set_line_and_column()
David Scherer7aced172000-08-15 01:13:23 +00001172 sys.stdout.softspace = 0
1173
1174 def write(self, s, tags=()):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +00001175 try:
1176 self.text.mark_gravity("iomark", "right")
1177 OutputWindow.write(self, s, tags, "iomark")
1178 self.text.mark_gravity("iomark", "left")
1179 except:
1180 pass
David Scherer7aced172000-08-15 01:13:23 +00001181 if self.canceled:
1182 self.canceled = 0
Kurt B. Kaiser7f38ec02003-05-15 03:19:42 +00001183 if not use_subprocess:
1184 raise KeyboardInterrupt
David Scherer7aced172000-08-15 01:13:23 +00001185
1186class PseudoFile:
1187
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001188 def __init__(self, shell, tags, encoding=None):
David Scherer7aced172000-08-15 01:13:23 +00001189 self.shell = shell
1190 self.tags = tags
Chui Tey5d2af632002-05-26 13:36:41 +00001191 self.softspace = 0
Martin v. Löwisbcc651a2003-06-22 07:52:56 +00001192 self.encoding = encoding
David Scherer7aced172000-08-15 01:13:23 +00001193
1194 def write(self, s):
1195 self.shell.write(s, self.tags)
1196
1197 def writelines(self, l):
1198 map(self.write, l)
1199
1200 def flush(self):
1201 pass
1202
1203 def isatty(self):
Kurt B. Kaiser837d15c2002-09-18 02:29:59 +00001204 return True
David Scherer7aced172000-08-15 01:13:23 +00001205
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001206
David Scherer7aced172000-08-15 01:13:23 +00001207usage_msg = """\
David Scherer7aced172000-08-15 01:13:23 +00001208
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001209USAGE: idle [-deins] [-t title] [file]*
1210 idle [-dns] [-t title] (-c cmd | -r file) [arg]*
1211 idle [-dns] [-t title] - [arg]*
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001212
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001213 -h print this help message and exit
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001214 -n run IDLE without a subprocess (see Help/IDLE Help for details)
David Scherer7aced172000-08-15 01:13:23 +00001215
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001216The following options will override the IDLE 'settings' configuration:
Kurt B. Kaiser96d88422001-07-17 04:59:01 +00001217
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001218 -e open an edit window
1219 -i open a shell window
1220
1221The following options imply -i and will open a shell:
1222
1223 -c cmd run the command in a shell, or
1224 -r file run script from file
1225
1226 -d enable the debugger
1227 -s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
1228 -t title set title of shell window
1229
1230A default edit window will be bypassed when -c, -r, or - are used.
1231
1232[arg]* are passed to the command (-c) or script (-r) in sys.argv[1:].
1233
1234Examples:
1235
1236idle
1237 Open an edit window or shell depending on IDLE's configuration.
1238
1239idle foo.py foobar.py
1240 Edit the files, also open a shell if configured to start with shell.
1241
1242idle -est "Baz" foo.py
1243 Run $IDLESTARTUP or $PYTHONSTARTUP, edit foo.py, and open a shell
1244 window with the title "Baz".
1245
1246idle -c "import sys; print sys.argv" "foo"
1247 Open a shell window and run the command, passing "-c" in sys.argv[0]
1248 and "foo" in sys.argv[1].
1249
1250idle -d -s -r foo.py "Hello World"
1251 Open a shell window, run a startup script, enable the debugger, and
1252 run foo.py, passing "foo.py" in sys.argv[0] and "Hello World" in
1253 sys.argv[1].
1254
1255echo "import sys; print sys.argv" | idle - "foobar"
1256 Open a shell window, run the script piped in, passing '' in sys.argv[0]
1257 and "foobar" in sys.argv[1].
David Scherer7aced172000-08-15 01:13:23 +00001258"""
1259
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001260def main():
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001261 global flist, root, use_subprocess
David Scherer7aced172000-08-15 01:13:23 +00001262
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001263 use_subprocess = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001264 enable_shell = False
1265 enable_edit = False
1266 debug = False
1267 cmd = None
1268 script = None
1269 startup = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001270 try:
Kurt B. Kaiser4ada7ad2002-12-29 22:03:38 +00001271 sys.ps1
1272 except AttributeError:
1273 sys.ps1 = '>>> '
1274 try:
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001275 opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001276 except getopt.error, msg:
1277 sys.stderr.write("Error: %s\n" % str(msg))
1278 sys.stderr.write(usage_msg)
1279 sys.exit(2)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001280 for o, a in opts:
1281 if o == '-c':
1282 cmd = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001283 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001284 if o == '-d':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001285 debug = True
1286 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001287 if o == '-e':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001288 enable_edit = True
1289 if o == '-h':
1290 sys.stdout.write(usage_msg)
1291 sys.exit()
1292 if o == '-i':
1293 enable_shell = True
Kurt B. Kaiser8f570a72003-05-15 18:52:51 +00001294 if o == '-n':
1295 use_subprocess = False
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001296 if o == '-r':
1297 script = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001298 if os.path.isfile(script):
1299 pass
1300 else:
1301 print "No script file: ", script
1302 sys.exit()
1303 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001304 if o == '-s':
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001305 startup = True
1306 enable_shell = True
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001307 if o == '-t':
1308 PyShell.shell_title = a
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001309 enable_shell = True
1310 if args and args[0] == '-':
1311 cmd = sys.stdin.read()
1312 enable_shell = True
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001313 # process sys.argv and sys.path:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001314 for i in range(len(sys.path)):
1315 sys.path[i] = os.path.abspath(sys.path[i])
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001316 if args and args[0] == '-':
1317 sys.argv = [''] + args[1:]
1318 elif cmd:
1319 sys.argv = ['-c'] + args
1320 elif script:
1321 sys.argv = [script] + args
1322 elif args:
1323 enable_edit = True
1324 pathx = []
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001325 for filename in args:
1326 pathx.append(os.path.dirname(filename))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001327 for dir in pathx:
1328 dir = os.path.abspath(dir)
1329 if not dir in sys.path:
1330 sys.path.insert(0, dir)
Kurt B. Kaiserff002b92002-12-21 21:39:11 +00001331 else:
1332 dir = os.getcwd()
1333 if not dir in sys.path:
1334 sys.path.insert(0, dir)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001335 # check the IDLE settings configuration (but command line overrides)
1336 edit_start = idleConf.GetOption('main', 'General',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001337 'editor-on-startup', type='bool')
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001338 enable_edit = enable_edit or edit_start
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00001339 enable_shell = enable_shell or not edit_start
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001340 # start editor and/or shell windows:
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001341 root = Tk(className="Idle")
1342 fixwordbreaks(root)
1343 root.withdraw()
1344 flist = PyShellFileList(root)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001345 if enable_edit:
1346 if not (cmd or script):
1347 for filename in args:
1348 flist.open(filename)
1349 if not args:
1350 flist.new()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001351 if enable_shell:
1352 if not flist.open_shell():
1353 return # couldn't open shell
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001354 shell = flist.pyshell
1355 # handle remaining options:
1356 if debug:
1357 shell.open_debugger()
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001358 if startup:
1359 filename = os.environ.get("IDLESTARTUP") or \
1360 os.environ.get("PYTHONSTARTUP")
1361 if filename and os.path.isfile(filename):
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001362 shell.interp.execfile(filename)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +00001363 if shell and cmd or script:
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001364 shell.interp.runcommand("""if 1:
1365 import sys as _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001366 _sys.argv = %r
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001367 del _sys
Walter Dörwald70a6b492004-02-12 17:35:32 +00001368 \n""" % (sys.argv,))
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001369 if cmd:
1370 shell.interp.execsource(cmd)
1371 elif script:
Kurt B. Kaiser11659ad2003-05-15 23:23:21 +00001372 shell.interp.prepend_syspath(script)
Kurt B. Kaiserf06eed02002-12-11 04:42:04 +00001373 shell.interp.execfile(script)
Kurt B. Kaiser969de452002-06-12 03:28:57 +00001374 root.mainloop()
1375 root.destroy()
1376
David Scherer7aced172000-08-15 01:13:23 +00001377if __name__ == "__main__":
Kurt B. Kaiser9e8b8282003-06-15 17:38:45 +00001378 sys.modules['PyShell'] = sys.modules['__main__']
David Scherer7aced172000-08-15 01:13:23 +00001379 main()